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.ir.Operators.SPLIT;
016
017import java.util.Enumeration;
018import java.util.HashMap;
019import java.util.HashSet;
020import java.util.Map;
021
022import org.jikesrvm.classloader.TypeReference;
023import org.jikesrvm.compilers.opt.DefUse;
024import org.jikesrvm.compilers.opt.OptOptions;
025import org.jikesrvm.compilers.opt.OptimizingCompilerException;
026import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
027import org.jikesrvm.compilers.opt.controlflow.DominanceFrontier;
028import org.jikesrvm.compilers.opt.controlflow.DominatorsPhase;
029import org.jikesrvm.compilers.opt.controlflow.LSTGraph;
030import org.jikesrvm.compilers.opt.controlflow.LSTNode;
031import org.jikesrvm.compilers.opt.driver.CompilerPhase;
032import org.jikesrvm.compilers.opt.driver.OptimizationPlanAtomicElement;
033import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement;
034import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement;
035import org.jikesrvm.compilers.opt.ir.BasicBlock;
036import org.jikesrvm.compilers.opt.ir.IR;
037import org.jikesrvm.compilers.opt.ir.IRTools;
038import org.jikesrvm.compilers.opt.ir.Instruction;
039import org.jikesrvm.compilers.opt.ir.Register;
040import org.jikesrvm.compilers.opt.ir.Unary;
041import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
042import org.jikesrvm.compilers.opt.liveness.LiveAnalysis;
043import org.jikesrvm.compilers.opt.regalloc.CoalesceMoves;
044import org.jikesrvm.compilers.opt.util.GraphNode;
045import org.jikesrvm.util.BitVector;
046
047
048/**
049 * Perform live-range splitting.
050 *
051 * <p>This pass splits live ranges where they enter and exit loop bodies
052 * by normal (unexceptional) control flow.
053 * It splits a live range for register r by inserting the instruction
054 * <code> r = SPLIT r </code>.  Then,  SSA renaming will introduce a new
055 * name for r.  The SPLIT operator is later turned into a MOVE during
056 * BURS.
057 *
058 * <p>This pass also splits live ranges on edges to and from infrequent code.
059 *
060 * <p> This composite phase should be performed at the end of SSA in LIR.
061 */
062public class LiveRangeSplitting extends OptimizationPlanCompositeElement {
063
064  @Override
065  public final boolean shouldPerform(OptOptions options) {
066    return options.SSA_LIVE_RANGE_SPLITTING;
067  }
068
069  /**
070   * Build this phase as a composite of others.
071   */
072  public LiveRangeSplitting() {
073    super("LIR SSA Live Range Splitting", new OptimizationPlanElement[]{
074        // 0. Clean up the IR
075        new OptimizationPlanAtomicElement(new BranchOptimizations(2, true, true)),
076        new OptimizationPlanAtomicElement(new CoalesceMoves()),
077        // 1. Insert the split operations.
078        new OptimizationPlanAtomicElement(new LiveRangeSplittingPhase()),
079        new OptimizationPlanAtomicElement(new BranchOptimizations(2, true, true)),
080        // 2. Use SSA to rename
081        new OptimizationPlanAtomicElement(new DominatorsPhase(true)),
082        new OptimizationPlanAtomicElement(new DominanceFrontier()),
083        new OptimizationPlanAtomicElement(new RenamePreparation()),
084        new OptimizationPlanAtomicElement(new EnterSSA()),
085        new OptimizationPlanAtomicElement(new LeaveSSA())});
086  }
087
088  private static class LiveRangeSplittingPhase extends CompilerPhase {
089
090    /**
091     * Return this instance of this phase. This phase contains no
092     * per-compilation instance fields.
093     * @param ir not used
094     * @return this
095     */
096    @Override
097    public CompilerPhase newExecution(IR ir) {
098      return this;
099    }
100
101    @Override
102    public final boolean shouldPerform(OptOptions options) {
103      return options.SSA_LIVE_RANGE_SPLITTING;
104    }
105
106    @Override
107    public final String getName() {
108      return "Live Range Splitting";
109    }
110
111    @Override
112    public final void perform(IR ir) {
113      // 1. Compute an up-to-date loop structure tree.
114      DominatorsPhase dom = new DominatorsPhase(true);
115      dom.perform(ir);
116      LSTGraph lst = ir.HIRInfo.loopStructureTree;
117      if (lst == null) {
118        throw new OptimizingCompilerException("null loop structure tree");
119      }
120
121      // 2. Compute liveness.
122      // TODO It was previously necessary to perform liveness analysis after
123      // dominators had been computed to prevent probelms with usage of scratch
124      // fields. Scratch fields have since been removed. It is now possible to
125      // change the order if we ever get around to fixing SSA and testing the
126      // compiler phases that rely on it.
127      LiveAnalysis live = new LiveAnalysis(false,  // don't create GC maps
128                                                   false,  // don't skip (final) local
129                                                   // propagation step of live analysis
130                                                   false,  // don't store information at handlers
131                                                   true);  // skip guards
132      live.perform(ir);
133
134      // 3. Perform the analysis
135      DefUse.computeDU(ir);
136      HashMap<BasicBlockPair, HashSet<Register>> result = findSplitPoints(ir, live, lst);
137
138      // 4. Perform the transformation.
139      transform(ir, result);
140
141      // 5. Record that we've destroyed SSA
142      if (ir.actualSSAOptions != null) {
143        ir.actualSSAOptions.setScalarValid(false);
144        ir.actualSSAOptions.setHeapValid(false);
145      }
146    }
147
148    /**
149     * Find the points the IR where live ranges should be split.
150     *
151     * @param ir the governing IR
152     * @param live valid liveness information
153     * @param lst a valid loop structure tree
154     * @return the result as a mapping from BasicBlockPair to a set of registers
155     */
156    private static HashMap<BasicBlockPair, HashSet<Register>> findSplitPoints(IR ir, LiveAnalysis live,
157                                                                                  LSTGraph lst) {
158
159      HashMap<BasicBlockPair, HashSet<Register>> result = new HashMap<BasicBlockPair, HashSet<Register>>(10);
160      for (Enumeration<GraphNode> e = lst.enumerateNodes(); e.hasMoreElements();) {
161        LSTNode node = (LSTNode) e.nextElement();
162        BasicBlock header = node.getHeader();
163        BitVector loop = node.getLoop();
164        if (loop == null) continue;
165
166        // First split live ranges on edges coming into the loop header.
167        for (Enumeration<BasicBlock> in = header.getIn(); in.hasMoreElements();) {
168          BasicBlock bb = in.nextElement();
169          if (loop.get(bb.getNumber())) continue;
170          HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, header);
171          for (Register r : liveRegisters) {
172            if (r.isSymbolic()) {
173              HashSet<Register> s = findOrCreateSplitSet(result, bb, header);
174              s.add(r);
175            }
176          }
177        }
178
179        // Next split live ranges on every normal exit from the loop.
180        for (int i = 0; i < loop.length(); i++) {
181          if (loop.get(i)) {
182            BasicBlock bb = ir.getBasicBlock(i);
183            for (Enumeration<BasicBlock> out = bb.getNormalOut(); out.hasMoreElements();) {
184              BasicBlock dest = out.nextElement();
185              if (loop.get(dest.getNumber())) continue;
186              HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, dest);
187              for (Register r : liveRegisters) {
188                if (r.isSymbolic()) {
189                  HashSet<Register> s = findOrCreateSplitSet(result, bb, dest);
190                  s.add(r);
191                }
192              }
193            }
194          }
195        }
196      }
197
198      addEntriesForInfrequentBlocks(ir, live, result);
199
200      return result;
201    }
202
203    /**
204     * Split live ranges on entry and exit to infrequent regions.
205     * Add this information to 'result', a mapping from BasicBlockPair to a set of
206     * registers to split.
207     *
208     * @param ir the governing IR
209     * @param live valid liveness information
210     * @param result mapping from BasicBlockPair to a set of registers
211     */
212    private static void addEntriesForInfrequentBlocks(IR ir, LiveAnalysis live,
213                                                      HashMap<BasicBlockPair, HashSet<Register>> result) {
214      for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) {
215        BasicBlock bb = e.nextElement();
216        boolean bbInfrequent = bb.getInfrequent();
217        for (Enumeration<BasicBlock> out = bb.getNormalOut(); out.hasMoreElements();) {
218          BasicBlock dest = out.nextElement();
219          boolean destInfrequent = dest.getInfrequent();
220          if (bbInfrequent ^ destInfrequent) {
221            HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, dest);
222            for (Register r : liveRegisters) {
223              if (r.isSymbolic()) {
224                HashSet<Register> s = findOrCreateSplitSet(result, bb, dest);
225                s.add(r);
226              }
227            }
228          }
229        }
230      }
231    }
232
233    /**
234     * Given a mapping from BasicBlockPair -&gt; HashSet, find or create the hash
235     * set corresponding to a given basic block pair
236     *
237     * @param map the mapping to search
238     * @param b1 the first basic block in the pair
239     * @param b2 the second basic block in the pair
240     * @return the set corresponding to the basic block pair
241     */
242    private static HashSet<Register> findOrCreateSplitSet(HashMap<BasicBlockPair, HashSet<Register>> map,
243                                                              BasicBlock b1, BasicBlock b2) {
244      BasicBlockPair pair = new BasicBlockPair(b1, b2);
245      HashSet<Register> set = map.get(pair);
246      if (set == null) {
247        set = new HashSet<Register>(5);
248        map.put(pair, set);
249      }
250      return set;
251    }
252
253    /**
254     * Perform the transformation
255     *
256     * @param ir the governing IR
257     * @param xform a mapping from BasicBlockPair to the set of registers
258     * to split
259     */
260    private static void transform(IR ir, HashMap<BasicBlockPair, HashSet<Register>> xform) {
261      for (Map.Entry<BasicBlockPair, HashSet<Register>> entry : xform.entrySet()) {
262        BasicBlockPair bbp = entry.getKey();
263        HashSet<Register> toSplit = entry.getValue();
264
265        // we go ahead and split all edges, instead of just critical ones.
266        // we'll clean up the mess later after SSA.
267        BasicBlock target = IRTools.makeBlockOnEdge(bbp.src, bbp.dest, ir);
268        SSA.replaceBlockInPhis(bbp.dest, bbp.src, target);
269
270        for (Register r : toSplit) {
271          if (r.defList == null) continue;
272          Instruction s = null;
273          switch (r.getType()) {
274            case Register.ADDRESS_TYPE:
275              RegisterOperand lhs2 = IRTools.A(r);
276              RegisterOperand rhs2 = IRTools.A(r);
277              s = Unary.create(SPLIT, lhs2, rhs2);
278              // fix up types: only split live ranges when the type is
279              // consistent at all defs
280              TypeReference t2 = null;
281              Enumeration<RegisterOperand> e2 = DefUse.defs(r);
282              if (!e2.hasMoreElements()) {
283                s = null;
284              } else {
285                RegisterOperand rop2 = e2.nextElement();
286                t2 = rop2.getType();
287                while (e2.hasMoreElements()) {
288                  RegisterOperand nextOp2 = e2.nextElement();
289                  if (nextOp2.getType() != t2) {
290                    s = null;
291                  }
292                }
293              }
294              if (s != null) {
295                lhs2.setType(t2);
296                rhs2.setType(t2);
297              }
298              break;
299            case Register.INTEGER_TYPE:
300              RegisterOperand lhs = IRTools.I(r);
301              RegisterOperand rhs = IRTools.I(r);
302              s = Unary.create(SPLIT, lhs, rhs);
303              // fix up types: only split live ranges when the type is
304              // consistent at all defs
305              TypeReference t = null;
306              Enumeration<RegisterOperand> e = DefUse.defs(r);
307              if (!e.hasMoreElements()) {
308                s = null;
309              } else {
310                RegisterOperand rop = e.nextElement();
311                t = rop.getType();
312                while (e.hasMoreElements()) {
313                  RegisterOperand nextOp = e.nextElement();
314                  if (nextOp.getType() != t) {
315                    s = null;
316                  }
317                }
318              }
319              if (s != null) {
320                lhs.setType(t);
321                rhs.setType(t);
322              }
323              break;
324            case Register.FLOAT_TYPE:
325              s = Unary.create(SPLIT, IRTools.F(r), IRTools.F(r));
326              break;
327            case Register.DOUBLE_TYPE:
328              s = Unary.create(SPLIT, IRTools.D(r), IRTools.D(r));
329              break;
330            case Register.LONG_TYPE:
331              s = Unary.create(SPLIT, IRTools.L(r), IRTools.L(r));
332              break;
333            default:
334              // we won't split live ranges for other types.
335              s = null;
336              break;
337          }
338          if (s != null) {
339            target.prependInstruction(s);
340          }
341        }
342      }
343    }
344
345    /**
346     * A utility class to represent an edge in the CFG.
347     */
348    private static class BasicBlockPair {
349      /**
350       * The source of a control-flow edge
351       */
352      final BasicBlock src;
353
354      /**
355       * The sink of a control-flow edge
356       */
357      final BasicBlock dest;
358
359      BasicBlockPair(BasicBlock src, BasicBlock dest) {
360        this.src = src;
361        this.dest = dest;
362      }
363
364      static int nextHash = 0;
365      int myHash = ++nextHash;
366
367      @Override
368      public int hashCode() {
369        return myHash;
370      }
371
372      @Override
373      public boolean equals(Object o) {
374        if (!(o instanceof BasicBlockPair)) return false;
375        BasicBlockPair p = (BasicBlockPair) o;
376        return (src.equals(p.src) && dest.equals(p.dest));
377      }
378
379      @Override
380      public String toString() {
381        return "<" + src + "," + dest + ">";
382      }
383    }
384  }
385
386  /**
387   * This class sets up the IR state prior to entering SSA.
388   */
389  private static class RenamePreparation extends CompilerPhase {
390
391    /**
392     * Return this instance of this phase. This phase contains no
393     * per-compilation instance fields.
394     * @param ir not used
395     * @return this
396     */
397    @Override
398    public CompilerPhase newExecution(IR ir) {
399      return this;
400    }
401
402    @Override
403    public final boolean shouldPerform(OptOptions options) {
404      return options.SSA_LIVE_RANGE_SPLITTING;
405    }
406
407    @Override
408    public final String getName() {
409      return "Rename Preparation";
410    }
411
412    /**
413     * register in the IR the SSA properties we need for simple scalar
414     * renaming
415     */
416    @Override
417    public final void perform(IR ir) {
418      ir.desiredSSAOptions = new SSAOptions();
419      ir.desiredSSAOptions.setScalarsOnly(true);
420      ir.desiredSSAOptions.setBackwards(false);
421      ir.desiredSSAOptions.setInsertUsePhis(false);
422    }
423  }
424}