001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.ssa;
014
015import static org.jikesrvm.compilers.opt.driver.OptConstants.SSA_SYNTH_BCI;
016import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
017import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
018
019import java.lang.reflect.Constructor;
020import java.util.Enumeration;
021import java.util.HashMap;
022import java.util.HashSet;
023import java.util.Iterator;
024import java.util.LinkedList;
025import java.util.Stack;
026
027import org.jikesrvm.VM;
028import org.jikesrvm.classloader.TypeReference;
029import org.jikesrvm.compilers.opt.DefUse;
030import org.jikesrvm.compilers.opt.OptOptions;
031import org.jikesrvm.compilers.opt.OptimizingCompilerException;
032import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
033import org.jikesrvm.compilers.opt.controlflow.DominatorTree;
034import org.jikesrvm.compilers.opt.controlflow.DominatorTreeNode;
035import org.jikesrvm.compilers.opt.controlflow.LTDominators;
036import org.jikesrvm.compilers.opt.driver.CompilerPhase;
037import org.jikesrvm.compilers.opt.ir.BasicBlock;
038import org.jikesrvm.compilers.opt.ir.IR;
039import org.jikesrvm.compilers.opt.ir.IRTools;
040import org.jikesrvm.compilers.opt.ir.Instruction;
041import org.jikesrvm.compilers.opt.ir.Move;
042import org.jikesrvm.compilers.opt.ir.Phi;
043import org.jikesrvm.compilers.opt.ir.Register;
044import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
045import org.jikesrvm.compilers.opt.ir.operand.Operand;
046import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
047import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
048import org.jikesrvm.compilers.opt.ir.operand.UnreachableOperand;
049import org.jikesrvm.compilers.opt.liveness.LiveAnalysis;
050import org.jikesrvm.compilers.opt.liveness.LiveSet;
051import org.jikesrvm.compilers.opt.util.TreeNode;
052
053/**
054 * This compiler phase translates out of SSA form.
055 *
056 * @see SSA
057 * @see SSAOptions
058 * @see LTDominators
059 */
060public class LeaveSSA extends CompilerPhase {
061
062  /**
063   *  verbose debugging flag
064   */
065  static final boolean DEBUG = false;
066
067  /**
068   * The IR to manipulate
069   */
070  private IR ir;
071
072  private final BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true);
073
074  private boolean splitSomeBlock = false;
075
076  private final HashSet<Instruction> globalRenameTable = new HashSet<Instruction>();
077
078  private final HashSet<Register> globalRenamePhis = new HashSet<Register>();
079
080  /**
081   * Is SSA form enabled for the HIR?
082   */
083  @Override
084  public final boolean shouldPerform(OptOptions options) {
085    return options.SSA;
086  }
087
088  /**
089   * Constructor for this compiler phase
090   */
091  private static final Constructor<CompilerPhase> constructor = getCompilerPhaseConstructor(LeaveSSA.class);
092
093  /**
094   * Get a constructor object for this compiler phase
095   * @return compiler phase constructor
096   */
097  @Override
098  public Constructor<CompilerPhase> getClassConstructor() {
099    return constructor;
100  }
101
102  /**
103   * Return a string name for this phase.
104   * @return "Leave SSA"
105   */
106  @Override
107  public final String getName() {
108    return "Leave SSA";
109  }
110
111  /**
112   * perform the main out-of-ssa transformation
113   */
114  @Override
115  public final void perform(IR ir) {
116    this.ir = ir;
117    translateFromSSA(ir);
118
119    // reset ir.SSADictionary
120    ir.HIRInfo.dictionary = null;
121    // reset ssa options
122    ir.actualSSAOptions = null;
123
124    branchOpts.perform(ir, true);
125
126    ir.HIRInfo.dominatorsAreComputed = false;
127  }
128
129  /**
130   * This class provides an abstraction over stacks of names
131   * for registers.
132   */
133  static final class VariableStacks extends HashMap<Register, Stack<Operand>> {
134    /** Support for map serialization */
135    static final long serialVersionUID = -5664504465082745314L;
136
137    /**
138     * Get the name at the top of the stack for a particular register
139     * @param s the register in question
140     * @return the name at the top of the stack for the register
141     */
142    Operand peek(Register s) {
143      Stack<Operand> stack = get(s);
144      if (stack == null || stack.isEmpty()) {
145        return null;
146      } else {
147        return stack.peek();
148      }
149    }
150
151    /**
152     * Pop the name at the top of the stack for a particular register
153     * @param s the register in question
154     * @return the name at the top of the stack for the register
155     */
156    Operand pop(Register s) {
157      Stack<Operand> stack = get(s);
158      if (stack == null) {
159        throw new OptimizingCompilerException(
160            "Failure in translating out of SSA form: trying to pop operand from non-existant stack");
161      } else {
162        return stack.pop();
163      }
164    }
165
166    /**
167     * Push a name at the top of the stack for a particular register
168     * @param s the register in question
169     * @param name the name to push on the stack
170     */
171    void push(Register s, Operand name) {
172      Stack<Operand> stack = get(s);
173      if (stack == null) {
174        stack = new Stack<Operand>();
175        put(s, stack);
176      }
177      stack.push(name);
178    }
179  }
180
181  /**
182   * An instance of this class represents a pending copy instruction
183   * to be inserted.
184   */
185  static final class Copy {
186    /**
187     * The right-hand side of the copy instruction
188     */
189    final Operand source;
190    /**
191     * The left-hand side of the copy instruction
192     */
193    final RegisterOperand destination;
194    /**
195     *  The phi instruction which generated this copy instruction
196     */
197    final Instruction phi;
198
199    /**
200     * Create a pending copy operation for an operand of a phi instruction
201     * @param     phi   the phi instruction
202     * @param     index which operand of the instruction to copy
203     */
204    Copy(Instruction phi, int index) {
205      this.phi = phi;
206      destination = Phi.getResult(phi).asRegister();
207      source = Phi.getValue(phi, index);
208    }
209  }
210
211  // substitute variables renamed in control parents
212  private void performRename(BasicBlock bb, DominatorTree dom, VariableStacks s) {
213    if (DEBUG) VM.sysWriteln("performRename: " + bb);
214
215    Enumeration<Instruction> e = bb.forwardRealInstrEnumerator();
216    while (e.hasMoreElements()) {
217      Instruction i = e.nextElement();
218      Enumeration<Operand> ee = i.getUses();
219      while (ee.hasMoreElements()) {
220        Operand o = ee.nextElement();
221        if (o instanceof RegisterOperand) {
222          Register r1 = ((RegisterOperand) o).getRegister();
223          if (r1.isValidation()) continue;
224          Operand r2 = s.peek(r1);
225          if (r2 != null) {
226            if (DEBUG) {
227              VM.sysWriteln("replace operand in " + i + "(" + r2 + " for " + o);
228            }
229            i.replaceOperand(o, r2.copy());
230          }
231        }
232      }
233    }
234
235    // record renamings required in children
236    e = bb.forwardRealInstrEnumerator();
237    while (e.hasMoreElements()) {
238      Instruction i = e.nextElement();
239      if (globalRenameTable.contains(i)) {
240        Register original = Move.getVal(i).asRegister().getRegister();
241        RegisterOperand rename = Move.getResult(i);
242        if (DEBUG) VM.sysWriteln("record rename " + rename + " for " + original);
243        s.push(original, rename);
244      }
245    }
246
247    // insert copies in control children
248    Enumeration<TreeNode> children = dom.getChildren(bb);
249    while (children.hasMoreElements()) {
250      BasicBlock c = ((DominatorTreeNode) children.nextElement()).getBlock();
251      performRename(c, dom, s);
252    }
253
254    // pop renamings from this block off stack
255    e = bb.forwardRealInstrEnumerator();
256    while (e.hasMoreElements()) {
257      Instruction i = e.nextElement();
258      if (globalRenameTable.contains(i)) {
259        Register original = Move.getVal(i).asRegister().getRegister();
260        s.pop(original);
261      }
262    }
263  }
264
265  private boolean usedBelowCopy(BasicBlock bb, Register r) {
266    Enumeration<Instruction> ie = bb.reverseRealInstrEnumerator();
267    while (ie.hasMoreElements()) {
268      Instruction inst = ie.nextElement();
269      if (inst.isBranch()) {
270        Enumeration<Operand> oe = inst.getUses();
271        while (oe.hasMoreElements()) {
272          Operand op = oe.nextElement();
273          if (op.isRegister() && op.asRegister().getRegister() == r) {
274            return true;
275          }
276        }
277      } else {
278        break;
279      }
280    }
281
282    return false;
283  }
284
285  /**
286   * Record pending copy operations needed to insert at the end of a basic
287   * block.<p>
288   *
289   * TODO: this procedure is getting long and ugly.  Rewrite or refactor
290   * it.
291   * @param bb the basic block to process
292   * @param live valid liveness information for the IR
293   */
294  private void scheduleCopies(BasicBlock bb, LiveAnalysis live) {
295
296    if (DEBUG) VM.sysWrite("scheduleCopies: " + bb + "\n");
297
298    // compute out liveness from information in LiveAnalysis
299    LiveSet out = new LiveSet();
300    for (Enumeration<BasicBlock> outBlocks = bb.getOut(); outBlocks.hasMoreElements();) {
301      BasicBlock ob = outBlocks.nextElement();
302      LiveAnalysis.BBLiveElement le = live.getLiveInfo(ob);
303      out.add(le.getIn());
304    }
305
306    // usedByAnother represents the set of registers that appear on the
307    // left-hand side of subsequent phi nodes.  This is important, since
308    // we be careful to order copies if the same register appears as the
309    // source and dest of copies in the same basic block.
310    HashSet<Register> usedByAnother = new HashSet<Register>(4);
311
312    // for each basic block successor b of bb, if we make a block on the
313    // critical edge bb->b, then store this critical block.
314    HashMap<BasicBlock, BasicBlock> criticalBlocks = new HashMap<BasicBlock, BasicBlock>(4);
315
316    // For each critical basic block b in which we are inserting copies: return the
317    // mapping of registers to names implied by the copies that have
318    // already been inserted into b.
319    HashMap<BasicBlock, HashMap<Register, Register>> currentNames =
320        new HashMap<BasicBlock, HashMap<Register, Register>>(4);
321
322    // Additionally store the current names for the current basic block bb.
323    HashMap<Register, Register> bbNames = new HashMap<Register, Register>(4);
324
325    // copySet is a linked-list of copies we need to insert in this block.
326    final LinkedList<Copy> copySet = new LinkedList<Copy>();
327
328    /* Worklist is actually used like a stack - should we make this an Stack ?? */
329    final LinkedList<Copy> workList = new LinkedList<Copy>();
330
331    // collect copies required in this block.  These copies move
332    // the appropriate rval into the lval of each phi node in
333    // control children of the current block.
334    Enumeration<BasicBlock> e = bb.getOut();
335    while (e.hasMoreElements()) {
336      BasicBlock bbs = e.nextElement();
337      if (bbs.isExit()) continue;
338      for (Instruction phi = bbs.firstInstruction(); phi != bbs.lastInstruction(); phi =
339          phi.nextInstructionInCodeOrder()) {
340        if (phi.operator() != PHI) continue;
341        for (int index = 0; index < Phi.getNumberOfPreds(phi); index++) {
342          if (Phi.getPred(phi, index).block != bb) continue;
343          Operand rval = Phi.getValue(phi, index);
344          if (rval.isRegister() && Phi.getResult(phi).asRegister().getRegister() == rval.asRegister().getRegister()) {
345            continue;
346          }
347          Copy c = new Copy(phi, index);
348          copySet.add(0, c);
349          if (c.source instanceof RegisterOperand) {
350            Register r = c.source.asRegister().getRegister();
351            usedByAnother.add(r);
352          }
353        }
354      }
355    }
356    //  the copies that need to be added to this block are processed
357    //  in a worklist that ensures that copies are inserted only
358    //  after the destination register has been read by any other copy
359    //  that needs it.
360    //
361    // initialize work list with all copies whose destination is not
362    // the source for any other copy, and delete such copies from
363    // the set of needed copies.
364    for (Iterator<Copy> copySetIter = copySet.iterator(); copySetIter.hasNext();) {
365      Copy c = copySetIter.next();
366      if (!usedByAnother.contains(c.destination.getRegister())) {
367        workList.add(0, c);
368        copySetIter.remove();
369      }
370    }
371    // while there is any more work to do.
372    while (!workList.isEmpty() || !copySet.isEmpty()) {
373      // while there are copies that can be correctly inserted.
374      while (!workList.isEmpty()) {
375        Copy c = workList.remove(0);
376        Register r = c.destination.getRegister();
377        TypeReference tt = c.destination.getType();
378        if (VM.VerifyAssertions && tt == null) {
379          tt = TypeReference.Int;
380          VM.sysWrite("SSA, warning: null type in " + c.destination + "\n");
381        }
382
383        Register rr = null;
384        if (c.source.isRegister()) rr = c.source.asRegister().getRegister();
385        boolean shouldSplitBlock =
386            !c.phi.getBasicBlock().isExceptionHandlerBasicBlock() &&
387            ((ir.options.SSA_SPLITBLOCK_TO_AVOID_RENAME && out.contains(r)) ||
388             (rr != null && ir.options.SSA_SPLITBLOCK_FOR_LOCAL_LIVE && usedBelowCopy(bb, rr)));
389
390        if (ir.options.SSA_SPLITBLOCK_INTO_INFREQUENT) {
391          if (!bb.getInfrequent() &&
392              c.phi.getBasicBlock().getInfrequent() &&
393              !c.phi.getBasicBlock().isExceptionHandlerBasicBlock()) {
394            shouldSplitBlock = true;
395          }
396        }
397
398        // this check captures cases when the result of a phi
399        // in a control successor is live on exit of the current
400        // block.  this means it is incorrect to simply insert
401        // a copy of the destination in the current block.  so
402        // we rename the destination to a new temporary, and
403        // record the renaming so that dominator blocks get the
404        // new name.
405        if (out.contains(r) && !shouldSplitBlock) {
406          if (!globalRenamePhis.contains(r)) {
407            Register t = ir.regpool.getReg(r);
408            Instruction save = SSA.makeMoveInstruction(ir, t, r, tt);
409            if (DEBUG) {
410              VM.sysWriteln("Inserting " + save + " before " + c.phi + " in " + c.phi.getBasicBlock());
411            }
412            c.phi.insertAfter(save);
413            globalRenamePhis.add(r);
414            globalRenameTable.add(save);
415          }
416        }
417        Instruction ci = null;
418
419        // insert copy operation required to remove phi
420        if (c.source instanceof ConstantOperand) {
421          if (c.source instanceof UnreachableOperand) {
422            ci = null;
423          } else {
424            ci = SSA.makeMoveInstruction(ir, r, (ConstantOperand) c.source);
425          }
426        } else if (c.source instanceof RegisterOperand) {
427          if (shouldSplitBlock) {
428            if (DEBUG) VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock());
429            BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock());
430            if (criticalBlock == null) {
431              criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir);
432              if (c.phi.getBasicBlock().getInfrequent()) {
433                criticalBlock.setInfrequent();
434              }
435              splitSomeBlock = true;
436              criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock);
437              HashMap<Register, Register> newNames = new HashMap<Register, Register>(4);
438              currentNames.put(criticalBlock, newNames);
439            }
440            Register sr = c.source.asRegister().getRegister();
441            HashMap<Register, Register> criticalBlockNames = currentNames.get(criticalBlock);
442            Register nameForSR = criticalBlockNames.get(sr);
443            if (nameForSR == null) {
444              nameForSR = bbNames.get(sr);
445              if (nameForSR == null) nameForSR = sr;
446            }
447            if (DEBUG) VM.sysWriteln("dest(r): " + r);
448            if (DEBUG) VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR);
449            ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt);
450            criticalBlockNames.put(sr, r);
451            criticalBlock.appendInstructionRespectingTerminalBranch(ci);
452          } else {
453            Register sr = c.source.asRegister().getRegister();
454            Register nameForSR = bbNames.get(sr);
455            if (nameForSR == null) nameForSR = sr;
456            if (DEBUG) VM.sysWriteln("not splitting edge: " + bb + "->" + c.phi.getBasicBlock());
457            if (DEBUG) VM.sysWriteln("dest(r): " + r);
458            if (DEBUG) VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR);
459            ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt);
460            bbNames.put(sr, r);
461            SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
462          }
463          // ugly hack: having already added ci; set ci to null to skip remaining code;
464          ci = null;
465        } else {
466          throw new OptimizingCompilerException("Unexpected phi operand " +
467                                                    c
468                                                        .source +
469                                                                " encountered during SSA teardown", true);
470        }
471        if (ci != null) {
472          if (shouldSplitBlock) {
473            if (DEBUG) VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock());
474            BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock());
475            if (criticalBlock == null) {
476              criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir);
477              if (c.phi.getBasicBlock().getInfrequent()) {
478                criticalBlock.setInfrequent();
479              }
480              splitSomeBlock = true;
481              criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock);
482              HashMap<Register, Register> newNames = new HashMap<Register, Register>(4);
483              currentNames.put(criticalBlock, newNames);
484            }
485            criticalBlock.appendInstructionRespectingTerminalBranch(ci);
486          } else {
487            SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
488          }
489        }
490
491        // source has been copied and so can now be overwritten
492        // safely.  so now add any copies _to_ the source of the
493        // current copy to the work list.
494        if (c.source instanceof RegisterOperand) {
495          Register saved = c.source.asRegister().getRegister();
496          Iterator<Copy> copySetIter = copySet.iterator();
497          while (copySetIter.hasNext()) {
498            Copy cc = copySetIter.next();
499            if (cc.destination.asRegister().getRegister() == saved) {
500              workList.add(0, cc);
501              copySetIter.remove();
502            }
503          }
504        }
505      }
506      // an empty work list with work remaining in the copy set
507      // implies a cycle in the dependencies amongst copies.  deal
508      // with this: break the cycle by copying the destination
509      // of an arbitrary member of the copy set into a temporary.
510      // this destination has thus been saved, and can now be
511      // safely overwritten.  so, add that copy to the work list.
512      if (!copySet.isEmpty()) {
513        Copy c = copySet.remove(0);
514        Register tt = ir.regpool.getReg(c.destination.getRegister());
515        SSA.addAtEnd(ir,
516                         bb,
517                         SSA.makeMoveInstruction(ir, tt, c.destination.getRegister(), c.destination.getType()),
518                         c.phi.getBasicBlock().isExceptionHandlerBasicBlock());
519        bbNames.put(c.destination.getRegister(), tt);
520        workList.add(0, c);
521      }
522    }
523  }
524
525  /**
526   * Insert copy instructions into a basic block to safely translate out
527   * of SSA form.
528   *
529   * @param bb the basic block
530   * @param dom a valid dominator tree for the IR
531   * @param live valid liveness information for the IR
532   */
533  private void insertCopies(BasicBlock bb, DominatorTree dom, LiveAnalysis live) {
534    // add copies required in this block to remove phis.
535    // (record renaming required by simultaneous liveness in global tables)
536    scheduleCopies(bb, live);
537
538    // insert copies in control children
539    Enumeration<TreeNode> children = dom.getChildren(bb);
540    while (children.hasMoreElements()) {
541      BasicBlock c = ((DominatorTreeNode) children.nextElement()).getBlock();
542      insertCopies(c, dom, live);
543    }
544  }
545
546  /**
547   * Main driver to translate an IR out of SSA form.
548   *
549   * @param ir the IR in SSA form
550   */
551  public void translateFromSSA(IR ir) {
552    // 0. Deal with guards (validation registers)
553    unSSAGuards(ir);
554
555    // 1. re-compute dominator tree in case of control flow changes
556    LTDominators.perform(ir, true, true);
557    DominatorTree dom = new DominatorTree(ir, true);
558
559    // 1.5 Perform Sreedhar's naive translation from TSSA to CSSA
560    //if (ir.options.UNROLL_LOG == 0) normalizeSSA(ir);
561
562    // 2. compute liveness
563    LiveAnalysis live = new LiveAnalysis(false,  // don't create GC maps
564                                                 true,   // skip (final) local propagation step
565                                                 // of live analysis
566                                                 false,  // don't store information at handlers
567                                                 false); // don't skip guards
568
569    live.perform(ir);
570    // 3. initialization
571    VariableStacks s = new VariableStacks();
572    // 4. convert phi nodes into copies
573    BasicBlock b = ((DominatorTreeNode) dom.getRoot()).getBlock();
574    insertCopies(b, dom, live);
575    // 5. If necessary, recompute dominators to account for new control flow.
576    if (splitSomeBlock) {
577      LTDominators.perform(ir, true, true);
578      dom = new DominatorTree(ir, true);
579    }
580    // 6. compensate for copies required by simultaneous liveness
581    performRename(b, dom, s);
582    // 7. phis are now redundant
583    removeAllPhis(ir);
584  }
585
586  /**
587   * Remove all phi instructions from the IR.
588   *
589   * @param ir the governing IR
590   */
591  static void removeAllPhis(IR ir) {
592    for (Instruction s = ir.firstInstructionInCodeOrder(),
593        sentinel = ir.lastInstructionInCodeOrder(),
594        nextInstr = null; s != sentinel; s = nextInstr) {
595      // cache because remove nulls next/prev fields
596      nextInstr = s.nextInstructionInCodeOrder();
597      if (Phi.conforms(s)) s.remove();
598    }
599  }
600
601  /**
602   * Special treatment for guard registers:
603   * Remove guard-phis by evaluating operands into same register.
604   * If this target register is not unique, unite the alternatives.
605   *
606   * @param ir the governing IR, currently in SSA form
607   */
608  private void unSSAGuards(IR ir) {
609    // 0. initialization
610    unSSAGuardsInit(ir);
611    // 1. Determine target registers
612    unSSAGuardsDetermineReg(ir);
613    // 2. Rename targets and remove Phis
614    unSSAGuardsFinalize(ir);
615  }
616
617  Instruction guardPhis = null;
618
619  private HashMap<Instruction, Instruction> inst2guardPhi;
620  private HashMap<Register, Integer> guardRegUnion;
621  private HashMap<Register, Register> associatedRegisters;
622
623  /**
624   * Initialization for removal of guard phis.
625   *
626   * @param ir the governing IR, currently in SSA form
627   */
628  private void unSSAGuardsInit(IR ir) {
629    guardPhis = null;
630    Enumeration<Instruction> e = ir.forwardInstrEnumerator();
631
632    // visit all instructions, looking for guard phis
633
634    inst2guardPhi = new HashMap<Instruction, Instruction>();
635
636    while (e.hasMoreElements()) {
637      Instruction inst = e.nextElement();
638      if (!Phi.conforms(inst)) continue;
639      Operand res = Phi.getResult(inst);
640      if (!(res instanceof RegisterOperand)) continue;
641      Register r = res.asRegister().getRegister();
642      if (!r.isValidation()) continue;
643
644      // force all operands of Phis into registers.
645      inst2guardPhi.put(inst, guardPhis);
646      guardPhis = inst;
647
648      int values = Phi.getNumberOfValues(inst);
649      for (int i = 0; i < values; ++i) {
650        Operand op = Phi.getValue(inst, i);
651        if (!(op instanceof RegisterOperand)) {
652          if (op instanceof TrueGuardOperand) {
653            BasicBlock bb = Phi.getPred(inst, i).block;
654            Instruction move = Move.create(GUARD_MOVE, res.asRegister().copyD2D(), new TrueGuardOperand());
655            move.position = ir.gc.getInlineSequence();
656            move.bcIndex = SSA_SYNTH_BCI;
657            bb.appendInstructionRespectingTerminalBranchOrPEI(move);
658          } else if (op instanceof UnreachableOperand) {
659            // do nothing
660          } else {
661            if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
662          }
663        }
664      }
665    }
666
667    guardRegUnion = new HashMap<Register, Integer>();
668    associatedRegisters = new HashMap<Register, Register>();
669    // visit all guard registers, init union/find
670    for (Register r = ir.regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) {
671      if (!r.isValidation()) continue;
672      guardRegUnion.put(r, Integer.valueOf(1));
673      associatedRegisters.put(r, r);
674    }
675  }
676
677  /**
678   * Determine target register for guard phi operands
679   *
680   * @param ir the governing IR, currently in SSA form
681   */
682  private void unSSAGuardsDetermineReg(IR ir) {
683    Instruction inst = guardPhis;
684    while (inst != null) {
685      Register r = Phi.getResult(inst).asRegister().getRegister();
686      int values = Phi.getNumberOfValues(inst);
687      for (int i = 0; i < values; ++i) {
688        Operand op = Phi.getValue(inst, i);
689        if (op instanceof RegisterOperand) {
690          guardUnion(op.asRegister().getRegister(), r);
691        } else {
692          if (VM.VerifyAssertions) {
693            VM._assert(op instanceof TrueGuardOperand || op instanceof UnreachableOperand);
694          }
695        }
696      }
697      inst = inst2guardPhi.get(inst);
698    }
699  }
700
701  /**
702   * Rename registers and delete Phis.
703   *
704   * @param ir the governing IR, currently in SSA form
705   */
706  private void unSSAGuardsFinalize(IR ir) {
707    DefUse.computeDU(ir);
708    for (Register r = ir.regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) {
709      if (!r.isValidation()) continue;
710      Register nreg = guardFind(r);
711      Enumeration<RegisterOperand> uses = DefUse.uses(r);
712      while (uses.hasMoreElements()) {
713        RegisterOperand use = uses.nextElement();
714        use.setRegister(nreg);
715      }
716      Enumeration<RegisterOperand> defs = DefUse.defs(r);
717      while (defs.hasMoreElements()) {
718        RegisterOperand def = defs.nextElement();
719        def.setRegister(nreg);
720      }
721    }
722    Instruction inst = guardPhis;
723    while (inst != null) {
724      inst.remove();
725      inst = inst2guardPhi.get(inst);
726    }
727  }
728
729  private Register guardUnion(Register from, Register to) {
730    Register a = guardFind(from);
731    Register b = guardFind(to);
732    if (a == b) return a;
733    int aUnion = guardRegUnion.get(a);
734    int bUnion = guardRegUnion.get(b);
735    if (aUnion == bUnion) {
736      guardRegUnion.put(a, Integer.valueOf(aUnion + 1));
737      associatedRegisters.put(b, a);
738      return a;
739    }
740    if (aUnion > bUnion) {
741      associatedRegisters.put(b, a);
742      return a;
743    }
744    associatedRegisters.put(a, b);
745    return b;
746  }
747
748  private Register guardFind(Register r) {
749    Register start = r;
750    if (VM.VerifyAssertions) VM._assert(associatedRegisters.get(r) != null);
751    while (associatedRegisters.get(r) != r) r = associatedRegisters.get(r);
752    while (associatedRegisters.get(start) != r) {
753      associatedRegisters.put(start, r);
754      start = associatedRegisters.get(start);
755    }
756    return r;
757  }
758
759  /**
760   * Avoid potential lost copy and other associated problems by
761   * Sreedhar's naive translation from TSSA to CSSA. Guards are rather
762   * trivial to un-SSA so they have already been removed from the IR.
763   * This algorithm is very wasteful of registers so needs good
764   * coalescing.
765   * @param ir the IR to work upon
766   */
767  @SuppressWarnings("unused") // NB this was an aborted attempt to fix a bug in leave SSA
768  private static void normalizeSSA(IR ir) {
769    for (Instruction s = ir.firstInstructionInCodeOrder(),
770        sentinel = ir.lastInstructionInCodeOrder(),
771        nextInstr = null; s != sentinel; s = nextInstr) {
772      // cache so we don't process inserted instructions
773      nextInstr = s.nextInstructionInCodeOrder();
774      if (Phi.conforms(s) && !s.getBasicBlock().isExceptionHandlerBasicBlock()) {
775        // We ignore exception handler BBs as they cause problems when inserting copies
776        if (DEBUG) VM.sysWriteln("Processing " + s + " of basic block " + s.getBasicBlock());
777        // Does the phi instruction have an unreachable operand?
778        boolean hasUnreachable = false;
779        // 1. Naively copy source operands into predecessor blocks
780        for (int index = 0; index < Phi.getNumberOfPreds(s); index++) {
781          Operand op = Phi.getValue(s, index);
782          if (op.isRegister()) {
783            // Get rval
784            Register rval = op.asRegister().getRegister();
785            if (rval.isValidation()) {
786              continue; // ignore guards
787            } else {
788              // Make rval'
789              Register rvalPrime = ir.regpool.getReg(rval);
790              // Make copy instruction
791              Instruction copy = SSA.makeMoveInstruction(ir, rvalPrime, rval, op.getType());
792              // Insert a copy of rval to rval' in predBlock
793              BasicBlock pred = Phi.getPred(s, index).block;
794              pred.appendInstructionRespectingTerminalBranch(copy);
795              if (DEBUG) VM.sysWriteln("Inserted rval copy of " + copy + " into basic block " + pred);
796              // Rename rval to rval' in phi instruction
797              op.asRegister().setRegister(rvalPrime);
798            }
799          } else if (op instanceof UnreachableOperand) {
800            hasUnreachable = true;
801          }
802        }
803        // 2. Naively copy the result if there were no unreachable operands
804        if (!hasUnreachable) {
805          Operand op = Phi.getResult(s);
806          if (!op.isRegister()) {
807            // ignore heap operands
808          } else {
809            // Get lval
810            Register lval = op.asRegister().getRegister();
811            // Make lval'
812            Register lvalPrime = ir.regpool.getReg(lval);
813            // Make copy instruction
814            Instruction copy = SSA.makeMoveInstruction(ir, lval, lvalPrime, op.getType());
815            // Insert a copy of lval' to lval after phi instruction
816            s.insertAfter(copy);
817            // Rename lval to lval' in phi instruction
818            op.asRegister().setRegister(lvalPrime);
819            if (DEBUG) VM.sysWriteln("Inserted lval copy of " + copy + " after " + s);
820          }
821        }
822      }
823    }
824  }
825}