Skip to content

Commit 3524355

Browse files
CptGitIgor Veresov
authored andcommitted
8277882: New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x"
Reviewed-by: dlong, iveresov
1 parent 83e6a4c commit 3524355

File tree

3 files changed

+272
-15
lines changed

3 files changed

+272
-15
lines changed

src/hotspot/share/opto/subnode.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,23 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){
196196
}
197197
}
198198

199-
200-
// Convert "x - (y+c0)" into "(x-y) - c0"
199+
// Convert "x - (y+c0)" into "(x-y) - c0" AND
200+
// Convert "c1 - (y+c0)" into "(c1-c0) - y"
201201
// Need the same check as in above optimization but reversed.
202-
if (op2 == Op_AddI && ok_to_convert(in2, in1)) {
202+
if (op2 == Op_AddI
203+
&& ok_to_convert(in2, in1)
204+
&& in2->in(2)->Opcode() == Op_ConI) {
205+
jint c0 = phase->type(in2->in(2))->isa_int()->get_con();
203206
Node* in21 = in2->in(1);
204-
Node* in22 = in2->in(2);
205-
const TypeInt* tcon = phase->type(in22)->isa_int();
206-
if (tcon != NULL && tcon->is_con()) {
207-
Node* sub2 = phase->transform( new SubINode(in1, in21) );
208-
Node* neg_c0 = phase->intcon(- tcon->get_con());
207+
if (in1->Opcode() == Op_ConI) {
208+
// Match c1
209+
jint c1 = phase->type(in1)->isa_int()->get_con();
210+
Node* sub2 = phase->intcon(java_subtract(c1, c0));
211+
return new SubINode(sub2, in21);
212+
} else {
213+
// Match x
214+
Node* sub2 = phase->transform(new SubINode(in1, in21));
215+
Node* neg_c0 = phase->intcon(-c0);
209216
return new AddINode(sub2, neg_c0);
210217
}
211218
}
@@ -374,15 +381,22 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
374381
}
375382
}
376383

377-
// Convert "x - (y+c0)" into "(x-y) - c0"
384+
// Convert "x - (y+c0)" into "(x-y) - c0" AND
385+
// Convert "c1 - (y+c0)" into "(c1-c0) - y"
378386
// Need the same check as in above optimization but reversed.
379-
if (op2 == Op_AddL && ok_to_convert(in2, in1)) {
387+
if (op2 == Op_AddL
388+
&& ok_to_convert(in2, in1)
389+
&& in2->in(2)->Opcode() == Op_ConL) {
390+
jlong c0 = phase->type(in2->in(2))->isa_long()->get_con();
380391
Node* in21 = in2->in(1);
381-
Node* in22 = in2->in(2);
382-
const TypeLong* tcon = phase->type(in22)->isa_long();
383-
if (tcon != NULL && tcon->is_con()) {
384-
Node* sub2 = phase->transform( new SubLNode(in1, in21) );
385-
Node* neg_c0 = phase->longcon(- tcon->get_con());
392+
if (in1->Opcode() == Op_ConL) {
393+
// Match c1
394+
jlong c1 = phase->type(in1)->isa_long()->get_con();
395+
Node* sub2 = phase->longcon(java_subtract(c1, c0));
396+
return new SubLNode(sub2, in21);
397+
} else {
398+
Node* sub2 = phase->transform(new SubLNode(in1, in21));
399+
Node* neg_c0 = phase->longcon(-c0);
386400
return new AddLNode(sub2, neg_c0);
387401
}
388402
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8277882
27+
* @summary New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x"
28+
* @library /test/lib
29+
* @run main/othervm -XX:-TieredCompilation -Xbatch
30+
* -XX:CompileCommand=dontinline,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test*
31+
* -XX:CompileCommand=compileonly,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test*
32+
* compiler.c2.TestSubIdealC0Minus_YPlusC1_
33+
*/
34+
package compiler.c2;
35+
36+
import jdk.test.lib.Asserts;
37+
38+
public class TestSubIdealC0Minus_YPlusC1_ {
39+
40+
private static final int I_C0_0 = 1234;
41+
private static final int I_C1 = 1234;
42+
private static final int I_C0_1 = 4321;
43+
44+
private static final long L_C0_0 = 123_456_789_123L;
45+
private static final long L_C1 = 123_456_789_123L;
46+
private static final long L_C0_1 = 654_321;
47+
48+
public static int testIC0EqualsC1(int x) {
49+
return I_C0_0 - (x + I_C1);
50+
}
51+
52+
public static long testLC0EqualsC1(long x) {
53+
return L_C0_0 - (x + L_C1);
54+
}
55+
56+
public static int testIC0NotEqualsC1(int x) {
57+
return I_C0_1 - (x + I_C1);
58+
}
59+
60+
public static long testLC0NotEqualsC1(long x) {
61+
return L_C0_1 - (x + L_C1);
62+
}
63+
64+
public static int testIXPlusC1IsOverflow(int x) {
65+
return Integer.MAX_VALUE - (x + Integer.MAX_VALUE);
66+
}
67+
68+
public static long testLXPlusC1IsOverflow(long x) {
69+
return Long.MAX_VALUE - (x + Long.MAX_VALUE);
70+
}
71+
72+
public static int testIXPlusC1IsUnderflow(int x) {
73+
return Integer.MIN_VALUE - (x + Integer.MIN_VALUE);
74+
}
75+
76+
public static long testLXPlusC1IsUnderflow(long x) {
77+
return Long.MIN_VALUE - (x + Long.MIN_VALUE);
78+
}
79+
80+
public static int testIC0MinusC1IsOverflow(int x) {
81+
return Integer.MAX_VALUE - (x + Integer.MIN_VALUE);
82+
}
83+
84+
public static long testLC0MinusC1IsOverflow(long x) {
85+
return Long.MAX_VALUE - (x + Long.MIN_VALUE);
86+
}
87+
88+
public static int testIC0MinusC1IsUnderflow(int x) {
89+
return Integer.MIN_VALUE - (x + Integer.MAX_VALUE);
90+
}
91+
92+
public static long testLC0MinusC1IsUnderflow(long x) {
93+
return Long.MIN_VALUE - (x + Long.MAX_VALUE);
94+
}
95+
96+
public static int testIResultIsOverflow(int x) {
97+
return 2147483637 - (x + 10); // Integer.MAX_VALUE == 2147483647
98+
}
99+
100+
public static long testLResultIsOverflow(long x) {
101+
return 9223372036854775797L - (x + 10); // Long.MAX_VALUE == 9223372036854775807
102+
}
103+
104+
public static int testIResultIsUnderflow(int x) {
105+
return -2147483637 - (x + 10); // Integer.MIN_VALUE == -2147483648
106+
}
107+
108+
public static long testLResultIsUnderflow(long x) {
109+
return -9223372036854775797L - (x + 10); // Long.MIN_VALUE == -9223372036854775808
110+
}
111+
112+
public static void main(String... args) {
113+
for (int i = 0; i < 50_000; i++) {
114+
Asserts.assertTrue(testIC0EqualsC1(10) == -10);
115+
Asserts.assertTrue(testIC0NotEqualsC1(100) == 2987);
116+
Asserts.assertTrue(testIXPlusC1IsOverflow(10) == -10);
117+
Asserts.assertTrue(testIXPlusC1IsUnderflow(-10) == 10);
118+
Asserts.assertTrue(testIC0MinusC1IsOverflow(10) == -11);
119+
Asserts.assertTrue(testIC0MinusC1IsUnderflow(10) == -9);
120+
Asserts.assertTrue(testIResultIsOverflow(-21) == Integer.MIN_VALUE);
121+
Asserts.assertTrue(testIResultIsUnderflow(2) == Integer.MAX_VALUE);
122+
123+
Asserts.assertTrue(testLC0EqualsC1(10) == -10);
124+
Asserts.assertTrue(testLC0NotEqualsC1(100) == -123456134902L);
125+
Asserts.assertTrue(testLXPlusC1IsOverflow(10) == -10);
126+
Asserts.assertTrue(testLXPlusC1IsUnderflow(-10) == 10);
127+
Asserts.assertTrue(testLC0MinusC1IsOverflow(10) == -11);
128+
Asserts.assertTrue(testLC0MinusC1IsUnderflow(10) == -9);
129+
Asserts.assertTrue(testLResultIsOverflow(-21) == Long.MIN_VALUE);
130+
Asserts.assertTrue(testLResultIsUnderflow(2) == Long.MAX_VALUE);
131+
}
132+
}
133+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package org.openjdk.bench.vm.compiler;
25+
26+
import org.openjdk.jmh.annotations.Benchmark;
27+
import org.openjdk.jmh.annotations.BenchmarkMode;
28+
import org.openjdk.jmh.annotations.CompilerControl;
29+
import org.openjdk.jmh.annotations.Fork;
30+
import org.openjdk.jmh.annotations.Measurement;
31+
import org.openjdk.jmh.annotations.Mode;
32+
import org.openjdk.jmh.annotations.Scope;
33+
import org.openjdk.jmh.annotations.Setup;
34+
import org.openjdk.jmh.annotations.State;
35+
import org.openjdk.jmh.annotations.OutputTimeUnit;
36+
import org.openjdk.jmh.annotations.Warmup;
37+
import org.openjdk.jmh.infra.Blackhole;
38+
39+
import java.util.concurrent.TimeUnit;
40+
41+
/**
42+
* Tests transformation that converts "c0 - (x + c1)" into "(c0 - c1)
43+
* - x" in SubINode::Ideal and SubLNode::Ideal.
44+
*/
45+
@BenchmarkMode(Mode.AverageTime)
46+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
47+
@State(Scope.Thread)
48+
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
49+
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
50+
@Fork(value = 3 , jvmArgsAppend = {"-XX:-TieredCompilation", "-Xbatch", "-Xcomp"})
51+
public class SubIdealC0Minus_YPlusC1_ {
52+
53+
private static final int I_C0 = 1234567;
54+
55+
private static final int I_C1 = 1234567;
56+
57+
private static final long L_C0 = 123_456_789_123_456L;
58+
59+
private static final long L_C1 = 123_456_789_123_456L;
60+
61+
private final int size = 100_000_000;
62+
63+
private int[] ints_a;
64+
65+
private long[] longs_a;
66+
67+
@Setup
68+
public void init() {
69+
ints_a = new int[size];
70+
longs_a = new long[size];
71+
for (int i = 0; i < size; i++) {
72+
ints_a[i] = i;
73+
longs_a[i] = i * i;
74+
}
75+
}
76+
77+
@Benchmark
78+
public void baseline() {
79+
for (int i = 0; i < size; i++) {
80+
sink(ints_a[i]);
81+
sink(longs_a[i]);
82+
}
83+
}
84+
85+
@Benchmark
86+
public void test() {
87+
for (int i = 0; i < size; i++) {
88+
sink(helper(ints_a[i]));
89+
sink(helper(longs_a[i]));
90+
}
91+
}
92+
93+
// Convert "c0 - (x + c1)" into "(c0 - c1) - x" for int.
94+
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
95+
private static int helper(int x) {
96+
return I_C0 - (x + I_C1);
97+
}
98+
99+
// Convert "c0 - (x + c1)" into "(c0 - c1) - x" for long.
100+
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
101+
private static long helper(long x) {
102+
return L_C0 - (x + L_C1);
103+
}
104+
105+
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
106+
private static void sink(int v) {}
107+
108+
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
109+
private static void sink(long v) {}
110+
}

0 commit comments

Comments
 (0)