reg_split.cpp revision 2667
1879N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A//------------------------------Split-------------------------------------- 605N/A// Walk the graph in RPO and for each lrg which spills, propagate reaching 605N/A// definitions. During propagation, split the live range around regions of 0N/A// High Register Pressure (HRP). If a Def is in a region of Low Register 0N/A// Pressure (LRP), it will not get spilled until we encounter a region of 0N/A// HRP between it and one of its uses. We will spill at the transition 0N/A// point between LRP and HRP. Uses in the HRP region will use the spilled 0N/A// Def. The first Use outside the HRP region will generate a SpillCopy to 0N/A// hoist the live range back up into a register, and all subsequent uses 0N/A// will use that new Def until another HRP region is encountered. Defs in 0N/A// HRP regions will get trailing SpillCopies to push the LRG down into the 0N/A// stack immediately. 0N/A// As a side effect, unlink from (hence make dead) coalesced copies. 0N/A//------------------------------get_spillcopy_wide----------------------------- 0N/A// Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the 0N/A// wide ideal-register spill-mask if possible. If the 'wide-mask' does 0N/A// not cover the input (or output), use the input (or output) mask instead. 0N/A // If ideal reg doesn't exist we've got a bad schedule happening 0N/A // that is forcing us to spill something that isn't spillable. 0N/A // Bail rather than abort 415N/A assert(
false,
"attempted to spill a non-spillable item");
0N/A // Don't come here for mis-aligned doubles 0N/A }
else {
// wide ideal mask does not overlap with o_mask 0N/A // Mis-aligned doubles come here and XMM->FPR moves on x86. 0N/A // Does the ideal-reg-mask overlap with o_mask? I.e., can I use 0N/A // a reg-reg move or do I need a trip across register classes 0N/A // (and thus through memory)? 0N/A // Here we assume a trip through memory is required. 0N/A//------------------------------insert_proj------------------------------------ 605N/A// Insert the spill at chosen location. Skip over any intervening Proj's or 0N/A// Phis. Skip over a CatchNode and projs, inserting in the fall-through block 0N/A// instead. Update high-pressure indices. Create a new live range. 0N/A // Skip intervening ProjNodes. Do not insert between a ProjNode and 0N/A // Do not insert between a call and his Catch 0N/A // Put the instruction at the top of the fall-thru block. 0N/A // Find the fall-thru projection 0N/A i =
1;
// Right at start of block 0N/A // Adjust the point where we go hi-pressure 0N/A // Assign a new Live Range Number to the SpillCopy and grow 0N/A // the node->live range mapping. 0N/A//------------------------------split_DEF-------------------------------------- 0N/A// Only three of these really occur as DOWN/USE will always color 0N/A// Any Split with a DEF cannot CISC-Spill now. Thus we need 0N/A// two helper routines, one for Split DEFS (insert after instruction), 0N/A// one for Split USES (insert before instruction). DEF insertion 0N/A// happens inside Split, where the Leaveblock array is updated. 0N/A // Increment the counter for this lrg 0N/A // If we are spilling the memory op for an implicit null check, at the 0N/A // null check location (ie - null check is in HRP block) we need to do 0N/A // the null-check first, then spill-down in the following block. 0N/A // (The implicit_null_check function ensures the use is also dominated 0N/A // by the branch-not-taken block.) 0N/A // Spill goes in the branch-not-taken block 0N/A loc = 0;
// Just past the Region 0N/A // Get a def-side SpillCopy 0N/A // Did we fail to split?, then bail 0N/A // Insert the spill at chosen location 0N/A // Insert new node into Reaches array 0N/A // Update debug list of reaching down definitions by adding this one 0N/A // return updated count of live ranges 0N/A//------------------------------split_USE-------------------------------------- 0N/A// Splits at uses can involve redeffing the LRG, so no CISC Spilling there. 0N/A// Debug uses want to know if def is already stack enabled. 0N/A // Increment the counter for this lrg 0N/A // Some setup stuff for handling debug node uses 0N/A //------------------------------------------- 0N/A // Check for use of debug info 0N/A // Actually it's perfectly legal for constant debug info to appear 0N/A // just unlikely. In this case the optimizer left a ConI of a 4 0N/A // as both inputs to a Phi with only a debug use. It's a single-def 0N/A // live range of a rematerializable value. The live range spills, 0N/A // rematerializes and now the ConI directly feeds into the debug info. 0N/A // assert(!def->is_Con(), "constant debug info already constructed directly"); 0N/A // Special split handling for Debug Info 0N/A // If DEF is DOWN, just hook the edge and return 0N/A // If DEF is UP, Split it DOWN for this USE. 0N/A // DEF is DOWN, so connect USE directly to the DEF 0N/A // Block and index where the use occurs. 0N/A // Put the clone just prior to use 0N/A // DEF is UP, so must copy it DOWN and hook in USE 0N/A // Insert SpillCopy before the USE, which uses DEF as its input, 0N/A // and defs a new live range, which is used by this node. 0N/A // did we fail to split? 0N/A // insert into basic block 0N/A // Use the new split 0N/A // No further split handling needed for this use 0N/A }
// End special splitting for debug info live range 0N/A // Finally, check to see if USE is CISC-Spillable, and if so, 0N/A // gather_lrg_masks will add the flags bit to its mask, and 0N/A // no use side copy is needed. This frees up the live range 0N/A // register choices without causing copy coalescing, etc. 0N/A // Convert operand number to edge index number 0N/A //------------------------------------------- 0N/A // Insert a Copy before the use 0N/A // Block and index where the use occurs. 0N/A // Phi input spill-copys belong at the end of the prior block 0N/A // Put the clone just prior to use 0N/A // Insert SpillCopy before the USE, which uses the reaching DEF as 0N/A // its input, and defs a new live range, which is used by this node. 0N/A // return updated live range count 1613N/A//------------------------------clone_node---------------------------- 1613N/A// Clone node with anti dependence check. 1613N/A // Retry with subsume_loads == false 1613N/A // If this is the first failure, the sentinel string will "stick" 1613N/A // to the Compile object, and the C2Compiler will see it and retry. 0N/A//------------------------------split_Rematerialize---------------------------- 0N/A// Clone a local copy of the def. 0N/A // The input live ranges will be stretched to the site of the new 0N/A // instruction. They might be stretched past a def and will thus 0N/A // have the old and new values of the same live range alive at the 0N/A // same time - a definite no-no. Split out private copies of 0N/A // Check for single-def (LRG cannot redefined) 0N/A // Check when generating nodes 0N/A // See if any inputs are currently being spilled, and take the 0N/A // latest copy of spilled inputs. 0N/A // Walk backwards thru spill copy node intermediates 295N/A // walkThru found a multidef LRG, which is unsafe to use, so 295N/A // just keep the original def used in the clone. 0N/A // Rematerialized op is def->spilled+1 0N/A // Increment the counter for this lrg 0N/A // See if the cloned def kills any flags, and copy those kills as well 0N/A // Adjust the point where we go hi-pressure 0N/A//------------------------------is_high_pressure------------------------------- 0N/A// Function to compute whether or not this live range is "high pressure" 0N/A// in this block - whether it spills eagerly or not. 0N/A // Forced spilling due to conflict? Then split only at binding uses 0N/A // or defs, not for supposed capacity problems. 0N/A // CNC - Turned off 7/8/99, causes too much spilling 0N/A // if( lrg->_is_bound ) return false; 0N/A // Not yet reached the high-pressure cutoff point, so low pressure 0N/A // Register pressure for the block as a whole depends on reg class 0N/A // Bound live ranges will split at the binding points first; 0N/A // Intermediate splits should assume the live range's register set 0N/A // got "freed up" and that num_regs will become INT_PRESSURE. 0N/A // Effective register pressure limit. 0N/A // High pressure if block pressure requires more register freedom 0N/A // than live range has. 0N/A//------------------------------prompt_use--------------------------------- 0N/A// True if lidx is used before any real register is def'd in the block 0N/A // Scan block for 1st use. 0N/A // Ignore PHI use, these can be up or down 0N/A return true;
// Found 1st use! 0N/A//------------------------------Split-------------------------------------- 0N/A//----------Split Routine---------- 0N/A// ***** NEW SPLITTING HEURISTIC ***** 0N/A// DEFS: If the DEF is in a High Register Pressure(HRP) Block, split there. 0N/A// Else, no split unless there is a HRP block between a DEF and 0N/A// one of its uses, and then split at the HRP block. 0N/A// USES: If USE is in HRP, split at use to leave main LRG on stack. 0N/A// Else, hoist LRG back up to register only (ie - split is also DEF) 0N/A// We will compute a new maxlrg as we go 0N/A // Array of counters to count splits per live range 0N/A //----------Setup Code---------- 0N/A // Keep track of DEFS & Phis for later passes 0N/A // Gather info on which LRG's are spilling, and build maps 0N/A // Initialize the split counts to zero 0N/A // Create side arrays for propagating reaching defs info. 0N/A // Each block needs a node pointer for each spilling live range for the 0N/A // Def which is live into the block. Phi nodes handle multiple input 0N/A // Defs by querying the output of their predecessor blocks and resolving 0N/A // them to a single Def at the phi. The pointer is updated for each 0N/A // Def in the block, and then becomes the output for the block when 0N/A // processing of the block is complete. We also need to track whether 0N/A // a Def is UP or DOWN. UP means that it should get a register (ie - 0N/A // it is always in LRP regions), and DOWN means that it is probably 0N/A // on the stack (ie - it crosses HRP regions). 0N/A // Initialize Reaches & UP 0N/A // Initialize to array of empty vectorsets 0N/A //----------PASS 1---------- 0N/A //----------Propagation & Node Insertion Code---------- 0N/A // Walk the Blocks in RPO for DEF & USE info 0N/A // Reaches & UP arrays for this block 0N/A // Reset counter of start of non-Phi nodes in block 0N/A //----------Block Entry Handling---------- 0N/A // Check for need to insert a new phi 0N/A // Cycle through this block's predecessors, collecting Reaches 0N/A // info for each spilled LRG. If they are identical, no phi is 0N/A // needed. If they differ, check for a phi, and insert if missing, 0N/A // or update edges if present. Set current block's Reaches set to 0N/A // be either the phi's or the reaching def, as appropriate. 0N/A // If no Phi is needed, check if the LRG needs to spill on entry 0N/A // to the block due to HRP. 0N/A // Grab the live range number 0N/A // Do not bother splitting or putting in Phis for single-def 0N/A // rematerialized live ranges. This happens alot to constants 0N/A // with long live ranges. 0N/A // reset the Reaches & UP entries 0N/A // Record following instruction in case 'n' rematerializes and 0N/A // Initialize needs_phi and needs_split 0N/A // Walk the predecessor blocks to check inputs for that live range 0N/A // Grab predecessor block header 0N/A // Grab the appropriate reaching def info for inpidx 0N/A // Initialize node for saving type info 0N/A // Compare inputs to see if a Phi is needed 0N/A // Grab predecessor block headers 0N/A // Grab the appropriate reaching def info for inpidx 0N/A // For each LRG, decide if a phi is necessary 0N/A // See if the phi has mismatched inputs, UP vs. DOWN 0N/A // Preserve a non-NULL predecessor for later type referencing 0N/A }
// End for all potential Phi inputs 330N/A // check block for appropriate phinode & update edges 330N/A // bail if this is not a phi 330N/A // Keep track of index of first non-PhiNode instruction in block 330N/A // break out of the for loop as we have handled all phi nodes 330N/A // must be looking at a phi 330N/A // found the necessary phi 330N/A // initialize the Reaches entry for this LRG 330N/A }
// end if found correct phi 330N/A // If a phi is needed or exist, check for it 0N/A // add new phinode if one not already found 0N/A // create a new phi node and insert it into the block 0N/A // type is taken from left over pointer to a predecessor 0N/A // initialize the Reaches entry for this LRG 0N/A // add node to block & node_to_block mapping 0N/A // Reset new phi's mapping to be the spilling live range 0N/A }
// end if not found correct phi 0N/A // Here you have either found or created the Phi, so record it 0N/A // PhiNodes should either force the LRG UP or DOWN depending 0N/A // on its inputs and the register pressure in the Phi's block. 0N/A // If entering a high-pressure area with no immediate use, 0N/A // assume Phi is DOWN 0N/A // If we are not split up/down and all inputs are down, then we 0N/A }
// end if phi is needed 0N/A // Do not need a phi, so grab the reaching DEF 0N/A // Grab predecessor block header 0N/A // Grab the appropriate reaching def info for k 0N/A // reset the Reaches & UP entries 0N/A }
// end else no Phi is needed 0N/A }
// end for all spilling live ranges 0N/A tty->
print(
"Reaching Definitions after Phi handling\n");
0N/A //----------Non-Phi Node Splitting---------- 0N/A // Since phi-nodes have now been handled, the Reachblock array for this 0N/A // block is initialized with the correct starting value for the defs which 0N/A // reach non-phi instructions in this block. Thus, process non-phi 0N/A // instructions normally, inserting SpillCopy nodes for all spill 0N/A // Memoize any DOWN reaching definitions for use as DEBUG info 0N/A //----------Walk Instructions in the Block and Split---------- 0N/A // For all non-phi instructions in the block 0N/A // Find the defining Node's live range index 0N/A // Skip phi nodes after removing dead copies. 0N/A // Check for useless Phis. These appear if we spill, then 0N/A // coalesce away copies. Dont touch Phis in spilling live 0N/A // ranges; they are busy getting modifed in this pass. 0N/A // Look for the Phi merging 2 unique inputs 0N/A // Ignore repeats and self 0N/A if( n->
in(i) != u && n->
in(i) != n ) {
0N/A // Found a unique input 0N/A if( u !=
NULL )
// If it's the 2nd, bail out 0N/A u = n->
in(i);
// Else record it 0N/A assert( u,
"at least 1 valid input expected" );
330N/A if( i >=
cnt ) {
// Found one unique input 0N/A // ********** Handle Crossing HRP Boundry ********** 605N/A // Check for need to split at HRP boundary - split if UP 0N/A // bail out if no reaching DEF 0N/A // bail out if live range is 'isolated' around inner loop 0N/A // If live range is currently UP 0N/A // set location to insert spills at 0N/A // SPLIT DOWN HERE - NO CISC SPILL 0N/A // If there is already a valid stack definition available, use it 0N/A // Insert point is just past last use or def in the block 0N/A // Hit top of block? Quit going backwards 0N/A // Found a def? Better split after it. 0N/A for( i =
1; i < n->
req(); i++ )
0N/A // Found a use? Better split after it. 0N/A // If it wasn't split bail 0N/A // This is a new DEF, so update UP 0N/A }
// end if LRG is UP 0N/A }
// end for all spilling live ranges 0N/A }
// end if crossing HRP Boundry 0N/A // If the LRG index is oob, then this is a new spillcopy, skip it. 0N/A // Remove coalesced copy from CFG 0N/A // ********** Handle USES ********** 0N/A // Implicit null checks never use the spilled value 0N/A // Search all inputs for a Spill-USE 0N/A // If inpidx > old_last, then one of these new inputs is being 0N/A // handled. Skip the derived part of the pair, but process 0N/A // the base like any other input. 0N/A continue;
// skip derived_debug added below 0N/A // Get lidx of input 0N/A // Not a brand-new split, and it is a spill use 0N/A // Check for valid reaching DEF 0N/A // monitor references do not care where they live, so just hook 0N/A // The effect of this clone is to drop the node out of the block, 0N/A // so that the allocator does not see it anymore, and therefore 0N/A // does not attempt to assign it a register. 0N/A // Rematerializable? Then clone def at use site instead 0N/A if( !
def )
return 0;
// Bail out 0N/A // Base pointers and oopmap references do not care where they live. 0N/A // This def has been rematerialized a couple of times without 0N/A // progress. It doesn't care if it lives UP or DOWN, so 0N/A // spill it down now. 0N/A // If it wasn't split bail 0N/A insidx++;
// Reset iterator to skip USE side split 0N/A // Just hook the def edge 0N/A // derived value is spilling and we have a copy both in Reachblock 0N/A // (called here 'def') and debug_defs[slidx] we need to mention 0N/A // We have already set 'def' as a derived value. 0N/A // Also set debug_defs[slidx] as a derived value. 0N/A break;
// Found an instance of debug derived 0N/A if( k ==
cnt ) {
// No instance of debug_defs[slidx] 0N/A // We have to process the added base later since it is not 0N/A // handled yet at this point but skip derived part. 0N/A "must match skip condition above");
0N/A // Increment cnt to handle added input edges on 0N/A // subsequent iterations. 0N/A // Special logic for DEBUG info 0N/A // If this is debug info use & there is a reaching DOWN def 0N/A // Just hook it in & move on 0N/A // (Note that this can make two sides of a split live at the 0N/A // same time: The debug def on stack, and another def in a 0N/A // register. The GC needs to know about both of them, but any 0N/A // derived pointers after oopoff will refer to only one of the 0N/A // two defs and the GC would therefore miss the other. Thus 0N/A // this hack is only allowed for debug info which is Java state 0N/A // and therefore never a derived pointer.) 0N/A // Grab register mask info 0N/A // Need special logic to handle bound USES. Insert a split at this 0N/A // bound use if we can't rematerialize the def, or if we need the 0N/A // split to form a misaligned pair. 0N/A // These need a Split regardless of overlap or pressure 0N/A // SPLIT - NO DEF - NO CISC SPILL 0N/A // If it wasn't split bail 0N/A insidx++;
// Reset iterator to skip USE side split 1650N/A // The use at the call can force the def down so insert 1650N/A // a split before the use to allow the def more freedom. 0N/A // Here is the logic chart which describes USE Splitting: 0N/A // 0 = false or DOWN, 1 = true or UP 0N/A // Overlap | DEF | USE | Action 0N/A //------------------------------------------------------- 0N/A // 0 | 0 | 0 | Copy - mem -> mem 0N/A // 0 | 0 | 1 | Split-UP - Check HRP 0N/A // 0 | 1 | 0 | Split-DOWN - Debug Info? 0N/A // 0 | 1 | 1 | Copy - reg -> reg 0N/A // 1 | 0 | 0 | Reset Input Edge (no Split) 0N/A // 1 | 0 | 1 | Split-UP - Check HRP 0N/A // 1 | 1 | 0 | Split-DOWN - Debug Info? 0N/A // 1 | 1 | 1 | Reset Input Edge (no Split) 0N/A // So, if (dup == uup), then overlap test determines action, 0N/A // with true being no split, and false being copy. Else, 0N/A // if DEF is DOWN, Split-UP, and check HRP to decide on 0N/A // resetting DEF. Finally if DEF is UP, Split-DOWN, with 0N/A // special handling for Debug Info. 0N/A // Both are either up or down, and there is overlap, No Split 0N/A else {
// Both are either up or down, and there is no overlap 0N/A if(
dup ) {
// If UP, reg->reg copy 0N/A // COPY ACROSS HERE - NO DEF - NO CISC SPILL 0N/A // If it wasn't split bail 0N/A insidx++;
// Reset iterator to skip USE side split 0N/A else {
// DOWN, mem->mem copy 0N/A // COPY UP & DOWN HERE - NO DEF - NO CISC SPILL 0N/A // First Split-UP to move value into Register 0N/A // Then Split-DOWN as if previous Split was DEF 0N/A // If it wasn't split bail 0N/A insidx +=
2;
// Reset iterator to skip USE side splits 0N/A }
// End else no overlap 0N/A }
// End if dup == uup 0N/A // dup != uup, so check dup for direction of Split 0N/A if(
dup ) {
// If UP, Split-DOWN and check Debug Info 0N/A // If this node is already a SpillCopy, just patch the edge 0N/A // except the case of spilling to stack. 0N/A // COPY DOWN HERE - NO DEF - NO CISC SPILL 0N/A // If it wasn't split bail 0N/A insidx++;
// Reset iterator to skip USE side split 0N/A // Check for debug-info split. Capture it for later 0N/A // debug splits of the same value 0N/A else {
// DOWN, Split-UP and check register pressure 0N/A // COPY UP HERE - NO DEF - CISC SPILL 0N/A // If it wasn't split bail 0N/A insidx++;
// Reset iterator to skip USE side split 0N/A // COPY UP HERE - WITH DEF - NO CISC SPILL 0N/A // If it wasn't split bail 0N/A // Flag this lift-up in a low-pressure block as 0N/A // already-spilled, so if it spills again it will 0N/A // spill hard (instead of not spilling hard and 0N/A // coalescing away). 0N/A // Since this is a new DEF, update Reachblock & UP 0N/A insidx++;
// Reset iterator to skip USE side split 0N/A }
// End if Spill USE 0N/A }
// End For All Inputs 0N/A }
// End If not nullcheck 0N/A // ********** Handle DEFS ********** 0N/A // DEFS either Split DOWN in HRP regions or when the LRG is bound, or 0N/A // just reset the Reaches info in LRP regions. DEFS must always update 0N/A // Add to defs list for later assignment of new live range number 0N/A // Set a flag on the Node indicating it has already spilled. 0N/A // Only do it for capacity spills not conflict spills. 0N/A // Grab UP info for DEF 0N/A // Only split at Def if this is a HRP block or bound (and spilled once) 0N/A // Check for LRG being up in a register and we are inside a high 0N/A // pressure area. Spill it down immediately. 0N/A // Do a split at the def site. 0N/A // If it wasn't split bail 0N/A else {
// Neither bound nor HRP, must be LRP 0N/A // otherwise, just record the def 0N/A // UP should come from the outRegmask() of the DEF 0N/A // Update debug list of reaching down definitions, kill if DEF is UP 0N/A }
// End if spill def 0N/A // ********** Split Left Over Mem-Mem Moves ********** 0N/A // Check for mem-mem copies and split them now. Do not do this 0N/A // to copies about to be spilled; they will be Split shortly. 0N/A // Put the spill just before the copy 0N/A }
// End For All Instructions in Block - Non-PHI Pass 0N/A // Check if each LRG is live out of this block so as not to propagate 0N/A // beyond the last use of a LRG. 0N/A // The index defidx is not live. Check the liveout array to ensure that 0N/A // it contains no members which compress to defidx. Finding such an 0N/A // instance may be a case to add liveout adjustment in compress_uf_map(). 0N/A }
// End For All Blocks 0N/A //----------PASS 2---------- 0N/A // Reset all DEF live range numbers here 0N/A // Set new lidx for DEF 0N/A //----------Phi Node Splitting---------- 0N/A // Clean up a phi here, and assign a new live range number 0N/A // Cycle through this block's predecessors, collecting Reaches 0N/A // info for each spilled LRG and update edges. 0N/A // Walk the phis list to patch inputs, split phis, and name phis 0N/A // Grab the live range number 0N/A // Update node to lidx map 0N/A // Get PASS1's up/down decision for the block. 0N/A // Force down if double-spilling live range 0N/A // When splitting a Phi we an split it normal or "inverted". 0N/A // An inverted split makes the splits target the Phi's UP/DOWN 0N/A // sense inverted; then the Phi is followed by a final def-side 0N/A // split to invert back. It changes which blocks the spill code 0N/A // Walk the predecessor blocks and assign the reaching def to the Phi. 0N/A // Split Phi nodes by placing USE side splits wherever the reaching 0N/A // Get predecessor block pre-order number 0N/A // Grab reaching def 0N/A // If input up/down sense and reg-pressure DISagree 1923N/A // Place the rematerialized node above any MSCs created during 1923N/A // phi node splitting. end_idx points at the insertion point 1923N/A // so look at the node before it. 0N/A if( !
def )
return 0;
// Bail out 0N/A // Update the Phi's input edge array 0N/A // If it wasn't split bail 0N/A }
// End for all inputs to the Phi 0N/A }
// End for all Phi Nodes 0N/A // Update _maxlrg to save Union asserts 0N/A //----------PASS 3---------- 0N/A // Pass over all Phi's to union the live ranges 0N/A // Walk all inputs to Phi and Union input live range with Phi live range 0N/A // Grab the input node 0N/A }
// End for all inputs to the Phi Node 0N/A }
// End for all Phi Nodes 0N/A // Now union all two address instructions 0N/A // Set new lidx for DEF & handle 2-addr instructions 0N/A // Union the input and output live ranges 0N/A }
// End if two address 0N/A }
// End for all defs 0N/A // Validate all live range index assignments 0N/A // Issue a warning if splitting made no progress 0N/A // Return updated count of live ranges