uint Block::code_alignment() { // Check for Root block if( _pre_order == 0 ) return CodeEntryAlignment; // Check for Start block if( _pre_order == 1 ) return InteriorEntryAlignment; // Check for loop alignment LoopNode *l = head()->is_Loop(); if( l && l->is_inner_loop() ) { // Pre- and post-loops have low trip count so do not bother with // NOPs for align loop head. The constants are hidden from tuning // but only because my "divide by 4" heuristic surely gets nearly // all possible gain (a "do not align at all" heuristic has a // chance of getting a really tiny gain). CountedLoopNode *cl = head()->is_CountedLoop(); if( cl && (cl->is_pre_loop() || cl->is_post_loop()) ) return (OptoLoopAlignment > 4) ? (OptoLoopAlignment>>2) : 1; // Loops with low backedge frequency should not be aligned. MachNode *mach = l->in(LoopNode::LoopBackControl)->in(0)->is_Mach(); if( mach ) { const MachIfNode *miff = mach->is_MachIf(); if( miff && miff->_prob < 0.01 ) return 1; // Loop does not loop, more often than not! } return OptoLoopAlignment; // Otherwise align loop head }
//------------------------------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; }
LoopNode* PhaseIdealLoop::create_reserve_version_of_loop(IdealLoopTree *loop, CountedLoopReserveKit* lk) { Node_List old_new; LoopNode* head = loop->_head->as_Loop(); bool counted_loop = head->is_CountedLoop(); Node* entry = head->in(LoopNode::EntryControl); _igvn.rehash_node_delayed(entry); IdealLoopTree* outer_loop = loop->_parent; ConINode* const_1 = _igvn.intcon(1); set_ctrl(const_1, C->root()); IfNode* iff = new IfNode(entry, const_1, PROB_MAX, COUNT_UNKNOWN); register_node(iff, outer_loop, entry, dom_depth(entry)); ProjNode* iffast = new IfTrueNode(iff); register_node(iffast, outer_loop, iff, dom_depth(iff)); ProjNode* ifslow = new IfFalseNode(iff); register_node(ifslow, outer_loop, iff, dom_depth(iff)); // Clone the loop body. The clone becomes the fast loop. The // original pre-header will (illegally) have 3 control users // (old & new loops & new if). clone_loop(loop, old_new, dom_depth(head), iff); assert(old_new[head->_idx]->is_Loop(), "" ); LoopNode* slow_head = old_new[head->_idx]->as_Loop(); #ifndef PRODUCT if (TraceLoopOpts) { tty->print_cr("PhaseIdealLoop::create_reserve_version_of_loop:"); tty->print("\t iff = %d, ", iff->_idx); iff->dump(); tty->print("\t iffast = %d, ", iffast->_idx); iffast->dump(); tty->print("\t ifslow = %d, ", ifslow->_idx); ifslow->dump(); tty->print("\t before replace_input_of: head = %d, ", head->_idx); head->dump(); tty->print("\t before replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); } #endif // Fast (true) control _igvn.replace_input_of(head, LoopNode::EntryControl, iffast); // Slow (false) control _igvn.replace_input_of(slow_head, LoopNode::EntryControl, ifslow); recompute_dom_depth(); lk->set_iff(iff); #ifndef PRODUCT if (TraceLoopOpts ) { tty->print("\t after replace_input_of: head = %d, ", head->_idx); head->dump(); tty->print("\t after replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); } #endif return slow_head->as_Loop(); }
void Block::dump_head( const Block_Array *bbs ) const { // Print the basic block dump_bidx(this); C2OUT->print(": #\t"); // Print the incoming CFG edges and the outgoing CFG edges for( uint i=0; i<_num_succs; i++ ) { non_connector_successor(i)->dump_bidx(_succs[i]); C2OUT->print(" "); } C2OUT->print("<- "); if( head()->is_block_start() ) { for (uint i=1; i<num_preds(); i++) { Node *s = pred(i); if (bbs) { Block *p = (*bbs)[s->_idx]; p->dump_pred(bbs, p); } else { while (!s->is_block_start()) s = s->in(0); C2OUT->print("N%d ",s->_idx); } } } else C2OUT->print("BLOCK HEAD IS JUNK "); // Print loop, if any const Block *bhead = this; // Head of self-loop Node *bh = bhead->head(); if( bbs && bh->is_Loop() && !head()->is_Root() ) { LoopNode *loop = bh->as_Loop(); const Block *bx = (*bbs)[loop->in(LoopNode::LoopBackControl)->_idx]; while (bx->is_connector()) { bx = (*bbs)[bx->pred(1)->_idx]; } C2OUT->print("\tLoop: B%d-B%d ",bhead->_pre_order,bx->_pre_order); // Dump any loop-specific bits, especially for CountedLoops. loop->dump_spec(C2OUT); } C2OUT->print(" Freq: %g",_freq); if( Verbose ) { C2OUT->print(" IDom: %d/#%d",_idom?_idom->_pre_order:0,_dom_depth); C2OUT->print(" RegPressure: %d",_reg_pressure); C2OUT->print(" IHRP Index: %d",_ihrp_index); C2OUT->print(" FRegPressure: %d",_freg_pressure); C2OUT->print(" FHRP Index: %d",_fhrp_index); } C2OUT->cr(); }
//-------------------------create_slow_version_of_loop------------------------ // Create a slow version of the loop by cloning the loop // and inserting an if to select fast-slow versions. // Return control projection of the entry to the fast version. ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, Node_List &old_new, int opcode) { LoopNode* head = loop->_head->as_Loop(); bool counted_loop = head->is_CountedLoop(); Node* entry = head->in(LoopNode::EntryControl); _igvn.rehash_node_delayed(entry); IdealLoopTree* outer_loop = loop->_parent; Node *cont = _igvn.intcon(1); set_ctrl(cont, C->root()); Node* opq = new Opaque1Node(C, cont); register_node(opq, outer_loop, entry, dom_depth(entry)); Node *bol = new Conv2BNode(opq); register_node(bol, outer_loop, entry, dom_depth(entry)); IfNode* iff = (opcode == Op_RangeCheck) ? new RangeCheckNode(entry, bol, PROB_MAX, COUNT_UNKNOWN) : new IfNode(entry, bol, PROB_MAX, COUNT_UNKNOWN); register_node(iff, outer_loop, entry, dom_depth(entry)); ProjNode* iffast = new IfTrueNode(iff); register_node(iffast, outer_loop, iff, dom_depth(iff)); ProjNode* ifslow = new IfFalseNode(iff); register_node(ifslow, outer_loop, iff, dom_depth(iff)); // Clone the loop body. The clone becomes the fast loop. The // original pre-header will (illegally) have 3 control users // (old & new loops & new if). clone_loop(loop, old_new, dom_depth(head), iff); assert(old_new[head->_idx]->is_Loop(), "" ); // Fast (true) control Node* iffast_pred = clone_loop_predicates(entry, iffast, !counted_loop); _igvn.replace_input_of(head, LoopNode::EntryControl, iffast_pred); set_idom(head, iffast_pred, dom_depth(head)); // Slow (false) control Node* ifslow_pred = clone_loop_predicates(entry, ifslow, !counted_loop); LoopNode* slow_head = old_new[head->_idx]->as_Loop(); _igvn.replace_input_of(slow_head, LoopNode::EntryControl, ifslow_pred); set_idom(slow_head, ifslow_pred, dom_depth(slow_head)); recompute_dom_depth(); return iffast; }
//-------------------------create_slow_version_of_loop------------------------ // Create a slow version of the loop by cloning the loop // and inserting an if to select fast-slow versions. // Return control projection of the entry to the fast version. ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, Node_List &old_new) { LoopNode* head = loop->_head->as_Loop(); Node* entry = head->in(LoopNode::EntryControl); _igvn.hash_delete(entry); _igvn._worklist.push(entry); IdealLoopTree* outer_loop = loop->_parent; Node *cont = _igvn.intcon(1); set_ctrl(cont, C->root()); Node* opq = new (C, 2) Opaque1Node(C, cont); register_node(opq, outer_loop, entry, dom_depth(entry)); Node *bol = new (C, 2) Conv2BNode(opq); register_node(bol, outer_loop, entry, dom_depth(entry)); IfNode* iff = new (C, 2) IfNode(entry, bol, PROB_MAX, COUNT_UNKNOWN); register_node(iff, outer_loop, entry, dom_depth(entry)); ProjNode* iffast = new (C, 1) IfTrueNode(iff); register_node(iffast, outer_loop, iff, dom_depth(iff)); ProjNode* ifslow = new (C, 1) IfFalseNode(iff); register_node(ifslow, outer_loop, iff, dom_depth(iff)); // Clone the loop body. The clone becomes the fast loop. The // original pre-header will (illegally) have 2 control users (old & new loops). clone_loop(loop, old_new, dom_depth(head), iff); assert(old_new[head->_idx]->is_Loop(), "" ); // Fast (true) control _igvn.hash_delete(head); head->set_req(LoopNode::EntryControl, iffast); set_idom(head, iffast, dom_depth(head)); _igvn._worklist.push(head); // Slow (false) control LoopNode* slow_head = old_new[head->_idx]->as_Loop(); _igvn.hash_delete(slow_head); slow_head->set_req(LoopNode::EntryControl, ifslow); set_idom(slow_head, ifslow, dom_depth(slow_head)); _igvn._worklist.push(slow_head); recompute_dom_depth(); return iffast; }
//------------------------------do_unswitching----------------------------- // Clone loop with an invariant test (that does not exit) and // insert a clone of the test that selects which version to // execute. void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { // Find first invariant test that doesn't exit the loop LoopNode *head = loop->_head->as_Loop(); IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop); assert(unswitch_iff != NULL, "should be at least one"); #ifndef PRODUCT if (TraceLoopOpts) { tty->print("Unswitch %d ", head->unswitch_count()+1); loop->dump_head(); } #endif // Need to revert back to normal loop if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) { head->as_CountedLoop()->set_normal_loop(); } ProjNode* proj_true = create_slow_version_of_loop(loop, old_new, unswitch_iff->Opcode()); #ifdef ASSERT Node* uniqc = proj_true->unique_ctrl_out(); Node* entry = head->in(LoopNode::EntryControl); Node* predicate = find_predicate(entry); if (predicate != NULL && LoopLimitCheck && UseLoopPredicate) { // We may have two predicates, find first. entry = find_predicate(entry->in(0)->in(0)); if (entry != NULL) predicate = entry; } if (predicate != NULL) predicate = predicate->in(0); assert(proj_true->is_IfTrue() && (predicate == NULL && uniqc == head || predicate != NULL && uniqc == predicate), "by construction"); #endif // Increment unswitch count LoopNode* head_clone = old_new[head->_idx]->as_Loop(); int nct = head->unswitch_count() + 1; head->set_unswitch_count(nct); head_clone->set_unswitch_count(nct); // Add test to new "if" outside of loop IfNode* invar_iff = proj_true->in(0)->as_If(); Node* invar_iff_c = invar_iff->in(0); BoolNode* bol = unswitch_iff->in(1)->as_Bool(); invar_iff->set_req(1, bol); invar_iff->_prob = unswitch_iff->_prob; ProjNode* proj_false = invar_iff->proj_out(0)->as_Proj(); // Hoist invariant casts out of each loop to the appropriate // control projection. Node_List worklist; for (DUIterator_Fast imax, i = unswitch_iff->fast_outs(imax); i < imax; i++) { ProjNode* proj= unswitch_iff->fast_out(i)->as_Proj(); // Copy to a worklist for easier manipulation for (DUIterator_Fast jmax, j = proj->fast_outs(jmax); j < jmax; j++) { Node* use = proj->fast_out(j); if (use->Opcode() == Op_CheckCastPP && loop->is_invariant(use->in(1))) { worklist.push(use); } } ProjNode* invar_proj = invar_iff->proj_out(proj->_con)->as_Proj(); while (worklist.size() > 0) { Node* use = worklist.pop(); Node* nuse = use->clone(); nuse->set_req(0, invar_proj); _igvn.replace_input_of(use, 1, nuse); register_new_node(nuse, invar_proj); // Same for the clone Node* use_clone = old_new[use->_idx]; _igvn.replace_input_of(use_clone, 1, nuse); } } // Hardwire the control paths in the loops into if(true) and if(false) _igvn.rehash_node_delayed(unswitch_iff); short_circuit_if(unswitch_iff, proj_true); IfNode* unswitch_iff_clone = old_new[unswitch_iff->_idx]->as_If(); _igvn.rehash_node_delayed(unswitch_iff_clone); short_circuit_if(unswitch_iff_clone, proj_false); // Reoptimize loops loop->record_for_igvn(); for(int i = loop->_body.size() - 1; i >= 0 ; i--) { Node *n = loop->_body[i]; Node *n_clone = old_new[n->_idx]; _igvn._worklist.push(n_clone); } #ifndef PRODUCT if (TraceLoopUnswitching) { tty->print_cr("Loop unswitching orig: %d @ %d new: %d @ %d", head->_idx, unswitch_iff->_idx, old_new[head->_idx]->_idx, unswitch_iff_clone->_idx); } #endif C->set_major_progress(); }