/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.ir.Goto; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GOTO; import org.jikesrvm.compilers.opt.ir.OPT_WeightedBranchTargets; /** * This Phase supports * <ul> * <li> transforming while into until loops, * <li> elimination of critical edges, * </ul> */ class OPT_CFGTransformations extends OPT_CompilerPhase { private static final boolean DEBUG = false; /** * Return this instance of this phase. This phase contains no * per-compilation instance fields. * @param ir not used * @return this */ public OPT_CompilerPhase newExecution(OPT_IR ir) { return this; } /** * This is the method that actually does the work of the phase. */ public void perform(OPT_IR ir) { staticPerform(ir); } /** * static version of perform * @param ir */ static void staticPerform(OPT_IR ir) { if (ir.hasReachableExceptionHandlers()) return; // Note: the following unfactors the CFG. OPT_DominatorsPhase dom = new OPT_DominatorsPhase(true); boolean moreToCome = true; while (moreToCome) { dom.perform(ir); moreToCome = turnWhilesIntoUntils(ir); } ensureLandingPads(ir); dom.perform(ir); ir.cfg.compactNodeNumbering(); ir.HIRInfo.dominatorsAreComputed = false; // compacting the node numbering destroys the dominator info } /** * This method determines if the phase should be run, based on the * OPT_Options object it is passed */ public boolean shouldPerform(OPT_Options options) { if (options.getOptLevel() < 2) { return false; } return options.TURN_WHILES_INTO_UNTILS; } /** * Returns the name of the phase. */ public String getName() { return "Loop Normalization"; } /** * Returns true if the phase wants the IR dumped before and/or after it runs. */ public boolean printingEnabled(OPT_Options options, boolean before) { return false; } //Implementation /** * treat all loops of the ir */ private static boolean turnWhilesIntoUntils(OPT_IR ir) { OPT_LSTGraph lstg = ir.HIRInfo.LoopStructureTree; if (lstg != null) { return turnLoopTreeIntoUntils((OPT_LSTNode) lstg.firstNode(), ir); } return false; } /** * deal with a sub tree of the loop structure tree */ private static boolean turnLoopTreeIntoUntils(OPT_LSTNode t, OPT_IR ir) { OPT_GraphNodeEnumeration e = t.outNodes(); while (e.hasMoreElements()) { OPT_LSTNode n = (OPT_LSTNode) e.nextElement(); if (turnLoopTreeIntoUntils(n, ir)) { return true; } if (turnLoopIntoUntil(n, ir)) { return true; } } return false; } /** * treat all loops of the ir */ private static void ensureLandingPads(OPT_IR ir) { OPT_LSTGraph lstg = ir.HIRInfo.LoopStructureTree; if (lstg != null) { ensureLandingPads((OPT_LSTNode) lstg.firstNode(), ir); } } /** * deal with a sub tree of the loop structure tree */ private static void ensureLandingPads(OPT_LSTNode t, OPT_IR ir) { OPT_GraphNodeEnumeration e = t.outNodes(); while (e.hasMoreElements()) { OPT_LSTNode n = (OPT_LSTNode) e.nextElement(); ensureLandingPads(n, ir); ensureLandingPad(n, ir); } } private static float edgeFrequency(OPT_BasicBlock a, OPT_BasicBlock b) { float prop = 0f; OPT_WeightedBranchTargets ws = new OPT_WeightedBranchTargets(a); while (ws.hasMoreElements()) { if (ws.curBlock() == b) prop += ws.curWeight(); ws.advance(); } return a.getExecutionFrequency() * prop; } private static void ensureLandingPad(OPT_LSTNode n, OPT_IR ir) { OPT_BasicBlock[] ps = loopPredecessors(n); if (ps.length == 1 && ps[0].getNumberOfOut() == 1) return; float frequency = 0f; for (OPT_BasicBlock bb : ps) { frequency += edgeFrequency(bb, n.header); } OPT_BasicBlock newPred; newPred = n.header.createSubBlock(n.header.firstInstruction().bcIndex, ir, 1f); newPred.setLandingPad(); newPred.setExecutionFrequency(frequency); OPT_BasicBlock p = n.header.prevBasicBlockInCodeOrder(); if (VM.VerifyAssertions) VM._assert(p != null); p.killFallThrough(); ir.cfg.breakCodeOrder(p, n.header); ir.cfg.linkInCodeOrder(p, newPred); ir.cfg.linkInCodeOrder(newPred, n.header); newPred.lastInstruction().insertBefore(Goto.create(GOTO, n.header.makeJumpTarget())); newPred.recomputeNormalOut(ir); for (OPT_BasicBlock bb : ps) { bb.redirectOuts(n.header, newPred, ir); } } /** * Transform a given loop * * <p> Look for the set S of in-loop predecessors of the loop header h. * Make a copy h' of the loop header and redirect all edges going from * nodes in S to h. Make them point to h' instead. * * <p> As an effect of this transformation, the old header is now not anymore * part of the loop, but guards it. */ private static boolean turnLoopIntoUntil(OPT_LSTNode n, OPT_IR ir) { OPT_BasicBlock header = n.header; OPT_BasicBlock newLoopTest = null; int i = 0; int exiters = 0; OPT_BasicBlockEnumeration e = ir.getBasicBlocks(n.loop); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); if (!exitsLoop(b, n.loop)) { // header doesn't exit: nothing to do if (b == n.header) return false; } else { exiters++; } i++; } // all blocks exit: can't improve if (i == exiters) return false; // rewriting loops where the header has more than one in-loop // successor will lead to irreducible control flow. OPT_BasicBlock[] succ = inLoopSuccessors(n); if (succ.length > 1) { if (DEBUG) VM.sysWrite("unwhiling would lead to irreducible CFG\n"); return false; } OPT_BasicBlock[] pred = inLoopPredecessors(n); float frequency = 0f; if (pred.length > 0) { frequency += edgeFrequency(pred[0], header); // replicate the header as successor of pred[0] OPT_BasicBlock p = header.prevBasicBlockInCodeOrder(); p.killFallThrough(); newLoopTest = pred[0].replicateThisOut(ir, header, p); } for (i = 1; i < pred.length; ++i) { // check for aditional back edges frequency += edgeFrequency(pred[i], header); pred[i].redirectOuts(header, newLoopTest, ir); } newLoopTest.setExecutionFrequency(frequency); header.setExecutionFrequency(header.getExecutionFrequency() - frequency); return true; } /** * the predecessors of the loop header that are not part of the loop */ private static OPT_BasicBlock[] loopPredecessors(OPT_LSTNode n) { OPT_BasicBlock header = n.header; OPT_BitVector loop = n.loop; int i = 0; OPT_BasicBlockEnumeration be = header.getIn(); while (be.hasMoreElements()) if (!inLoop(be.next(), loop)) i++; OPT_BasicBlock[] res = new OPT_BasicBlock[i]; i = 0; be = header.getIn(); while (be.hasMoreElements()) { OPT_BasicBlock in = be.nextElement(); if (!inLoop(in, loop)) res[i++] = in; } return res; } /** * the predecessors of the loop header that are part of the loop. */ private static OPT_BasicBlock[] inLoopPredecessors(OPT_LSTNode n) { OPT_BasicBlock header = n.header; OPT_BitVector loop = n.loop; int i = 0; OPT_BasicBlockEnumeration be = header.getIn(); while (be.hasMoreElements()) if (inLoop(be.next(), loop)) i++; OPT_BasicBlock[] res = new OPT_BasicBlock[i]; i = 0; be = header.getIn(); while (be.hasMoreElements()) { OPT_BasicBlock in = be.nextElement(); if (inLoop(in, loop)) res[i++] = in; } return res; } /** * the successors of the loop header that are part of the loop. */ private static OPT_BasicBlock[] inLoopSuccessors(OPT_LSTNode n) { OPT_BasicBlock header = n.header; OPT_BitVector loop = n.loop; int i = 0; OPT_BasicBlockEnumeration be = header.getOut(); while (be.hasMoreElements()) if (inLoop(be.next(), loop)) i++; OPT_BasicBlock[] res = new OPT_BasicBlock[i]; i = 0; be = header.getOut(); while (be.hasMoreElements()) { OPT_BasicBlock in = be.nextElement(); if (inLoop(in, loop)) res[i++] = in; } return res; } static void killFallThroughs(OPT_IR ir, OPT_BitVector nloop) { OPT_BasicBlockEnumeration bs = ir.getBasicBlocks(nloop); while (bs.hasMoreElements()) { OPT_BasicBlock block = bs.next(); OPT_BasicBlockEnumeration bi = block.getIn(); while (bi.hasMoreElements()) { OPT_BasicBlock in = bi.next(); if (inLoop(in, nloop)) continue; in.killFallThrough(); } block.killFallThrough(); } } static boolean inLoop(OPT_BasicBlock b, OPT_BitVector nloop) { int idx = b.getNumber(); if (idx >= nloop.length()) return false; return nloop.get(idx); } private static boolean exitsLoop(OPT_BasicBlock b, OPT_BitVector loop) { OPT_BasicBlockEnumeration be = b.getOut(); while (be.hasMoreElements()) { if (!inLoop(be.next(), loop)) return true; } return false; } /** * Critical edge removal: if (a,b) is an edge in the cfg where `a' has more * than one out-going edge and `b' has more than one in-coming edge, * insert a new empty block `c' on the edge between `a' and `b'. * * <p> We do this to provide landing pads for loop-invariant code motion. * So we split only edges, where `a' has a lower loop nesting depth than `b'. */ public static void splitCriticalEdges(OPT_IR ir) { OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); int numberOfIns = b.getNumberOfIn(); //Exception handlers and blocks with less than two inputs // are no candidates for `b'. if (b.isExceptionHandlerBasicBlock() || numberOfIns <= 1) { continue; } // copy the predecessors, since we will alter the incoming edges. OPT_BasicBlock[] ins = new OPT_BasicBlock[numberOfIns]; OPT_BasicBlockEnumeration ie = b.getIn(); for (int i = 0; i < numberOfIns; ++i) { ins[i] = ie.next(); } // skip blocks, that do not fullfil our requirements for `a' for (int i = 0; i < numberOfIns; ++i) { OPT_BasicBlock a = ins[i]; if (a.getNumberOfOut() <= 1) { continue; } // insert pads only for moving code up to the start of the method //if (a.getExecutionFrequency() >= b.getExecutionFrequency()) continue; // create a new block as landing pad OPT_BasicBlock landingPad; OPT_Instruction firstInB = b.firstInstruction(); int bcIndex = firstInB != null ? firstInB.bcIndex : -1; landingPad = b.createSubBlock(bcIndex, ir); landingPad.setLandingPad(); landingPad.setExecutionFrequency(edgeFrequency(a, b)); // make the landing pad jump to `b' OPT_Instruction g; g = Goto.create(GOTO, b.makeJumpTarget()); landingPad.appendInstruction(g); landingPad.recomputeNormalOut(ir); // redirect a's outputs from b to the landing pad a.redirectOuts(b, landingPad, ir); a.killFallThrough(); OPT_BasicBlock aNext = a.nextBasicBlockInCodeOrder(); if (aNext != null) { ir.cfg.breakCodeOrder(a, aNext); ir.cfg.linkInCodeOrder(landingPad, aNext); } ir.cfg.linkInCodeOrder(a, landingPad); } } } }