Skip to content

Commit 6150578

Browse files
martinuyRealCLanger
authored andcommitted
8330045: Enhance array handling
Backport-of: 727c2612766dd1737bf59fb0d9ba1e58a7b8c32b
1 parent bdc07d2 commit 6150578

File tree

1 file changed

+66
-24
lines changed

1 file changed

+66
-24
lines changed

src/hotspot/share/opto/subnode.cpp

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,44 +1483,86 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
14831483
return new BoolNode( ncmp, _test.negate() );
14841484
}
14851485

1486-
// Change ((x & m) u<= m) or ((m & x) u<= m) to always true
1487-
// Same with ((x & m) u< m+1) and ((m & x) u< m+1)
1486+
// We use the following Lemmas/insights for the following two transformations (1) and (2):
1487+
// x & y <=u y, for any x and y (Lemma 1, masking always results in a smaller unsigned number)
1488+
// y <u y + 1 is always true if y != -1 (Lemma 2, (uint)(-1 + 1) == (uint)(UINT_MAX + 1) which overflows)
1489+
// y <u 0 is always false for any y (Lemma 3, 0 == UINT_MIN and nothing can be smaller than that)
1490+
//
1491+
// (1a) Always: Change ((x & m) <=u m ) or ((m & x) <=u m ) to always true (true by Lemma 1)
1492+
// (1b) If m != -1: Change ((x & m) <u m + 1) or ((m & x) <u m + 1) to always true:
1493+
// x & m <=u m is always true // (Lemma 1)
1494+
// x & m <=u m <u m + 1 is always true // (Lemma 2: m <u m + 1, if m != -1)
1495+
//
1496+
// A counter example for (1b), if we allowed m == -1:
1497+
// (x & m) <u m + 1
1498+
// (x & -1) <u 0
1499+
// x <u 0
1500+
// which is false for any x (Lemma 3)
14881501
if (cop == Op_CmpU &&
14891502
cmp1_op == Op_AndI) {
1490-
Node* bound = nullptr;
1503+
Node* m = nullptr;
14911504
if (_test._test == BoolTest::le) {
1492-
bound = cmp2;
1505+
// (1a) "((x & m) <=u m)", cmp2 = m
1506+
m = cmp2;
14931507
} else if (_test._test == BoolTest::lt &&
14941508
cmp2->Opcode() == Op_AddI &&
14951509
cmp2->in(2)->find_int_con(0) == 1) {
1496-
bound = cmp2->in(1);
1510+
// (1b) "(x & m) <u m + 1" and "(m & x) <u m + 1", cmp2 = m + 1
1511+
Node* rhs_m = cmp2->in(1);
1512+
const TypeInt* rhs_m_type = phase->type(rhs_m)->isa_int();
1513+
if (rhs_m_type->_lo > -1 || rhs_m_type->_hi < -1) {
1514+
// Exclude any case where m == -1 is possible.
1515+
m = rhs_m;
1516+
}
14971517
}
1498-
if (cmp1->in(2) == bound || cmp1->in(1) == bound) {
1518+
if (cmp1->in(2) == m || cmp1->in(1) == m) {
14991519
return ConINode::make(1);
15001520
}
15011521
}
15021522

1503-
// Change ((x & (m - 1)) u< m) into (m > 0)
1504-
// This is the off-by-one variant of the above
1523+
// (2) Change ((x & (m - 1)) <u m) or (((m - 1) & x) <u m) to (m >u 0)
1524+
// This is the off-by-one variant of the above.
1525+
//
1526+
// We now prove that this replacement is correct. This is the same as proving
1527+
// "m >u 0" if and only if "x & (m - 1) <u m", i.e. "m >u 0 <=> x & (m - 1) <u m"
1528+
//
1529+
// We use (Lemma 1) and (Lemma 3) from above.
1530+
//
1531+
// Case "x & (m - 1) <u m => m >u 0":
1532+
// We prove this by contradiction:
1533+
// Assume m <=u 0 which is equivalent to m == 0:
1534+
// and thus
1535+
// x & (m - 1) <u m = 0 // m == 0
1536+
// y <u 0 // y = x & (m - 1)
1537+
// by Lemma 3, this is always false, i.e. a contradiction to our assumption.
1538+
//
1539+
// Case "m >u 0 => x & (m - 1) <u m":
1540+
// x & (m - 1) <=u (m - 1) // (Lemma 1)
1541+
// x & (m - 1) <=u (m - 1) <u m // Using assumption m >u 0, no underflow of "m - 1"
1542+
//
1543+
//
1544+
// Note that the signed version of "m > 0":
1545+
// m > 0 <=> x & (m - 1) <u m
1546+
// does not hold:
1547+
// Assume m == -1 and x == -1:
1548+
// x & (m - 1) <u m
1549+
// -1 & -2 <u -1
1550+
// -2 <u -1
1551+
// UINT_MAX - 1 <u UINT_MAX // Signed to unsigned numbers
1552+
// which is true while
1553+
// m > 0
1554+
// is false which is a contradiction.
15051555
if (cop == Op_CmpU &&
15061556
_test._test == BoolTest::lt &&
15071557
cmp1_op == Op_AndI) {
1508-
Node* l = cmp1->in(1);
1509-
Node* r = cmp1->in(2);
1510-
for (int repeat = 0; repeat < 2; repeat++) {
1511-
bool match = r->Opcode() == Op_AddI && r->in(2)->find_int_con(0) == -1 &&
1512-
r->in(1) == cmp2;
1513-
if (match) {
1514-
// arraylength known to be non-negative, so a (arraylength != 0) is sufficient,
1515-
// but to be compatible with the array range check pattern, use (arraylength u> 0)
1516-
Node* ncmp = cmp2->Opcode() == Op_LoadRange
1517-
? phase->transform(new CmpUNode(cmp2, phase->intcon(0)))
1518-
: phase->transform(new CmpINode(cmp2, phase->intcon(0)));
1519-
return new BoolNode(ncmp, BoolTest::gt);
1520-
} else {
1521-
// commute and try again
1522-
l = cmp1->in(2);
1523-
r = cmp1->in(1);
1558+
Node* m = cmp2; // RHS: m
1559+
for (int add_idx = 1; add_idx <= 2; add_idx++) { // LHS: "(m + (-1)) & x" or "x & (m + (-1))"?
1560+
Node* maybe_m_minus_1 = cmp1->in(add_idx);
1561+
if (maybe_m_minus_1->Opcode() == Op_AddI &&
1562+
maybe_m_minus_1->in(2)->find_int_con(0) == -1 &&
1563+
maybe_m_minus_1->in(1) == m) {
1564+
Node* m_cmpu_0 = phase->transform(new CmpUNode(m, phase->intcon(0)));
1565+
return new BoolNode(m_cmpu_0, BoolTest::gt);
15241566
}
15251567
}
15261568
}

0 commit comments

Comments
 (0)