/** * 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 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 a two way conditional branch. * * <p>Precondition: IfCmp2.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 processTwoTargetConditionalBranch(IR ir, Instruction cb, BasicBlock bb) { // First condition/target Instruction target1Label = IfCmp2.getTarget1(cb).target; Instruction target1Inst = firstRealInstructionFollowing(target1Label); Instruction nextLabel = firstLabelFollowing(cb); boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND; if (target1Inst != null && target1Inst != cb) { if (Goto.conforms(target1Inst)) { // conditional branch to unconditional branch. // change conditional branch target to latter's target IfCmp2.setTarget1(cb, (BranchOperand) Goto.getTarget(target1Inst).copy()); bb.recomputeNormalOut(ir); // fix CFG return true; } BasicBlock target1Block = target1Label.getBasicBlock(); if (target1Block.isEmpty()) { // branch to an empty block. Change target to the next block. BasicBlock nextBlock = target1Block.getFallThroughBlock(); IfCmp2.setTarget1(cb, nextBlock.makeJumpTarget()); bb.recomputeNormalOut(ir); // fix the CFG return true; } } // Second condition/target Instruction target2Label = IfCmp2.getTarget2(cb).target; Instruction target2Inst = firstRealInstructionFollowing(target2Label); if (target2Inst != null && target2Inst != cb) { if (Goto.conforms(target2Inst)) { // conditional branch to unconditional branch. // change conditional branch target to latter's target IfCmp2.setTarget2(cb, (BranchOperand) Goto.getTarget(target2Inst).copy()); bb.recomputeNormalOut(ir); // fix CFG return true; } if ((target2Label == nextLabel) && endsBlock) { // found a conditional branch to the next instruction. Reduce to IfCmp if (VM.VerifyAssertions) VM._assert(cb.operator() == INT_IFCMP2); IfCmp.mutate( cb, INT_IFCMP, IfCmp2.getGuardResult(cb), IfCmp2.getVal1(cb), IfCmp2.getVal2(cb), IfCmp2.getCond1(cb), IfCmp2.getTarget1(cb), IfCmp2.getBranchProfile1(cb)); return true; } BasicBlock target2Block = target2Label.getBasicBlock(); if (target2Block.isEmpty()) { // branch to an empty block. Change target to the next block. BasicBlock nextBlock = target2Block.getFallThroughBlock(); IfCmp2.setTarget2(cb, nextBlock.makeJumpTarget()); bb.recomputeNormalOut(ir); // fix the CFG return true; } } // if fall through to a goto; replicate the goto if (endsBlock) { Instruction nextI = firstRealInstructionFollowing(nextLabel); if (nextI != null && Goto.conforms(nextI)) { // replicate Goto cb.insertAfter(nextI.copyWithoutLinks()); bb.recomputeNormalOut(ir); // fix the CFG return true; } } return false; }
/** * 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; }