diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 823745ea8e7fd..16e93a8010e51 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -541,6 +541,23 @@ Node *DivINode::Ideal(PhaseGVN *phase, bool can_reshape) { // Dividing by MININT does not optimize as a power-of-2 shift. if( i == min_jint ) return nullptr; + // Keep this node as-is initially; we want Value() and + // other optimizations checking for this node type to work. + // Consider the following expression: + // x / 100_000 >= 21_475, x in TypeInt::INT + // This will always be false since max_jint / 100_000 == 21_474. + // After transform_int_divide, we have a Sub node to round towards 0. + // That means we subtract -1 if the dividend is negative, and 0 otherwise. + // As the Sub node is not aware of representing a division, it overapproximates + // [-21_475, 21_474] - [-1, 0] = [-21_475, 21_475], which prevents constant folding. + // + // Less precise comparisons still work after transform_int_divide, e.g., + // comparing with >= 21_476 does not conflict with the off-by-one overapproximation. + if (phase->is_IterGVN() == nullptr) { + phase->C->record_for_igvn(this); + return nullptr; + } + return transform_int_divide( phase, in(1), i ); } @@ -647,6 +664,14 @@ Node *DivLNode::Ideal( PhaseGVN *phase, bool can_reshape) { // Dividing by MINLONG does not optimize as a power-of-2 shift. if( l == min_jlong ) return nullptr; + // Keep this node as-is initially; we want Value() and + // other optimizations checking for this node type to work. + // See DivINode::Ideal for an explanation. + if (phase->is_IterGVN() == nullptr) { + phase->C->record_for_igvn(this); + return nullptr; + } + return transform_long_divide( phase, in(1), l ); } @@ -1094,6 +1119,18 @@ Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) { return this; } + // Keep this node as-is initially; we want Value() and + // other optimizations checking for this node type to work. + // Consider the following expression: + // x % 2, x in TypeInt::INT + // With ModINode::Value, we can trivially tell the resulting range is [-1,1]. + // After idealizing, we have a subtraction from x, which means without + // recognizing that as a modulo operation, we end up with a range of TypeInt::INT. + if (phase->is_IterGVN() == nullptr) { + phase->C->record_for_igvn(this); + return nullptr; + } + // See if we are MOD'ing by 2^k or 2^k-1. if( !ti->is_con() ) return nullptr; jint con = ti->get_con(); @@ -1389,6 +1426,14 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) { return this; } + // Keep this node as-is initially; we want Value() and + // other optimizations checking for this node type to work. + // See ModINode::Ideal for an explanation. + if (phase->is_IterGVN() == nullptr) { + phase->C->record_for_igvn(this); + return nullptr; + } + // See if we are MOD'ing by 2^k or 2^k-1. if( !tl->is_con() ) return nullptr; jlong con = tl->get_con(); diff --git a/test/hotspot/jtreg/compiler/c2/gvn/ModINodeValueTests.java b/test/hotspot/jtreg/compiler/c2/gvn/ModINodeValueTests.java index 7870ce1091048..ae942f1704b1b 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/ModINodeValueTests.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/ModINodeValueTests.java @@ -36,7 +36,7 @@ /* * @test - * @bug 8356813 + * @bug 8356813 8366815 * @summary Test that Value method of ModINode is working as expected. * @key randomness * @library /test/lib / @@ -54,6 +54,8 @@ public static void main(String[] args) { @Run(test = { "nonNegativeDividend", "nonNegativeDividendInRange", "negativeDividend", "negativeDividendInRange", + "positiveDivisor", "positiveDivisor2", + "negativeDivisor", "negativeDivisor2", "modByKnownBoundsUpper", "modByKnownBoundsUpperInRange", "modByKnownBoundsLower", "modByKnownBoundsLowerInRange", "modByKnownBoundsLimitedByDividendUpper", "modByKnownBoundsLimitedByDividendUpperInRange", @@ -79,6 +81,10 @@ public void assertResult(int x, int y) { Asserts.assertEQ(x != 0 && POS_INT % x <= 0, nonNegativeDividendInRange(x)); Asserts.assertEQ(x != 0 && NEG_INT % x > 0, negativeDividend(x)); Asserts.assertEQ(x != 0 && NEG_INT % x >= 0, negativeDividendInRange(x)); + Asserts.assertEQ(x % POS_INT >= POS_INT, positiveDivisor(x)); + Asserts.assertEQ(x % POS_INT <= -POS_INT, positiveDivisor2(x)); + Asserts.assertEQ(x % NEG_INT <= NEG_INT, negativeDivisor(x)); + Asserts.assertEQ(x % NEG_INT > -(NEG_INT + 1), negativeDivisor2(x)); Asserts.assertEQ(x % (((byte) y) + 129) > 255, modByKnownBoundsUpper(x, y)); Asserts.assertEQ(x % (((byte) y) + 129) >= 255, modByKnownBoundsUpperInRange(x, y)); Asserts.assertEQ(x % (((byte) y) + 129) < -255, modByKnownBoundsLower(x, y)); @@ -137,6 +143,39 @@ public boolean negativeDividendInRange(int x) { return x != 0 && NEG_INT % x >= 0; } + @Test + @IR(failOn = {IRNode.MOD_I, IRNode.CMP_I, IRNode.AND_I, IRNode.RSHIFT_I}) + // The result is always smaller than the positive divisor. + // Constant fold to false. + public boolean positiveDivisor(int x) { + return x % POS_INT >= POS_INT; + } + + @Test + @IR(failOn = {IRNode.MOD_I, IRNode.CMP_I, IRNode.AND_I, IRNode.RSHIFT_I}) + // The result is always bigger than the negated positive divisor. + // Constant fold to false. + public boolean positiveDivisor2(int x) { + return x % POS_INT <= -POS_INT; + } + + @Test + @IR(failOn = {IRNode.MOD_I, IRNode.CMP_I, IRNode.AND_I, IRNode.RSHIFT_I}) + // The result is always smaller than the negated negative divisor with exception if MIN_VALUE. + // Constant fold to false. + public boolean negativeDivisor(int x) { + // > with + 1 to avoid -MIN_VALUE == MIN_VALUE + return x % NEG_INT > -(NEG_INT + 1); + } + + @Test + @IR(failOn = {IRNode.MOD_I, IRNode.CMP_I, IRNode.AND_I, IRNode.RSHIFT_I}) + // The result is always bigger than the negative divisor. + // Constant fold to false. + public boolean negativeDivisor2(int x) { + return x % NEG_INT <= NEG_INT; + } + @Test @IR(failOn = {IRNode.MOD_I, IRNode.CMP_I}) // The magnitude of the result is less than the divisor. diff --git a/test/hotspot/jtreg/compiler/c2/gvn/ModLNodeValueTests.java b/test/hotspot/jtreg/compiler/c2/gvn/ModLNodeValueTests.java index a6eef6d332608..186a9284ac65e 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/ModLNodeValueTests.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/ModLNodeValueTests.java @@ -35,7 +35,7 @@ /* * @test - * @bug 8356813 + * @bug 8356813 8366815 * @summary Test that Value method of ModLNode is working as expected. * @key randomness * @library /test/lib / @@ -53,6 +53,8 @@ public static void main(String[] args) { @Run(test = { "nonNegativeDividend", "nonNegativeDividendInRange", "negativeDividend", "negativeDividendInRange", + "positiveDivisor", "positiveDivisor2", + "negativeDivisor", "negativeDivisor2", "modByKnownBoundsUpper", "modByKnownBoundsUpperInRange", "modByKnownBoundsLower", "modByKnownBoundsLowerInRange", "modByKnownBoundsLimitedByDividendUpper", "modByKnownBoundsLimitedByDividendUpperInRange", @@ -78,6 +80,10 @@ public void assertResult(long x, long y) { Asserts.assertEQ(x != 0 && POS_LONG % x <= 0, nonNegativeDividendInRange(x)); Asserts.assertEQ(x != 0 && NEG_LONG % x > 0, negativeDividend(x)); Asserts.assertEQ(x != 0 && NEG_LONG % x >= 0, negativeDividendInRange(x)); + Asserts.assertEQ(x % POS_LONG >= POS_LONG, positiveDivisor(x)); + Asserts.assertEQ(x % POS_LONG <= -POS_LONG, positiveDivisor2(x)); + Asserts.assertEQ(x % NEG_LONG <= NEG_LONG, negativeDivisor(x)); + Asserts.assertEQ(x % NEG_LONG > -(NEG_LONG + 1), negativeDivisor2(x)); Asserts.assertEQ(x % (((byte) y) + 129L) > 255, modByKnownBoundsUpper(x, y)); Asserts.assertEQ(x % (((byte) y) + 129L) >= 255, modByKnownBoundsUpperInRange(x, y)); Asserts.assertEQ(x % (((byte) y) + 129L) < -255, modByKnownBoundsLower(x, y)); @@ -136,6 +142,39 @@ public boolean negativeDividendInRange(long x) { return x != 0 && NEG_LONG % x >= 0; } + @Test + @IR(failOn = {IRNode.MOD_L, IRNode.CMP_L, IRNode.AND_L, IRNode.RSHIFT_L}) + // The result is always smaller than the positive divisor. + // Constant fold to false. + public boolean positiveDivisor(long x) { + return x % POS_LONG >= POS_LONG; + } + + @Test + @IR(failOn = {IRNode.MOD_L, IRNode.CMP_L, IRNode.AND_L, IRNode.RSHIFT_L}) + // The result is always bigger than the negated positive divisor. + // Constant fold to false. + public boolean positiveDivisor2(long x) { + return x % POS_LONG <= -POS_LONG; + } + + @Test + @IR(failOn = {IRNode.MOD_L, IRNode.CMP_L, IRNode.AND_L, IRNode.RSHIFT_L}) + // The result is always smaller than the negated negative divisor with exception if MIN_VALUE. + // Constant fold to false. + public boolean negativeDivisor(long x) { + // > with + 1 to avoid -MIN_VALUE == MIN_VALUE + return x % NEG_LONG > -(NEG_LONG + 1); + } + + @Test + @IR(failOn = {IRNode.MOD_L, IRNode.CMP_L, IRNode.AND_L, IRNode.RSHIFT_L}) + // The result is always bigger than the negative divisor. + // Constant fold to false. + public boolean negativeDivisor2(long x) { + return x % NEG_LONG <= NEG_LONG; + } + @Test @IR(failOn = {IRNode.MOD_L, IRNode.CMP_L}) // The magnitude of the result is less than the divisor.