Skip to content

Commit bd0eb29

Browse files
Faye GaoFei Gao
authored andcommitted
8276673: Optimize abs operations in C2 compiler
The patch aims to help optimize Math.abs() mainly from these three parts: 1) Remove redundant instructions for abs with constant values 2) Remove redundant instructions for abs with char type 3) Convert some common abs operations to ideal forms 1. Remove redundant instructions for abs with constant values If we can decide the value of the input node for function Math.abs() at compile-time, we can substitute the Abs node with the absolute value of the constant and don't have to calculate it at runtime. For example, int[] a for (int i = 0; i < SIZE; i++) { a[i] = Math.abs(-38); } Before the patch, the generated code for the testcase above is: ... mov w10, #0xffffffda cmp w10, wzr cneg w17, w10, lt dup v16.8h, w17 ... After the patch, the generated code for the testcase above is : ... movi v16.4s, #0x26 ... 2. Remove redundant instructions for abs with char type In Java semantics, as the char type is always non-negative, we could actually remove the absI node in the C2 middle end. As for vectorization part, in current SLP, the vectorization of Math.abs() with char type is intentionally disabled after JDK-8261022 because it generates incorrect result before. After removing the AbsI node in the middle end, Math.abs(char) can be vectorized naturally. For example, char[] a; char[] b; for (int i = 0; i < SIZE; i++) { b[i] = (char) Math.abs(a[i]); } Before the patch, the generated assembly code for the testcase above is: B15: add x13, x21, w20, sxtw #1 ldrh w11, [x13, #16] cmp w11, wzr cneg w10, w11, lt strh w10, [x13, #16] ldrh w10, [x13, #18] cmp w10, wzr cneg w10, w10, lt strh w10, [x13, #18] ... add w20, w20, #0x1 cmp w20, w17 b.lt B15 After the patch, the generated assembly code is: B15: sbfiz x18, x19, #1, #32 add x0, x14, x18 ldr q16, [x0, #16] add x18, x21, x18 str q16, [x18, #16] ldr q16, [x0, #32] str q16, [x18, #32] ... add w19, w19, #0x40 cmp w19, w17 b.lt B15 3. Convert some common abs operations to ideal forms The patch overrides some virtual support functions for AbsNode so that optimization of gvn can work on it. Here are the optimizable forms: a) abs(0 - x) => abs(x) Before the patch: ... ldr w13, [x13, #16] neg w13, w13 cmp w13, wzr cneg w14, w13, lt ... After the patch: ... ldr w13, [x13, #16] cmp w13, wzr cneg w13, w13, lt ... b) abs(abs(x)) => abs(x) Before the patch: ... ldr w12, [x12, #16] cmp w12, wzr cneg w12, w12, lt cmp w12, wzr cneg w12, w12, lt ... After the patch: ... ldr w13, [x13, #16] cmp w13, wzr cneg w13, w13, lt ... Change-Id: I5434c01a225796caaf07ffbb19983f4fe2e206bd
1 parent d7ad546 commit bd0eb29

File tree

4 files changed

+231
-7
lines changed

4 files changed

+231
-7
lines changed

src/hotspot/share/opto/subnode.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,72 @@ bool BoolNode::is_counted_loop_exit_test() {
18251825
return false;
18261826
}
18271827

1828+
//=============================================================================
1829+
//------------------------------Value------------------------------------------
1830+
const Type* AbsNode::Value(PhaseGVN* phase) const {
1831+
const Type* t1 = phase->type(in(1));
1832+
if (t1 == Type::TOP) return Type::TOP;
1833+
1834+
switch (t1->base()) {
1835+
case Type::Int: {
1836+
const TypeInt* ti = t1->is_int();
1837+
if (ti->is_con()) {
1838+
// Special case for min_jint: Math.abs(min_jint) = min_jint.
1839+
// Do not use C++ abs() for min_jint to avoid undefined behavior.
1840+
return (ti->is_con(min_jint)) ? TypeInt::MIN : TypeInt::make(abs(ti->get_con()));
1841+
}
1842+
break;
1843+
}
1844+
case Type::Long: {
1845+
const TypeLong* tl = t1->is_long();
1846+
if (tl->is_con()) {
1847+
// Special case for min_jlong: Math.abs(min_jlong) = min_jlong.
1848+
// Do not use C++ abs() for min_jlong to avoid undefined behavior.
1849+
return (tl->is_con(min_jlong)) ? TypeLong::MIN : TypeLong::make(abs(tl->get_con()));
1850+
}
1851+
break;
1852+
}
1853+
case Type::FloatCon:
1854+
return TypeF::make(abs(t1->getf()));
1855+
case Type::DoubleCon:
1856+
return TypeD::make(abs(t1->getd()));
1857+
default:
1858+
break;
1859+
}
1860+
1861+
return bottom_type();
1862+
}
1863+
1864+
//------------------------------Identity----------------------------------------
1865+
Node* AbsNode::Identity(PhaseGVN* phase) {
1866+
Node* in1 = in(1);
1867+
// No need to do abs for non-negative values
1868+
if (phase->type(in1)->higher_equal(TypeInt::POS) ||
1869+
phase->type(in1)->higher_equal(TypeLong::POS)) {
1870+
return in1;
1871+
}
1872+
// Convert "abs(abs(x))" into "abs(x)"
1873+
if (in1->Opcode() == Opcode()) {
1874+
return in1;
1875+
}
1876+
return this;
1877+
}
1878+
1879+
//------------------------------Ideal------------------------------------------
1880+
Node* AbsNode::Ideal(PhaseGVN* phase, bool can_reshape) {
1881+
Node* in1 = in(1);
1882+
// Convert "abs(0-x)" into "abs(x)"
1883+
if (in1->is_Sub() && phase->type(in1->in(1))->is_zero_type()) {
1884+
set_req(1, in1->in(2));
1885+
PhaseIterGVN* igvn = phase->is_IterGVN();
1886+
if (igvn) {
1887+
igvn->_worklist.push(in1);
1888+
}
1889+
return this;
1890+
}
1891+
return NULL;
1892+
}
1893+
18281894
//=============================================================================
18291895
//------------------------------Value------------------------------------------
18301896
// Compute sqrt

