8277882: New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x"
Reviewed-by: dlong, iveresov
This commit is contained in:
parent
83e6a4c0e9
commit
352435581e
@ -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);
|
||||
}
|
||||
}
|
||||
|
133
test/hotspot/jtreg/compiler/c2/TestSubIdealC0Minus_YPlusC1_.java
Normal file
133
test/hotspot/jtreg/compiler/c2/TestSubIdealC0Minus_YPlusC1_.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user