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