diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index a097a08607a..143398c57d0 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1179,6 +1179,14 @@ static bool can_overflow(const TypeInt* t, jint c) { (c > 0 && (java_add(t_hi, c) < t_hi))); } +// Check if addition of a long with type 't' and a constant 'c' can overflow. +static bool can_overflow(const TypeLong* t, jlong c) { + jlong t_lo = t->_lo; + jlong t_hi = t->_hi; + return ((c < 0 && (java_add(t_lo, c) > t_lo)) || + (c > 0 && (java_add(t_hi, c) < t_hi))); +} + // Let = x_operands and = y_operands. // If x == y and neither add(x, x_off) nor add(y, y_off) overflow, return // add(x, op(x_off, y_off)). Otherwise, return nullptr. @@ -1363,6 +1371,31 @@ const Type *MinINode::add_ring( const Type *t0, const Type *t1 ) const { // // Note: we assume that SubL was already replaced by an AddL, and that the stride // has its sign flipped: SubL(limit, stride) -> AddL(limit, -stride). +// +// Proof MaxL collapsed version equivalent to original (MinL version similar): +// is_sub_con ensures that con1, con2 ∈ [min_int, 0[ +// +// Original: +// - AddL2 underflow => x + con2 ∈ ]max_long - min_int, max_long], ALWAYS BAILOUT as x + con1 + con2 surely fails can_overflow (*) +// - AddL2 no underflow => x + con2 ∈ [min_long, max_long] +// - MaxL2 clamp => min_int +// - AddL1 underflow: NOT POSSIBLE: cannot underflow since min_int + con1 ∈ [2 * min_int, min_int] always > min_long +// - AddL1 no underflow => min_int + con1 ∈ [2 * min_int, min_int] +// - MaxL1 clamp => min_int (RESULT 1) +// - MaxL1 no clamp: NOT POSSIBLE: min_int + con1 ∈ [2 * min_int, min_int] always <= min_int, so clamp always taken +// - MaxL2 no clamp => x + con2 ∈ [min_int, max_long] +// - AddL1 underflow: NOT POSSIBLE: cannot underflow since x + con2 + con1 ∈ [2 * min_int, max_long] always > min_long +// - AddL1 no underflow => x + con2 + con1 ∈ [2 * min_int, max_long] +// - MaxL1 clamp => min_int (RESULT 2) +// - MaxL1 no clamp => x + con2 + con1 ∈ ]min_int, max_long] (RESULT 3) +// +// Collapsed: +// - AddL2 (cannot underflow) => con2 + con1 ∈ [2 * min_int, 0] +// - AddL1 underflow: NOT POSSIBLE: would have bailed out at can_overflow (*) +// - AddL1 no underflow => x + con2 + con1 ∈ [min_long, max_long] +// - MaxL clamp => min_int (RESULT 1 and RESULT 2) +// - MaxL no clamp => x + con2 + con1 ∈ ]min_int, max_long] (RESULT 3) +// static Node* fold_subI_no_underflow_pattern(Node* n, PhaseGVN* phase) { assert(n->Opcode() == Op_MaxL || n->Opcode() == Op_MinL, "sanity"); // Check that the two clamps have the correct values. @@ -1392,6 +1425,10 @@ static Node* fold_subI_no_underflow_pattern(Node* n, PhaseGVN* phase) { Node* x = add2->in(1); Node* con2 = add2->in(2); if (is_sub_con(con2)) { + // Collapsed graph not equivalent if potential over/underflow -> bailing out (*) + if (can_overflow(phase->type(x)->is_long(), con1->get_long() + con2->get_long())) { + return nullptr; + } Node* new_con = phase->transform(new AddLNode(con1, con2)); Node* new_sub = phase->transform(new AddLNode(x, new_con)); n->set_req_X(1, new_sub, phase);