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}