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 7884 : 8073480: C2 should optimize explicit range checks
Summary: explicit range checks should be recognized by C2
Reviewed-by:

*** 28,37 **** --- 28,38 ---- #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/phaseX.hpp" #include "opto/runtime.hpp" + #include "opto/rootnode.hpp" #include "opto/subnode.hpp" // Portions of code courtesy of Clifford Click // Optimization - Graph Style
*** 447,512 **** // 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); } ! //------------------------------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) { Node* b = in(1); ! if (b == NULL || !b->is_Bool()) return 0; BoolNode* bn = b->as_Bool(); Node* cmp = bn->in(1); ! if (cmp == NULL) return 0; ! if (cmp->Opcode() != Op_CmpU) return 0; ! Node* l = cmp->in(1); ! Node* r = cmp->in(2); ! int flip_test = 1; if (bn->_test._test == BoolTest::le) { l = cmp->in(2); r = cmp->in(1); flip_test = 2; } else if (bn->_test._test != BoolTest::lt) { ! return 0; } ! if (l->is_top()) return 0; // Top input means dead test ! if (r->Opcode() != Op_LoadRange) return 0; // We have recognized one of these forms: // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... // Make sure it's a real range check by requiring an uncommon trap // along the OOB path. Otherwise, it's possible that the user wrote // something which optimized to look like a range check but behaves // in some other way. ! Node* iftrap = proj_out(flip_test == 2 ? true : false); ! bool found_trap = false; ! if (iftrap != NULL) { ! Node* u = iftrap->unique_ctrl_out(); ! if (u != NULL) { ! // It could be a merge point (Region) for uncommon trap. ! if (u->is_Region()) { ! Node* c = u->unique_ctrl_out(); ! if (c != NULL) { ! iftrap = u; ! u = c; ! } ! } ! if (u->in(0) == iftrap && u->is_CallStaticJava()) { ! int req = u->as_CallStaticJava()->uncommon_trap_request(); ! if (Deoptimization::trap_request_reason(req) == ! Deoptimization::Reason_range_check) { ! found_trap = true; ! } ! } ! } } - if (!found_trap) return 0; // sorry, no cigar // Look for index+offset form Node* ind = l; jint off = 0; if (l->is_top()) { --- 448,510 ---- // 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); } ! // if this IfNode follows a range check pattern return the projection ! // for the failed path ! ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { Node* b = in(1); ! if (b == NULL || !b->is_Bool()) return NULL; BoolNode* bn = b->as_Bool(); Node* cmp = bn->in(1); ! if (cmp == NULL) return NULL; ! if (cmp->Opcode() != Op_CmpU) return NULL; ! l = cmp->in(1); ! r = cmp->in(2); ! flip_test = 1; if (bn->_test._test == BoolTest::le) { l = cmp->in(2); r = cmp->in(1); flip_test = 2; } else if (bn->_test._test != BoolTest::lt) { ! return NULL; } ! if (l->is_top()) return NULL; // Top input means dead test ! if (r->Opcode() != Op_LoadRange) return NULL; // We have recognized one of these forms: // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... + ProjNode* iftrap = proj_out(flip_test == 2 ? true : false); + return iftrap; + } + + + //------------------------------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); + + if (iftrap == NULL) { + return 0; + } + // Make sure it's a real range check by requiring an uncommon trap // along the OOB path. Otherwise, it's possible that the user wrote // something which optimized to look like a range check but behaves // in some other way. ! if (iftrap->is_uncommon_trap_proj(Deoptimization::Reason_range_check) == NULL) { ! return 0; } // Look for index+offset form Node* ind = l; jint off = 0; if (l->is_top()) {
*** 662,676 **** } //------------------------------fold_compares---------------------------- // See if a pair of CmpIs can be converted into a CmpU. In some cases // the direction of this if is determined by the preceding if so it ! // can be eliminate entirely. Given an if testing (CmpI n c) check ! // for an immediately control dependent if that is testing (CmpI n c2) ! // and has one projection leading to this if and the other projection ! // leading to a region that merges one of this ifs control ! // projections. // // If // / | // / | // / | --- 660,675 ---- } //------------------------------fold_compares---------------------------- // See if a pair of CmpIs can be converted into a CmpU. In some cases // the direction of this if is determined by the preceding if so it ! // can be eliminate entirely. ! // ! // Given an if testing (CmpI n v) check for an immediately control ! // dependent if that is testing (CmpI n v2) and has one projection ! // leading to this if and the other projection leading to a region ! // that merges one of this ifs control projections. // // If // / | // / | // / |
*** 678,760 **** // /\ | // / \ | // / \ | // / Region // ! Node* IfNode::fold_compares(PhaseGVN* phase) { ! if (Opcode() != Op_If) return NULL; ! Node* this_cmp = in(1)->in(1); ! if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI && ! this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) { ! Node* ctrl = in(0); ! BoolNode* this_bool = in(1)->as_Bool(); ! Node* n = this_cmp->in(1); ! int hi = this_cmp->in(2)->get_int(); ! if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 && ctrl->in(0)->is_If() && ctrl->in(0)->outcnt() == 2 && ! ctrl->in(0)->in(1)->is_Bool() && ! ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI && ! ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() && ! ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() && ! ctrl->in(0)->in(1)->in(1)->in(1) == n) { ! IfNode* dom_iff = ctrl->in(0)->as_If(); ! Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con); ! if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() && ! this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) { ! // Identify which proj goes to the region and which continues on ! RegionNode* region = otherproj->unique_out()->as_Region(); ! Node* success = NULL; ! Node* fail = NULL; for (int i = 0; i < 2; i++) { ! Node* proj = proj_out(i); if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { success = proj; } else if (fail == NULL) { fail = proj; } else { success = fail = NULL; } } ! if (success != NULL && fail != NULL && !region->has_phi()) { ! int lo = dom_iff->in(1)->in(1)->in(2)->get_int(); BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); ! Node* dom_cmp = dom_bool->in(1); ! const TypeInt* failtype = filtered_int_type(phase, n, ctrl); if (failtype != NULL) { ! const TypeInt* type2 = filtered_int_type(phase, n, fail); if (type2 != NULL) { failtype = failtype->join(type2)->is_int(); ! } else { ! failtype = NULL; } } ! if (failtype != NULL && ! dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) { ! int bound = failtype->_hi - failtype->_lo + 1; ! if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) { ! // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi) ! BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge; ! Node* adjusted = phase->transform(new SubINode(n, phase->intcon(failtype->_lo))); ! Node* newcmp = phase->transform(new CmpUNode(adjusted, phase->intcon(bound))); ! Node* newbool = phase->transform(new BoolNode(newcmp, cond)); ! phase->is_IterGVN()->replace_input_of(dom_iff, 1, phase->intcon(ctrl->as_Proj()->_con)); ! phase->hash_delete(this); set_req(1, newbool); ! return this; } - if (failtype->_lo > failtype->_hi) { - // previous if determines the result of this if so - // replace Bool with constant - phase->hash_delete(this); - set_req(1, phase->intcon(success->as_Proj()->_con)); - return this; } } } } } } return NULL; } --- 677,1024 ---- // /\ | // / \ | // / \ | // / Region // ! // Or given an if testing (CmpI n v) check for a dominating if that is ! // testing (CmpI n v2), both having one projection leading to an ! // uncommon trap. Allow Another independent guard in between to cover ! // an explicit range check: ! // if (index < 0 || index >= array.length) { ! // which may need a null check to guard the LoadRange ! // ! // If ! // / \ ! // / \ ! // / \ ! // If unc ! // /\ ! // / \ ! // / \ ! // / unc ! // ! // Is the comparison for this If suitable for folding? ! bool IfNode::cmpi_if(PhaseIterGVN* igvn) { ! return in(1)->is_Bool() && ! in(1)->in(1)->Opcode() == Op_CmpI && ! in(1)->in(1)->in(2) != igvn->C->top() && ! in(1)->as_Bool()->_test._test != BoolTest::ne && ! in(1)->as_Bool()->_test._test != BoolTest::eq; ! } ! ! // Is a dominating control suitable for folding with this if? ! bool IfNode::proj_cmpi_with(Node* ctrl, PhaseIterGVN* igvn) { ! return ctrl != NULL && ! ctrl->is_Proj() && ctrl->in(0)->is_If() && ctrl->in(0)->outcnt() == 2 && ! ctrl->in(0)->as_If()->cmpi_if(igvn) && ! // Must compare same value ! ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1); ! } ! ! // Do this If and the dominating If share a region? ! bool IfNode::shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail) { ! ProjNode* otherproj = proj->other_if_proj(); ! Node* otherproj_ctrl_use = otherproj->unique_ctrl_out(); ! RegionNode* region = (otherproj_ctrl_use != NULL && otherproj_ctrl_use->is_Region()) ? otherproj_ctrl_use->as_Region() : NULL; ! success = NULL; ! fail = NULL; ! ! if (otherproj->outcnt() == 1 && region != NULL && !region->has_phi()) { for (int i = 0; i < 2; i++) { ! ProjNode* proj = proj_out(i); if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { success = proj; } else if (fail == NULL) { fail = proj; } else { success = fail = NULL; } } ! } ! return success != NULL && fail != NULL; ! } ! ! // Return projection that leads to an uncommon trap if any ! ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { ! for (int i = 0; i < 2; i++) { ! call = proj_out(i)->is_uncommon_trap_proj(Deoptimization::Reason_none); ! if (call != NULL) { ! return proj_out(i); ! } ! } ! return NULL; ! } ! ! // Do this If and the dominating If both branch out to an uncommon trap ! bool IfNode::uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) { ! ProjNode* otherproj = proj->other_if_proj(); ! CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); ! ! if (otherproj->outcnt() == 1 && dom_unc != NULL) { ! CallStaticJavaNode* unc = NULL; ! ProjNode* unc_proj = uncommon_trap_proj(unc); ! if (unc_proj != NULL && unc_proj->outcnt() == 1) { ! if (dom_unc == unc) { ! // Allow the uncommon trap to be shared through a region ! RegionNode* r = unc->in(0)->as_Region(); ! if (r->outcnt() != 2 || r->req() != 3 || r->find_edge(otherproj) == -1 || r->find_edge(unc_proj) == -1) { ! return false; ! } ! assert(r->has_phi() == NULL, "simple region shouldn't have a phi"); ! } else if (dom_unc->in(0) != otherproj || unc->in(0) != unc_proj) { ! return false; ! } ! // See merge_uncommon_traps: the reason of the uncmmon trap will ! // be changed and the state of the dominating If will be ! // used. Checked that we didn't apply this transformation in a ! // previous compilation and it didn't cause too many traps ! if (!igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_unstable_fused_if) && ! !igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_range_check)) { ! success = unc_proj; ! fail = unc_proj->other_if_proj(); ! return true; ! } ! } ! } ! return false; ! } ! ! // Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding ! bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { ! Node* this_cmp = in(1)->in(1); ! BoolNode* this_bool = in(1)->as_Bool(); ! IfNode* dom_iff = proj->in(0)->as_If(); BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); ! Node* lo = dom_iff->in(1)->in(1)->in(2); ! Node* hi = this_cmp->in(2); ! Node* n = this_cmp->in(1); ! ProjNode* otherproj = proj->other_if_proj(); ! ! const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj); ! const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success); ! ! BoolTest::mask lo_test = dom_bool->_test._test; ! BoolTest::mask hi_test = this_bool->_test._test; ! BoolTest::mask cond = hi_test; ! ! // Figure out which of the two tests sets the upper bound and which ! // sets the lower bound if any. ! if (hi_type->_lo > lo_type->_hi && hi_type->_hi == max_jint && lo_type->_lo == min_jint) { ! ! assert(((lo_test == BoolTest::le || lo_test == BoolTest::lt) && !proj->_con) || ! ((lo_test == BoolTest::ge || lo_test == BoolTest::gt) && proj->_con), "incorrect test"); ! // this test was canonicalized ! assert((hi_test == BoolTest::le || hi_test == BoolTest::lt) && fail->_con, "incorrect test"); ! ! if (lo_test == BoolTest::gt || lo_test == BoolTest::le) { ! lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); ! } ! } else if (lo_type->_lo > hi_type->_hi && lo_type->_hi == max_jint && hi_type->_lo == min_jint) { ! swap(lo, hi); ! swap(lo_type, hi_type); ! swap(lo_test, hi_test); ! ! assert(((hi_test == BoolTest::le || hi_test == BoolTest::lt) && proj->_con) || ! ((hi_test == BoolTest::ge || hi_test == BoolTest::gt) && !proj->_con), "incorrect test"); ! // this test was canonicalized ! assert((lo_test == BoolTest::le || lo_test == BoolTest::lt) && !fail->_con, "incorrect test"); ! ! cond = (hi_test == BoolTest::le || hi_test == BoolTest::gt) ? BoolTest::gt : BoolTest::ge; ! ! if (lo_test == BoolTest::le) { ! lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); ! } ! ! } else { ! const TypeInt* failtype = filtered_int_type(igvn, n, proj); if (failtype != NULL) { ! const TypeInt* type2 = filtered_int_type(igvn, n, fail); 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; ! hi = NULL; ! } ! ! if (lo && hi) { ! // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo)) ! Node* adjusted_val = igvn->transform(new SubINode(n, lo)); ! Node* adjusted_lim = igvn->transform(new SubINode(hi, lo)); ! Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim)); ! Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); ! ! igvn->is_IterGVN()->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); ! igvn->hash_delete(this); 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, 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); ! ! if (unc != dom_unc) { ! Node* r = new RegionNode(3); ! ! r->set_req(1, otherproj); ! r->set_req(2, success); ! r = igvn->transform(r); ! assert(r->is_Region(), "can't go away"); ! ! // Make both If trap at the state of the first If: once the CmpI ! // nodes are merged, if we trap we don't know which of the CmpI ! // nodes would have caused the trap so we have to restart ! // execution at the first one ! igvn->replace_input_of(dom_unc, 0, r); ! igvn->replace_input_of(unc, 0, igvn->C->top()); ! } ! int trap_request = dom_unc->uncommon_trap_request(); ! Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); ! Deoptimization::DeoptAction action = Deoptimization::trap_request_action(trap_request); ! if (success->in(0)->as_If()->range_check_trap_proj() != NULL) { ! // If this looks like a range check, change the trap to ! // 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); ! } 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)); ! } ! ! // Check that the If that is in between the 2 integer comparisons has ! // no side effect ! bool IfNode::side_effect_free(ProjNode* proj, PhaseIterGVN* igvn) { ! if (proj != NULL && ! proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && ! proj->outcnt() <= 2) { ! Node* this_cmp = in(1)->in(1); ! Node* other = this_cmp->in(2); ! if (proj->outcnt() == 1 || ! // Allow simple null check from LoadRange ! (other->Opcode() == Op_LoadRange && ! ((other->in(0) != NULL && other->in(0) == proj) || ! (other->in(0) == NULL && other->in(2)->is_AddP() && other->in(2)->in(1)->Opcode() == Op_CastPP && other->in(2)->in(1)->in(0) == proj)))) { ! CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); ! CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); ! ! // reroute_side_effect_free_unc changes the state of this ! // uncommon trap to restart execution at the previous ! // CmpI. Check that this change in a previous compilation didn't ! // cause too many traps. ! int trap_request = unc->uncommon_trap_request(); ! Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); ! ! if (igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), reason)) { ! return false; ! } ! ! return true; } } + return false; + } + + // Make the If between the 2 integer comparisons trap at the state of + // the first If: the last CmpI is the one replaced by a CmpU and the + // first CmpI is eliminated, so the test between the 2 CmpI nodes + // won't be guarded by the first CmpI anymore. It can trap in cases + // where the first CmpI would have prevented it from executing: on a + // trap, we need to restart execution at the state of the first CmpI + void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) { + CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + ProjNode* otherproj = proj->other_if_proj(); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + + CallStaticJavaNode* new_unc = dom_unc->clone()->as_CallStaticJava(); + Node* call_proj = dom_unc->unique_ctrl_out(); + Node* halt = call_proj->unique_ctrl_out(); + + call_proj = call_proj->clone(); + halt = halt->clone(); + Node* c = otherproj->clone(); + new_unc->set_req(TypeFunc::Parms, unc->in(TypeFunc::Parms)); + new_unc->set_req(0, c); + call_proj->set_req(0, new_unc); + halt->set_req(0, call_proj); + + igvn->replace_node(otherproj, igvn->C->top()); + + igvn->transform(c); + igvn->transform(new_unc); + igvn->transform(call_proj); + igvn->transform(halt); + + igvn->C->root()->add_req(halt); + } + + Node* IfNode::fold_compares(PhaseIterGVN* igvn) { + if (Opcode() != Op_If) return NULL; + + if (cmpi_if(igvn)) { + Node* ctrl = in(0); + if (proj_cmpi_with(ctrl, igvn) && + ctrl->outcnt() == 1) { + // A integer comparison immediately dominated by another integer + // comparison + ProjNode* success = NULL; + ProjNode* fail = NULL; + ProjNode* dom_cmp = ctrl->as_Proj(); + if (shared_region(dom_cmp, success, fail) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + return this; } + if (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, igvn); + return this; } + return NULL; + } else { + ProjNode* success = NULL; + ProjNode* fail = NULL; + Node* dom = ctrl->in(0)->in(0); + ProjNode* dom_cmp = dom->isa_Proj(); + ProjNode* other_cmp = ctrl->isa_Proj(); + + // Check if it's an integer comparison dominated by another + // integer comparison with another test in between + if (proj_cmpi_with(dom, igvn) && + uncommon_traps(dom_cmp, success, fail, igvn) && + side_effect_free(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, igvn); + return this; } } } return NULL; }
*** 1027,1037 **** } // Normal equivalent-test check. if( !dom ) return NULL; // Dead loop? ! Node* result = fold_compares(phase); if (result != NULL) { return result; } // Search up the dominator tree for an If with an identical test --- 1291,1301 ---- } // 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
*** 1087,1097 **** // Loop predicates may have depending checks which should not // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); ! if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) prev_dom = idom; // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses. for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) { --- 1351,1361 ---- // Loop predicates may have depending checks which should not // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); ! if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) prev_dom = idom; // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses. for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) {
src/share/vm/opto/ifnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File