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.regalloc;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.NOP;
016
017import java.lang.reflect.Constructor;
018import java.util.ArrayList;
019import java.util.Enumeration;
020
021import org.jikesrvm.VM;
022import org.jikesrvm.compilers.opt.OptOptions;
023import org.jikesrvm.compilers.opt.driver.CompilerPhase;
024import org.jikesrvm.compilers.opt.ir.BasicBlock;
025import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
026import org.jikesrvm.compilers.opt.ir.Empty;
027import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet;
028import org.jikesrvm.compilers.opt.ir.IR;
029import org.jikesrvm.compilers.opt.ir.Instruction;
030import org.jikesrvm.compilers.opt.ir.Register;
031import org.jikesrvm.compilers.opt.ir.operand.Operand;
032import org.jikesrvm.compilers.opt.liveness.LiveInterval;
033
034/**
035 * phase to compute linear scan intervals.
036 */
037public final class IntervalAnalysis extends CompilerPhase {
038  /**
039   * the governing ir
040   */
041  private IR ir;
042
043  private RegisterAllocatorState regAllocState;
044
045  /**
046   * a list of basic blocks in topological order
047   */
048  private BasicBlock listOfBlocks;
049
050  /**
051   *  a reverse topological list of basic blocks
052   */
053  private BasicBlock reverseTopFirst;
054
055  /**
056   * Mark FMOVs that end a live range?
057   */
058  private static final boolean MUTATE_FMOV = VM.BuildForIA32;
059
060  /**
061   * Constructor for this compiler phase
062   */
063  private static final Constructor<CompilerPhase> constructor =
064      getCompilerPhaseConstructor(IntervalAnalysis.class);
065
066  /**
067   * Get a constructor object for this compiler phase
068   * @return compiler phase constructor
069   */
070  @Override
071  public Constructor<CompilerPhase> getClassConstructor() {
072    return constructor;
073  }
074
075  /**
076   * should we perform this phase? yes.
077   */
078  @Override
079  public boolean shouldPerform(OptOptions options) {
080    return true;
081  }
082
083  /**
084   * a name for this phase.
085   */
086  @Override
087  public String getName() {
088    return "Interval Analysis";
089  }
090
091  /**
092   * should we print the ir?
093   */
094  @Override
095  public boolean printingEnabled(OptOptions options, boolean before) {
096    return false;
097  }
098
099  /**
100   * compute live intervals for this ir
101   * the result is a sorted (by beginning point) set of compound
102   * intervals, stored in the private 'intervals' field.
103   *
104   * @param ir the ir
105   */
106  @Override
107  public void perform(IR ir) {
108    this.ir = ir;
109    this.regAllocState = ir.MIRInfo.regAllocState;
110
111    ControlFlowGraph cfg = ir.cfg;
112    GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
113    LinearScanState state = new LinearScanState();
114    ir.MIRInfo.linearScanState = state;
115
116    // create topological list and a reverse topological list
117    // the results are on listOfBlocks and reverseTopFirst lists
118    createTopAndReverseList(cfg);
119
120    // give dfn values to each instruction
121    assignDepthFirstNumbers(cfg);
122
123    // initialize registers
124    initializeRegisters();
125
126    int lastBeginSeen = -1;
127
128    // visit each basic block in the listOfBlocks list
129    for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) {
130
131      // visit each live interval for this basic block
132      LiveInterval liveIntervals = ir.getLivenessInformation();
133      for (LiveIntervalElement live = liveIntervals.getFirstLiveIntervalElement(bb); live != null; live = live.getNext()) {
134
135        // check that we process live intervals in order of increasing
136        // begin.
137        if (VM.VerifyAssertions) {
138          int begin = regAllocState.getDfnBegin(live, bb);
139          VM._assert(begin >= lastBeginSeen);
140          lastBeginSeen = begin;
141        }
142
143        // skip registers which are not allocated.
144        if (live.getRegister().isPhysical() && !phys.isAllocatable(live.getRegister())) {
145          continue;
146        }
147
148        CompoundInterval resultingInterval = processLiveInterval(live, bb);
149        if (!bb.getInfrequent() && resultingInterval != null) {
150          resultingInterval.setFrequent();
151        }
152      }
153    }
154
155    // debug support
156    if (LinearScan.VERBOSE_DEBUG) {
157      VM.sysWrite("**** start of interval dump " + ir.method + " ****\n");
158      VM.sysWrite(ir.MIRInfo.linearScanState.intervals.toString());
159      VM.sysWrite("**** end   of interval dump ****\n");
160    }
161  }
162
163  /**
164   *  create topological list and a reverse topological list
165   *  the results are on listOfBlocks and reverseTopFirst lists
166   *  @param cfg the control flow graph
167   */
168  private void createTopAndReverseList(ControlFlowGraph cfg) {
169    // dfs: create a list of nodes (basic blocks) in a topological order
170    cfg.clearDFS();
171    listOfBlocks = cfg.entry();
172    listOfBlocks.sortDFS();
173
174    // this loop reverses the topological list by using the sortedPrev field
175    reverseTopFirst = null;
176    for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) {
177
178      // put back pointers in the "prev" field
179      // set reverseTopFirst to be the more recent node we've seen,
180      // it will be the front of the list when we are done
181      bb.sortedPrev = reverseTopFirst;
182      reverseTopFirst = bb;
183    }
184  }
185
186  /**
187   *  this method processes all basic blocks, do the following to each block
188   *   1) add it to the begining of the "listOfBlocks" list
189   *   2) number the instructions
190   *   3) process the instructions that restrict physical register
191   *   assignment
192   *  @param cfg the control flow graph
193   */
194  void assignDepthFirstNumbers(ControlFlowGraph cfg) {
195    int instructionCount = ir.countInstructions();
196    regAllocState.initializeDepthFirstNumbering(instructionCount);
197
198    int curDfn = instructionCount - 1;
199    listOfBlocks = null;
200    for (BasicBlock bb = reverseTopFirst; bb != null; bb = (BasicBlock) bb.sortedPrev) {
201
202      // insert bb at the front of the list
203      bb.nextSorted = listOfBlocks;
204      listOfBlocks = bb;
205
206      // number the instructions last to first
207      Enumeration<Instruction> e = bb.reverseInstrEnumerator();
208      while (e.hasMoreElements()) {
209        Instruction inst = e.nextElement();
210        regAllocState.setDFN(inst, curDfn);
211        curDfn--;
212      }
213    }
214
215    if (LinearScan.DEBUG) {
216      regAllocState.printDfns(ir);
217    }
218  }
219
220  /**
221   * Initialize the interval for each register to null.
222   */
223  private void initializeRegisters() {
224    RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState;
225
226    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
227      regAllocState.setInterval(reg, null);
228      regAllocState.setSpill(reg, 0);
229      // clear the 'long' type if it's persisted to here.
230      if (VM.BuildFor32Addr && reg.isLong()) {
231        reg.clearType();
232        reg.setInteger();
233      }
234    }
235  }
236
237  /**
238   * Mutate FMOVs that end live ranges
239   *
240   * @param live The live interval for a basic block/reg pair
241   * @param register The register for this live interval
242   * @param dfnbegin The (adjusted) begin for this interval
243   * @param dfnend The (adjusted) end for this interval
244   * @return whether an actual change was necessary (as opposed to
245   *  simple removal because the end was dead)
246   */
247  private boolean mutateFMOVs(LiveIntervalElement live, Register register, int dfnbegin, int dfnend) {
248    Instruction end = live.getEnd();
249    if (end != null && end.operator() == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV) {
250      if (dfnend == dfnbegin) {
251        // if end, an FMOV, both begins and ends the live range,
252        // then end is dead.  Change it to a NOP and return null.
253        Empty.mutate(end, NOP);
254        return false;
255      } else {
256        if (!end.isPEI()) {
257          if (VM.VerifyAssertions) {
258            Operand value = org.jikesrvm.compilers.opt.ir.ia32.MIR_Move.getValue(end);
259            VM._assert(value.isRegister());
260            VM._assert(org.jikesrvm.compilers.opt.ir.ia32.MIR_Move.getValue(end).asRegister().getRegister() == register);
261          }
262          end.changeOperatorTo(org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV_ENDING_LIVE_RANGE);
263        }
264      }
265    }
266    return true;
267  }
268
269  /**
270   * for each live interval associated with this block
271   * we either add a new interval, or extend a previous interval
272   * if it is contiguous
273   *
274   * @param live the liveintervalelement for a basic block/reg pair
275   * @param bb the basic block
276   * @return the resulting CompoundInterval. null if the live interval
277   * is not relevant to register allocation.
278   */
279  private CompoundInterval processLiveInterval(LiveIntervalElement live, BasicBlock bb) {
280
281    // get the reg and (adjusted) begin, end pair for this interval
282    Register reg = live.getRegister();
283    int dfnend = regAllocState.getDfnEnd(live, bb);
284    int dfnbegin = regAllocState.getDfnBegin(live, bb);
285
286    if (MUTATE_FMOV && reg.isFloatingPoint()) {
287      mutateFMOVs(live, reg, dfnbegin, dfnend);
288    }
289
290    // check for an existing live interval for this register
291    CompoundInterval existingInterval = regAllocState.getInterval(reg);
292    if (existingInterval == null) {
293      // create a new live interval
294      CompoundInterval newInterval = new CompoundInterval(dfnbegin, dfnend, reg);
295      if (LinearScan.VERBOSE_DEBUG) System.out.println("created a new interval " + newInterval);
296
297      // associate the interval with the register
298      regAllocState.setInterval(reg, newInterval);
299
300      // add the new interval to the sorted set of intervals.
301      BasicInterval b = newInterval.first();
302      ir.MIRInfo.linearScanState.intervals.add(b);
303
304      return newInterval;
305
306    } else {
307      // add the new live range to the existing interval
308      ArrayList<BasicInterval> intervals = ir.MIRInfo.linearScanState.intervals;
309      BasicInterval added = existingInterval.addRange(regAllocState, live, bb);
310      if (added != null) {
311        intervals.add(added);
312      }
313      if (LinearScan.VERBOSE_DEBUG) System.out.println("Extended old interval " + reg);
314      if (LinearScan.VERBOSE_DEBUG) System.out.println(existingInterval);
315
316      return existingInterval;
317    }
318  }
319}