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     */
013    package org.jikesrvm.compilers.opt.ssa;
014    
015    import java.util.Enumeration;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.classloader.TypeReference;
018    import org.jikesrvm.compilers.opt.ir.BBend;
019    import org.jikesrvm.compilers.opt.ir.Move;
020    import org.jikesrvm.compilers.opt.ir.BasicBlock;
021    import org.jikesrvm.compilers.opt.ir.IR;
022    import org.jikesrvm.compilers.opt.ir.IRTools;
023    import org.jikesrvm.compilers.opt.ir.Instruction;
024    import org.jikesrvm.compilers.opt.ir.Operator;
025    
026    import static org.jikesrvm.compilers.opt.driver.OptConstants.SSA_SYNTH_BCI;
027    import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
028    import org.jikesrvm.compilers.opt.ir.Register;
029    import org.jikesrvm.compilers.opt.ir.Phi;
030    import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand;
031    import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
032    import org.jikesrvm.compilers.opt.ir.operand.HeapOperand;
033    import org.jikesrvm.compilers.opt.ir.operand.Operand;
034    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
035    
036    /**
037     * This module holds utility functions for SSA form.
038     *
039     * <p> Our SSA form is <em> Heap Array SSA Form </em>, an extension of
040     * SSA that allows analysis of scalars, arrays, and object fields
041     * in a unified framework.  See our SAS 2000 paper
042     * <a href="http://www.research.ibm.com/jalapeno/publication.html#sas00">
043     *  Unified Analysis of Arrays and Object References in Strongly Typed
044     *  Languages </a>
045     * <p> Details about our current implementation include:
046     * <ul>
047     *  <li> We explicitly place phi-functions as instructions in the IR.
048     *  <li> Scalar registers are explicitly renamed in the IR.
049     *  <li> Heap variables are represented implicitly. Each instruction
050     *       that reads or writes from the heap implicitly uses a Heap variable.
051     *       The particular heap variable for each instruction is cached
052     *       in {@link SSADictionary <code> ir.HIRInfo.dictionary </code>}.
053     *       dphi functions do <em> not </em>
054     *       explicitly appear in the IR.
055     *  <p>
056     *  For example, consider the code:
057     *  <p>
058     *  <pre>
059     *              a.x = z;
060     *              b[100] = 5;
061     *              y = a.x;
062     *  </pre>
063     *
064     *  <p>Logically, we translate to Array SSA form (before renumbering) as:
065     *  <pre>
066     *              HEAP_x[a] = z
067     *              HEAP_x = dphi(HEAP_x,HEAP_x)
068     *              HEAP_I[] = { < b,100,5 > }
069     *              HEAP_I[] = dphi(HEAP_I[], HEAP_I[])
070     *              y = HEAP_x[a]
071     *  </pre>
072     *
073     *  <p> However, the implementation does not actually modify the instruction
074     *      stream. Instead, we keep track of the following information with
075     *  <code> ir.HIRInfo.dictionary </code>:
076     *  <pre>
077     *              a.x = z  (implicit: reads HEAP_x, writes HEAP_x)
078     *              b[100] =5 (implicit: reads HEAP_I[], writes HEAP_I[])
079     *              y = a.x   (implicit: reads HEAP_x)
080     *  </pre>
081     *
082     *  <p>Similarly, phi functions for the implicit heap
083     *  variables <em> will not </em>
084     *  appear explicitly in the instruction stream. Instead, the
085     *  SSADictionary data structure keeps the heap control phi
086     *  functions for each basic block in a lookaside table.
087     *  </ul>
088     *
089     * @see EnterSSA
090     * @see LeaveSSA
091     * @see SSADictionary
092     * @see org.jikesrvm.compilers.opt.ir.HIRInfo
093     */
094    class SSA {
095    
096      /**
097       * Add a move instruction at the end of a basic block, renaming
098       * with a temporary register if needed to protect conditional branches
099       * at the end of the block.
100       *
101       * @param ir governing IR
102       * @param bb the basic block
103       * @param c  the move instruction to insert
104       * @param exp whether or not to respect exception control flow at the
105       *            end of the block
106       */
107      static void addAtEnd(IR ir, BasicBlock bb, Instruction c, boolean exp) {
108        if (exp) {
109          bb.appendInstructionRespectingTerminalBranchOrPEI(c);
110        } else {
111          bb.appendInstructionRespectingTerminalBranch(c);
112        }
113        RegisterOperand aux = null;
114        if (VM.VerifyAssertions) {
115          VM._assert(Move.conforms(c));
116        }
117        RegisterOperand lhs = Move.getResult(c);
118        Instruction i = c.nextInstructionInCodeOrder();
119        while (!BBend.conforms(i)) {
120          Enumeration<Operand> os = i.getUses();
121          while (os.hasMoreElements()) {
122            Operand op = os.nextElement();
123            if (lhs.similar(op)) {
124              if (aux == null) {
125                aux = ir.regpool.makeTemp(lhs);
126                c.insertBefore(makeMoveInstruction(ir, aux.getRegister(), lhs.getRegister(), lhs.getType()));
127              }
128              op.asRegister().setRegister(aux.getRegister());
129            }
130          }
131          i = i.nextInstructionInCodeOrder();
132        }
133      }
134    
135      /**
136       * Print the instructions in SSA form.
137       *
138       * @param ir the IR, assumed to be in SSA form
139       */
140      public static void printInstructions(IR ir) {
141        SSADictionary dictionary = ir.HIRInfo.dictionary;
142        System.out.println("********* START OF IR DUMP in SSA FOR " + ir.method);
143        for (Enumeration<BasicBlock> be = ir.forwardBlockEnumerator(); be.hasMoreElements();) {
144          BasicBlock bb = be.nextElement();
145          // print the explicit instructions for basic block bb
146          for (Enumeration<Instruction> e = dictionary.getAllInstructions(bb); e.hasMoreElements();) {
147            Instruction s = e.nextElement();
148            System.out.print(s.bcIndex + "\t" + s);
149            if (dictionary.defsHeapVariable(s) && s.operator != PHI) {
150              System.out.print("  (Implicit Defs: ");
151              HeapOperand<?>[] defs = dictionary.getHeapDefs(s);
152              if (defs != null) {
153                for (HeapOperand<?> def : defs) System.out.print(def + " ");
154              }
155              System.out.print(" )");
156            }
157            if (dictionary.usesHeapVariable(s) && s.operator != PHI) {
158              System.out.print("  (Implicit Uses: ");
159              HeapOperand<?>[] uses = dictionary.getHeapUses(s);
160              if (uses != null) {
161                for (HeapOperand<?> use : uses) System.out.print(use + " ");
162              }
163              System.out.print(" )");
164            }
165            System.out.print("\n");
166          }
167        }
168        System.out.println("*********   END OF IR DUMP in SSA FOR " + ir.method);
169      }
170    
171      /**
172       * Create a move instruction r1 := r2.<p>
173       *
174       * TODO: This utility function should be moved elsewhere.
175       *
176       * @param ir the governing ir
177       * @param r1 the destination
178       * @param r2 the source
179       * @param t the type of r1 and r2.
180       */
181      static Instruction makeMoveInstruction(IR ir, Register r1, Register r2, TypeReference t) {
182        Operator mv = IRTools.getMoveOp(t);
183        RegisterOperand o1 = new RegisterOperand(r1, t);
184        RegisterOperand o2 = new RegisterOperand(r2, t);
185        Instruction s = Move.create(mv, o1, o2);
186        s.position = ir.gc.inlineSequence;
187        s.bcIndex = SSA_SYNTH_BCI;
188        return s;
189      }
190    
191      /**
192       * Create a move instruction r1 := c.<p>
193       *
194       * !!TODO: put this functionality elsewhere.
195       *
196       * @param ir the governing ir
197       * @param r1 the destination
198       * @param c the source
199       */
200      static Instruction makeMoveInstruction(IR ir, Register r1, ConstantOperand c) {
201        Operator mv = IRTools.getMoveOp(c.getType());
202        RegisterOperand o1 = new RegisterOperand(r1, c.getType());
203        Operand o2 = c.copy();
204        Instruction s = Move.create(mv, o1, o2);
205        s.position = ir.gc.inlineSequence;
206        s.bcIndex = SSA_SYNTH_BCI;
207        return s;
208      }
209    
210      /**
211       * Fix up any PHI instructions in the given target block to reflect that
212       * the given source block is no longer a predecessor of target.
213       * The basic algorithm is to erase the PHI operands related to the edge
214       * from source to target by sliding the other PHI operands down as required.
215       *
216       * @param source the source block to remove from PHIs in target
217       * @param target the target block that may contain PHIs to update.
218       */
219      static void purgeBlockFromPHIs(BasicBlock source, BasicBlock target) {
220        for (Enumeration<Instruction> e = target.forwardRealInstrEnumerator(); e.hasMoreElements();) {
221          Instruction s = e.nextElement();
222          if (s.operator() != PHI) return; // all done (assume PHIs are first!)
223          int numPairs = Phi.getNumberOfPreds(s);
224          int dst = 0;
225          for (int src = 0; src < numPairs; src++) {
226            BasicBlockOperand bbop = Phi.getPred(s, src);
227            if (bbop.block == source) {
228              Phi.setValue(s, src, null);
229              Phi.setPred(s, src, null);
230            } else {
231              if (src != dst) {
232                Phi.setValue(s, dst, Phi.getClearValue(s, src));
233                Phi.setPred(s, dst, Phi.getClearPred(s, src));
234              }
235              dst++;
236            }
237          }
238          for (int i = dst; i < numPairs; i++) {
239            Phi.setValue(s, i, null);
240            Phi.setPred(s, i, null);
241          }
242        }
243      }
244    
245      /**
246       * Update PHI instructions in the target block so that any PHIs that
247       * come from basic block B1, now come from basic block B2.
248       *
249       * @param target the target block that may contain PHIs to update.
250       * @param B1 the block to replace in the phi instructions
251       * @param B2 the replacement block for B1
252       */
253      static void replaceBlockInPhis(BasicBlock target, BasicBlock B1, BasicBlock B2) {
254        for (Enumeration<Instruction> e = target.forwardRealInstrEnumerator(); e.hasMoreElements();) {
255          Instruction s = e.nextElement();
256          if (s.operator() != PHI) return; // all done (assume PHIs are first!)
257          int numPairs = Phi.getNumberOfPreds(s);
258          for (int src = 0; src < numPairs; src++) {
259            BasicBlockOperand bbop = Phi.getPred(s, src);
260            if (bbop.block == B1) {
261              Phi.setPred(s, src, new BasicBlockOperand(B2));
262            }
263          }
264        }
265      }
266    }