src/share/vm/opto/ifnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/vm/opto/ifnode.cpp	Fri Sep 25 16:46:45 2015
--- new/src/share/vm/opto/ifnode.cpp	Fri Sep 25 16:46:44 2015

*** 303,318 **** --- 303,322 ---- 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); ! 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 = new IfNode(region_x,b_x,iff->_prob, iff->_fcnt); ! 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
*** 493,503 **** --- 497,507 ---- //------------------------------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 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);
*** 721,731 **** --- 725,735 ---- // 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)->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);
*** 939,950 **** --- 943,954 ---- 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)); ! igvn->_worklist.push(in(1)); ! igvn->replace_input_of(this, 1, igvn->intcon(success->_con)); return true; } } } lo = NULL;
*** 959,979 **** --- 963,987 ---- } 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); ! 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 ! void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { ! 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);
*** 1005,1023 **** --- 1013,1034 ---- // 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
*** 1207,1218 **** --- 1218,1228 ---- 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 this; } return NULL; } else if (ctrl->in(0) != NULL && ctrl->in(0)->in(0) != NULL) { ProjNode* success = NULL;
*** 1227,1238 **** --- 1237,1247 ---- 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 this; } } } return NULL; }
*** 1309,1326 **** --- 1318,1331 ---- 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) { + 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; 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;
*** 1332,1496 **** --- 1337,1377 ---- // 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; // 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; + if (in(0) == NULL) return NULL; // Dead loop? // 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; } + PhaseIterGVN *igvn = phase->is_IterGVN(); + Node* result = fold_compares(igvn); + if (result != NULL) { + return result; } - } 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 ) {
*** 1502,1564 **** --- 1383,1416 ---- } } 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; } + Node* prev_dom = search_identical(dist); // 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 ) + if (prev_dom == NULL) { return NULL; + } if( dist > 2 ) // Add to count of NULL checks elided ! explicit_null_checks_elided++; } // End of Else scan for an equivalent test + // Replace dominated IfNode ! return dominated_by(prev_dom, igvn); + } // Hit! Remove this IF + //------------------------------dominated_by----------------------------------- + Node* IfNode::dominated_by( Node *prev_dom, PhaseIterGVN *igvn ) { #ifndef PRODUCT ! if( TraceIterativeGVN ) { ! if (TraceIterativeGVN) { tty->print(" Removing IfNode: "); this->dump(); } ! if( VerifyOpto && !phase->allow_progress() ) { ! 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 // 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
*** 1602,1611 **** --- 1454,1495 ---- 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) {
*** 1693,1703 **** --- 1577,1589 ---- 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); ! 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;
*** 1718,1722 **** --- 1604,1770 ---- 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, *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, *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