src/share/vm/opto/ifnode.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot Cdiff src/share/vm/opto/ifnode.cpp
src/share/vm/opto/ifnode.cpp
Print this page
rev 8157 : 8078426: mb/jvm/compiler/InterfaceCalls/testAC2 - assert(predicate_proj == 0L) failed: only one predicate entry expected
Summary: split if finds predicates on several incoming paths when unswitched's loops are optimized out
Reviewed-by:
rev 9360 : 8137168: Replace IfNode with a new RangeCheckNode for range checks
Summary: new RangeCheckNode to enable optimization of explicit library level range checks
Reviewed-by:
*** 304,319 ****
cmp_x = phase->transform(cmp_x);
// Make the bool
Node *b_c = phase->transform(new BoolNode(cmp_c,b->_test._test));
Node *b_x = phase->transform(new BoolNode(cmp_x,b->_test._test));
// Make the IfNode
! IfNode *iff_c = new IfNode(region_c,b_c,iff->_prob,iff->_fcnt);
igvn->set_type_bottom(iff_c);
igvn->_worklist.push(iff_c);
hook->init_req(2, iff_c);
! IfNode *iff_x = new IfNode(region_x,b_x,iff->_prob, iff->_fcnt);
igvn->set_type_bottom(iff_x);
igvn->_worklist.push(iff_x);
hook->init_req(3, iff_x);
// Make the true/false arms
--- 304,323 ----
cmp_x = phase->transform(cmp_x);
// Make the bool
Node *b_c = phase->transform(new BoolNode(cmp_c,b->_test._test));
Node *b_x = phase->transform(new BoolNode(cmp_x,b->_test._test));
// Make the IfNode
! IfNode* iff_c = iff->clone()->as_If();
! iff_c->set_req(0, region_c);
! iff_c->set_req(1, b_c);
igvn->set_type_bottom(iff_c);
igvn->_worklist.push(iff_c);
hook->init_req(2, iff_c);
! IfNode* iff_x = iff->clone()->as_If();
! iff_x->set_req(0, region_x);
! iff_x->set_req(1, b_x);
igvn->set_type_bottom(iff_x);
igvn->_worklist.push(iff_x);
hook->init_req(3, iff_x);
// Make the true/false arms
*** 494,504 ****
//------------------------------is_range_check---------------------------------
// Return 0 if not a range check. Return 1 if a range check and set index and
// offset. Return 2 if we had to negate the test. Index is NULL if the check
// is versus a constant.
! int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) {
int flip_test = 0;
Node* l = NULL;
Node* r = NULL;
ProjNode* iftrap = range_check_trap_proj(flip_test, l, r);
--- 498,508 ----
//------------------------------is_range_check---------------------------------
// Return 0 if not a range check. Return 1 if a range check and set index and
// offset. Return 2 if we had to negate the test. Index is NULL if the check
// is versus a constant.
! int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) {
int flip_test = 0;
Node* l = NULL;
Node* r = NULL;
ProjNode* iftrap = range_check_trap_proj(flip_test, l, r);
*** 722,732 ****
// Is a dominating control suitable for folding with this if?
bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) {
return ctrl != NULL &&
ctrl->is_Proj() &&
ctrl->in(0) != NULL &&
! ctrl->in(0)->is_If() &&
ctrl->in(0)->outcnt() == 2 &&
ctrl->in(0)->as_If()->cmpi_folds(igvn) &&
// Must compare same value
ctrl->in(0)->in(1)->in(1)->in(1) != NULL &&
ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1);
--- 726,736 ----
// Is a dominating control suitable for folding with this if?
bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) {
return ctrl != NULL &&
ctrl->is_Proj() &&
ctrl->in(0) != NULL &&
! ctrl->in(0)->Opcode() == Op_If &&
ctrl->in(0)->outcnt() == 2 &&
ctrl->in(0)->as_If()->cmpi_folds(igvn) &&
// Must compare same value
ctrl->in(0)->in(1)->in(1)->in(1) != NULL &&
ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1);
*** 970,981 ****
if (type2 != NULL) {
failtype = failtype->join(type2)->is_int();
if (failtype->_lo > failtype->_hi) {
// previous if determines the result of this if so
// replace Bool with constant
! igvn->hash_delete(this);
! set_req(1, igvn->intcon(success->_con));
return true;
}
}
}
lo = NULL;
--- 974,985 ----
if (type2 != NULL) {
failtype = failtype->join(type2)->is_int();
if (failtype->_lo > failtype->_hi) {
// previous if determines the result of this if so
// replace Bool with constant
! igvn->_worklist.push(in(1));
! igvn->replace_input_of(this, 1, igvn->intcon(success->_con));
return true;
}
}
}
lo = NULL;
*** 990,1010 ****
}
Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim));
Node* newbool = igvn->transform(new BoolNode(newcmp, cond));
igvn->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con));
! set_req(1, newbool);
return true;
}
return false;
}
// Merge the branches that trap for this If and the dominating If into
// a single region that branches to the uncommon trap for the
// dominating If
! void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) {
ProjNode* otherproj = proj->other_if_proj();
CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none);
CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none);
--- 994,1018 ----
}
Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim));
Node* newbool = igvn->transform(new BoolNode(newcmp, cond));
igvn->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con));
! igvn->_worklist.push(in(1));
! igvn->replace_input_of(this, 1, newbool);
return true;
}
return false;
}
// Merge the branches that trap for this If and the dominating If into
// a single region that branches to the uncommon trap for the
// dominating If
! Node* IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) {
! Node* res = this;
! assert(success->in(0) == this, "bad projection");
!
ProjNode* otherproj = proj->other_if_proj();
CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none);
CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none);
*** 1036,1054 ****
--- 1044,1065 ----
// Reason_range_check so the compiler recognizes it as a range
// check and applies the corresponding optimizations
trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_range_check, action);
improve_address_types(l, r, fail, igvn);
+
+ res = igvn->transform(new RangeCheckNode(in(0), in(1), _prob, _fcnt));
} else if (unc != dom_unc) {
// If we trap we won't know what CmpI would have caused the trap
// so use a special trap reason to mark this pair of CmpI nodes as
// bad candidate for folding. On recompilation we won't fold them
// and we may trap again but this time we'll know what branch
// traps
trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_unstable_fused_if, action);
}
igvn->replace_input_of(dom_unc, TypeFunc::Parms, igvn->intcon(trap_request));
+ return res;
}
// If we are turning 2 CmpI nodes into a CmpU that follows the pattern
// of a rangecheck on index i, on 64 bit the compares may be followed
// by memory accesses using i as index. In that case, the CmpU tells
*** 1238,1249 ****
return this;
}
if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
// Next call modifies graph so must be last
fold_compares_helper(dom_cmp, success, fail, igvn)) {
! merge_uncommon_traps(dom_cmp, success, fail, igvn);
! return this;
}
return NULL;
} else if (ctrl->in(0) != NULL &&
ctrl->in(0)->in(0) != NULL) {
ProjNode* success = NULL;
--- 1249,1259 ----
return this;
}
if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
// Next call modifies graph so must be last
fold_compares_helper(dom_cmp, success, fail, igvn)) {
! return merge_uncommon_traps(dom_cmp, success, fail, igvn);
}
return NULL;
} else if (ctrl->in(0) != NULL &&
ctrl->in(0)->in(0) != NULL) {
ProjNode* success = NULL;
*** 1258,1269 ****
has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
is_side_effect_free_test(other_cmp, igvn) &&
// Next call modifies graph so must be last
fold_compares_helper(dom_cmp, success, fail, igvn)) {
reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn);
! merge_uncommon_traps(dom_cmp, success, fail, igvn);
! return this;
}
}
}
return NULL;
}
--- 1268,1278 ----
has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
is_side_effect_free_test(other_cmp, igvn) &&
// Next call modifies graph so must be last
fold_compares_helper(dom_cmp, success, fail, igvn)) {
reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn);
! return merge_uncommon_traps(dom_cmp, success, fail, igvn);
}
}
}
return NULL;
}
*** 1340,1357 ****
struct RangeCheck {
Node* ctl;
jint off;
};
! //------------------------------Ideal------------------------------------------
! // Return a node which is more "ideal" than the current node. Strip out
! // control copies
! Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// No Def-Use info?
if (!can_reshape) return NULL;
- PhaseIterGVN *igvn = phase->is_IterGVN();
// Don't bother trying to transform a dead if
if (in(0)->is_top()) return NULL;
// Don't bother trying to transform an if with a dead test
if (in(1)->is_top()) return NULL;
--- 1349,1362 ----
struct RangeCheck {
Node* ctl;
jint off;
};
! Node* IfNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// No Def-Use info?
if (!can_reshape) return NULL;
// Don't bother trying to transform a dead if
if (in(0)->is_top()) return NULL;
// Don't bother trying to transform an if with a dead test
if (in(1)->is_top()) return NULL;
*** 1363,1527 ****
// Canonicalize the test.
Node* idt_if = idealize_test(phase, this);
if (idt_if != NULL) return idt_if;
// Try to split the IF
Node *s = split_if(this, igvn);
if (s != NULL) return s;
// Check for people making a useless boolean: things like
// if( (x < y ? true : false) ) { ... }
// Replace with if( x < y ) { ... }
Node *bol2 = remove_useless_bool(this, phase);
if( bol2 ) return bol2;
! // Setup to scan up the CFG looking for a dominating test
! Node *dom = in(0);
! Node *prev_dom = this;
!
! // Check for range-check vs other kinds of tests
! Node *index1, *range1;
! jint offset1;
! int flip1 = is_range_check(range1, index1, offset1);
! if( flip1 ) {
! // Try to remove extra range checks. All 'up_one_dom' gives up at merges
! // so all checks we inspect post-dominate the top-most check we find.
! // If we are going to fail the current check and we reach the top check
! // then we are guaranteed to fail, so just start interpreting there.
! // We 'expand' the top 3 range checks to include all post-dominating
! // checks.
!
! // The top 3 range checks seen
! const int NRC =3;
! RangeCheck prev_checks[NRC];
! int nb_checks = 0;
!
! // Low and high offsets seen so far
! jint off_lo = offset1;
! jint off_hi = offset1;
!
! bool found_immediate_dominator = false;
!
! // Scan for the top checks and collect range of offsets
! for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit
! if (dom->Opcode() == Op_If && // Not same opcode?
! prev_dom->in(0) == dom) { // One path of test does dominate?
! if (dom == this) return NULL; // dead loop
! // See if this is a range check
! Node *index2, *range2;
! jint offset2;
! int flip2 = dom->as_If()->is_range_check(range2, index2, offset2);
! // See if this is a _matching_ range check, checking against
! // the same array bounds.
! if (flip2 == flip1 && range2 == range1 && index2 == index1 &&
! dom->outcnt() == 2) {
! if (nb_checks == 0 && dom->in(1) == in(1)) {
! // Found an immediately dominating test at the same offset.
! // This kind of back-to-back test can be eliminated locally,
! // and there is no need to search further for dominating tests.
! assert(offset2 == offset1, "Same test but different offsets");
! found_immediate_dominator = true;
! break;
! }
! // Gather expanded bounds
! off_lo = MIN2(off_lo,offset2);
! off_hi = MAX2(off_hi,offset2);
! // Record top NRC range checks
! prev_checks[nb_checks%NRC].ctl = prev_dom;
! prev_checks[nb_checks%NRC].off = offset2;
! nb_checks++;
! }
! }
! prev_dom = dom;
! dom = up_one_dom(dom);
! if (!dom) break;
! }
!
! if (!found_immediate_dominator) {
! // Attempt to widen the dominating range check to cover some later
! // ones. Since range checks "fail" by uncommon-trapping to the
! // interpreter, widening a check can make us speculatively enter
! // the interpreter. If we see range-check deopt's, do not widen!
! if (!phase->C->allow_range_check_smearing()) return NULL;
! // Didn't find prior covering check, so cannot remove anything.
! if (nb_checks == 0) {
! return NULL;
! }
! // Constant indices only need to check the upper bound.
! // Non-constant indices must check both low and high.
! int chk0 = (nb_checks - 1) % NRC;
! if (index1) {
! if (nb_checks == 1) {
! return NULL;
! } else {
! // If the top range check's constant is the min or max of
! // all constants we widen the next one to cover the whole
! // range of constants.
! RangeCheck rc0 = prev_checks[chk0];
! int chk1 = (nb_checks - 2) % NRC;
! RangeCheck rc1 = prev_checks[chk1];
! if (rc0.off == off_lo) {
! adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
! prev_dom = rc1.ctl;
! } else if (rc0.off == off_hi) {
! adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
! prev_dom = rc1.ctl;
! } else {
! // If the top test's constant is not the min or max of all
! // constants, we need 3 range checks. We must leave the
! // top test unchanged because widening it would allow the
! // accesses it protects to successfully read/write out of
! // bounds.
! if (nb_checks == 2) {
! return NULL;
! }
! int chk2 = (nb_checks - 3) % NRC;
! RangeCheck rc2 = prev_checks[chk2];
! // The top range check a+i covers interval: -a <= i < length-a
! // The second range check b+i covers interval: -b <= i < length-b
! if (rc1.off <= rc0.off) {
! // if b <= a, we change the second range check to:
! // -min_of_all_constants <= i < length-min_of_all_constants
! // Together top and second range checks now cover:
! // -min_of_all_constants <= i < length-a
! // which is more restrictive than -b <= i < length-b:
! // -b <= -min_of_all_constants <= i < length-a <= length-b
! // The third check is then changed to:
! // -max_of_all_constants <= i < length-max_of_all_constants
! // so 2nd and 3rd checks restrict allowed values of i to:
! // -min_of_all_constants <= i < length-max_of_all_constants
! adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
! adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn);
! } else {
! // if b > a, we change the second range check to:
! // -max_of_all_constants <= i < length-max_of_all_constants
! // Together top and second range checks now cover:
! // -a <= i < length-max_of_all_constants
! // which is more restrictive than -b <= i < length-b:
! // -b < -a <= i < length-max_of_all_constants <= length-b
! // The third check is then changed to:
! // -max_of_all_constants <= i < length-max_of_all_constants
! // so 2nd and 3rd checks restrict allowed values of i to:
! // -min_of_all_constants <= i < length-max_of_all_constants
! adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
! adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn);
! }
! prev_dom = rc2.ctl;
! }
! }
! } else {
! RangeCheck rc0 = prev_checks[chk0];
! // 'Widen' the offset of the 1st and only covering check
! adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn);
! // Test is now covered by prior checks, dominate it out
! prev_dom = rc0.ctl;
! }
}
! } else { // Scan for an equivalent test
!
Node *cmp;
int dist = 0; // Cutoff limit for search
int op = Opcode();
if( op == Op_If &&
(cmp=in(1)->in(1))->Opcode() == Op_CmpP ) {
--- 1368,1408 ----
// Canonicalize the test.
Node* idt_if = idealize_test(phase, this);
if (idt_if != NULL) return idt_if;
// Try to split the IF
+ PhaseIterGVN *igvn = phase->is_IterGVN();
Node *s = split_if(this, igvn);
if (s != NULL) return s;
+ return NodeSentinel;
+ }
+
+ //------------------------------Ideal------------------------------------------
+ // Return a node which is more "ideal" than the current node. Strip out
+ // control copies
+ Node* IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+ Node* res = Ideal_common(phase, can_reshape);
+ if (res != NodeSentinel) {
+ return res;
+ }
+
// Check for people making a useless boolean: things like
// if( (x < y ? true : false) ) { ... }
// Replace with if( x < y ) { ... }
Node *bol2 = remove_useless_bool(this, phase);
if( bol2 ) return bol2;
! if (in(0) == NULL) return NULL; // Dead loop?
! PhaseIterGVN *igvn = phase->is_IterGVN();
! Node* result = fold_compares(igvn);
! if (result != NULL) {
! return result;
}
! // Scan for an equivalent test
Node *cmp;
int dist = 0; // Cutoff limit for search
int op = Opcode();
if( op == Op_If &&
(cmp=in(1)->in(1))->Opcode() == Op_CmpP ) {
*** 1533,1595 ****
}
} else {
dist = 4; // Limit for random junky scans
}
! // Normal equivalent-test check.
! if( !dom ) return NULL; // Dead loop?
! Node* result = fold_compares(igvn);
! if (result != NULL) {
! return result;
! }
!
! // Search up the dominator tree for an If with an identical test
! while( dom->Opcode() != op || // Not same opcode?
! dom->in(1) != in(1) || // Not same input 1?
! (req() == 3 && dom->in(2) != in(2)) || // Not same input 2?
! prev_dom->in(0) != dom ) { // One path of test does not dominate?
! if( dist < 0 ) return NULL;
!
! dist--;
! prev_dom = dom;
! dom = up_one_dom( dom );
! if( !dom ) return NULL;
! }
!
! // Check that we did not follow a loop back to ourselves
! if( this == dom )
return NULL;
! if( dist > 2 ) // Add to count of NULL checks elided
! explicit_null_checks_elided++;
!
! } // End of Else scan for an equivalent test
! // Hit! Remove this IF
#ifndef PRODUCT
! if( TraceIterativeGVN ) {
tty->print(" Removing IfNode: "); this->dump();
}
! if( VerifyOpto && !phase->allow_progress() ) {
// Found an equivalent dominating test,
// we can not guarantee reaching a fix-point for these during iterativeGVN
// since intervening nodes may not change.
return NULL;
}
#endif
- // Replace dominated IfNode
- dominated_by( prev_dom, igvn );
-
- // Must return either the original node (now dead) or a new node
- // (Do not return a top here, since that would break the uniqueness of top.)
- return new ConINode(TypeInt::ZERO);
- }
-
- //------------------------------dominated_by-----------------------------------
- void IfNode::dominated_by( Node *prev_dom, PhaseIterGVN *igvn ) {
igvn->hash_delete(this); // Remove self to prevent spurious V-N
Node *idom = in(0);
// Need opcode to decide which way 'this' test goes
int prev_op = prev_dom->Opcode();
Node *top = igvn->C->top(); // Shortcut to top
--- 1414,1447 ----
}
} else {
dist = 4; // Limit for random junky scans
}
! Node* prev_dom = search_identical(dist);
! if (prev_dom == NULL) {
return NULL;
+ }
! // Replace dominated IfNode
! return dominated_by(prev_dom, igvn);
! }
! //------------------------------dominated_by-----------------------------------
! Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) {
#ifndef PRODUCT
! if (TraceIterativeGVN) {
tty->print(" Removing IfNode: "); this->dump();
}
! if (VerifyOpto && !igvn->allow_progress()) {
// Found an equivalent dominating test,
// we can not guarantee reaching a fix-point for these during iterativeGVN
// since intervening nodes may not change.
return NULL;
}
#endif
igvn->hash_delete(this); // Remove self to prevent spurious V-N
Node *idom = in(0);
// Need opcode to decide which way 'this' test goes
int prev_op = prev_dom->Opcode();
Node *top = igvn->C->top(); // Shortcut to top
*** 1633,1642 ****
--- 1485,1526 ----
igvn->remove_dead_node(ifp);
} // End for each IfTrue/IfFalse child of If
// Kill the IfNode
igvn->remove_dead_node(this);
+
+ // Must return either the original node (now dead) or a new node
+ // (Do not return a top here, since that would break the uniqueness of top.)
+ return new ConINode(TypeInt::ZERO);
+ }
+
+ Node* IfNode::search_identical(int dist) {
+ // Setup to scan up the CFG looking for a dominating test
+ Node* dom = in(0);
+ Node* prev_dom = this;
+ int op = Opcode();
+ // Search up the dominator tree for an If with an identical test
+ while( dom->Opcode() != op || // Not same opcode?
+ dom->in(1) != in(1) || // Not same input 1?
+ (req() == 3 && dom->in(2) != in(2)) || // Not same input 2?
+ prev_dom->in(0) != dom ) { // One path of test does not dominate?
+ if( dist < 0 ) return NULL;
+
+ dist--;
+ prev_dom = dom;
+ dom = up_one_dom( dom );
+ if( !dom ) return NULL;
+ }
+
+ // Check that we did not follow a loop back to ourselves
+ if( this == dom )
+ return NULL;
+
+ if( dist > 2 ) // Add to count of NULL checks elided
+ explicit_null_checks_elided++;
+
+ return prev_dom;
}
//------------------------------Identity---------------------------------------
// If the test is constant & we match, then we are the input Control
Node *IfProjNode::Identity(PhaseTransform *phase) {
*** 1724,1734 ****
PhaseIterGVN *igvn = phase->is_IterGVN();
assert( igvn, "Test is not canonical in parser?" );
// The IF node never really changes, but it needs to be cloned
! iff = new IfNode( iff->in(0), b, 1.0-iff->_prob, iff->_fcnt);
Node *prior = igvn->hash_find_insert(iff);
if( prior ) {
igvn->remove_dead_node(iff);
iff = (IfNode*)prior;
--- 1608,1620 ----
PhaseIterGVN *igvn = phase->is_IterGVN();
assert( igvn, "Test is not canonical in parser?" );
// The IF node never really changes, but it needs to be cloned
! iff = iff->clone()->as_If();
! iff->set_req(1, b);
! iff->_prob = 1.0-iff->_prob;
Node *prior = igvn->hash_find_insert(iff);
if( prior ) {
igvn->remove_dead_node(iff);
iff = (IfNode*)prior;
*** 1749,1753 ****
--- 1635,1803 ----
igvn->replace_node(old_if_t, new_if_f);
// Progress
return iff;
}
+
+ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+ Node* res = Ideal_common(phase, can_reshape);
+ if (res != NodeSentinel) {
+ return res;
+ }
+
+ PhaseIterGVN *igvn = phase->is_IterGVN();
+ // Setup to scan up the CFG looking for a dominating test
+ Node* prev_dom = this;
+
+ // Check for range-check vs other kinds of tests
+ Node* index1;
+ Node* range1;
+ jint offset1;
+ int flip1 = is_range_check(range1, index1, offset1);
+ if (flip1) {
+ Node* dom = in(0);
+ // Try to remove extra range checks. All 'up_one_dom' gives up at merges
+ // so all checks we inspect post-dominate the top-most check we find.
+ // If we are going to fail the current check and we reach the top check
+ // then we are guaranteed to fail, so just start interpreting there.
+ // We 'expand' the top 3 range checks to include all post-dominating
+ // checks.
+
+ // The top 3 range checks seen
+ const int NRC =3;
+ RangeCheck prev_checks[NRC];
+ int nb_checks = 0;
+
+ // Low and high offsets seen so far
+ jint off_lo = offset1;
+ jint off_hi = offset1;
+
+ bool found_immediate_dominator = false;
+
+ // Scan for the top checks and collect range of offsets
+ for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit
+ if (dom->Opcode() == Op_RangeCheck && // Not same opcode?
+ prev_dom->in(0) == dom) { // One path of test does dominate?
+ if (dom == this) return NULL; // dead loop
+ // See if this is a range check
+ Node* index2;
+ Node* range2;
+ jint offset2;
+ int flip2 = dom->as_RangeCheck()->is_range_check(range2, index2, offset2);
+ // See if this is a _matching_ range check, checking against
+ // the same array bounds.
+ if (flip2 == flip1 && range2 == range1 && index2 == index1 &&
+ dom->outcnt() == 2) {
+ if (nb_checks == 0 && dom->in(1) == in(1)) {
+ // Found an immediately dominating test at the same offset.
+ // This kind of back-to-back test can be eliminated locally,
+ // and there is no need to search further for dominating tests.
+ assert(offset2 == offset1, "Same test but different offsets");
+ found_immediate_dominator = true;
+ break;
+ }
+ // Gather expanded bounds
+ off_lo = MIN2(off_lo,offset2);
+ off_hi = MAX2(off_hi,offset2);
+ // Record top NRC range checks
+ prev_checks[nb_checks%NRC].ctl = prev_dom;
+ prev_checks[nb_checks%NRC].off = offset2;
+ nb_checks++;
+ }
+ }
+ prev_dom = dom;
+ dom = up_one_dom(dom);
+ if (!dom) break;
+ }
+
+ if (!found_immediate_dominator) {
+ // Attempt to widen the dominating range check to cover some later
+ // ones. Since range checks "fail" by uncommon-trapping to the
+ // interpreter, widening a check can make us speculatively enter
+ // the interpreter. If we see range-check deopt's, do not widen!
+ if (!phase->C->allow_range_check_smearing()) return NULL;
+
+ // Didn't find prior covering check, so cannot remove anything.
+ if (nb_checks == 0) {
+ return NULL;
+ }
+ // Constant indices only need to check the upper bound.
+ // Non-constant indices must check both low and high.
+ int chk0 = (nb_checks - 1) % NRC;
+ if (index1) {
+ if (nb_checks == 1) {
+ return NULL;
+ } else {
+ // If the top range check's constant is the min or max of
+ // all constants we widen the next one to cover the whole
+ // range of constants.
+ RangeCheck rc0 = prev_checks[chk0];
+ int chk1 = (nb_checks - 2) % NRC;
+ RangeCheck rc1 = prev_checks[chk1];
+ if (rc0.off == off_lo) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ prev_dom = rc1.ctl;
+ } else if (rc0.off == off_hi) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ prev_dom = rc1.ctl;
+ } else {
+ // If the top test's constant is not the min or max of all
+ // constants, we need 3 range checks. We must leave the
+ // top test unchanged because widening it would allow the
+ // accesses it protects to successfully read/write out of
+ // bounds.
+ if (nb_checks == 2) {
+ return NULL;
+ }
+ int chk2 = (nb_checks - 3) % NRC;
+ RangeCheck rc2 = prev_checks[chk2];
+ // The top range check a+i covers interval: -a <= i < length-a
+ // The second range check b+i covers interval: -b <= i < length-b
+ if (rc1.off <= rc0.off) {
+ // if b <= a, we change the second range check to:
+ // -min_of_all_constants <= i < length-min_of_all_constants
+ // Together top and second range checks now cover:
+ // -min_of_all_constants <= i < length-a
+ // which is more restrictive than -b <= i < length-b:
+ // -b <= -min_of_all_constants <= i < length-a <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn);
+ } else {
+ // if b > a, we change the second range check to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // Together top and second range checks now cover:
+ // -a <= i < length-max_of_all_constants
+ // which is more restrictive than -b <= i < length-b:
+ // -b < -a <= i < length-max_of_all_constants <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn);
+ }
+ prev_dom = rc2.ctl;
+ }
+ }
+ } else {
+ RangeCheck rc0 = prev_checks[chk0];
+ // 'Widen' the offset of the 1st and only covering check
+ adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn);
+ // Test is now covered by prior checks, dominate it out
+ prev_dom = rc0.ctl;
+ }
+ }
+ } else {
+ prev_dom = search_identical(4);
+
+ if (prev_dom == NULL) {
+ return NULL;
+ }
+ }
+
+ // Replace dominated IfNode
+ return dominated_by(prev_dom, igvn);
+ }
src/share/vm/opto/ifnode.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File