src/hotspot/share/opto/subnode.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -379,6 +379,9 @@ class BoolNode : public Node {
379379
class AbsNode : public Node {
380380
public:
381381
AbsNode( Node *value ) : Node(0,value) {}
382+
virtual Node* Identity(PhaseGVN* phase);
383+
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
384+
virtual const Type* Value(PhaseGVN* phase) const;
382385
};
383386

384387
//------------------------------AbsINode---------------------------------------

src/hotspot/share/opto/type.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ class TypeInt : public TypeInteger {
589589

590590
// Check for single integer
591591
int is_con() const { return _lo==_hi; }
592-
bool is_con(int i) const { return is_con() && _lo == i; }
592+
bool is_con(jint i) const { return is_con() && _lo == i; }
593593
jint get_con() const { assert( is_con(), "" ); return _lo; }
594594

595595
virtual bool is_finite() const; // Has a finite value
@@ -657,7 +657,7 @@ class TypeLong : public TypeInteger {
657657

658658
// Check for single integer
659659
int is_con() const { return _lo==_hi; }
660-
bool is_con(int i) const { return is_con() && _lo == i; }
660+
bool is_con(jlong i) const { return is_con() && _lo == i; }
661661
jlong get_con() const { assert( is_con(), "" ); return _lo; }
662662

663663
// Check for positive 32-bit value.

test/hotspot/jtreg/compiler/c2/TestAbs.java

Lines changed: 159 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,159 @@
2121
* questions.
2222
*/
2323

24-
package compiler.c2;
25-
2624
/*
2725
* @test
28-
* @bug 8248445
29-
* @summary Use of AbsI / AbsL nodes should be limited to supported platforms
26+
* @bug 8248445 8276673
27+
* @summary Abs nodes detection and optimization in C2
28+
* @library /test/lib
3029
* @requires vm.debug == true
3130
*
3231
* @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileOnly=java.lang.Math::abs compiler.c2.TestAbs
32+
* @run main/othervm -XX:-TieredCompilation compiler.c2.TestAbs
3333
*/
34+
35+
package compiler.c2;
36+
import jdk.test.lib.Asserts;
37+
import jdk.internal.math.DoubleConsts;
38+
import jdk.internal.math.FloatConsts;
39+
3440
public class TestAbs {
41+
private static int SIZE = 500;
42+
43+
public static char [] cspecial = {
44+
0, 42, 128, 256, 1024, 4096, 65535
45+
};
46+
47+
public static int [] ispecial = {
48+
0, Integer.MAX_VALUE, Integer.MIN_VALUE, -42, 42, -1, 1
49+
};
50+
51+
public static long [] lspecial = {
52+
0, Long.MAX_VALUE, Long.MIN_VALUE, -42, 42, -1, 1
53+
};
54+
55+
public static float [] fspecial = {
56+
0.0f,
57+
-0.0f,
58+
Float.MAX_VALUE,
59+
Float.MIN_VALUE,
60+
-Float.MAX_VALUE,
61+
-Float.MIN_VALUE,
62+
Float.NaN,
63+
Float.POSITIVE_INFINITY,
64+
Float.NEGATIVE_INFINITY,
65+
Integer.MAX_VALUE,
66+
Integer.MIN_VALUE,
67+
Long.MAX_VALUE,
68+
Long.MIN_VALUE,
69+
-1.0f,
70+
1.0f,
71+
-42.0f,
72+
42.0f,
73+
Float.intBitsToFloat((1 << FloatConsts.SIGNIFICAND_WIDTH) |
74+
((1 << FloatConsts.SIGNIFICAND_WIDTH) - 1)),
75+
FloatConsts.MAG_BIT_MASK >>> 1
76+
};
77+
78+
public static double [] dspecial = {
79+
0.0,
80+
-0.0,
81+
Double.MAX_VALUE,
82+
Double.MIN_VALUE,
83+
-Double.MAX_VALUE,
84+
-Double.MIN_VALUE,
85+
Double.NaN,
86+
Double.POSITIVE_INFINITY,
87+
Double.NEGATIVE_INFINITY,
88+
Integer.MAX_VALUE,
89+
Integer.MIN_VALUE,
90+
Long.MIN_VALUE,
91+
Long.MAX_VALUE,
92+
-1,
93+
1,
94+
42,
95+
-42,
96+
Math.PI,
97+
Math.E,
98+
Float.MAX_VALUE,
99+
Float.MIN_VALUE,
100+
-Float.MAX_VALUE,
101+
-Float.MIN_VALUE,
102+
Float.NaN,
103+
Float.POSITIVE_INFINITY,
104+
Float.NEGATIVE_INFINITY,
105+
Double.longBitsToDouble((1L << DoubleConsts.SIGNIFICAND_WIDTH) |
106+
((1L << DoubleConsts.SIGNIFICAND_WIDTH) - 1)),
107+
DoubleConsts.MAG_BIT_MASK >>> 1
108+
};
109+
110+
public static void testAbsConstant() {
111+
// Test abs(constant) optimization for int
112+
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(Integer.MAX_VALUE));
113+
Asserts.assertEquals(Integer.MIN_VALUE, Math.abs(Integer.MIN_VALUE));
114+
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(-Integer.MAX_VALUE));
115+
116+
// Test abs(constant) optimization for long
117+
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(Long.MAX_VALUE));
118+
Asserts.assertEquals(Long.MIN_VALUE, Math.abs(Long.MIN_VALUE));
119+
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(-Long.MAX_VALUE));
120+
121+
// Test abs(constant) optimization for float
122+
Asserts.assertEquals(Float.NaN, Math.abs(Float.NaN));
123+
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.NEGATIVE_INFINITY));
124+
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.POSITIVE_INFINITY));
125+
Asserts.assertEquals(0.0f, Math.abs(0.0f));
126+
Asserts.assertEquals(0.0f, Math.abs(-0.0f));
127+
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(Float.MAX_VALUE));
128+
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(Float.MIN_VALUE));
129+
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(-Float.MAX_VALUE));
130+
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(-Float.MIN_VALUE));
131+
132+
// Test abs(constant) optimization for double
133+
Asserts.assertEquals(Double.NaN, Math.abs(Double.NaN));
134+
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.NEGATIVE_INFINITY));
135+
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.POSITIVE_INFINITY));
136+
Asserts.assertEquals(0.0, Math.abs(0.0));
137+
Asserts.assertEquals(0.0, Math.abs(-0.0));
138+
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(Double.MAX_VALUE));
139+
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(Double.MIN_VALUE));
140+
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(-Double.MAX_VALUE));
141+
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(-Double.MIN_VALUE));
142+
}
143+
144+
private static void testAbsTransformInt(int[] a) {
145+
for (int i = 0; i < a.length; i++) {
146+
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i]));
147+
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i]));
148+
}
149+
}
150+
151+
private static void testAbsTransformLong(long[] a) {
152+
for (int i = 0; i < a.length; i++) {
153+
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i]));
154+
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i]));
155+
}
156+
}
157+
158+
private static void testAbsTransformFloat(float[] a) {
159+
for (int i = 0; i < a.length; i++) {
160+
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i]));
161+
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i]));
162+
}
163+
}
164+
165+
private static void testAbsTransformDouble(double[] a) {
166+
for (int i = 0; i < a.length; i++) {
167+
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i]));
168+
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i]));
169+
}
170+
}
171+
172+
private static void testAbsOptChar(char[] a) {
173+
for (int i = 0; i < a.length; i++) {
174+
Asserts.assertEquals(a[i], (char) Math.abs(a[i]));
175+
}
176+
}
35177

36178
public static void test() {
37179
// java.lang.Math.abs() collapses into AbsI/AbsL nodes on platforms that support the correspondent nodes
@@ -45,7 +187,20 @@ public static void test() {
45187
public static void main(String args[]) {
46188
for (int i = 0; i < 20_000; i++) {
47189
test();
190+
191+
testAbsConstant();
192+
193+
// Verify abs(abs(x)) = abs(x) for all types
194+
// Verify abs(0-x) = abs(x) for all types
195+
testAbsTransformInt(ispecial);
196+
testAbsTransformLong(lspecial);
197+
testAbsTransformFloat(fspecial);
198+
testAbsTransformDouble(dspecial);
199+
200+
// Verify abs(non-negative_value) = non-negative_value
201+
testAbsOptChar(cspecial);
48202
}
203+
49204
}
50205
}
51206

0 commit comments

Comments
 (0)