-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8276673: Optimize abs operations in C2 compiler #6755
Changes from 4 commits
563fbde
e28d72d
e5b02a6
2d122a2
e254d9f
7430320
845d43a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1839,6 +1839,72 @@ bool BoolNode::is_counted_loop_exit_test() { | |
return false; | ||
} | ||
|
||
//============================================================================= | ||
//------------------------------Value------------------------------------------ | ||
const Type* AbsNode::Value(PhaseGVN* phase) const { | ||
const Type* t1 = phase->type(in(1)); | ||
if (t1 == Type::TOP) return Type::TOP; | ||
|
||
switch (t1->base()) { | ||
case Type::Int: { | ||
const TypeInt* ti = t1->is_int(); | ||
if (ti->is_con()) { | ||
// Special case for min_jint: Math.abs(min_jint) = min_jint. | ||
// Do not use C++ abs() for min_jint to avoid undefined behavior. | ||
return (ti->is_con(min_jint)) ? TypeInt::MIN : TypeInt::make(abs(ti->get_con())); | ||
} | ||
break; | ||
} | ||
case Type::Long: { | ||
const TypeLong* tl = t1->is_long(); | ||
if (tl->is_con()) { | ||
// Special case for min_jlong: Math.abs(min_jlong) = min_jlong. | ||
// Do not use C++ abs() for min_jlong to avoid undefined behavior. | ||
return (tl->is_con(min_jlong)) ? TypeLong::MIN : TypeLong::make(abs(tl->get_con())); | ||
} | ||
break; | ||
} | ||
case Type::FloatCon: | ||
return TypeF::make(abs(t1->getf())); | ||
case Type::DoubleCon: | ||
return TypeD::make(abs(t1->getd())); | ||
default: | ||
break; | ||
} | ||
|
||
return bottom_type(); | ||
} | ||
|
||
//------------------------------Identity---------------------------------------- | ||
Node* AbsNode::Identity(PhaseGVN* phase) { | ||
Node* in1 = in(1); | ||
// No need to do abs for non-negative values | ||
if (phase->type(in1)->higher_equal(TypeInt::POS) || | ||
phase->type(in1)->higher_equal(TypeLong::POS)) { | ||
return in1; | ||
} | ||
// Convert "abs(abs(x))" into "abs(x)" | ||
if (in1->Opcode() == Opcode()) { | ||
return in1; | ||
} | ||
return this; | ||
} | ||
|
||
//------------------------------Ideal------------------------------------------ | ||
Node* AbsNode::Ideal(PhaseGVN* phase, bool can_reshape) { | ||
Node* in1 = in(1); | ||
// Convert "abs(0-x)" into "abs(x)" | ||
if (in1->is_Sub() && phase->type(in1->in(1))->is_zero_type()) { | ||
set_req(1, in1->in(2)); | ||
PhaseIterGVN* igvn = phase->is_IterGVN(); | ||
if (igvn) { | ||
igvn->_worklist.push(in1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is that needed? Because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Thanks. |
||
} | ||
return this; | ||
} | ||
return NULL; | ||
} | ||
|
||
//============================================================================= | ||
//------------------------------Value------------------------------------------ | ||
// Compute sqrt | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,17 +21,151 @@ | |
* questions. | ||
*/ | ||
|
||
package compiler.c2; | ||
|
||
/* | ||
* @test | ||
* @bug 8248445 | ||
* @summary Use of AbsI / AbsL nodes should be limited to supported platforms | ||
* @bug 8248445 8276673 | ||
* @summary Abs nodes detection and optimization in C2 | ||
* @library /test/lib | ||
* @requires vm.debug == true | ||
* | ||
* @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileOnly=java.lang.Math::abs compiler.c2.TestAbs | ||
* @run main/othervm -XX:-TieredCompilation compiler.c2.TestAbs | ||
*/ | ||
|
||
package compiler.c2; | ||
import jdk.test.lib.Asserts; | ||
|
||
public class TestAbs { | ||
private static int SIZE = 500; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Thanks. |
||
|
||
public static char [] cspecial = { | ||
0, 42, 128, 256, 1024, 4096, 65535 | ||
}; | ||
|
||
public static int [] ispecial = { | ||
0, Integer.MAX_VALUE, Integer.MIN_VALUE, -42, 42, -1, 1 | ||
}; | ||
|
||
public static long [] lspecial = { | ||
0, Long.MAX_VALUE, Long.MIN_VALUE, -42, 42, -1, 1 | ||
}; | ||
|
||
public static float [] fspecial = { | ||
0.0f, | ||
-0.0f, | ||
Float.MAX_VALUE, | ||
Float.MIN_VALUE, | ||
-Float.MAX_VALUE, | ||
-Float.MIN_VALUE, | ||
Float.NaN, | ||
Float.POSITIVE_INFINITY, | ||
Float.NEGATIVE_INFINITY, | ||
Integer.MAX_VALUE, | ||
Integer.MIN_VALUE, | ||
Long.MAX_VALUE, | ||
Long.MIN_VALUE, | ||
-1.0f, | ||
1.0f, | ||
-42.0f, | ||
42.0f | ||
}; | ||
|
||
public static double [] dspecial = { | ||
0.0, | ||
-0.0, | ||
Double.MAX_VALUE, | ||
Double.MIN_VALUE, | ||
-Double.MAX_VALUE, | ||
-Double.MIN_VALUE, | ||
Double.NaN, | ||
Double.POSITIVE_INFINITY, | ||
Double.NEGATIVE_INFINITY, | ||
Integer.MAX_VALUE, | ||
Integer.MIN_VALUE, | ||
Long.MIN_VALUE, | ||
Long.MAX_VALUE, | ||
-1, | ||
1, | ||
42, | ||
-42, | ||
Math.PI, | ||
Math.E, | ||
Float.MAX_VALUE, | ||
Float.MIN_VALUE, | ||
-Float.MAX_VALUE, | ||
-Float.MIN_VALUE, | ||
Float.NaN, | ||
Float.POSITIVE_INFINITY, | ||
Float.NEGATIVE_INFINITY | ||
}; | ||
|
||
public static void testAbsConstant() { | ||
// Test abs(constant) optimization for int | ||
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(Integer.MAX_VALUE)); | ||
Asserts.assertEquals(Integer.MIN_VALUE, Math.abs(Integer.MIN_VALUE)); | ||
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(-Integer.MAX_VALUE)); | ||
|
||
// Test abs(constant) optimization for long | ||
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(Long.MAX_VALUE)); | ||
Asserts.assertEquals(Long.MIN_VALUE, Math.abs(Long.MIN_VALUE)); | ||
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(-Long.MAX_VALUE)); | ||
|
||
// Test abs(constant) optimization for float | ||
Asserts.assertEquals(Float.NaN, Math.abs(Float.NaN)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Thanks. |
||
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.NEGATIVE_INFINITY)); | ||
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.POSITIVE_INFINITY)); | ||
Asserts.assertEquals(0.0f, Math.abs(0.0f)); | ||
Asserts.assertEquals(0.0f, Math.abs(-0.0f)); | ||
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(Float.MAX_VALUE)); | ||
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(Float.MIN_VALUE)); | ||
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(-Float.MAX_VALUE)); | ||
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(-Float.MIN_VALUE)); | ||
|
||
// Test abs(constant) optimization for double | ||
Asserts.assertEquals(Double.NaN, Math.abs(Double.NaN)); | ||
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.NEGATIVE_INFINITY)); | ||
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.POSITIVE_INFINITY)); | ||
Asserts.assertEquals(0.0, Math.abs(0.0)); | ||
Asserts.assertEquals(0.0, Math.abs(-0.0)); | ||
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(Double.MAX_VALUE)); | ||
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(Double.MIN_VALUE)); | ||
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(-Double.MAX_VALUE)); | ||
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(-Double.MIN_VALUE)); | ||
} | ||
|
||
private static void testAbsTransformInt(int[] a) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to verify C2's transformation, probably we should use C2's IR test framework. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Thanks. |
||
for (int i = 0; i < a.length; i++) { | ||
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i])); | ||
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i])); | ||
} | ||
} | ||
|
||
private static void testAbsTransformLong(long[] a) { | ||
for (int i = 0; i < a.length; i++) { | ||
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i])); | ||
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i])); | ||
} | ||
} | ||
|
||
private static void testAbsTransformFloat(float[] a) { | ||
for (int i = 0; i < a.length; i++) { | ||
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i])); | ||
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i])); | ||
} | ||
} | ||
|
||
private static void testAbsTransformDouble(double[] a) { | ||
for (int i = 0; i < a.length; i++) { | ||
Asserts.assertEquals(Math.abs(Math.abs(a[i])), Math.abs(a[i])); | ||
Asserts.assertEquals(Math.abs(0 - a[i]), Math.abs(a[i])); | ||
} | ||
} | ||
|
||
private static void testAbsOptChar(char[] a) { | ||
for (int i = 0; i < a.length; i++) { | ||
Asserts.assertEquals(a[i], (char) Math.abs(a[i])); | ||
} | ||
} | ||
|
||
public static void test() { | ||
// java.lang.Math.abs() collapses into AbsI/AbsL nodes on platforms that support the correspondent nodes | ||
|
@@ -45,7 +179,20 @@ public static void test() { | |
public static void main(String args[]) { | ||
for (int i = 0; i < 20_000; i++) { | ||
test(); | ||
|
||
testAbsConstant(); | ||
|
||
// Verify abs(abs(x)) = abs(x) for all types | ||
// Verify abs(0-x) = abs(x) for all types | ||
testAbsTransformInt(ispecial); | ||
testAbsTransformLong(lspecial); | ||
testAbsTransformFloat(fspecial); | ||
testAbsTransformDouble(dspecial); | ||
|
||
// Verify abs(non-negative_value) = non-negative_value | ||
testAbsOptChar(cspecial); | ||
} | ||
|
||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have uabs() for julong and unsigned int.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your review. Fixed.