@@ -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