8288564: C2: LShiftLNode::Ideal produces wrong result after JDK-8278114

Reviewed-by: kvn, iveresov, thartmann
This commit is contained in:
Christian Hagedorn 2022-06-20 06:47:40 +00:00
parent ae030bcbc5
commit ed714af854
2 changed files with 39 additions and 2 deletions

View File

@ -813,6 +813,8 @@ Node *LShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Left input is an add of the same number?
if (add1->in(1) == add1->in(2)) {
// Convert "(x + x) << c0" into "x << (c0 + 1)"
// In general, this optimization cannot be applied for c0 == 31 since
// 2x << 31 != x << 32 = x << 0 = x (e.g. x = 1: 2 << 31 = 0 != 1)
return new LShiftINode(add1->in(1), phase->intcon(con + 1));
}
@ -930,8 +932,13 @@ Node *LShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
assert( add1 != add1->in(1), "dead loop in LShiftLNode::Ideal" );
// Left input is an add of the same number?
if (add1->in(1) == add1->in(2)) {
if (con != (BitsPerJavaLong - 1) && add1->in(1) == add1->in(2)) {
// Convert "(x + x) << c0" into "x << (c0 + 1)"
// Can only be applied if c0 != 63 because:
// (x + x) << 63 = 2x << 63, while
// (x + x) << 63 --transform--> x << 64 = x << 0 = x (!= 2x << 63, for example for x = 1)
// According to the Java spec, chapter 15.19, we only consider the six lowest-order bits of the right-hand operand
// (i.e. "right-hand operand" & 0b111111). Therefore, x << 64 is the same as x << 0 (64 = 0b10000000 & 0b0111111 = 0).
return new LShiftLNode(add1->in(1), phase->intcon(con + 1));
}

View File

@ -28,7 +28,7 @@ import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8278114
* @bug 8278114 8288564
* @summary Test that transformation from (x + x) >> c to x >> (c + 1) works as intended.
* @library /test/lib /
* @requires vm.compiler2.enabled
@ -149,4 +149,34 @@ public class TestIRLShiftIdeal_XPlusX_LShiftC {
Asserts.assertTrue(info.isTestC2Compiled());
}
}
@Test
@IR(failOn = {IRNode.MUL_I})
@IR(counts = {IRNode.LSHIFT_I, "1",
IRNode.ADD_I, "1"})
public int testIntRandom(int x) {
return (x + x) << 31;
}
@Run(test = "testIntRandom")
public void runTestIntRandom() {
int random = RunInfo.getRandom().nextInt();
int interpreterResult = (random + random) << 31;
Asserts.assertEQ(testIntRandom(random), interpreterResult);
}
@Test
@IR(failOn = {IRNode.MUL_L})
@IR(counts = {IRNode.LSHIFT_L, "1",
IRNode.ADD_L, "1"})
public long testLongRandom(long x) {
return (x + x) << 63;
}
@Run(test = "testLongRandom")
public void runTestLongRandom() {
long random = RunInfo.getRandom().nextLong();
long interpreterResult = (random + random) << 63;
Asserts.assertEQ(testLongRandom(random), interpreterResult);
}
}