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 -> 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}