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.controlflow; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO; 016 017 import java.util.Enumeration; 018 019 import org.jikesrvm.VM; 020 import org.jikesrvm.compilers.opt.OptOptions; 021 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 022 import org.jikesrvm.compilers.opt.ir.BasicBlock; 023 import org.jikesrvm.compilers.opt.ir.Goto; 024 import org.jikesrvm.compilers.opt.ir.IR; 025 import org.jikesrvm.compilers.opt.ir.Instruction; 026 import org.jikesrvm.compilers.opt.ir.WeightedBranchTargets; 027 import org.jikesrvm.compilers.opt.util.GraphNode; 028 import org.jikesrvm.util.BitVector; 029 030 /** 031 * This Phase supports 032 * <ul> 033 * <li>transforming while into until loops, 034 * <li>elimination of critical edges, 035 * </ul> 036 */ 037 public class CFGTransformations extends CompilerPhase { 038 039 private static final boolean DEBUG = false; 040 041 /** 042 * Return this instance of this phase. This phase contains no 043 * per-compilation instance fields. 044 * @param ir not used 045 * @return this 046 */ 047 @Override 048 public CompilerPhase newExecution(IR ir) { 049 return this; 050 } 051 052 @Override 053 public void perform(IR ir) { 054 staticPerform(ir); 055 } 056 057 /** 058 * static version of perform 059 * @param ir 060 */ 061 static void staticPerform(IR ir) { 062 if (ir.hasReachableExceptionHandlers()) return; 063 064 // Note: the following unfactors the CFG. 065 DominatorsPhase dom = new DominatorsPhase(true); 066 boolean moreToCome = true; 067 while (moreToCome) { 068 dom.perform(ir); 069 moreToCome = turnWhilesIntoUntils(ir); 070 } 071 072 ensureLandingPads(ir); 073 074 dom.perform(ir); 075 ir.cfg.compactNodeNumbering(); 076 ir.HIRInfo.dominatorsAreComputed = false; // compacting the node numbering destroys the dominator info 077 } 078 079 /** 080 * Should this phase be performed? 081 * @return <code>true</code> if the opt level is at least 2 and whiles should be turned into untils 082 */ 083 @Override 084 public boolean shouldPerform(OptOptions options) { 085 if (options.getOptLevel() < 2) { 086 return false; 087 } 088 return options.CONTROL_TURN_WHILES_INTO_UNTILS; 089 } 090 091 /** 092 * Returns the name of the phase. 093 */ 094 @Override 095 public String getName() { 096 return "Loop Normalization"; 097 } 098 099 /** 100 * Returns {@code true} if the phase wants the IR dumped before and/or after it runs. 101 */ 102 @Override 103 public boolean printingEnabled(OptOptions options, boolean before) { 104 return false; 105 } 106 107 //Implementation 108 /** 109 * treat all loops of the ir 110 */ 111 private static boolean turnWhilesIntoUntils(IR ir) { 112 LSTGraph lstg = ir.HIRInfo.loopStructureTree; 113 if (lstg != null) { 114 return turnLoopTreeIntoUntils((LSTNode) lstg.firstNode(), ir); 115 } 116 return false; 117 } 118 119 /** 120 * deal with a sub tree of the loop structure tree 121 */ 122 private static boolean turnLoopTreeIntoUntils(LSTNode t, IR ir) { 123 Enumeration<GraphNode> e = t.outNodes(); 124 while (e.hasMoreElements()) { 125 LSTNode n = (LSTNode) e.nextElement(); 126 if (turnLoopTreeIntoUntils(n, ir)) { 127 return true; 128 } 129 if (turnLoopIntoUntil(n, ir)) { 130 return true; 131 } 132 } 133 return false; 134 } 135 136 /** 137 * treat all loops of the ir 138 */ 139 private static void ensureLandingPads(IR ir) { 140 LSTGraph lstg = ir.HIRInfo.loopStructureTree; 141 if (lstg != null) { 142 ensureLandingPads((LSTNode) lstg.firstNode(), ir); 143 } 144 } 145 146 /** 147 * deal with a sub tree of the loop structure tree 148 */ 149 private static void ensureLandingPads(LSTNode t, IR ir) { 150 Enumeration<GraphNode> e = t.outNodes(); 151 while (e.hasMoreElements()) { 152 LSTNode n = (LSTNode) e.nextElement(); 153 ensureLandingPads(n, ir); 154 ensureLandingPad(n, ir); 155 } 156 } 157 158 private static float edgeFrequency(BasicBlock a, BasicBlock b) { 159 float prop = 0f; 160 WeightedBranchTargets ws = new WeightedBranchTargets(a); 161 while (ws.hasMoreElements()) { 162 if (ws.curBlock() == b) prop += ws.curWeight(); 163 ws.advance(); 164 } 165 return a.getExecutionFrequency() * prop; 166 } 167 168 private static void ensureLandingPad(LSTNode n, IR ir) { 169 BasicBlock[] ps = loopPredecessors(n); 170 if (ps.length == 1 && ps[0].getNumberOfOut() == 1) return; 171 172 float frequency = 0f; 173 for (BasicBlock bb : ps) { 174 frequency += edgeFrequency(bb, n.header); 175 } 176 BasicBlock newPred; 177 newPred = n.header.createSubBlock(n.header.firstInstruction().bcIndex, ir, 1f); 178 newPred.setLandingPad(); 179 newPred.setExecutionFrequency(frequency); 180 181 BasicBlock p = n.header.prevBasicBlockInCodeOrder(); 182 if (VM.VerifyAssertions) VM._assert(p != null); 183 p.killFallThrough(); 184 ir.cfg.breakCodeOrder(p, n.header); 185 ir.cfg.linkInCodeOrder(p, newPred); 186 ir.cfg.linkInCodeOrder(newPred, n.header); 187 188 newPred.lastInstruction().insertBefore(Goto.create(GOTO, n.header.makeJumpTarget())); 189 newPred.recomputeNormalOut(ir); 190 191 for (BasicBlock bb : ps) { 192 bb.redirectOuts(n.header, newPred, ir); 193 } 194 } 195 196 /** 197 * Transform a given loop 198 * 199 * <p> Look for the set S of in-loop predecessors of the loop header h. 200 * Make a copy h' of the loop header and redirect all edges going from 201 * nodes in S to h. Make them point to h' instead. 202 * 203 * <p> As an effect of this transformation, the old header is now not anymore 204 * part of the loop, but guards it. 205 */ 206 private static boolean turnLoopIntoUntil(LSTNode n, IR ir) { 207 BasicBlock header = n.header; 208 BasicBlock newLoopTest = null; 209 210 int i = 0; 211 int exiters = 0; 212 213 Enumeration<BasicBlock> e = ir.getBasicBlocks(n.loop); 214 while (e.hasMoreElements()) { 215 BasicBlock b = e.nextElement(); 216 if (!exitsLoop(b, n.loop)) { 217 // header doesn't exit: nothing to do 218 if (b == n.header) return false; 219 } else { 220 exiters++; 221 } 222 i++; 223 } 224 // all blocks exit: can't improve 225 if (i == exiters) return false; 226 227 // rewriting loops where the header has more than one in-loop 228 // successor will lead to irreducible control flow. 229 BasicBlock[] succ = inLoopSuccessors(n); 230 if (succ.length > 1) { 231 if (DEBUG) VM.sysWrite("unwhiling would lead to irreducible CFG\n"); 232 return false; 233 } 234 235 BasicBlock[] pred = inLoopPredecessors(n); 236 float frequency = 0f; 237 238 if (pred.length > 0) { 239 frequency += edgeFrequency(pred[0], header); 240 // replicate the header as successor of pred[0] 241 BasicBlock p = header.prevBasicBlockInCodeOrder(); 242 p.killFallThrough(); 243 newLoopTest = pred[0].replicateThisOut(ir, header, p); 244 } 245 for (i = 1; i < pred.length; ++i) { // check for aditional back edges 246 frequency += edgeFrequency(pred[i], header); 247 pred[i].redirectOuts(header, newLoopTest, ir); 248 } 249 newLoopTest.setExecutionFrequency(frequency); 250 header.setExecutionFrequency(header.getExecutionFrequency() - frequency); 251 return true; 252 } 253 254 /** 255 * the predecessors of the loop header that are not part of the loop 256 */ 257 private static BasicBlock[] loopPredecessors(LSTNode n) { 258 BasicBlock header = n.header; 259 BitVector loop = n.loop; 260 261 int i = 0; 262 Enumeration<BasicBlock> be = header.getIn(); 263 while (be.hasMoreElements()) if (!inLoop(be.nextElement(), loop)) i++; 264 265 BasicBlock[] res = new BasicBlock[i]; 266 267 i = 0; 268 be = header.getIn(); 269 while (be.hasMoreElements()) { 270 BasicBlock in = be.nextElement(); 271 if (!inLoop(in, loop)) res[i++] = in; 272 } 273 return res; 274 } 275 276 /** 277 * the predecessors of the loop header that are part of the loop. 278 */ 279 private static BasicBlock[] inLoopPredecessors(LSTNode n) { 280 BasicBlock header = n.header; 281 BitVector loop = n.loop; 282 283 int i = 0; 284 Enumeration<BasicBlock> be = header.getIn(); 285 while (be.hasMoreElements()) if (inLoop(be.nextElement(), loop)) i++; 286 287 BasicBlock[] res = new BasicBlock[i]; 288 289 i = 0; 290 be = header.getIn(); 291 while (be.hasMoreElements()) { 292 BasicBlock in = be.nextElement(); 293 if (inLoop(in, loop)) res[i++] = in; 294 } 295 return res; 296 } 297 298 /** 299 * the successors of the loop header that are part of the loop. 300 */ 301 private static BasicBlock[] inLoopSuccessors(LSTNode n) { 302 BasicBlock header = n.header; 303 BitVector loop = n.loop; 304 305 int i = 0; 306 Enumeration<BasicBlock> be = header.getOut(); 307 while (be.hasMoreElements()) if (inLoop(be.nextElement(), loop)) i++; 308 309 BasicBlock[] res = new BasicBlock[i]; 310 311 i = 0; 312 be = header.getOut(); 313 while (be.hasMoreElements()) { 314 BasicBlock in = be.nextElement(); 315 if (inLoop(in, loop)) res[i++] = in; 316 } 317 return res; 318 } 319 320 static void killFallThroughs(IR ir, BitVector nloop) { 321 Enumeration<BasicBlock> bs = ir.getBasicBlocks(nloop); 322 while (bs.hasMoreElements()) { 323 BasicBlock block = bs.nextElement(); 324 Enumeration<BasicBlock> bi = block.getIn(); 325 while (bi.hasMoreElements()) { 326 BasicBlock in = bi.nextElement(); 327 if (inLoop(in, nloop)) continue; 328 in.killFallThrough(); 329 } 330 block.killFallThrough(); 331 } 332 } 333 334 static boolean inLoop(BasicBlock b, BitVector nloop) { 335 int idx = b.getNumber(); 336 if (idx >= nloop.length()) return false; 337 return nloop.get(idx); 338 } 339 340 private static boolean exitsLoop(BasicBlock b, BitVector loop) { 341 Enumeration<BasicBlock> be = b.getOut(); 342 while (be.hasMoreElements()) { 343 if (!inLoop(be.nextElement(), loop)) return true; 344 } 345 return false; 346 } 347 348 /** 349 * Critical edge removal: if (a,b) is an edge in the cfg where `a' has more 350 * than one out-going edge and `b' has more than one in-coming edge, 351 * insert a new empty block `c' on the edge between `a' and `b'. 352 * 353 * <p> We do this to provide landing pads for loop-invariant code motion. 354 * So we split only edges, where `a' has a lower loop nesting depth than `b'. 355 */ 356 public static void splitCriticalEdges(IR ir) { 357 Enumeration<BasicBlock> e = ir.getBasicBlocks(); 358 while (e.hasMoreElements()) { 359 BasicBlock b = e.nextElement(); 360 int numberOfIns = b.getNumberOfIn(); 361 //Exception handlers and blocks with less than two inputs 362 // are no candidates for `b'. 363 if (b.isExceptionHandlerBasicBlock() || numberOfIns <= 1) { 364 continue; 365 } 366 // copy the predecessors, since we will alter the incoming edges. 367 BasicBlock[] ins = new BasicBlock[numberOfIns]; 368 Enumeration<BasicBlock> ie = b.getIn(); 369 for (int i = 0; i < numberOfIns; ++i) { 370 ins[i] = ie.nextElement(); 371 } 372 // skip blocks, that do not fulfill our requirements for `a' 373 for (int i = 0; i < numberOfIns; ++i) { 374 BasicBlock a = ins[i]; 375 if (a.getNumberOfOut() <= 1) { 376 continue; 377 } 378 // insert pads only for moving code up to the start of the method 379 //if (a.getExecutionFrequency() >= b.getExecutionFrequency()) continue; 380 381 // create a new block as landing pad 382 BasicBlock landingPad; 383 Instruction firstInB = b.firstInstruction(); 384 int bcIndex = firstInB != null ? firstInB.bcIndex : -1; 385 landingPad = b.createSubBlock(bcIndex, ir); 386 landingPad.setLandingPad(); 387 landingPad.setExecutionFrequency(edgeFrequency(a, b)); 388 389 // make the landing pad jump to `b' 390 Instruction g; 391 g = Goto.create(GOTO, b.makeJumpTarget()); 392 landingPad.appendInstruction(g); 393 landingPad.recomputeNormalOut(ir); 394 // redirect a's outputs from b to the landing pad 395 a.redirectOuts(b, landingPad, ir); 396 397 a.killFallThrough(); 398 BasicBlock aNext = a.nextBasicBlockInCodeOrder(); 399 if (aNext != null) { 400 ir.cfg.breakCodeOrder(a, aNext); 401 ir.cfg.linkInCodeOrder(landingPad, aNext); 402 } 403 ir.cfg.linkInCodeOrder(a, landingPad); 404 } 405 } 406 } 407 }