mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 03:54:33 +02:00
8042786: Proper fix for 8032566
Check for overflow cases in range checks and collapse it if we can. Reviewed-by: jrose, iveresov
This commit is contained in:
parent
a354960abb
commit
6bfc0288f3
7 changed files with 101 additions and 5 deletions
|
@ -452,7 +452,7 @@
|
||||||
notproduct(bool, PrintEliminateLocks, false, \
|
notproduct(bool, PrintEliminateLocks, false, \
|
||||||
"Print out when locks are eliminated") \
|
"Print out when locks are eliminated") \
|
||||||
\
|
\
|
||||||
product(bool, EliminateAutoBox, false, \
|
product(bool, EliminateAutoBox, true, \
|
||||||
"Control optimizations for autobox elimination") \
|
"Control optimizations for autobox elimination") \
|
||||||
\
|
\
|
||||||
diagnostic(bool, UseImplicitStableValues, true, \
|
diagnostic(bool, UseImplicitStableValues, true, \
|
||||||
|
|
|
@ -391,7 +391,7 @@ void LateInlineCallGenerator::do_late_inline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup default node notes to be picked up by the inlining
|
// Setup default node notes to be picked up by the inlining
|
||||||
Node_Notes* old_nn = C->default_node_notes();
|
Node_Notes* old_nn = C->node_notes_at(call->_idx);
|
||||||
if (old_nn != NULL) {
|
if (old_nn != NULL) {
|
||||||
Node_Notes* entry_nn = old_nn->clone(C);
|
Node_Notes* entry_nn = old_nn->clone(C);
|
||||||
entry_nn->set_jvms(jvms);
|
entry_nn->set_jvms(jvms);
|
||||||
|
|
|
@ -364,7 +364,7 @@ bool Compile::should_delay_string_inlining(ciMethod* call_method, JVMState* jvms
|
||||||
bool Compile::should_delay_boxing_inlining(ciMethod* call_method, JVMState* jvms) {
|
bool Compile::should_delay_boxing_inlining(ciMethod* call_method, JVMState* jvms) {
|
||||||
if (eliminate_boxing() && call_method->is_boxing_method()) {
|
if (eliminate_boxing() && call_method->is_boxing_method()) {
|
||||||
set_has_boxed_value(true);
|
set_has_boxed_value(true);
|
||||||
return true;
|
return aggressive_unboxing();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -673,7 +673,7 @@ const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj
|
||||||
// / Region
|
// / Region
|
||||||
//
|
//
|
||||||
Node* IfNode::fold_compares(PhaseGVN* phase) {
|
Node* IfNode::fold_compares(PhaseGVN* phase) {
|
||||||
if (!phase->C->eliminate_boxing() || Opcode() != Op_If) return NULL;
|
if (Opcode() != Op_If) return NULL;
|
||||||
|
|
||||||
Node* this_cmp = in(1)->in(1);
|
Node* this_cmp = in(1)->in(1);
|
||||||
if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
|
if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
|
||||||
|
|
|
@ -1393,6 +1393,15 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
|
||||||
_worklist.push(u);
|
_worklist.push(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If changed AddI/SubI inputs, check CmpU for range check optimization.
|
||||||
|
if (use_op == Op_AddI || use_op == Op_SubI) {
|
||||||
|
for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
|
||||||
|
Node* u = use->fast_out(i2);
|
||||||
|
if (u->is_Cmp() && (u->Opcode() == Op_CmpU)) {
|
||||||
|
_worklist.push(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// If changed AddP inputs, check Stores for loop invariant
|
// If changed AddP inputs, check Stores for loop invariant
|
||||||
if( use_op == Op_AddP ) {
|
if( use_op == Op_AddP ) {
|
||||||
for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
|
for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
|
||||||
|
|
|
@ -80,7 +80,7 @@ Node *SubNode::Identity( PhaseTransform *phase ) {
|
||||||
|
|
||||||
//------------------------------Value------------------------------------------
|
//------------------------------Value------------------------------------------
|
||||||
// A subtract node differences it's two inputs.
|
// A subtract node differences it's two inputs.
|
||||||
const Type *SubNode::Value( PhaseTransform *phase ) const {
|
const Type* SubNode::Value_common(PhaseTransform *phase) const {
|
||||||
const Node* in1 = in(1);
|
const Node* in1 = in(1);
|
||||||
const Node* in2 = in(2);
|
const Node* in2 = in(2);
|
||||||
// Either input is TOP ==> the result is TOP
|
// Either input is TOP ==> the result is TOP
|
||||||
|
@ -97,6 +97,16 @@ const Type *SubNode::Value( PhaseTransform *phase ) const {
|
||||||
if( t1 == Type::BOTTOM || t2 == Type::BOTTOM )
|
if( t1 == Type::BOTTOM || t2 == Type::BOTTOM )
|
||||||
return bottom_type();
|
return bottom_type();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type* SubNode::Value(PhaseTransform *phase) const {
|
||||||
|
const Type* t = Value_common(phase);
|
||||||
|
if (t != NULL) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const Type* t1 = phase->type(in(1));
|
||||||
|
const Type* t2 = phase->type(in(2));
|
||||||
return sub(t1,t2); // Local flavor of type subtraction
|
return sub(t1,t2); // Local flavor of type subtraction
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -570,6 +580,81 @@ const Type *CmpUNode::sub( const Type *t1, const Type *t2 ) const {
|
||||||
return TypeInt::CC; // else use worst case results
|
return TypeInt::CC; // else use worst case results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Type* CmpUNode::Value(PhaseTransform *phase) const {
|
||||||
|
const Type* t = SubNode::Value_common(phase);
|
||||||
|
if (t != NULL) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const Node* in1 = in(1);
|
||||||
|
const Node* in2 = in(2);
|
||||||
|
const Type* t1 = phase->type(in1);
|
||||||
|
const Type* t2 = phase->type(in2);
|
||||||
|
assert(t1->isa_int(), "CmpU has only Int type inputs");
|
||||||
|
if (t2 == TypeInt::INT) { // Compare to bottom?
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
uint in1_op = in1->Opcode();
|
||||||
|
if (in1_op == Op_AddI || in1_op == Op_SubI) {
|
||||||
|
// The problem rise when result of AddI(SubI) may overflow
|
||||||
|
// signed integer value. Let say the input type is
|
||||||
|
// [256, maxint] then +128 will create 2 ranges due to
|
||||||
|
// overflow: [minint, minint+127] and [384, maxint].
|
||||||
|
// But C2 type system keep only 1 type range and as result
|
||||||
|
// it use general [minint, maxint] for this case which we
|
||||||
|
// can't optimize.
|
||||||
|
//
|
||||||
|
// Make 2 separate type ranges based on types of AddI(SubI) inputs
|
||||||
|
// and compare results of their compare. If results are the same
|
||||||
|
// CmpU node can be optimized.
|
||||||
|
const Node* in11 = in1->in(1);
|
||||||
|
const Node* in12 = in1->in(2);
|
||||||
|
const Type* t11 = (in11 == in1) ? Type::TOP : phase->type(in11);
|
||||||
|
const Type* t12 = (in12 == in1) ? Type::TOP : phase->type(in12);
|
||||||
|
// Skip cases when input types are top or bottom.
|
||||||
|
if ((t11 != Type::TOP) && (t11 != TypeInt::INT) &&
|
||||||
|
(t12 != Type::TOP) && (t12 != TypeInt::INT)) {
|
||||||
|
const TypeInt *r0 = t11->is_int();
|
||||||
|
const TypeInt *r1 = t12->is_int();
|
||||||
|
jlong lo_r0 = r0->_lo;
|
||||||
|
jlong hi_r0 = r0->_hi;
|
||||||
|
jlong lo_r1 = r1->_lo;
|
||||||
|
jlong hi_r1 = r1->_hi;
|
||||||
|
if (in1_op == Op_SubI) {
|
||||||
|
jlong tmp = hi_r1;
|
||||||
|
hi_r1 = -lo_r1;
|
||||||
|
lo_r1 = -tmp;
|
||||||
|
// Note, for substructing [minint,x] type range
|
||||||
|
// long arithmetic provides correct overflow answer.
|
||||||
|
// The confusion come from the fact that in 32-bit
|
||||||
|
// -minint == minint but in 64-bit -minint == maxint+1.
|
||||||
|
}
|
||||||
|
jlong lo_long = lo_r0 + lo_r1;
|
||||||
|
jlong hi_long = hi_r0 + hi_r1;
|
||||||
|
int lo_tr1 = min_jint;
|
||||||
|
int hi_tr1 = (int)hi_long;
|
||||||
|
int lo_tr2 = (int)lo_long;
|
||||||
|
int hi_tr2 = max_jint;
|
||||||
|
bool underflow = lo_long != (jlong)lo_tr2;
|
||||||
|
bool overflow = hi_long != (jlong)hi_tr1;
|
||||||
|
// Use sub(t1, t2) when there is no overflow (one type range)
|
||||||
|
// or when both overflow and underflow (too complex).
|
||||||
|
if ((underflow != overflow) && (hi_tr1 < lo_tr2)) {
|
||||||
|
// Overflow only on one boundary, compare 2 separate type ranges.
|
||||||
|
int w = MAX2(r0->_widen, r1->_widen); // _widen does not matter here
|
||||||
|
const TypeInt* tr1 = TypeInt::make(lo_tr1, hi_tr1, w);
|
||||||
|
const TypeInt* tr2 = TypeInt::make(lo_tr2, hi_tr2, w);
|
||||||
|
const Type* cmp1 = sub(tr1, t2);
|
||||||
|
const Type* cmp2 = sub(tr2, t2);
|
||||||
|
if (cmp1 == cmp2) {
|
||||||
|
return cmp1; // Hit!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub(t1, t2); // Local flavor of type subtraction
|
||||||
|
}
|
||||||
|
|
||||||
bool CmpUNode::is_index_range_check() const {
|
bool CmpUNode::is_index_range_check() const {
|
||||||
// Check for the "(X ModI Y) CmpU Y" shape
|
// Check for the "(X ModI Y) CmpU Y" shape
|
||||||
return (in(1)->Opcode() == Op_ModI &&
|
return (in(1)->Opcode() == Op_ModI &&
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
// Compute a new Type for this node. Basically we just do the pre-check,
|
// Compute a new Type for this node. Basically we just do the pre-check,
|
||||||
// then call the virtual add() to set the type.
|
// then call the virtual add() to set the type.
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
const Type* Value_common( PhaseTransform *phase ) const;
|
||||||
|
|
||||||
// Supplied function returns the subtractend of the inputs.
|
// Supplied function returns the subtractend of the inputs.
|
||||||
// This also type-checks the inputs for sanity. Guaranteed never to
|
// This also type-checks the inputs for sanity. Guaranteed never to
|
||||||
|
@ -158,6 +159,7 @@ public:
|
||||||
CmpUNode( Node *in1, Node *in2 ) : CmpNode(in1,in2) {}
|
CmpUNode( Node *in1, Node *in2 ) : CmpNode(in1,in2) {}
|
||||||
virtual int Opcode() const;
|
virtual int Opcode() const;
|
||||||
virtual const Type *sub( const Type *, const Type * ) const;
|
virtual const Type *sub( const Type *, const Type * ) const;
|
||||||
|
const Type *Value( PhaseTransform *phase ) const;
|
||||||
bool is_index_range_check() const;
|
bool is_index_range_check() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue