/** Transform cb into a GOTO, updating PHI nodes to maintain SSA form. */ private void takeCondBranch(BasicBlock source, Instruction cb, IR ir) { if (DEBUG) VM.sysWrite("Eliminating definitely taken branch " + cb + "\n"); BasicBlock deadBB = source.nextBasicBlockInCodeOrder(); Instruction next = cb.nextInstructionInCodeOrder(); if (Goto.conforms(next)) { deadBB = next.getBranchTarget(); next.remove(); } Goto.mutate(cb, GOTO, cb.getBranchTarget().makeJumpTarget()); source.recomputeNormalOut(ir); if (!source.pointsOut(deadBB)) { // there is no longer an edge from source to target; // update any PHIs in target to reflect this. SSA.purgeBlockFromPHIs(source, deadBB); } }
/** * Perform optimizations for an inline guard. * * <p>Precondition: InlineGuard.conforms(cb) * * @param ir the governing IR * @param cb the instruction to optimize * @param bb the basic block holding if * @return {@code true} iff made a transformation */ private boolean processInlineGuard(IR ir, Instruction cb, BasicBlock bb) { BasicBlock targetBlock = cb.getBranchTarget(); Instruction targetLabel = targetBlock.firstInstruction(); // get the first real instruction at the branch target // NOTE: this instruction is not necessarily in targetBlock, // iff targetBlock has no real instructions Instruction targetInst = firstRealInstructionFollowing(targetLabel); if (targetInst == null || targetInst == cb) { return false; } boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND; if (endsBlock) { Instruction nextLabel = firstLabelFollowing(cb); if (targetLabel == nextLabel) { // found a conditional branch to the next instruction. just remove it. cb.remove(); return true; } Instruction nextI = firstRealInstructionFollowing(nextLabel); if (nextI != null && Goto.conforms(nextI)) { // replicate Goto cb.insertAfter(nextI.copyWithoutLinks()); bb.recomputeNormalOut(ir); // fix the CFG return true; } } // do we fall through to a block that has only a goto? BasicBlock fallThrough = bb.getFallThroughBlock(); if (fallThrough != null) { Instruction fallThroughInstruction = fallThrough.firstRealInstruction(); if ((fallThroughInstruction != null) && Goto.conforms(fallThroughInstruction)) { // copy goto to bb bb.appendInstruction(fallThroughInstruction.copyWithoutLinks()); bb.recomputeNormalOut(ir); } } if (Goto.conforms(targetInst)) { // conditional branch to unconditional branch. // change conditional branch target to latter's target InlineGuard.setTarget(cb, (BranchOperand) Goto.getTarget(targetInst).copy()); bb.recomputeNormalOut(ir); // fix the CFG return true; } if (targetBlock.isEmpty()) { // branch to an empty block. Change target to the next block. BasicBlock nextBlock = targetBlock.getFallThroughBlock(); InlineGuard.setTarget(cb, nextBlock.makeJumpTarget()); bb.recomputeNormalOut(ir); // fix the CFG return true; } return false; }
/** * Remove cb from source, updating PHI nodes to maintain SSA form. * * @param source basic block containing cb * @param cb conditional branch to remove * @param ir containing IR * @param di branch that dominates cb */ private void removeCondBranch(BasicBlock source, Instruction cb, IR ir, Instruction di) { if (DEBUG) VM.sysWrite("Eliminating definitely not-taken branch " + cb + "\n"); if (IfCmp.conforms(cb) && IfCmp.hasGuardResult(cb)) { cb.insertBefore( Move.create(GUARD_MOVE, IfCmp.getGuardResult(cb), IfCmp.getGuardResult(di).copy())); } BasicBlock deadBB = cb.getBranchTarget(); cb.remove(); source.recomputeNormalOut(ir); if (!source.pointsOut(deadBB)) { // there is no longer an edge from source to target; // update any PHIs in target to reflect this. SSA.purgeBlockFromPHIs(source, deadBB); } }
/** * Transform to eliminate redundant branches passed on GVNs and dominator information. * * @param ir The IR on which to apply the phase */ public void perform(IR ir) { // (1) Remove redundant conditional branches and locally fix the PHIs GlobalValueNumberState gvns = ir.HIRInfo.valueNumbers; DominatorTree dt = ir.HIRInfo.dominatorTree; for (BasicBlockEnumeration bbs = ir.getBasicBlocks(); bbs.hasMoreElements(); ) { BasicBlock candBB = bbs.next(); Instruction candTest = candBB.firstBranchInstruction(); if (candTest == null) continue; if (!(IfCmp.conforms(candTest) || InlineGuard.conforms(candTest))) continue; GVCongruenceClass cc = gvns.congruenceClass(candTest); if (cc.size() > 1) { for (ValueGraphVertex vertex : cc) { Instruction poss = (Instruction) vertex.getName(); if (poss != candTest) { BasicBlock notTaken = getNotTakenBlock(poss); BasicBlock taken = poss.getBranchTarget(); if (taken == notTaken) continue; // both go to same block, so we don't know anything! if (notTaken.hasOneIn() && dt.dominates(notTaken, candBB)) { if (DEBUG) VM.sysWrite(candTest + " is dominated by not-taken branch of " + poss + "\n"); removeCondBranch(candBB, candTest, ir, poss); cc.removeVertex(gvns.valueGraph.getVertex(candTest)); break; } if (taken.hasOneIn() && dt.dominates(taken, candBB)) { if (DEBUG) VM.sysWrite(candTest + " is dominated by taken branch of " + poss + "\n"); takeCondBranch(candBB, candTest, ir); cc.removeVertex(gvns.valueGraph.getVertex(candTest)); break; } } } } } // (2) perform a Depth-first search of the control flow graph, // and remove any nodes we have made unreachable removeUnreachableCode(ir); }
/** * Perform optimizations for a conditional branch. * * <pre> * 1) IF .. GOTO A replaced by IF .. GOTO B * ... * A: GOTO B * 2) conditional branch to next instruction eliminated * 3) IF (condition) GOTO A replaced by IF (!condition) GOTO B * GOTO B A: ... * A: ... * 4) special case to generate Boolean compare opcode * 5) special case to generate conditional move sequence * 6) IF .. GOTO A replaced by IF .. GOTO B * A: LABEL * BBEND * B: * 7) fallthrough to a goto: replicate goto to enable other optimizations. * </pre> * * <p>Precondition: IfCmp.conforms(cb) * * @param ir the governing IR * @param cb the instruction to optimize * @param bb the basic block holding if * @return {@code true} iff made a transformation */ private boolean processConditionalBranch(IR ir, Instruction cb, BasicBlock bb) { BasicBlock targetBlock = cb.getBranchTarget(); // don't optimize jumps to a code motion landing pad if (targetBlock.getLandingPad()) return false; Instruction targetLabel = targetBlock.firstInstruction(); // get the first real instruction at the branch target // NOTE: this instruction is not necessarily in targetBlock, // iff targetBlock has no real instructions Instruction targetInst = firstRealInstructionFollowing(targetLabel); if (targetInst == null || targetInst == cb) { return false; } boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND; if (endsBlock) { Instruction nextLabel = firstLabelFollowing(cb); if (targetLabel == nextLabel) { // found a conditional branch to the next instruction. just remove it. cb.remove(); return true; } Instruction nextI = firstRealInstructionFollowing(nextLabel); if (nextI != null && Goto.conforms(nextI)) { // Check that the target is not the fall through (the goto itself). // If we add a goto to the next block, it will be removed by // processGoto and we will loop indefinitely. // This can be tripped by (strange) code such as: // if (condition) while (true); BasicBlock gotoTarget = nextI.getBranchTarget(); Instruction gotoLabel = gotoTarget.firstInstruction(); Instruction gotoInst = firstRealInstructionFollowing(gotoLabel); if (gotoInst != nextI) { // replicate Goto cb.insertAfter(nextI.copyWithoutLinks()); bb.recomputeNormalOut(ir); // fix the CFG return true; } } } // attempt to generate boolean compare. if (generateBooleanCompare(ir, bb, cb, targetBlock)) { // generateBooleanCompare does all necessary CFG fixup. return true; } // attempt to generate a sequence using conditional moves if (generateCondMove(ir, bb, cb)) { // generateCondMove does all necessary CFG fixup. return true; } // do we fall through to a block that has only a goto? BasicBlock fallThrough = bb.getFallThroughBlock(); if (fallThrough != null) { Instruction fallThroughInstruction = fallThrough.firstRealInstruction(); if ((fallThroughInstruction != null) && Goto.conforms(fallThroughInstruction)) { // copy goto to bb bb.appendInstruction(fallThroughInstruction.copyWithoutLinks()); bb.recomputeNormalOut(ir); } } if (Goto.conforms(targetInst)) { // conditional branch to unconditional branch. // change conditional branch target to latter's target Instruction target2 = firstRealInstructionFollowing(targetInst.getBranchTarget().firstInstruction()); if (target2 == targetInst) { // Avoid an infinite recursion in the following scenario: // g: if (...) goto L // ... // L: goto L // This happens in GCUtil in some systems due to a while(true) {} return false; } IfCmp.setTarget(cb, (BranchOperand) Goto.getTarget(targetInst).copy()); bb.recomputeNormalOut(ir); // fix the CFG return true; } if (targetBlock.isEmpty()) { // branch to an empty block. Change target to the next block. BasicBlock nextBlock = targetBlock.getFallThroughBlock(); IfCmp.setTarget(cb, nextBlock.makeJumpTarget()); bb.recomputeNormalOut(ir); // fix the CFG return true; } if (isFlipCandidate(cb, targetInst)) { flipConditionalBranch(cb); bb.recomputeNormalOut(ir); // fix the CFG return true; } return false; }
/** * Perform optimizations for a Goto. * * <p> Patterns: * <pre> * 1) GOTO A replaced by GOTO B * A: GOTO B * * 2) GOTO A replaced by IF .. GOTO B * A: IF .. GOTO B GOTO C * C: ... * 3) GOTO next instruction eliminated * 4) GOTO A replaced by GOTO B * A: LABEL * BBEND * B: * 5) GOTO BBn where BBn has exactly one in edge * - move BBn immediately after the GOTO in the code order, * so that pattern 3) will create a fallthrough * <pre> * * <p> Precondition: Goto.conforms(g) * * @param ir governing IR * @param g the instruction to optimize * @param bb the basic block holding g * @return {@code true} if made a transformation */ private boolean processGoto(IR ir, Instruction g, BasicBlock bb) { BasicBlock targetBlock = g.getBranchTarget(); // don't optimize jumps to a code motion landing pad if (targetBlock.getLandingPad()) return false; Instruction targetLabel = targetBlock.firstInstruction(); // get the first real instruction at the g target // NOTE: this instruction is not necessarily in targetBlock, // iff targetBlock has no real instructions Instruction targetInst = firstRealInstructionFollowing(targetLabel); if (targetInst == null || targetInst == g) { return false; } Instruction nextLabel = firstLabelFollowing(g); if (targetLabel == nextLabel) { // found a GOTO to the next instruction. just remove it. g.remove(); return true; } if (Goto.conforms(targetInst)) { // unconditional branch to unconditional branch. // replace g with goto to targetInst's target Instruction target2 = firstRealInstructionFollowing(targetInst.getBranchTarget().firstInstruction()); if (target2 == targetInst) { // Avoid an infinite recursion in the following bizarre scenario: // g: goto L // ... // L: goto L // This happens in jByteMark.EmFloatPnt.denormalize() due to a while(true) {} return false; } Goto.setTarget(g, (BranchOperand) Goto.getTarget(targetInst).copy()); bb.recomputeNormalOut(ir); // fix the CFG return true; } if (targetBlock.isEmpty()) { // GOTO an empty basic block. Change target to the // next block. BasicBlock nextBlock = targetBlock.getFallThroughBlock(); Goto.setTarget(g, nextBlock.makeJumpTarget()); bb.recomputeNormalOut(ir); // fix the CFG return true; } if (mayDuplicateCondBranches && IfCmp.conforms(targetInst)) { // unconditional branch to a conditional branch. // If the Goto is the only branch instruction in its basic block // and the IfCmp is the only non-GOTO branch instruction // in its basic block then replace the goto with a copy of // targetInst and append another GOTO to the not-taken // target of targetInst's block. // We impose these additional restrictions to avoid getting // multiple conditional branches in a single basic block. if (!g.prevInstructionInCodeOrder().isBranch() && (targetInst.nextInstructionInCodeOrder().operator == BBEND || targetInst.nextInstructionInCodeOrder().operator == GOTO)) { Instruction copy = targetInst.copyWithoutLinks(); g.replace(copy); Instruction newGoto = targetInst.getBasicBlock().getNotTakenNextBlock().makeGOTO(); copy.insertAfter(newGoto); bb.recomputeNormalOut(ir); // fix the CFG return true; } } // try to create a fallthrough if (mayReorderCode && targetBlock.getNumberOfIn() == 1) { BasicBlock ftBlock = targetBlock.getFallThroughBlock(); if (ftBlock != null) { BranchOperand ftTarget = ftBlock.makeJumpTarget(); targetBlock.appendInstruction(CPOS(g, Goto.create(GOTO, ftTarget))); } ir.cfg.removeFromCodeOrder(targetBlock); ir.cfg.insertAfterInCodeOrder(bb, targetBlock); targetBlock.recomputeNormalOut(ir); // fix the CFG return true; } return false; }
/** Return the basic block that s's block will goto if s is not taken. */ private BasicBlock getNotTakenBlock(Instruction s) { s = s.nextInstructionInCodeOrder(); if (Goto.conforms(s)) return s.getBranchTarget(); if (VM.VerifyAssertions) VM._assert(s.operator() == BBEND); return s.getBasicBlock().nextBasicBlockInCodeOrder(); }