8267265: Use new IR Test Framework to create tests for C2 Ideal transformations

Reviewed-by: chagedorn
This commit is contained in:
John Tortugo 2022-02-28 10:01:24 +00:00 committed by Christian Hagedorn
parent 86723d4892
commit efd3967b54
11 changed files with 1983 additions and 0 deletions

@ -0,0 +1,250 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of AddINode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.AddINodeIdealizationTests
*/
public class AddINodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"additions", "xMinusX", "test1",
"test2", "test3", "test4",
"test5", "test6", "test7",
"test8", "test9", "test10",
"test11", "test12", "test13",
"test14", "test15", "test16",
"test17", "test18", "test19"})
public void runMethod() {
int a = RunInfo.getRandom().nextInt();
int b = RunInfo.getRandom().nextInt();
int c = RunInfo.getRandom().nextInt();
int d = RunInfo.getRandom().nextInt();
int min = Integer.MIN_VALUE;
int max = Integer.MAX_VALUE;
assertResult(0, 0, 0, 0);
assertResult(a, b, c, d);
assertResult(min, min, min, min);
assertResult(max, max, max, max);
}
@DontCompile
public void assertResult(int a, int b, int c, int d) {
Asserts.assertEQ(((a+a) + (a+a)) , additions(a));
Asserts.assertEQ(0 , xMinusX(a));
Asserts.assertEQ(a + 1 + 2 , test1(a));
Asserts.assertEQ((a + 2021) + b , test2(a, b));
Asserts.assertEQ(a + (b + 2021) , test3(a, b));
Asserts.assertEQ((1 - a) + 2 , test4(a));
Asserts.assertEQ((a - b) + (c - d), test5(a, b, c, d));
Asserts.assertEQ((a - b) + (b + c), test6(a, b, c));
Asserts.assertEQ((a - b) + (c + b), test7(a, b, c));
Asserts.assertEQ((a - b) + (b - c), test8(a, b, c));
Asserts.assertEQ((a - b) + (c - a), test9(a, b, c));
Asserts.assertEQ(a + (0 - b) , test10(a, b));
Asserts.assertEQ((0 - b) + a , test11(a, b));
Asserts.assertEQ((a - b) + b , test12(a, b));
Asserts.assertEQ(b + (a - b) , test13(a, b));
Asserts.assertEQ(a + 0 , test14(a));
Asserts.assertEQ(0 + a , test15(a));
Asserts.assertEQ(a*b + a*c , test16(a, b, c));
Asserts.assertEQ(a*b + b*c , test17(a, b, c));
Asserts.assertEQ(a*c + b*c , test18(a, b, c));
Asserts.assertEQ(a*b + c*a , test19(a, b, c));
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks (x + x) + (x + x) => a=(x + x); r=a+a
public int additions(int x) {
return (x + x) + (x + x);
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks (x - x) + (x - x) => 0
public int xMinusX(int x) {
return (x - x) + (x - x);
}
@Test
@IR(counts = {IRNode.ADD, "1"})
// Checks (x + c1) + c2 => x + c3 where c3 = c1 + c2
public int test1(int x) {
return (x + 1) + 2;
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks (x + c1) + y => (x + y) + c1
public int test2(int x, int y) {
return (x + 2021) + y;
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks x + (y + c1) => (x + y) + c1
public int test3(int x, int y) {
return x + (y + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (c1 - x) + c2 => c3 - x where c3 = c1 + c2
public int test4(int x) {
return (1 - x) + 2;
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "2",
})
// Checks (a - b) + (c - d) => (a + c) - (b + d)
public int test5(int a, int b, int c, int d) {
return (a - b) + (c - d);
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (a - b) + (b + c) => (a + c)
public int test6(int a, int b, int c) {
return (a - b) + (b + c);
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (a - b) + (c + b) => (a + c)
public int test7(int a, int b, int c) {
return (a - b) + (c + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a - b) + (b - c) => (a - c)
public int test8(int a, int b, int c) {
return (a - b) + (b - c);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a - b) + (c - a) => (c - b)
public int test9(int a, int b, int c) {
return (a - b) + (c - a);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x + (0 - y) => (x - y)
public int test10(int x, int y) {
return x + (0 - y);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (0 - y) + x => (x - y)
public int test11(int x, int y) {
return (0 - y) + x;
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks (x - y) + y => x
public int test12(int x, int y) {
return (x - y) + y;
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks y + (x - y) => x
public int test13(int x, int y) {
return y + (x - y);
}
@Test
@IR(failOn = {IRNode.ADD})
// Checks x + 0 => x
public int test14(int x) {
return x + 0;
}
@Test
@IR(failOn = {IRNode.ADD})
// Checks 0 + x => x
public int test15(int x) {
return 0 + x;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks "a*b + a*c => a*(b+c)
public int test16(int a, int b, int c) {
return a*b + a*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*b + b*c => b*(a+c)
public int test17(int a, int b, int c) {
return a*b + b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*c + b*c => (a+b)*c
public int test18(int a, int b, int c) {
return a*c + b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*b + c*a => a*(b+c)
public int test19(int a, int b, int c) {
return a*b + c*a;
}
}

@ -0,0 +1,241 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of AddLNode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.AddLNodeIdealizationTests
*/
public class AddLNodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"additions", "xMinusX", "test1",
"test2", "test3", "test4",
"test5", "test6", "test7",
"test8", "test9", "test10",
"test11", "test12", "test13",
"test14", "test15", "test16",
"test17", "test18"})
public void runMethod() {
long a = RunInfo.getRandom().nextLong();
long b = RunInfo.getRandom().nextLong();
long c = RunInfo.getRandom().nextLong();
long d = RunInfo.getRandom().nextLong();
long min = Long.MIN_VALUE;
long max = Long.MAX_VALUE;
assertResult(0, 0, 0, 0);
assertResult(a, b, c, d);
assertResult(min, min, min, min);
assertResult(max, max, max, max);
}
@DontCompile
public void assertResult(long a, long b, long c, long d) {
Asserts.assertEQ(((a+a) + (a+a)) , additions(a));
Asserts.assertEQ(0L , xMinusX(a));
Asserts.assertEQ(a + 1 + 2 , test1(a));
Asserts.assertEQ((a + 2021) + b , test2(a, b));
Asserts.assertEQ(a + (b + 2021) , test3(a, b));
Asserts.assertEQ((1 - a) + 2 , test4(a));
Asserts.assertEQ((a - b) + (c - d), test5(a, b, c, d));
Asserts.assertEQ((a - b) + (b + c), test6(a, b, c));
Asserts.assertEQ((a - b) + (c + b), test7(a, b, c));
Asserts.assertEQ((a - b) + (c - a), test8(a, b, c));
Asserts.assertEQ(a + (0 - b) , test9(a, b));
Asserts.assertEQ((0 - b) + a , test10(a, b));
Asserts.assertEQ((a - b) + b , test11(a, b));
Asserts.assertEQ(b + (a - b) , test12(a, b));
Asserts.assertEQ(a + 0 , test13(a));
Asserts.assertEQ(0 + a , test14(a));
Asserts.assertEQ(a*b + a*c , test15(a, b, c));
Asserts.assertEQ(a*b + b*c , test16(a, b, c));
Asserts.assertEQ(a*c + b*c , test17(a, b, c));
Asserts.assertEQ(a*b + c*a , test18(a, b, c));
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks (x + x) + (x + x) => a=(x + x); r=a+a
public long additions(long x) {
return (x + x) + (x + x);
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks (x - x) => 0 and 0 - 0 => 0
public long xMinusX(long x) {
return (x - x) + (x - x);
}
@Test
@IR(counts = {IRNode.ADD, "1"})
// Checks (x + c1) + c2 => x + c3 where c3 = c1 + c2
public long test1(long x) {
return (x + 1) + 2;
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks (x + c1) + y => (x + y) + c1
public long test2(long x, long y) {
return (x + 2021) + y;
}
@Test
@IR(counts = {IRNode.ADD, "2"})
// Checks x + (y + c1) => (x + y) + c1
public long test3(long x, long y) {
return x + (y + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (c1 - x) + c2 => c3 - x where c3 = c1 + c2
public long test4(long x) {
return (1 - x) + 2;
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "2",
})
// Checks (a - b) + (c - d) => (a + c) - (b + d)
public long test5(long a, long b, long c, long d) {
return (a - b) + (c - d);
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (a - b) + (b + c) => (a + c)
public long test6(long a, long b, long c) {
return (a - b) + (b + c);
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (a - b) + (c + b) => (a + c)
public long test7(long a, long b, long c) {
return (a - b) + (c + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a - b) + (c - a) => (c - b)
public long test8(long a, long b, long c) {
return (a - b) + (c - a);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x + (0 - y) => (x - y)
public long test9(long x, long y) {
return x + (0 - y);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (0 - y) + x => (x - y)
public long test10(long x, long y) {
return (0 - y) + x;
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks (x - y) + y => x
public long test11(long x, long y) {
return (x - y) + y;
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.SUB})
// Checks y + (x - y) => x
public long test12(long x, long y) {
return y + (x - y);
}
@Test
@IR(failOn = {IRNode.ADD})
// Checks x + 0 => x
public long test13(long x) {
return x + 0;
}
@Test
@IR(failOn = {IRNode.ADD})
// Checks 0 + x => x
public long test14(long x) {
return 0 + x;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks "a*b + a*c => a*(b+c)
public long test15(long a, long b, long c) {
return a*b + a*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*b + b*c => b*(a+c)
public long test16(long a, long b, long c) {
return a*b + b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*c + b*c => (a+b)*c
public long test17(long a, long b, long c) {
return a*c + b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1"
})
// Checks a*b + c*a => a*(b+c)
public long test18(long a, long b, long c) {
return a*b + c*a;
}
}

@ -0,0 +1,205 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of DivINode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.DivINodeIdealizationTests
*/
public class DivINodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"constant", "identity", "identityAgain", "identityThird",
"retainDenominator", "divByNegOne", "divByPow2And",
"divByPow2And1", "divByPow2", "divByNegPow2",
"magicDiv"})
public void runMethod() {
int a = RunInfo.getRandom().nextInt();
a = (a == 0) ? 1 : a;
int b = RunInfo.getRandom().nextInt();
b = (b == 0) ? 1 : b;
int min = Integer.MIN_VALUE;
int max = Integer.MAX_VALUE;
assertResult(0, 0, true);
assertResult(a, b, false);
assertResult(min, min, false);
assertResult(max, max, false);
}
@DontCompile
public void assertResult(int a, int b, boolean shouldThrow) {
try {
Asserts.assertEQ(a / a, constant(a));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
try {
Asserts.assertEQ(a / (b / b), identityThird(a, b));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
try {
Asserts.assertEQ((a * b) / b, retainDenominator(a, b));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
Asserts.assertEQ(a / 1 , identity(a));
Asserts.assertEQ(a / (13 / 13), identityAgain(a));
Asserts.assertEQ(a / -1 , divByNegOne(a));
Asserts.assertEQ((a & -4) / 2 , divByPow2And(a));
Asserts.assertEQ((a & -2) / 2 , divByPow2And1(a));
Asserts.assertEQ(a / 8 , divByPow2(a));
Asserts.assertEQ(a / -8 , divByNegPow2(a));
Asserts.assertEQ(a / 13 , magicDiv(a));
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"})
// Checks x / x => 1
public int constant(int x) {
return x / x;
}
@Test
@IR(failOn = {IRNode.DIV})
// Checks x / 1 => x
public int identity(int x) {
return x / 1;
}
@Test
@IR(failOn = {IRNode.DIV})
// Checks x / (c / c) => x
public int identityAgain(int x) {
return x / (13 / 13);
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"})
// Checks x / (y / y) => x
public int identityThird(int x, int y) {
return x / (y / y);
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.DIV, "1",
IRNode.DIV_BY_ZERO_TRAP, "1"
})
// Hotspot should keep the division because it may cause a division by zero trap
public int retainDenominator(int x, int y) {
return (x * y) / y;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.SUB_I, "1"})
// Checks x / -1 => 0 - x
public int divByNegOne(int x) {
return x / -1;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.AND, "1",
IRNode.RSHIFT, "1",
})
// Checks (x & -(2^c0)) / 2^c1 => (x >> c1) & (2^c0 >> c1) => (x >> c1) & c3 where 2^c0 > |2^c1| "AND" c3 = 2^c0 >> c1
// Having a large enough and in the dividend removes the need to account for rounding when converting to shifts and multiplies as in divByPow2()
public int divByPow2And(int x) {
return (x & -4) / 2;
}
@Test
@IR(failOn = {IRNode.DIV, IRNode.AND})
@IR(counts = {IRNode.RSHIFT, "1"})
// Checks (x & -(2^c0)) / 2^c0 => x >> c0
// If the negative of the constant within the & equals the divisor then the and can be removed as it only affects bits that will be shifted off
public int divByPow2And1(int x) {
return (x & -2) / 2;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.URSHIFT, "1",
IRNode.RSHIFT, "2",
IRNode.ADD_I, "1",
})
// Checks x / 2^c0 => x + ((x >> (32-1)) >>> (32 - c0)) >> c0 => x + ((x >> 31) >>> c1) >> c0 where c1 = 32 - c0
// An additional (dividend - 1) needs to be added to the shift to account for rounding when dealing with negative numbers.
// Since x may be negative in this method, an additional add, logical right shift, and signed shift are needed to account for rounding.
public int divByPow2(int x) {
return x / 8;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.URSHIFT, "1",
IRNode.RSHIFT, "2",
IRNode.ADD_I, "1",
IRNode.SUB_I, "1",
})
// Checks x / -(2^c0) =>0 - (x + ((x >> (32-1)) >>> (32 - c0)) >> c0) => 0 - (x + ((x >> 31) >>> c1) >> c0) where c1 = 32 - c0
// Similar to divByPow2() except a negative divisor turns positive.
// After the transformations, 0 is subtracted by the whole expression
// to account for the negative.
public int divByNegPow2(int x) {
return x / -8;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.SUB, "1",
IRNode.MUL, "1",
IRNode.CONV_I2L, "1",
IRNode.CONV_L2I, "1",
})
// Checks magic int division occurs in general when dividing by a non power of 2.
// More tests can be made to cover the specific cases for differences in the
// graph that depend upon different values for the "magic constant" and the
// "shift constant"
public int magicDiv(int x) {
return x / 13;
}
}

@ -0,0 +1,190 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of DivLNode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.DivLNodeIdealizationTests
*/
public class DivLNodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"constant", "identity", "identityAgain", "identityThird",
"retainDenominator", "divByNegOne", "divByPow2And",
"divByPow2And1", "divByPow2", "divByNegPow2"})
public void runMethod() {
long a = RunInfo.getRandom().nextLong();
a = (a == 0) ? 1 : a;
long b = RunInfo.getRandom().nextLong();
b = (b == 0) ? 1 : b;
long min = Long.MIN_VALUE;
long max = Long.MAX_VALUE;
assertResult(0, 0, true);
assertResult(a, b, false);
assertResult(min, min, false);
assertResult(max, max, false);
}
@DontCompile
public void assertResult(long a, long b, boolean shouldThrow) {
try {
Asserts.assertEQ(a / a, constant(a));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
try {
Asserts.assertEQ((a * b) / b, retainDenominator(a, b));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
try {
Asserts.assertEQ(a / (b / b), identityThird(a, b));
Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown.");
}
catch (ArithmeticException e) {
Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown.");
}
Asserts.assertEQ(a / 1 , identity(a));
Asserts.assertEQ(a / (13 / 13), identityAgain(a));
Asserts.assertEQ(a / -1 , divByNegOne(a));
Asserts.assertEQ((a & -4) / 2 , divByPow2And(a));
Asserts.assertEQ((a & -2) / 2 , divByPow2And1(a));
Asserts.assertEQ(a / 8 , divByPow2(a));
Asserts.assertEQ(a / -8 , divByNegPow2(a));
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"})
// Checks x / x => 1
public long constant(long x) {
return x / x;
}
@Test
@IR(failOn = {IRNode.DIV})
// Checks x / 1 => x
public long identity(long x) {
return x / 1L;
}
@Test
@IR(failOn = {IRNode.DIV})
// Checks x / (c / c) => x
public long identityAgain(long x) {
return x / (13L / 13L);
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"})
// Checks x / (y / y) => x
public long identityThird(long x, long y) {
return x / (y / y);
}
@Test
@IR(counts = {IRNode.MUL_L, "1",
IRNode.DIV_L, "1",
IRNode.DIV_BY_ZERO_TRAP, "1"
})
// Hotspot should keep the division because it may cause a division by zero trap
public long retainDenominator(long x, long y) {
return (x * y) / y;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.SUB, "1"})
// Checks x / -1 => 0 - x
public long divByNegOne(long x) {
return x / -1L;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.AND, "1",
IRNode.RSHIFT, "1",
})
// Checks (x & -(2^c0)) / 2^c1 => (x >> c1) & (2^c0 >> c1) => (x >> c1) & c3 where 2^c0 > |2^c1| "and" c3 = 2^c0 >> c1
// Having a large enough and in the dividend removes the need to account for
// rounding when converting to shifts and multiplies as in divByPow2()
public long divByPow2And(long x) {
return (x & -4L) / 2L;
}
@Test
@IR(failOn = {IRNode.DIV, IRNode.AND})
@IR(counts = {IRNode.RSHIFT, "1"})
// Checks (x & -(2^c0)) / 2^c0 => x >> c0
// If the negative of the constant within the & equals the divisor then
// the and can be removed as it only affects bits that will be shifted off
public long divByPow2And1(long x) {
return (x & -2L) / 2L;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.URSHIFT, "1",
IRNode.RSHIFT, "2",
IRNode.ADD, "1",
})
// Checks x / 2^c0 => x + ((x >>)ith negative numbers. Since x may be negative
// in this method, an additional add, logical right shift, and signed shift
// are needed to account for rounding.
public long divByPow2(long x) {
return x / 8L;
}
@Test
@IR(failOn = {IRNode.DIV})
@IR(counts = {IRNode.URSHIFT, "1",
IRNode.RSHIFT, "2",
IRNode.ADD, "1",
IRNode.SUB, "1",
})
// Checks x / -(2^c0) =>0 - (x + ((x >> (32-1)) >>> (32 - c0)) >> c0) => 0 - (x + ((x >> 31) >>> c1) >> c0) where c1 = 32 - c0
// Similar to divByPow2() except a negative divisor turns positive.
// After the transformations, 0 is subtracted by the whole expression
// to account for the negative.
public long divByNegPow2(long x) {
return x / -8L;
}
}

@ -0,0 +1,166 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of MulINode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.MulINodeIdealizationTests
*/
public class MulINodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"combineConstants", "moveConstants", "moveConstantsAgain",
"multiplyZero", "multiplyZeroAgain", "distribute",
"identity", "identityAgain", "powerTwo",
"powerTwoAgain", "powerTwoPlusOne", "powerTwoMinusOne"})
public void runMethod() {
int a = RunInfo.getRandom().nextInt();
int b = RunInfo.getRandom().nextInt();
int min = Integer.MIN_VALUE;
int max = Integer.MAX_VALUE;
assertResult(0, 0);
assertResult(a, b);
assertResult(min, min);
assertResult(max, max);
}
@DontCompile
public void assertResult(int a, int b) {
Asserts.assertEQ((a * 13) * 14 , combineConstants(a));
Asserts.assertEQ((a * 13) * b , moveConstants(a, b));
Asserts.assertEQ(a * (b * 13) , moveConstantsAgain(a, b));
Asserts.assertEQ(0 * a , multiplyZero(a));
Asserts.assertEQ(a * 0 , multiplyZeroAgain(a));
Asserts.assertEQ((13 + a) * 14 , distribute(a));
Asserts.assertEQ(1 * a , identity(a));
Asserts.assertEQ(a * 1 , identityAgain(a));
Asserts.assertEQ(a * 64 , powerTwo(a));
Asserts.assertEQ(a * (1025 - 1), powerTwoAgain(a));
Asserts.assertEQ(a * (64 + 1) , powerTwoPlusOne(a));
Asserts.assertEQ(a * (64 - 1) , powerTwoMinusOne(a));
}
@Test
@IR(counts = {IRNode.MUL, "1"})
//Checks (x * c1) * c2 => x * c3 where c3 = c1 * c2
public int combineConstants(int x){
return (x * 13) * 14;
}
@Test
@IR(counts = {IRNode.MUL, "2"})
// Checks (x * c1) * y => (x * y) * c1
public int moveConstants(int x, int y) {
return (x * 13) * y;
}
@Test
@IR(counts = {IRNode.MUL, "2"})
// Checks x * (y * c1) => (x * y) * c1
public int moveConstantsAgain(int x, int y) {
return x * (y * 13);
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks 0 * x => 0
public int multiplyZero(int x) {
return 0 * x;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks x * 0 => 0
public int multiplyZeroAgain(int x) {
return x * 0;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1",
})
// Checks (c1 + x) * c2 => x * c2 + c3 where c3 = c1 * c2
public int distribute(int x) {
return (13 + x) * 14;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks 1 * x => x
public int identity(int x) {
return 1 * x;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks x * 1 => x
public int identityAgain(int x) {
return x * 1;
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1"})
// Checks x * 2^n => x << n
public int powerTwo(int x) {
return x * 64;
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1"})
// Checks x * 2^n => x << n
public int powerTwoAgain(int x) {
return x * (1025 - 1);
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1",
IRNode.ADD, "1",
})
// Checks x * (2^n + 1) => (x << n) + x
public int powerTwoPlusOne(int x) {
return x * (64 + 1);
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1",
IRNode.SUB, "1",
})
// Checks x * (2^n - 1) => (x << n) - x
public int powerTwoMinusOne(int x) {
return x * (64 - 1);
}
}

@ -0,0 +1,166 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of MulLNode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.MulLNodeIdealizationTests
*/
public class MulLNodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"combineConstants", "moveConstants", "moveConstantsAgain",
"multiplyZero", "multiplyZeroAgain", "distribute",
"identity", "identityAgain", "powerTwo",
"powerTwoAgain", "powerTwoPlusOne", "powerTwoMinusOne"})
public void runMethod() {
long a = RunInfo.getRandom().nextLong();
long b = RunInfo.getRandom().nextLong();
long min = Long.MIN_VALUE;
long max = Long.MAX_VALUE;
assertResult(0, 0);
assertResult(a, b);
assertResult(min, min);
assertResult(max, max);
}
@DontCompile
public void assertResult(long a, long b) {
Asserts.assertEQ((a * 13) * 14 * 15, combineConstants(a));
Asserts.assertEQ((a * 13) * b , moveConstants(a, b));
Asserts.assertEQ(a * (b * 13) , moveConstantsAgain(a, b));
Asserts.assertEQ(0 * a , multiplyZero(a));
Asserts.assertEQ(a * 0 , multiplyZeroAgain(a));
Asserts.assertEQ((13 + a) * 14 , distribute(a));
Asserts.assertEQ(1 * a , identity(a));
Asserts.assertEQ(a * 1 , identityAgain(a));
Asserts.assertEQ(a * 64 , powerTwo(a));
Asserts.assertEQ(a * (1025 - 1) , powerTwoAgain(a));
Asserts.assertEQ(a * (64 + 1) , powerTwoPlusOne(a));
Asserts.assertEQ(a * (64 - 1) , powerTwoMinusOne(a));
}
@Test
@IR(counts = {IRNode.MUL, "1"})
//Checks (x * c1) * c2 => x * c3 where c3 = c1 * c2
public long combineConstants(long x){
return (x * 13) * 14 * 15;
}
@Test
@IR(counts = {IRNode.MUL, "2"})
// Checks (x * c1) * y => (x * y) * c1
public long moveConstants(long x, long y) {
return (x * 13) * y;
}
@Test
@IR(counts = {IRNode.MUL, "2"})
// Checks x * (y * c1) => (x * y) * c1
public long moveConstantsAgain(long x, long y) {
return x * (y * 13);
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks 0 * x => 0
public long multiplyZero(long x) {
return 0 * x;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks x * 0 => 0
public long multiplyZeroAgain(long x) {
return x * 0;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.ADD, "1",
})
// Checks (c1 + x) * c2 => x * c2 + c3 where c3 = c1 * c2
public long distribute(long x) {
return (13 + x) * 14;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks 1 * x => x
public long identity(long x) {
return 1 * x;
}
@Test
@IR(failOn = {IRNode.MUL})
// Checks x * 1 => x
public long identityAgain(long x) {
return x * 1;
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1"})
// Checks x * 2^n => x << n
public long powerTwo(long x) {
return x * 64;
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1"})
// Checks x * 2^n => x << n
public long powerTwoAgain(long x) {
return x * (1025 - 1);
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1",
IRNode.ADD, "1",
})
// Checks x * (2^n + 1) => (x << n) + x
public long powerTwoPlusOne(long x) {
return x * (64 + 1);
}
@Test
@IR(failOn = {IRNode.MUL})
@IR(counts = {IRNode.LSHIFT, "1",
IRNode.SUB, "1",
})
// Checks x * (2^n - 1) => (x << n) - x
public long powerTwoMinusOne(long x) {
return x * (64 - 1);
}
}

@ -0,0 +1,252 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of SubINode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.SubINodeIdealizationTests
*/
public class SubINodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"test1", "test2", "test3",
"test4", "test5", "test6",
"test7", "test8", "test9",
"test10", "test11", "test12",
"test13", "test14", "test15",
"test16", "test17", "test18",
"test19", "test20", "test21"})
public void runMethod() {
int a = RunInfo.getRandom().nextInt();
int b = RunInfo.getRandom().nextInt();
int c = RunInfo.getRandom().nextInt();
int min = Integer.MIN_VALUE;
int max = Integer.MAX_VALUE;
assertResult(0, 0, 0);
assertResult(a, b, c);
assertResult(min, min, min);
assertResult(max, max, max);
}
@DontCompile
public void assertResult(int a, int b, int c) {
Asserts.assertEQ(a - 1 , test1(a));
Asserts.assertEQ((a + 1) - b , test2(a, b));
Asserts.assertEQ(a - (b + 2021) , test3(a, b));
Asserts.assertEQ(a - (a + b) , test4(a, b));
Asserts.assertEQ((a - b) - a , test5(a, b));
Asserts.assertEQ(a - (b + a) , test6(a, b));
Asserts.assertEQ(0 - (a - b) , test7(a, b));
Asserts.assertEQ(0 - (a + 2021) , test8(a));
Asserts.assertEQ((a + b) - (a + c), test9(a, b, c));
Asserts.assertEQ((b + a) - (c + a), test10(a, b, c));
Asserts.assertEQ((b + a) - (a + c), test11(a, b, c));
Asserts.assertEQ((a + b) - (c + a), test12(a, b, c));
Asserts.assertEQ(a - (b - c) , test13(a, b, c));
Asserts.assertEQ(0 - (a >> 31) , test14(a));
Asserts.assertEQ(0 - (0 - a) , test15(a));
Asserts.assertEQ((a + b) - b , test16(a, b));
Asserts.assertEQ((a + b) - a , test17(a, b));
Asserts.assertEQ(a*b - a*c , test18(a, b, c));
Asserts.assertEQ(a*b - b*c , test19(a, b, c));
Asserts.assertEQ(a*c - b*c , test20(a, b, c));
Asserts.assertEQ(a*b - c*a , test21(a, b, c));
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (x - c0) => x + (-c0)
public int test1(int x) {
return (x - 1);
}
@Test
@IR(counts = {IRNode.ADD, "1",
IRNode.SUB, "1"
})
// Checks (x + c0) - y => (x - y) + c0
public int test2(int x, int y) {
return (x + 1) - y;
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "1"
})
// Checks x - (y + c0) => (x - y) + (-c0)
public int test3(int x, int y) {
return x - (y + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x - (x + y) => -y
public int test4(int x, int y) {
return x - (x + y);
}
@Test
@IR(counts = {IRNode.SUB, "1"})
// Checks (x - y) - x => -y
public int test5(int x, int y) {
return (x - y) - x;
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x - (y + x) => -y
public int test6(int x, int y) {
return x - (y + x);
}
@Test
@IR(counts = {IRNode.SUB, "1"})
// Checks 0 - (x - y) => y - x
public int test7(int x, int y) {
return 0 - (x - y);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks 0 - (x + 2021) => -2021 - x
public int test8(int x) {
return 0 - (x + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (x + a) - (x + b) => a - b;
public int test9(int x, int a, int b) {
return (x + a) - (x + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a + x) - (b + x) => a - b
public int test10(int x, int a, int b) {
return (a + x) - (b + x);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a + x) - (x + b) => a - b
public int test11(int x, int a, int b) {
return (a + x) - (x + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (x + a) - (b + x) => a - b
public int test12(int x, int a, int b) {
return (x + a) - (b + x);
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "1"
})
// Checks a - (b - c) => (a + c) - b
public int test13(int a, int b, int c) {
return a - (b - c);
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.RSHIFT_I})
@IR(counts = {IRNode.URSHIFT_I, "1"})
// Checks 0 - (a >> 31) => a >>> 31
// signed ^^ ^^^ unsigned
public int test14(int a) {
return 0 - (a >> 31);
}
@Test
@IR(failOn = {IRNode.SUB})
// Checks 0 - (0 - x) => x
public int test15(int x) {
return 0 - (0 - x);
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.ADD})
// Checks (x + y) - y => y
public int test16(int x, int y) {
return (x + y) - y;
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.ADD})
// Checks (x + y) - x => y
public int test17(int x, int y) {
return (x + y) - x;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks "a*b-a*c => a*(b-c)
public int test18(int a, int b, int c) {
return a*b - a*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*b-b*c => b*(a-c)
public int test19(int a, int b, int c) {
return a*b - b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*c-b*c => (a-b)*c
public int test20(int a, int b, int c) {
return a*c - b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*b-c*a => a*(b-c)
public int test21(int a, int b, int c) {
return a*b - c*a;
}
}

@ -0,0 +1,227 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests;
import jdk.test.lib.Asserts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of SubLNode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.SubLNodeIdealizationTests
*/
public class SubLNodeIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@Run(test = {"test1", "test2", "test3",
"test4", "test5", "test6",
"test7", "test8", "test9",
"test10", "test11", "test12",
"test13", "test14", "test15",
"test16", "test17", "test18"})
public void runMethod() {
long a = RunInfo.getRandom().nextLong();
long b = RunInfo.getRandom().nextLong();
long c = RunInfo.getRandom().nextLong();
long min = Long.MIN_VALUE;
long max = Long.MAX_VALUE;
assertResult(0, 0, 0);
assertResult(a, b, c);
assertResult(min, min, min);
assertResult(max, max, max);
}
@DontCompile
public void assertResult(long a, long b, long c) {
Asserts.assertEQ(a - 1 , test1(a));
Asserts.assertEQ((a + 1) - b , test2(a, b));
Asserts.assertEQ(a - (b + 2021) , test3(a, b));
Asserts.assertEQ(a - (a + b) , test4(a, b));
Asserts.assertEQ(a - (b + a) , test5(a, b));
Asserts.assertEQ(0 - (a - b) , test6(a, b));
Asserts.assertEQ(0 - (a + 2021) , test7(a, b));
Asserts.assertEQ((a + b) - (a + c), test8(a, b, c));
Asserts.assertEQ((b + a) - (c + a), test9(a, b, c));
Asserts.assertEQ((b + a) - (a + c), test10(a, b, c));
Asserts.assertEQ((a + b) - (c + a), test11(a, b, c));
Asserts.assertEQ(a - (b - c) , test12(a, b, c));
Asserts.assertEQ(0 - (a >> 63) , test13(a));
Asserts.assertEQ(0 - (0 - a) , test14(a));
Asserts.assertEQ(a*b - a*c , test15(a, b, c));
Asserts.assertEQ(a*b - b*c , test16(a, b, c));
Asserts.assertEQ(a*c - b*c , test17(a, b, c));
Asserts.assertEQ(a*b - c*a , test18(a, b, c));
}
@Test
@IR(failOn = {IRNode.SUB})
@IR(counts = {IRNode.ADD, "1"})
// Checks (x - c0) => x + (-c0)
public long test1(long x) {
return (x - 1);
}
@Test
@IR(counts = {IRNode.ADD, "1",
IRNode.SUB, "1"
})
// Checks (x + c0) - y => (x - y) + c0
public long test2(long x, long y) {
return (x + 1) - y;
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "1"
})
// Checks x - (y + c0) => (x - y) + (-c0)
public long test3(long x, long y) {
return x - (y + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x - (x + y) => 0 - y
public long test4(long x, long y) {
return x - (x + y);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks x - (y + x) => 0 - y
public long test5(long x, long y) {
return x - (y + x);
}
@Test
@IR(counts = {IRNode.SUB, "1"})
// Checks 0 - (x - y) => y - x
public long test6(long x, long y) {
return 0 - (x - y);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks 0 - (x + 2021) => -2021 - x
public long test7(long x, long y) {
return 0 - (x + 2021);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (x + a) - (x + b) => a - b;
public long test8(long x, long a, long b) {
return (x + a) - (x + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a + x) - (b + x) => a - b
public long test9(long x, long a, long b) {
return (a + x) - (b + x);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (a + x) - (x + b) => a - b
public long test10(long x, long a, long b) {
return (a + x) - (x + b);
}
@Test
@IR(failOn = {IRNode.ADD})
@IR(counts = {IRNode.SUB, "1"})
// Checks (x + a) - (b + x) => a - b
public long test11(long x, long a, long b) {
return (x + a) - (b + x);
}
@Test
@IR(counts = {IRNode.SUB, "1",
IRNode.ADD, "1"
})
// Checks a - (b - c) => (a + c) - b
public long test12(long a, long b, long c) {
return a - (b - c);
}
@Test
@IR(failOn = {IRNode.SUB, IRNode.RSHIFT_L})
@IR(counts = {IRNode.URSHIFT_L, "1"})
// Checks 0 - (a >> 63) => a >>> 63
// signed ^^ ^^^ unsigned
public long test13(long a) {
return 0 - (a >> 63);
}
@Test
@IR(failOn = {IRNode.SUB})
// Checks 0 - (0 - x) => x
public long test14(long x) {
return 0 - (0 - x);
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks "a*b-a*c => a*(b-c)
public long test15(long a, long b, long c) {
return a*b - a*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*b-b*c => b*(a-c)
public long test16(long a, long b, long c) {
return a*b - b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*c-b*c => (a-b)*c
public long test17(long a, long b, long c) {
return a*c - b*c;
}
@Test
@IR(counts = {IRNode.MUL, "1",
IRNode.SUB, "1"})
// Checks a*b-c*a => a*(b-c)
public long test18(long a, long b, long c) {
return a*b - c*a;
}
}

@ -0,0 +1,171 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests.loopOpts;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Test that Ideal transformations of CountedLoopNode* are being performed as expected.
* @library /test/lib /
* @run driver compiler.c2.irTests.loopOpts.LoopIdealizationTests
*/
public class LoopIdealizationTests {
public static void main(String[] args) {
TestFramework.run();
}
@DontInline
private void blackhole() { }
@Test
@IR(failOn = {IRNode.MUL, IRNode.DIV, IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.CALL})
// Checks that a for loop with 0 iterations is removed
public void zeroIterForLoop() {
for (int i = 0; i < 0; i++) {
System.out.println(13 / 17 * 23 + 1);
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.CALL})
// Checks that a for loop with 1 iteration doesn't have CountedLoop nodes
public void iterOneBreakForLoop() {
for (int i = 0; i < 500; i++) {
break;
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a for loop with 1 iteration is simplified to straight code
public void oneIterForLoop() {
for (int i = 0; i < 1; i++) {
this.blackhole();
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a for loop with 1 iteration is simplified to straight code
public void oneIterForLoop1() {
for (int i = 0; i < 500; i++) {
this.blackhole();
break;
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a for loop with 1 iteration is simplified to straight code
public void oneIterForLoop2() {
for (int i = 0; i < 500; i++) {
this.blackhole();
if (i == 0) {
break;
}
else {
this.blackhole();
i++;
}
}
}
@Test
@IR(failOn = {IRNode.LOOP, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterWhileLoop() {
while (true) {
this.blackhole();
break;
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterWhileLoop1() {
int i = 0;
while (i < 1) {
this.blackhole();
i++;
}
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterWhileLoop2() {
int i = 0;
while (i < 500) {
this.blackhole();
if (i == 0) {
break;
}
else {
this.blackhole();
i++;
}
}
}
@Test
@IR(failOn = {IRNode.LOOP, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterDoWhileLoop() {
do {
this.blackhole();
break;
} while (true);
}
@Test
@IR(failOn = {IRNode.LOOP, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterDoWhileLoop1() {
do {
this.blackhole();
} while (false);
}
@Test
@IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.TRAP})
@IR(counts = {IRNode.CALL, "1"})
// Checks that a while loop with 1 iteration is simplified to straight code
public void oneIterDoWhileLoop2() {
int i = 0;
do {
this.blackhole();
i++;
} while (i == -1);
}
}

@ -0,0 +1,100 @@
/*
* Copyright (c) 2022, 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 compiler.c2.irTests.scalarReplacement;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8267265
* @summary Tests that Escape Analysis and Scalar Replacement is able to handle some simple cases.
* @library /test/lib /
* @run driver compiler.c2.irTests.scalarReplacement.ScalarReplacementTests
*/
public class ScalarReplacementTests {
private class Person {
private String name;
private int age;
public Person(Person p) {
this.name = p.getName();
this.age = p.getAge();
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
public static void main(String[] args) {
TestFramework.run();
}
@Test
@Arguments(Argument.RANDOM_EACH)
@IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC})
public String stringConstant(int age) {
Person p = new Person("Java", age);
return p.getName();
}
@Test
@Arguments(Argument.RANDOM_EACH)
@IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC})
public int intConstant(int age) {
Person p = new Person("Java", age);
return p.getAge();
}
@Test
@Arguments(Argument.RANDOM_EACH)
@IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC})
public String nestedStringConstant(int age) {
Person p1 = new Person("Java", age);
Person p2 = new Person(p1);
return p2.getName();
}
@Test
@Arguments(Argument.RANDOM_EACH)
@IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC})
public int nestedIntConstant(int age) {
Person p1 = new Person("Java", age);
Person p2 = new Person(p1);
return p2.getAge();
}
@Test
@Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH})
@IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC})
public int nestedConstants(int age1, int age2) {
Person p = new Person(
new Person("Java", age1).getName(),
new Person("Java", age2).getAge());
return p.getAge();
}
}

@ -130,6 +130,7 @@ public class IRNode {
public static final String RANGE_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*range_check" + END;
public static final String UNHANDLED_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unhandled" + END;
public static final String INTRINSIC_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic" + END;
public static final String DIV_BY_ZERO_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*div0_check" + END;
// Does not work for VM builds without JVMCI like x86_32 (a rule containing this regex will be skipped without having JVMCI built).
public static final String INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic_or_type_checked_inlining" + END;
@ -140,22 +141,36 @@ public class IRNode {
public static final String ABS_L = START + "AbsL" + MID + END;
public static final String ABS_F = START + "AbsF" + MID + END;
public static final String ABS_D = START + "AbsD" + MID + END;
public static final String AND = START + "And(I|L)" + MID + END;
public static final String AND_I = START + "AndI" + MID + END;
public static final String AND_L = START + "AndL" + MID + END;
public static final String XOR_I = START + "XorI" + MID + END;
public static final String XOR_L = START + "XorL" + MID + END;
public static final String LSHIFT = START + "LShift(I|L)" + MID + END;
public static final String LSHIFT_I = START + "LShiftI" + MID + END;
public static final String LSHIFT_L = START + "LShiftL" + MID + END;
public static final String RSHIFT = START + "RShift(I|L)" + MID + END;
public static final String RSHIFT_I = START + "RShiftI" + MID + END;
public static final String RSHIFT_L = START + "RShiftL" + MID + END;
public static final String URSHIFT = START + "URShift(B|S|I|L)" + MID + END;
public static final String URSHIFT_I = START + "URShiftI" + MID + END;
public static final String URSHIFT_L = START + "URShiftL" + MID + END;
public static final String ADD = START + "Add(I|L|F|D|P)" + MID + END;
public static final String ADD_I = START + "AddI" + MID + END;
public static final String ADD_L = START + "AddL" + MID + END;
public static final String ADD_VD = START + "AddVD" + MID + END;
public static final String SUB = START + "Sub(I|L|F|D)" + MID + END;
public static final String SUB_I = START + "SubI" + MID + END;
public static final String SUB_L = START + "SubL" + MID + END;
public static final String SUB_F = START + "SubF" + MID + END;
public static final String SUB_D = START + "SubD" + MID + END;
public static final String MUL = START + "Mul(I|L|F|D)" + MID + END;
public static final String MUL_I = START + "MulI" + MID + END;
public static final String MUL_L = START + "MulL" + MID + END;
public static final String DIV = START + "Div(I|L|F|D)" + MID + END;
public static final String DIV_L = START + "DivL" + MID + END;
public static final String CONV_I2L = START + "ConvI2L" + MID + END;
public static final String CONV_L2I = START + "ConvL2I" + MID + END;
public static final String VECTOR_CAST_B2X = START + "VectorCastB2X" + MID + END;
public static final String VECTOR_CAST_S2X = START + "VectorCastS2X" + MID + END;