/** * 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; }
/** * Update the value graph to account for a given InlineGuard instruction. * * <p><b>PRECONDITION:</b> <code> InlineGuard.conforms(s); </code> * * @param s the instruction in question */ private void processInlineGuard(Instruction s) { ValueGraphVertex v = new ValueGraphVertex(s); graph.addGraphNode(v); nameMap.put(s, v); if (s.operator() == IG_PATCH_POINT) { // the 'goal' is irrelevant for patch_point guards. v.setLabel(s.operator(), 1); link(v, findOrCreateVertex(bypassMoves(InlineGuard.getValue(s))), 0); } else { v.setLabel(s.operator(), 2); link(v, findOrCreateVertex(bypassMoves(InlineGuard.getValue(s))), 0); link(v, findOrCreateVertex(InlineGuard.getGoal(s)), 1); } }
/** * Update the value graph to account for a given instruction. * * @param s the instruction in question */ private void processInstruction(Instruction s) { // TODO: support all necessary types of instructions if (s.isDynamicLinkingPoint()) { processCall(s); } else if (Move.conforms(s)) { processMove(s); } else if (s.operator == PI) { processPi(s); } else if (New.conforms(s)) { processNew(s); } else if (NewArray.conforms(s)) { processNewArray(s); } else if (Unary.conforms(s)) { processUnary(s); } else if (GuardedUnary.conforms(s)) { processGuardedUnary(s); } else if (NullCheck.conforms(s)) { processNullCheck(s); } else if (ZeroCheck.conforms(s)) { processZeroCheck(s); } else if (Binary.conforms(s)) { processBinary(s); } else if (GuardedBinary.conforms(s)) { processGuardedBinary(s); } else if (InlineGuard.conforms(s)) { processInlineGuard(s); } else if (IfCmp.conforms(s)) { processIfCmp(s); } else if (Call.conforms(s)) { processCall(s); } else if (MonitorOp.conforms(s)) { processCall(s); } else if (Prepare.conforms(s)) { processCall(s); } else if (Attempt.conforms(s)) { processCall(s); } else if (CacheOp.conforms(s)) { processCall(s); } else if (ALoad.conforms(s)) { processALoad(s); } else if (PutField.conforms(s)) { processPutField(s); } else if (PutStatic.conforms(s)) { processPutStatic(s); } else if (AStore.conforms(s)) { processAStore(s); } else if (Phi.conforms(s)) { processPhi(s); } else if (s.operator() == IR_PROLOGUE) { processPrologue(s); } }
/** * This method actually does the work of attempting to peephole optimize a branch instruction. See * Muchnick ~p.590 * * @param ir the containing IR * @param s the branch instruction to optimize * @param bb the containing basic block * @return {@code true} if an optimization was applied, {@code false} otherwise */ @Override protected boolean optimizeBranchInstruction(IR ir, Instruction s, BasicBlock bb) { if (Goto.conforms(s)) { return processGoto(ir, s, bb); } else if (IfCmp.conforms(s)) { return processConditionalBranch(ir, s, bb); } else if (InlineGuard.conforms(s)) { return processInlineGuard(ir, s, bb); } else if (IfCmp2.conforms(s)) { return processTwoTargetConditionalBranch(ir, s, bb); } else { return false; } }
/** * 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); }