diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java b/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java
index d3d86e64164..841aa9a9867 100644
--- a/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java
+++ b/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java
@@ -41,16 +41,58 @@ public class TestBoolNodeGVN {
}
/**
- * Test changing ((x & m) u<= m) or ((m & x) u<= m) to always true, same with ((x & m) u< m+1) and ((m & x) u< m+1)
- * The test is only applicable to x64, aarch64 and riscv64 for having Integer.compareUnsigned
- * intrinsified.
+ * Test CmpUNode::Value_cmpu_and_mask optimizations for cases 1a and 1b.
+ * The test is only applicable to x64, aarch64 and riscv64 for having
+ * Integer.compareUnsigned intrinsified.
*/
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForEQxm(int x, int m) {
+ // [BoolTest::eq] 1a) x & m =u m is unknown
+ return Integer.compareUnsigned((x & m), m) == 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForEQmx(int x, int m) {
+ // [BoolTest::eq] 1a) m & x =u m is unknown
+ return Integer.compareUnsigned((m & x), m) == 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForNExm(int x, int m) {
+ // [BoolTest::ne] 1a) x & m ≠u m is unknown
+ return Integer.compareUnsigned((x & m), m) != 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForNEmx(int x, int m) {
+ // [BoolTest::ne] 1a) m & x ≠u m is unknown
+ return Integer.compareUnsigned((m & x), m) != 0;
+ }
+
@Test
@Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
@IR(failOn = IRNode.CMP_U,
phase = CompilePhase.AFTER_PARSING,
applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
- public static boolean testShouldReplaceCpmUCase1(int x, int m) {
+ public static boolean testCase1aOptimizeAsTrueForLExm(int x, int m) {
+ // [BoolTest::le] 1a) x & m ≤u m is always true
return Integer.compareUnsigned((x & m), m) <= 0;
}
@@ -59,16 +101,166 @@ public class TestBoolNodeGVN {
@IR(failOn = IRNode.CMP_U,
phase = CompilePhase.AFTER_PARSING,
applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
- public static boolean testShouldReplaceCpmUCase2(int x, int m) {
+ public static boolean testCase1aOptimizeAsTrueForLEmx(int x, int m) {
+ // [BoolTest::le] 1a) m & x ≤u m is always true
return Integer.compareUnsigned((m & x), m) <= 0;
}
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForGExm(int x, int m) {
+ // [BoolTest::ge] 1a) x & m ≥u m is unknown
+ return Integer.compareUnsigned((x & m), m) >= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForGEmx(int x, int m) {
+ // [BoolTest::ge] 1a) m & x ≥u m is unknown
+ return Integer.compareUnsigned((m & x), m) >= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(counts = {IRNode.CMP_U, "1"},
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aDoNotOptimizeForLTxm(int x, int m) {
+ // [BoolTest::lt] 1a) x & m u m is always false
+ return Integer.compareUnsigned((x & m), m) > 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1aOptimizeAsFalseForGTmx(int x, int m) {
+ // [BoolTest::gt] 1a) m & x >u m is always false
+ return Integer.compareUnsigned((m & x), m) > 0;
+ }
+
@Test
@Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
@IR(failOn = IRNode.CMP_U,
phase = CompilePhase.AFTER_PARSING,
applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
- public static boolean testShouldReplaceCpmUCase3(int x, int m) {
+ public static boolean testCase1bOptimizeAsFalseForEQxm(int x, int m) {
+ // [BoolTest::eq] 1b) x & m =u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((x & m), m + 1) == 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsFalseForEQmx(int x, int m) {
+ // [BoolTest::eq] 1b) m & x =u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((m & x), m + 1) == 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsTrueForNExm(int x, int m) {
+ // [BoolTest::ne] 1b) x & m ≠u m + 1 is always true (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((x & m), m + 1) != 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsTrueForNEmx(int x, int m) {
+ // [BoolTest::ne] 1b) m & x ≠u m + 1 is always true (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((m & x), m + 1) != 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsTrueForLExm(int x, int m) {
+ // [BoolTest::le] 1b) x & m ≤u m + 1 is always true (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((x & m), m + 1) <= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsTrueForLEmx(int x, int m) {
+ // [BoolTest::le] 1b) m & x ≤u m + 1 is always true (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((m & x), m + 1) <= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsFalseForGExm(int x, int m) {
+ // [BoolTest::ge] 1b) x & m ≥u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((x & m), m + 1) >= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsFalseForGEmx(int x, int m) {
+ // [BoolTest::ge] 1b) m & x ≥u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((m & x), m + 1) >= 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsTrueForLTxm(int x, int m) {
+ // [BoolTest::lt] 1b) x & m u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((x & m), m + 1) > 0;
+ }
+
+ @Test
+ @Arguments(values = {Argument.DEFAULT, Argument.RANDOM_EACH})
+ @IR(failOn = IRNode.CMP_U,
+ phase = CompilePhase.AFTER_PARSING,
+ applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"})
+ public static boolean testCase1bOptimizeAsFalseForGTmx(int x, int m) {
+ // [BoolTest::gt] 1b) m & x >u m + 1 is always false (if m ≠ -1)
+ m = Math.max(0, m);
+ return Integer.compareUnsigned((m & x), m + 1) > 0;
+ }
+
@Test
@Arguments(values = {Argument.DEFAULT, Argument.DEFAULT})
@IR(counts = {IRNode.CMP_U, "1"}, // m could be -1 and thus optimization cannot be applied
@@ -145,11 +360,23 @@ public class TestBoolNodeGVN {
for (int x : values) {
for (int m : values) {
- if (!testShouldReplaceCpmUCase1(x, m) ||
- !testShouldReplaceCpmUCase2(x, m) ||
- !testShouldReplaceCpmUCase3(x, m) ||
- !testShouldReplaceCpmUCase4(x, m)) {
- throw new RuntimeException("Bad result for x = " + x + " and m = " + m + ", expected always true");
+ if (!testCase1aOptimizeAsTrueForLExm(x, m) ||
+ !testCase1aOptimizeAsTrueForLEmx(x, m) ||
+ testCase1aOptimizeAsFalseForGTxm(x, m) ||
+ testCase1aOptimizeAsFalseForGTmx(x, m) ||
+ testCase1bOptimizeAsFalseForEQxm(x, m) ||
+ testCase1bOptimizeAsFalseForEQmx(x, m) ||
+ !testCase1bOptimizeAsTrueForNExm(x, m) ||
+ !testCase1bOptimizeAsTrueForNEmx(x, m) ||
+ !testCase1bOptimizeAsTrueForLExm(x, m) ||
+ !testCase1bOptimizeAsTrueForLEmx(x, m) ||
+ testCase1bOptimizeAsFalseForGExm(x, m) ||
+ testCase1bOptimizeAsFalseForGEmx(x, m) ||
+ !testCase1bOptimizeAsTrueForLTxm(x, m) ||
+ !testCase1bOptimizeAsTrueForLTmx(x, m) ||
+ testCase1bOptimizeAsFalseForGTxm(x, m) ||
+ testCase1bOptimizeAsFalseForGTmx(x, m)) {
+ throw new RuntimeException("Bad result for x = " + x + " and m = " + m);
}
}
}