8277882: New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x"

Reviewed-by: dlong, iveresov
This commit is contained in:
Zhiqiang Zang 2021-12-09 00:18:59 +00:00 committed by Igor Veresov
parent 83e6a4c0e9
commit 352435581e
3 changed files with 272 additions and 15 deletions

View File

@ -196,16 +196,23 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){
}
}
// Convert "x - (y+c0)" into "(x-y) - c0"
// Convert "x - (y+c0)" into "(x-y) - c0" AND
// Convert "c1 - (y+c0)" into "(c1-c0) - y"
// Need the same check as in above optimization but reversed.
if (op2 == Op_AddI && ok_to_convert(in2, in1)) {
if (op2 == Op_AddI
&& ok_to_convert(in2, in1)
&& in2->in(2)->Opcode() == Op_ConI) {
jint c0 = phase->type(in2->in(2))->isa_int()->get_con();
Node* in21 = in2->in(1);
Node* in22 = in2->in(2);
const TypeInt* tcon = phase->type(in22)->isa_int();
if (tcon != NULL && tcon->is_con()) {
Node* sub2 = phase->transform( new SubINode(in1, in21) );
Node* neg_c0 = phase->intcon(- tcon->get_con());
if (in1->Opcode() == Op_ConI) {
// Match c1
jint c1 = phase->type(in1)->isa_int()->get_con();
Node* sub2 = phase->intcon(java_subtract(c1, c0));
return new SubINode(sub2, in21);
} else {
// Match x
Node* sub2 = phase->transform(new SubINode(in1, in21));
Node* neg_c0 = phase->intcon(-c0);
return new AddINode(sub2, neg_c0);
}
}
@ -374,15 +381,22 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
}
}
// Convert "x - (y+c0)" into "(x-y) - c0"
// Convert "x - (y+c0)" into "(x-y) - c0" AND
// Convert "c1 - (y+c0)" into "(c1-c0) - y"
// Need the same check as in above optimization but reversed.
if (op2 == Op_AddL && ok_to_convert(in2, in1)) {
if (op2 == Op_AddL
&& ok_to_convert(in2, in1)
&& in2->in(2)->Opcode() == Op_ConL) {
jlong c0 = phase->type(in2->in(2))->isa_long()->get_con();
Node* in21 = in2->in(1);
Node* in22 = in2->in(2);
const TypeLong* tcon = phase->type(in22)->isa_long();
if (tcon != NULL && tcon->is_con()) {
Node* sub2 = phase->transform( new SubLNode(in1, in21) );
Node* neg_c0 = phase->longcon(- tcon->get_con());
if (in1->Opcode() == Op_ConL) {
// Match c1
jlong c1 = phase->type(in1)->isa_long()->get_con();
Node* sub2 = phase->longcon(java_subtract(c1, c0));
return new SubLNode(sub2, in21);
} else {
Node* sub2 = phase->transform(new SubLNode(in1, in21));
Node* neg_c0 = phase->longcon(-c0);
return new AddLNode(sub2, neg_c0);
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8277882
* @summary New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x"
* @library /test/lib
* @run main/othervm -XX:-TieredCompilation -Xbatch
* -XX:CompileCommand=dontinline,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test*
* -XX:CompileCommand=compileonly,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test*
* compiler.c2.TestSubIdealC0Minus_YPlusC1_
*/
package compiler.c2;
import jdk.test.lib.Asserts;
public class TestSubIdealC0Minus_YPlusC1_ {
private static final int I_C0_0 = 1234;
private static final int I_C1 = 1234;
private static final int I_C0_1 = 4321;
private static final long L_C0_0 = 123_456_789_123L;
private static final long L_C1 = 123_456_789_123L;
private static final long L_C0_1 = 654_321;
public static int testIC0EqualsC1(int x) {
return I_C0_0 - (x + I_C1);
}
public static long testLC0EqualsC1(long x) {
return L_C0_0 - (x + L_C1);
}
public static int testIC0NotEqualsC1(int x) {
return I_C0_1 - (x + I_C1);
}
public static long testLC0NotEqualsC1(long x) {
return L_C0_1 - (x + L_C1);
}
public static int testIXPlusC1IsOverflow(int x) {
return Integer.MAX_VALUE - (x + Integer.MAX_VALUE);
}
public static long testLXPlusC1IsOverflow(long x) {
return Long.MAX_VALUE - (x + Long.MAX_VALUE);
}
public static int testIXPlusC1IsUnderflow(int x) {
return Integer.MIN_VALUE - (x + Integer.MIN_VALUE);
}
public static long testLXPlusC1IsUnderflow(long x) {
return Long.MIN_VALUE - (x + Long.MIN_VALUE);
}
public static int testIC0MinusC1IsOverflow(int x) {
return Integer.MAX_VALUE - (x + Integer.MIN_VALUE);
}
public static long testLC0MinusC1IsOverflow(long x) {
return Long.MAX_VALUE - (x + Long.MIN_VALUE);
}
public static int testIC0MinusC1IsUnderflow(int x) {
return Integer.MIN_VALUE - (x + Integer.MAX_VALUE);
}
public static long testLC0MinusC1IsUnderflow(long x) {
return Long.MIN_VALUE - (x + Long.MAX_VALUE);
}
public static int testIResultIsOverflow(int x) {
return 2147483637 - (x + 10); // Integer.MAX_VALUE == 2147483647
}
public static long testLResultIsOverflow(long x) {
return 9223372036854775797L - (x + 10); // Long.MAX_VALUE == 9223372036854775807
}
public static int testIResultIsUnderflow(int x) {
return -2147483637 - (x + 10); // Integer.MIN_VALUE == -2147483648
}
public static long testLResultIsUnderflow(long x) {
return -9223372036854775797L - (x + 10); // Long.MIN_VALUE == -9223372036854775808
}
public static void main(String... args) {
for (int i = 0; i < 50_000; i++) {
Asserts.assertTrue(testIC0EqualsC1(10) == -10);
Asserts.assertTrue(testIC0NotEqualsC1(100) == 2987);
Asserts.assertTrue(testIXPlusC1IsOverflow(10) == -10);
Asserts.assertTrue(testIXPlusC1IsUnderflow(-10) == 10);
Asserts.assertTrue(testIC0MinusC1IsOverflow(10) == -11);
Asserts.assertTrue(testIC0MinusC1IsUnderflow(10) == -9);
Asserts.assertTrue(testIResultIsOverflow(-21) == Integer.MIN_VALUE);
Asserts.assertTrue(testIResultIsUnderflow(2) == Integer.MAX_VALUE);
Asserts.assertTrue(testLC0EqualsC1(10) == -10);
Asserts.assertTrue(testLC0NotEqualsC1(100) == -123456134902L);
Asserts.assertTrue(testLXPlusC1IsOverflow(10) == -10);
Asserts.assertTrue(testLXPlusC1IsUnderflow(-10) == 10);
Asserts.assertTrue(testLC0MinusC1IsOverflow(10) == -11);
Asserts.assertTrue(testLC0MinusC1IsUnderflow(10) == -9);
Asserts.assertTrue(testLResultIsOverflow(-21) == Long.MIN_VALUE);
Asserts.assertTrue(testLResultIsUnderflow(2) == Long.MAX_VALUE);
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.vm.compiler;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.CompilerControl;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import java.util.concurrent.TimeUnit;
/**
* Tests transformation that converts "c0 - (x + c1)" into "(c0 - c1)
* - x" in SubINode::Ideal and SubLNode::Ideal.
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 3 , jvmArgsAppend = {"-XX:-TieredCompilation", "-Xbatch", "-Xcomp"})
public class SubIdealC0Minus_YPlusC1_ {
private static final int I_C0 = 1234567;
private static final int I_C1 = 1234567;
private static final long L_C0 = 123_456_789_123_456L;
private static final long L_C1 = 123_456_789_123_456L;
private final int size = 100_000_000;
private int[] ints_a;
private long[] longs_a;
@Setup
public void init() {
ints_a = new int[size];
longs_a = new long[size];
for (int i = 0; i < size; i++) {
ints_a[i] = i;
longs_a[i] = i * i;
}
}
@Benchmark
public void baseline() {
for (int i = 0; i < size; i++) {
sink(ints_a[i]);
sink(longs_a[i]);
}
}
@Benchmark
public void test() {
for (int i = 0; i < size; i++) {
sink(helper(ints_a[i]));
sink(helper(longs_a[i]));
}
}
// Convert "c0 - (x + c1)" into "(c0 - c1) - x" for int.
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
private static int helper(int x) {
return I_C0 - (x + I_C1);
}
// Convert "c0 - (x + c1)" into "(c0 - c1) - x" for long.
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
private static long helper(long x) {
return L_C0 - (x + L_C1);
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
private static void sink(int v) {}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
private static void sink(long v) {}
}