Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/hotspot/share/opto/divnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}

Expand Down Expand Up @@ -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 );
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
41 changes: 40 additions & 1 deletion test/hotspot/jtreg/compiler/c2/gvn/ModINodeValueTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 /
Expand All @@ -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",
Expand All @@ -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));
Expand Down Expand Up @@ -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.
Expand Down
41 changes: 40 additions & 1 deletion test/hotspot/jtreg/compiler/c2/gvn/ModLNodeValueTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 /
Expand All @@ -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",
Expand All @@ -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));
Expand Down Expand Up @@ -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.
Expand Down