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