/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.regalloc; import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert; import static org.jikesrvm.compilers.opt.ir.Operators.NOP; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Enumeration; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.OptOptions; import org.jikesrvm.compilers.opt.driver.CompilerPhase; import org.jikesrvm.compilers.opt.ir.BasicBlock; import org.jikesrvm.compilers.opt.ir.ControlFlowGraph; import org.jikesrvm.compilers.opt.ir.Empty; import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.IR; import org.jikesrvm.compilers.opt.ir.Instruction; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.ir.operand.Operand; import org.jikesrvm.compilers.opt.liveness.LiveInterval; /** * phase to compute linear scan intervals. */ public final class IntervalAnalysis extends CompilerPhase { /** * the governing ir */ private IR ir; private RegisterAllocatorState regAllocState; /** * a list of basic blocks in topological order */ private BasicBlock listOfBlocks; /** * a reverse topological list of basic blocks */ private BasicBlock reverseTopFirst; /** * Mark FMOVs that end a live range? */ private static final boolean MUTATE_FMOV = VM.BuildForIA32; /** * Constructor for this compiler phase */ private static final Constructor<CompilerPhase> constructor = getCompilerPhaseConstructor(IntervalAnalysis.class); /** * Get a constructor object for this compiler phase * @return compiler phase constructor */ @Override public Constructor<CompilerPhase> getClassConstructor() { return constructor; } /** * should we perform this phase? yes. */ @Override public boolean shouldPerform(OptOptions options) { return true; } /** * a name for this phase. */ @Override public String getName() { return "Interval Analysis"; } /** * should we print the ir? */ @Override public boolean printingEnabled(OptOptions options, boolean before) { return false; } /** * compute live intervals for this ir * the result is a sorted (by beginning point) set of compound * intervals, stored in the private 'intervals' field. * * @param ir the ir */ @Override public void perform(IR ir) { this.ir = ir; this.regAllocState = ir.MIRInfo.regAllocState; ControlFlowGraph cfg = ir.cfg; GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); LinearScanState state = new LinearScanState(); ir.MIRInfo.linearScanState = state; // create topological list and a reverse topological list // the results are on listOfBlocks and reverseTopFirst lists createTopAndReverseList(cfg); // give dfn values to each instruction assignDepthFirstNumbers(cfg); // initialize registers initializeRegisters(); int lastBeginSeen = -1; // visit each basic block in the listOfBlocks list for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) { // visit each live interval for this basic block LiveInterval liveIntervals = ir.getLivenessInformation(); for (LiveIntervalElement live = liveIntervals.getFirstLiveIntervalElement(bb); live != null; live = live.getNext()) { // check that we process live intervals in order of increasing // begin. if (VM.VerifyAssertions) { int begin = regAllocState.getDfnBegin(live, bb); VM._assert(begin >= lastBeginSeen); lastBeginSeen = begin; } // skip registers which are not allocated. if (live.getRegister().isPhysical() && !phys.isAllocatable(live.getRegister())) { continue; } CompoundInterval resultingInterval = processLiveInterval(live, bb); if (!bb.getInfrequent() && resultingInterval != null) { resultingInterval.setFrequent(); } } } // debug support if (LinearScan.VERBOSE_DEBUG) { VM.sysWriteln("**** start of interval dump " + ir.method + " ****"); VM.sysWrite(ir.MIRInfo.linearScanState.intervals.toString()); VM.sysWriteln("**** end of interval dump ****"); } } /** * create topological list and a reverse topological list * the results are on listOfBlocks and reverseTopFirst lists * @param cfg the control flow graph */ private void createTopAndReverseList(ControlFlowGraph cfg) { // dfs: create a list of nodes (basic blocks) in a topological order cfg.clearDFS(); listOfBlocks = cfg.entry(); listOfBlocks.sortDFS(); // this loop reverses the topological list by using the sortedPrev field reverseTopFirst = null; for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) { // put back pointers in the "prev" field // set reverseTopFirst to be the more recent node we've seen, // it will be the front of the list when we are done bb.sortedPrev = reverseTopFirst; reverseTopFirst = bb; } } /** * this method processes all basic blocks, do the following to each block * 1) add it to the begining of the "listOfBlocks" list * 2) number the instructions * 3) process the instructions that restrict physical register * assignment * @param cfg the control flow graph */ void assignDepthFirstNumbers(ControlFlowGraph cfg) { int instructionCount = ir.countInstructions(); regAllocState.initializeDepthFirstNumbering(instructionCount); int curDfn = instructionCount - 1; listOfBlocks = null; for (BasicBlock bb = reverseTopFirst; bb != null; bb = (BasicBlock) bb.sortedPrev) { // insert bb at the front of the list bb.nextSorted = listOfBlocks; listOfBlocks = bb; // number the instructions last to first Enumeration<Instruction> e = bb.reverseInstrEnumerator(); while (e.hasMoreElements()) { Instruction inst = e.nextElement(); regAllocState.setDFN(inst, curDfn); curDfn--; } } if (LinearScan.DEBUG) { regAllocState.printDfns(ir); } } /** * Initialize the interval for each register to null. */ private void initializeRegisters() { RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState; for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { regAllocState.setInterval(reg, null); regAllocState.setSpill(reg, 0); // clear the 'long' type if it's persisted to here. if (VM.BuildFor32Addr && reg.isLong()) { if (VM.VerifyAssertions) { opt_assert(reg.isLong(), "Found long-typed register on 32-bit."); } else { reg.clearType(); reg.setInteger(); } } } } /** * Mutate FMOVs that end live ranges * * @param live The live interval for a basic block/reg pair * @param register The register for this live interval * @param dfnbegin The (adjusted) begin for this interval * @param dfnend The (adjusted) end for this interval * @return whether an actual change was necessary (as opposed to * simple removal because the end was dead) */ private boolean mutateFMOVs(LiveIntervalElement live, Register register, int dfnbegin, int dfnend) { Instruction end = live.getEnd(); if (end != null && end.operator() == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV) { if (dfnend == dfnbegin) { // if end, an FMOV, both begins and ends the live range, // then end is dead. Change it to a NOP and return null. Empty.mutate(end, NOP); return false; } else { if (!end.isPEI()) { if (VM.VerifyAssertions) { Operand value = org.jikesrvm.compilers.opt.ir.ia32.MIR_Move.getValue(end); VM._assert(value.isRegister()); VM._assert(org.jikesrvm.compilers.opt.ir.ia32.MIR_Move.getValue(end).asRegister().getRegister() == register); } end.changeOperatorTo(org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV_ENDING_LIVE_RANGE); } } } return true; } /** * for each live interval associated with this block * we either add a new interval, or extend a previous interval * if it is contiguous * * @param live the liveintervalelement for a basic block/reg pair * @param bb the basic block * @return the resulting CompoundInterval. null if the live interval * is not relevant to register allocation. */ private CompoundInterval processLiveInterval(LiveIntervalElement live, BasicBlock bb) { // get the reg and (adjusted) begin, end pair for this interval Register reg = live.getRegister(); int dfnend = regAllocState.getDfnEnd(live, bb); int dfnbegin = regAllocState.getDfnBegin(live, bb); if (MUTATE_FMOV && reg.isFloatingPoint()) { mutateFMOVs(live, reg, dfnbegin, dfnend); } // check for an existing live interval for this register CompoundInterval existingInterval = regAllocState.getInterval(reg); if (existingInterval == null) { // create a new live interval CompoundInterval newInterval = new CompoundInterval(dfnbegin, dfnend, reg); if (LinearScan.VERBOSE_DEBUG) System.out.println("created a new interval " + newInterval); // associate the interval with the register regAllocState.setInterval(reg, newInterval); // add the new interval to the sorted set of intervals. BasicInterval b = newInterval.first(); ir.MIRInfo.linearScanState.intervals.add(b); return newInterval; } else { // add the new live range to the existing interval ArrayList<BasicInterval> intervals = ir.MIRInfo.linearScanState.intervals; BasicInterval added = existingInterval.addRange(regAllocState, live, bb); if (added != null) { intervals.add(added); } if (LinearScan.VERBOSE_DEBUG) System.out.println("Extended old interval " + reg); if (LinearScan.VERBOSE_DEBUG) System.out.println(existingInterval); return existingInterval; } } }