//------------------------------find_unswitching_candidate----------------------------- // Find candidate "if" for unswitching IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop) const { // Find first invariant test that doesn't exit the loop LoopNode *head = loop->_head->as_Loop(); IfNode* unswitch_iff = NULL; Node* n = head->in(LoopNode::LoopBackControl); while (n != head) { Node* n_dom = idom(n); if (n->is_Region()) { if (n_dom->is_If()) { IfNode* iff = n_dom->as_If(); if (iff->in(1)->is_Bool()) { BoolNode* bol = iff->in(1)->as_Bool(); if (bol->in(1)->is_Cmp()) { // If condition is invariant and not a loop exit, // then found reason to unswitch. if (loop->is_invariant(bol) && !loop->is_loop_exit(iff)) { unswitch_iff = iff; } } } } } n = n_dom; } return unswitch_iff; }
//------------------------------split_if--------------------------------------- // Look for places where we merge constants, then test on the merged value. // If the IF test will be constant folded on the path with the constant, we // win by splitting the IF to before the merge point. static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { // I could be a lot more general here, but I'm trying to squeeze this // in before the Christmas '98 break so I'm gonna be kinda restrictive // on the patterns I accept. CNC // Look for a compare of a constant and a merged value Node *i1 = iff->in(1); if( !i1->is_Bool() ) return NULL; BoolNode *b = i1->as_Bool(); Node *cmp = b->in(1); if( !cmp->is_Cmp() ) return NULL; i1 = cmp->in(1); if( i1 == NULL || !i1->is_Phi() ) return NULL; PhiNode *phi = i1->as_Phi(); if( phi->is_copy() ) return NULL; Node *con2 = cmp->in(2); if( !con2->is_Con() ) return NULL; // See that the merge point contains some constants Node *con1=NULL; uint i4; for( i4 = 1; i4 < phi->req(); i4++ ) { con1 = phi->in(i4); if( !con1 ) return NULL; // Do not optimize partially collapsed merges if( con1->is_Con() ) break; // Found a constant // Also allow null-vs-not-null checks const TypePtr *tp = igvn->type(con1)->isa_ptr(); if( tp && tp->_ptr == TypePtr::NotNull ) break; } if( i4 >= phi->req() ) return NULL; // Found no constants igvn->C->set_has_split_ifs(true); // Has chance for split-if // Make sure that the compare can be constant folded away Node *cmp2 = cmp->clone(); cmp2->set_req(1,con1); cmp2->set_req(2,con2); const Type *t = cmp2->Value(igvn); // This compare is dead, so whack it! igvn->remove_dead_node(cmp2); if( !t->singleton() ) return NULL; // No intervening control, like a simple Call Node *r = iff->in(0); if( !r->is_Region() ) return NULL; if( phi->region() != r ) return NULL; // No other users of the cmp/bool if (b->outcnt() != 1 || cmp->outcnt() != 1) { //tty->print_cr("many users of cmp/bool"); return NULL; } // Make sure we can determine where all the uses of merged values go for (DUIterator_Fast jmax, j = r->fast_outs(jmax); j < jmax; j++) { Node* u = r->fast_out(j); if( u == r ) continue; if( u == iff ) continue; if( u->outcnt() == 0 ) continue; // use is dead & ignorable if( !u->is_Phi() ) { /* if( u->is_Start() ) { tty->print_cr("Region has inlined start use"); } else { tty->print_cr("Region has odd use"); u->dump(2); }*/ return NULL; } if( u != phi ) { // CNC - do not allow any other merged value //tty->print_cr("Merging another value"); //u->dump(2); return NULL; } // Make sure we can account for all Phi uses for (DUIterator_Fast kmax, k = u->fast_outs(kmax); k < kmax; k++) { Node* v = u->fast_out(k); // User of the phi // CNC - Allow only really simple patterns. // In particular I disallow AddP of the Phi, a fairly common pattern if( v == cmp ) continue; // The compare is OK if( (v->is_ConstraintCast()) && v->in(0)->in(0) == iff ) continue; // CastPP/II of the IfNode is OK // Disabled following code because I cannot tell if exactly one // path dominates without a real dominator check. CNC 9/9/1999 //uint vop = v->Opcode(); //if( vop == Op_Phi ) { // Phi from another merge point might be OK // Node *r = v->in(0); // Get controlling point // if( !r ) return NULL; // Degraded to a copy // // Find exactly one path in (either True or False doms, but not IFF) // int cnt = 0; // for( uint i = 1; i < r->req(); i++ ) // if( r->in(i) && r->in(i)->in(0) == iff ) // cnt++; // if( cnt == 1 ) continue; // Exactly one of True or False guards Phi //} if( !v->is_Call() ) { /* if( v->Opcode() == Op_AddP ) { tty->print_cr("Phi has AddP use"); } else if( v->Opcode() == Op_CastPP ) { tty->print_cr("Phi has CastPP use"); } else if( v->Opcode() == Op_CastII ) { tty->print_cr("Phi has CastII use"); } else { tty->print_cr("Phi has use I cant be bothered with"); } */ } return NULL; /* CNC - Cut out all the fancy acceptance tests // Can we clone this use when doing the transformation? // If all uses are from Phis at this merge or constants, then YES. if( !v->in(0) && v != cmp ) { tty->print_cr("Phi has free-floating use"); v->dump(2); return NULL; } for( uint l = 1; l < v->req(); l++ ) { if( (!v->in(l)->is_Phi() || v->in(l)->in(0) != r) && !v->in(l)->is_Con() ) { tty->print_cr("Phi has use"); v->dump(2); return NULL; } // End of if Phi-use input is neither Phi nor Constant } // End of for all inputs to Phi-use */ } // End of for all uses of Phi } // End of for all uses of Region // Only do this if the IF node is in a sane state if (iff->outcnt() != 2) return NULL; // Got a hit! Do the Mondo Hack! // //ABC a1c def ghi B 1 e h A C a c d f g i // R - Phi - Phi - Phi Rc - Phi - Phi - Phi Rx - Phi - Phi - Phi // cmp - 2 cmp - 2 cmp - 2 // bool bool_c bool_x // if if_c if_x // T F T F T F // ..s.. ..t .. ..s.. ..t.. ..s.. ..t.. // // Split the paths coming into the merge point into 2 separate groups of // merges. On the left will be all the paths feeding constants into the // Cmp's Phi. On the right will be the remaining paths. The Cmp's Phi // will fold up into a constant; this will let the Cmp fold up as well as // all the control flow. Below the original IF we have 2 control // dependent regions, 's' and 't'. Now we will merge the two paths // just prior to 's' and 't' from the two IFs. At least 1 path (and quite // likely 2 or more) will promptly constant fold away. PhaseGVN *phase = igvn; // Make a region merging constants and a region merging the rest uint req_c = 0; Node* predicate_proj = NULL; for (uint ii = 1; ii < r->req(); ii++) { if (phi->in(ii) == con1) { req_c++; } Node* proj = PhaseIdealLoop::find_predicate(r->in(ii)); if (proj != NULL) { assert(predicate_proj == NULL, "only one predicate entry expected"); predicate_proj = proj; } } Node* predicate_c = NULL; Node* predicate_x = NULL; bool counted_loop = r->is_CountedLoop(); Node *region_c = new (igvn->C, req_c + 1) RegionNode(req_c + 1); Node *phi_c = con1; uint len = r->req(); Node *region_x = new (igvn->C, len - req_c) RegionNode(len - req_c); Node *phi_x = PhiNode::make_blank(region_x, phi); for (uint i = 1, i_c = 1, i_x = 1; i < len; i++) { if (phi->in(i) == con1) { region_c->init_req( i_c++, r ->in(i) ); if (r->in(i) == predicate_proj) predicate_c = predicate_proj; } else { region_x->init_req( i_x, r ->in(i) ); phi_x ->init_req( i_x++, phi->in(i) ); if (r->in(i) == predicate_proj) predicate_x = predicate_proj; } } if (predicate_c != NULL && (req_c > 1)) { assert(predicate_x == NULL, "only one predicate entry expected"); predicate_c = NULL; // Do not clone predicate below merge point } if (predicate_x != NULL && ((len - req_c) > 2)) { assert(predicate_c == NULL, "only one predicate entry expected"); predicate_x = NULL; // Do not clone predicate below merge point } // Register the new RegionNodes but do not transform them. Cannot // transform until the entire Region/Phi conglomerate has been hacked // as a single huge transform. igvn->register_new_node_with_optimizer( region_c ); igvn->register_new_node_with_optimizer( region_x ); // Prevent the untimely death of phi_x. Currently he has no uses. He is // about to get one. If this only use goes away, then phi_x will look dead. // However, he will be picking up some more uses down below. Node *hook = new (igvn->C, 4) Node(4); hook->init_req(0, phi_x); hook->init_req(1, phi_c); phi_x = phase->transform( phi_x ); // Make the compare Node *cmp_c = phase->makecon(t); Node *cmp_x = cmp->clone(); cmp_x->set_req(1,phi_x); cmp_x->set_req(2,con2); cmp_x = phase->transform(cmp_x); // Make the bool Node *b_c = phase->transform(new (igvn->C, 2) BoolNode(cmp_c,b->_test._test)); Node *b_x = phase->transform(new (igvn->C, 2) BoolNode(cmp_x,b->_test._test)); // Make the IfNode IfNode *iff_c = new (igvn->C, 2) 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 (igvn->C, 2) 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 Node *iff_c_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_c)); Node *iff_c_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_c)); if (predicate_c != NULL) { assert(predicate_x == NULL, "only one predicate entry expected"); // Clone loop predicates to each path iff_c_t = igvn->clone_loop_predicates(predicate_c, iff_c_t, !counted_loop); iff_c_f = igvn->clone_loop_predicates(predicate_c, iff_c_f, !counted_loop); } Node *iff_x_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_x)); Node *iff_x_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_x)); if (predicate_x != NULL) { assert(predicate_c == NULL, "only one predicate entry expected"); // Clone loop predicates to each path iff_x_t = igvn->clone_loop_predicates(predicate_x, iff_x_t, !counted_loop); iff_x_f = igvn->clone_loop_predicates(predicate_x, iff_x_f, !counted_loop); } // Merge the TRUE paths Node *region_s = new (igvn->C, 3) RegionNode(3); igvn->_worklist.push(region_s); region_s->init_req(1, iff_c_t); region_s->init_req(2, iff_x_t); igvn->register_new_node_with_optimizer( region_s ); // Merge the FALSE paths Node *region_f = new (igvn->C, 3) RegionNode(3); igvn->_worklist.push(region_f); region_f->init_req(1, iff_c_f); region_f->init_req(2, iff_x_f); igvn->register_new_node_with_optimizer( region_f ); igvn->hash_delete(cmp);// Remove soon-to-be-dead node from hash table. cmp->set_req(1,NULL); // Whack the inputs to cmp because it will be dead cmp->set_req(2,NULL); // Check for all uses of the Phi and give them a new home. // The 'cmp' got cloned, but CastPP/IIs need to be moved. Node *phi_s = NULL; // do not construct unless needed Node *phi_f = NULL; // do not construct unless needed for (DUIterator_Last i2min, i2 = phi->last_outs(i2min); i2 >= i2min; --i2) { Node* v = phi->last_out(i2);// User of the phi igvn->hash_delete(v); // Have to fixup other Phi users igvn->_worklist.push(v); uint vop = v->Opcode(); Node *proj = NULL; if( vop == Op_Phi ) { // Remote merge point Node *r = v->in(0); for (uint i3 = 1; i3 < r->req(); i3++) if (r->in(i3) && r->in(i3)->in(0) == iff) { proj = r->in(i3); break; } } else if( v->is_ConstraintCast() ) { proj = v->in(0); // Controlling projection } else { assert( 0, "do not know how to handle this guy" ); } Node *proj_path_data, *proj_path_ctrl; if( proj->Opcode() == Op_IfTrue ) { if( phi_s == NULL ) { // Only construct phi_s if needed, otherwise provides // interfering use. phi_s = PhiNode::make_blank(region_s,phi); phi_s->init_req( 1, phi_c ); phi_s->init_req( 2, phi_x ); hook->add_req(phi_s); phi_s = phase->transform(phi_s); } proj_path_data = phi_s; proj_path_ctrl = region_s; } else { if( phi_f == NULL ) { // Only construct phi_f if needed, otherwise provides // interfering use. phi_f = PhiNode::make_blank(region_f,phi); phi_f->init_req( 1, phi_c ); phi_f->init_req( 2, phi_x ); hook->add_req(phi_f); phi_f = phase->transform(phi_f); } proj_path_data = phi_f; proj_path_ctrl = region_f; } // Fixup 'v' for for the split if( vop == Op_Phi ) { // Remote merge point uint i; for( i = 1; i < v->req(); i++ ) if( v->in(i) == phi ) break; v->set_req(i, proj_path_data ); } else if( v->is_ConstraintCast() ) { v->set_req(0, proj_path_ctrl ); v->set_req(1, proj_path_data ); } else ShouldNotReachHere(); } // Now replace the original iff's True/False with region_s/region_t. // This makes the original iff go dead. for (DUIterator_Last i3min, i3 = iff->last_outs(i3min); i3 >= i3min; --i3) { Node* p = iff->last_out(i3); assert( p->Opcode() == Op_IfTrue || p->Opcode() == Op_IfFalse, "" ); Node *u = (p->Opcode() == Op_IfTrue) ? region_s : region_f; // Replace p with u igvn->add_users_to_worklist(p); for (DUIterator_Last lmin, l = p->last_outs(lmin); l >= lmin;) { Node* x = p->last_out(l); igvn->hash_delete(x); uint uses_found = 0; for( uint j = 0; j < x->req(); j++ ) { if( x->in(j) == p ) { x->set_req(j, u); uses_found++; } } l -= uses_found; // we deleted 1 or more copies of this edge } igvn->remove_dead_node(p); } // Force the original merge dead igvn->hash_delete(r); // First, remove region's dead users. for (DUIterator_Last lmin, l = r->last_outs(lmin); l >= lmin;) { Node* u = r->last_out(l); if( u == r ) { r->set_req(0, NULL); } else { assert(u->outcnt() == 0, "only dead users"); igvn->remove_dead_node(u); } l -= 1; } igvn->remove_dead_node(r); // Now remove the bogus extra edges used to keep things alive igvn->remove_dead_node( hook ); // 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 (igvn->C, 1) ConINode(TypeInt::ZERO); }
//============================================================================= //------------------------------AbsNode---------------------------------------- Node *AbsNode::is_absolute( PhaseGVN *phase, Node *phi_root ) { int chs = 0; // No need to change sign of result int abs = 1; // Assume ABS is being performed int typ = 0; // Assume integer ABS // ABS ends with the merge of 2 control flow paths. Find the merge point. Node *region = phi_root->in(0); if( region->req() != 3 ) return NULL; if( phi_root->req() != 3 ) return NULL; // Next up is the true/false control bits Node *iff = region->in(1); if( !iff ) return NULL; Node *ift = region->in(2); if( !ift ) return NULL; if( iff->Opcode() == Op_IfFalse && ift->Opcode() == Op_IfTrue ) { } else if( iff->Opcode() == Op_IfTrue && ift->Opcode() == Op_IfFalse ) { chs = 1-chs; // Test is reversed } else return NULL; // Not from same IF Node *fif = iff->in(0); if( ift->in(0) != fif ) return NULL; // Not from same IF // Roll up the predicate chain; get the Bool, CmpX BoolNode *bol = fif->in(1)->is_Bool(); if (bol == NULL) return NULL; // test is dead (constant true or false) switch( bol->_test._test ) { case BoolTest::lt: break; case BoolTest::le: break; case BoolTest::gt: chs = 1-chs; break; case BoolTest::ge: chs = 1-chs; break; case BoolTest::eq: abs = 0; break; // Not an ABS function case BoolTest::ne: abs = 0; chs = 1-chs; break; // Not an ABS function } // Test is next Node *cmp = bol->in(1); const Type *tzero = NULL; switch( cmp->Opcode() ) { case Op_CmpF: tzero = TypeF::ZERO; typ = 1; break; // Float ABS case Op_CmpD: tzero = TypeD::ZERO; typ = 2; break; // Double ABS default: return NULL; } // Left of float is value being ABS'd, right is a zero Node *x = cmp->in(1); if( phase->type(cmp->in(2)) != tzero ) return NULL; // Next get the 2 pieces being selected, one is the original value // and the other is the negated value. Node *neg_x = phi_root->in(2); if( phi_root->in(1) == x ) { } else if( phi_root->in(2) == x ) { chs = 1-chs; neg_x = phi_root->in(1); } // Check negated value for really negating int negop = neg_x->Opcode(); if( tzero == TypeF::ZERO ) { // Allow either NegF(x) or SubF(0,X) and fail out for all others if( !(negop == Op_NegF && neg_x->in(1) == x ) && !(negop == Op_SubF && neg_x->in(2) == x && phase->type(neg_x->in(1)) == tzero ) ) return NULL; } else { // Allow either NegD(x) or SubD(0,X) and fail out for all others if( !(negop == Op_NegD && neg_x->in(1) == x ) && !(negop == Op_SubD && neg_x->in(2) == x && phase->type(neg_x->in(1)) == tzero ) ) return NULL; } // Yeah-ha! A Hit! Now emit either: abs or nothing, then // a chs or nothing, of type float or double if( abs ) { // Doing ABS, or doing ID function if( typ == 1 ) x = new (2) AbsFNode(x); else x = new (2) AbsDNode(x); if( chs ) x = phase->transform(x); // transform all "new" interior nodes } if( chs ) { // Simply negating result? if( typ == 1 ) x = new (2) NegFNode(x); else x = new (2) NegDNode(x); } return x; }
//------------------------------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()) { return 0; } else if (l->is_Add()) { if ((off = l->in(1)->find_int_con(0)) != 0) { ind = l->in(2); } else if ((off = l->in(2)->find_int_con(0)) != 0) { ind = l->in(1); } } else if ((off = l->find_int_con(-1)) >= 0) { // constant offset with no variable index ind = NULL; } else { // variable index with no constant offset (or dead negative index) off = 0; } // Return all the values: index = ind; offset = off; range = r; return flip_test; }