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 static org.jikesrvm.compilers.opt.ir.Operators.SPLIT; 016 017 import java.util.Enumeration; 018 import java.util.HashMap; 019 import java.util.HashSet; 020 import java.util.Map; 021 022 import org.jikesrvm.classloader.TypeReference; 023 import org.jikesrvm.compilers.opt.DefUse; 024 import org.jikesrvm.compilers.opt.OptOptions; 025 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 026 import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations; 027 import org.jikesrvm.compilers.opt.controlflow.DominanceFrontier; 028 import org.jikesrvm.compilers.opt.controlflow.DominatorsPhase; 029 import org.jikesrvm.compilers.opt.controlflow.LSTGraph; 030 import org.jikesrvm.compilers.opt.controlflow.LSTNode; 031 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 032 import org.jikesrvm.compilers.opt.driver.OptimizationPlanAtomicElement; 033 import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; 034 import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 035 import org.jikesrvm.compilers.opt.ir.BasicBlock; 036 import org.jikesrvm.compilers.opt.ir.IR; 037 import org.jikesrvm.compilers.opt.ir.IRTools; 038 import org.jikesrvm.compilers.opt.ir.Instruction; 039 import org.jikesrvm.compilers.opt.ir.Register; 040 import org.jikesrvm.compilers.opt.ir.Unary; 041 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 042 import org.jikesrvm.compilers.opt.liveness.LiveAnalysis; 043 import org.jikesrvm.compilers.opt.regalloc.CoalesceMoves; 044 import org.jikesrvm.compilers.opt.util.GraphNode; 045 import 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 */ 062 public 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 // YUCK: We will later retrieve the live analysis info, relying on the 123 // scratchObject field of the Basic Blocks. Thus, liveness must be 124 // computed AFTER the dominators, since the dominator phase also uses 125 // the scratchObject field. 126 LiveAnalysis live = new LiveAnalysis(false, // don't create GC maps 127 false, // don't skip (final) local 128 // propagation step of live analysis 129 false, // don't store information at handlers 130 true); // skip guards 131 live.perform(ir); 132 133 // 3. Perform the analysis 134 DefUse.computeDU(ir); 135 HashMap<BasicBlockPair, HashSet<Register>> result = findSplitPoints(ir, live, lst); 136 137 // 4. Perform the transformation. 138 transform(ir, result); 139 140 // 5. Record that we've destroyed SSA 141 if (ir.actualSSAOptions != null) { 142 ir.actualSSAOptions.setScalarValid(false); 143 ir.actualSSAOptions.setHeapValid(false); 144 } 145 } 146 147 /** 148 * Find the points the IR where live ranges should be split. 149 * 150 * @param ir the governing IR 151 * @param live valid liveness information 152 * @param lst a valid loop structure tree 153 * @return the result as a mapping from BasicBlockPair to a set of registers 154 */ 155 private static HashMap<BasicBlockPair, HashSet<Register>> findSplitPoints(IR ir, LiveAnalysis live, 156 LSTGraph lst) { 157 158 HashMap<BasicBlockPair, HashSet<Register>> result = new HashMap<BasicBlockPair, HashSet<Register>>(10); 159 for (Enumeration<GraphNode> e = lst.enumerateNodes(); e.hasMoreElements();) { 160 LSTNode node = (LSTNode) e.nextElement(); 161 BasicBlock header = node.getHeader(); 162 BitVector loop = node.getLoop(); 163 if (loop == null) continue; 164 165 // First split live ranges on edges coming into the loop header. 166 for (Enumeration<BasicBlock> in = header.getIn(); in.hasMoreElements();) { 167 BasicBlock bb = in.nextElement(); 168 if (loop.get(bb.getNumber())) continue; 169 HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, header); 170 for (Register r : liveRegisters) { 171 if (r.isSymbolic()) { 172 HashSet<Register> s = findOrCreateSplitSet(result, bb, header); 173 s.add(r); 174 } 175 } 176 } 177 178 // Next split live ranges on every normal exit from the loop. 179 for (int i = 0; i < loop.length(); i++) { 180 if (loop.get(i)) { 181 BasicBlock bb = ir.getBasicBlock(i); 182 for (Enumeration<BasicBlock> out = bb.getNormalOut(); out.hasMoreElements();) { 183 BasicBlock dest = out.nextElement(); 184 if (loop.get(dest.getNumber())) continue; 185 HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, dest); 186 for (Register r : liveRegisters) { 187 if (r.isSymbolic()) { 188 HashSet<Register> s = findOrCreateSplitSet(result, bb, dest); 189 s.add(r); 190 } 191 } 192 } 193 } 194 } 195 } 196 197 addEntriesForInfrequentBlocks(ir, live, result); 198 199 return result; 200 } 201 202 /** 203 * Split live ranges on entry and exit to infrequent regions. 204 * Add this information to 'result', a mapping from BasicBlockPair to a set of 205 * registers to split. 206 * 207 * @param ir the governing IR 208 * @param live valid liveness information 209 * @param result mapping from BasicBlockPair to a set of registers 210 */ 211 private static void addEntriesForInfrequentBlocks(IR ir, LiveAnalysis live, 212 HashMap<BasicBlockPair, HashSet<Register>> result) { 213 for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) { 214 BasicBlock bb = e.nextElement(); 215 boolean bbInfrequent = bb.getInfrequent(); 216 for (Enumeration<BasicBlock> out = bb.getNormalOut(); out.hasMoreElements();) { 217 BasicBlock dest = out.nextElement(); 218 boolean destInfrequent = dest.getInfrequent(); 219 if (bbInfrequent ^ destInfrequent) { 220 HashSet<Register> liveRegisters = live.getLiveRegistersOnEdge(bb, dest); 221 for (Register r : liveRegisters) { 222 if (r.isSymbolic()) { 223 HashSet<Register> s = findOrCreateSplitSet(result, bb, dest); 224 s.add(r); 225 } 226 } 227 } 228 } 229 } 230 } 231 232 /** 233 * Given a mapping from BasicBlockPair -> HashSet, find or create the hash 234 * set corresponding to a given basic block pair 235 * 236 * @param map the mapping to search 237 * @param b1 the first basic block in the pair 238 * @param b2 the second basic block in the pair 239 */ 240 private static HashSet<Register> findOrCreateSplitSet(HashMap<BasicBlockPair, HashSet<Register>> map, 241 BasicBlock b1, BasicBlock b2) { 242 BasicBlockPair pair = new BasicBlockPair(b1, b2); 243 HashSet<Register> set = map.get(pair); 244 if (set == null) { 245 set = new HashSet<Register>(5); 246 map.put(pair, set); 247 } 248 return set; 249 } 250 251 /** 252 * Perform the transformation 253 * 254 * @param ir the governing IR 255 * @param xform a mapping from BasicBlockPair to the set of registers 256 * to split 257 */ 258 private static void transform(IR ir, HashMap<BasicBlockPair, HashSet<Register>> xform) { 259 for (Map.Entry<BasicBlockPair, HashSet<Register>> entry : xform.entrySet()) { 260 BasicBlockPair bbp = entry.getKey(); 261 HashSet<Register> toSplit = entry.getValue(); 262 263 // we go ahead and split all edges, instead of just critical ones. 264 // we'll clean up the mess later after SSA. 265 BasicBlock target = IRTools.makeBlockOnEdge(bbp.src, bbp.dest, ir); 266 SSA.replaceBlockInPhis(bbp.dest, bbp.src, target); 267 268 for (Register r : toSplit) { 269 if (r.defList == null) continue; 270 Instruction s = null; 271 switch (r.getType()) { 272 case Register.ADDRESS_TYPE: 273 RegisterOperand lhs2 = IRTools.A(r); 274 RegisterOperand rhs2 = IRTools.A(r); 275 s = Unary.create(SPLIT, lhs2, rhs2); 276 // fix up types: only split live ranges when the type is 277 // consistent at all defs 278 TypeReference t2 = null; 279 Enumeration<RegisterOperand> e2 = DefUse.defs(r); 280 if (!e2.hasMoreElements()) { 281 s = null; 282 } else { 283 RegisterOperand rop2 = e2.nextElement(); 284 t2 = rop2.getType(); 285 while (e2.hasMoreElements()) { 286 RegisterOperand nextOp2 = e2.nextElement(); 287 if (nextOp2.getType() != t2) { 288 s = null; 289 } 290 } 291 } 292 if (s != null) { 293 lhs2.setType(t2); 294 rhs2.setType(t2); 295 } 296 break; 297 case Register.INTEGER_TYPE: 298 RegisterOperand lhs = IRTools.I(r); 299 RegisterOperand rhs = IRTools.I(r); 300 s = Unary.create(SPLIT, lhs, rhs); 301 // fix up types: only split live ranges when the type is 302 // consistent at all defs 303 TypeReference t = null; 304 Enumeration<RegisterOperand> e = DefUse.defs(r); 305 if (!e.hasMoreElements()) { 306 s = null; 307 } else { 308 RegisterOperand rop = e.nextElement(); 309 t = rop.getType(); 310 while (e.hasMoreElements()) { 311 RegisterOperand nextOp = e.nextElement(); 312 if (nextOp.getType() != t) { 313 s = null; 314 } 315 } 316 } 317 if (s != null) { 318 lhs.setType(t); 319 rhs.setType(t); 320 } 321 break; 322 case Register.FLOAT_TYPE: 323 s = Unary.create(SPLIT, IRTools.F(r), IRTools.F(r)); 324 break; 325 case Register.DOUBLE_TYPE: 326 s = Unary.create(SPLIT, IRTools.D(r), IRTools.D(r)); 327 break; 328 case Register.LONG_TYPE: 329 s = Unary.create(SPLIT, IRTools.L(r), IRTools.L(r)); 330 break; 331 default: 332 // we won't split live ranges for other types. 333 s = null; 334 break; 335 } 336 if (s != null) { 337 target.prependInstruction(s); 338 } 339 } 340 } 341 } 342 343 /** 344 * A utility class to represent an edge in the CFG. 345 */ 346 private static class BasicBlockPair { 347 /** 348 * The source of a control-flow edge 349 */ 350 final BasicBlock src; 351 352 /** 353 * The sink of a control-flow edge 354 */ 355 final BasicBlock dest; 356 357 BasicBlockPair(BasicBlock src, BasicBlock dest) { 358 this.src = src; 359 this.dest = dest; 360 } 361 362 static int nextHash = 0; 363 int myHash = ++nextHash; 364 365 @Override 366 public int hashCode() { 367 return myHash; 368 } 369 370 @Override 371 public boolean equals(Object o) { 372 if (!(o instanceof BasicBlockPair)) return false; 373 BasicBlockPair p = (BasicBlockPair) o; 374 return (src.equals(p.src) && dest.equals(p.dest)); 375 } 376 377 @Override 378 public String toString() { 379 return "<" + src + "," + dest + ">"; 380 } 381 } 382 } 383 384 /** 385 * This class sets up the IR state prior to entering SSA. 386 */ 387 private static class RenamePreparation extends CompilerPhase { 388 389 /** 390 * Return this instance of this phase. This phase contains no 391 * per-compilation instance fields. 392 * @param ir not used 393 * @return this 394 */ 395 @Override 396 public CompilerPhase newExecution(IR ir) { 397 return this; 398 } 399 400 @Override 401 public final boolean shouldPerform(OptOptions options) { 402 return options.SSA_LIVE_RANGE_SPLITTING; 403 } 404 405 @Override 406 public final String getName() { 407 return "Rename Preparation"; 408 } 409 410 /** 411 * register in the IR the SSA properties we need for simple scalar 412 * renaming 413 */ 414 @Override 415 public final void perform(IR ir) { 416 ir.desiredSSAOptions = new SSAOptions(); 417 ir.desiredSSAOptions.setScalarsOnly(true); 418 ir.desiredSSAOptions.setBackwards(false); 419 ir.desiredSSAOptions.setInsertUsePhis(false); 420 } 421 } 422 }