--- old/src/share/vm/opto/subnode.cpp 2014-08-04 15:55:37.338223681 +0200 +++ new/src/share/vm/opto/subnode.cpp 2014-08-04 15:55:37.242223686 +0200 @@ -1296,6 +1296,51 @@ return new BoolNode( ncmp, _test.commute() ); } + // Change "bool eq/ne (cmp (add/sub A B) C)" into false/true if add/sub + // overflows and we can prove that C is not in the two resulting ranges. + // This optimization is similar to the one performed by CmpUNode::Value(). + if((_test._test == BoolTest::eq || _test._test == BoolTest::ne) && + (cop == Op_CmpI) && (cmp1_op == Op_AddI || cmp1_op == Op_SubI)) { + // Skip cases were inputs of add/sub are not integers or of bottom type + const TypeInt* r0 = phase->type(cmp1->in(1))->isa_int(); + const TypeInt* r1 = phase->type(cmp1->in(2))->isa_int(); + if ((r0 != NULL) && (r0 != TypeInt::INT) && + (r1 != NULL) && (r1 != TypeInt::INT) && + (cmp2_type != TypeInt::INT)) { + // Compute exact (long) type range of add/sub result + jlong lo_long = r0->_lo; + jlong hi_long = r0->_hi; + if (cmp1_op == Op_AddI) { + lo_long += r1->_lo; + hi_long += r1->_hi; + } else { + lo_long -= r1->_hi; + hi_long -= r1->_lo; + } + // Check for over-/underflow by casting to integer + int lo_int = (int)lo_long; + int hi_int = (int)hi_long; + bool underflow = lo_long != (jlong)lo_int; + bool overflow = hi_long != (jlong)hi_int; + if ((underflow != overflow) && (hi_int < lo_int)) { + // Overflow on one boundary, compute resulting type ranges: + // tr1 [MIN_INT, hi_int] and tr2 [lo_int, MAX_INT] + int w = MAX2(r0->_widen, r1->_widen); // _widen does not matter here + const TypeInt* tr1 = TypeInt::make(min_jint, hi_int, w); + const TypeInt* tr2 = TypeInt::make(lo_int, max_jint, w); + // Compare second input of cmp to both type ranges + const Type* sub_tr1 = cmp->as_Sub()->sub(tr1, cmp2_type); + const Type* sub_tr2 = cmp->as_Sub()->sub(tr2, cmp2_type); + if ((sub_tr1 == TypeInt::CC_LT && sub_tr2 == TypeInt::CC_GT) || + (sub_tr1 == TypeInt::CC_GT && sub_tr2 == TypeInt::CC_LT)) { + // The result of the add/sub will never equal cmp2. Replace BoolNode + // by false (0) if it tests for equality and by true (1) otherwise. + return ConINode::make(phase->C, (_test._test == BoolTest::eq) ? 0 : 1); + } + } + } + } + // The transformation below is not valid for either signed or unsigned // comparisons due to wraparound concerns at MAX_VALUE and MIN_VALUE. // This transformation can be resurrected when we are able to