/** * 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); } }
/** * Attempt to generate a boolean compare opcode from a conditional branch. * * <pre> * 1) IF .. GOTO A replaced by BOOLEAN_CMP x=.. * x = 0 * GOTO B * A: x = 1 * B: ... * </pre> * * <p>Precondition: <code>IfCmp.conforms(<i>cb</i>)</code> * * @param ir governing IR * @param bb basic block of cb * @param cb conditional branch instruction * @return true if the transformation succeeds, false otherwise */ private boolean generateBooleanCompare(IR ir, BasicBlock bb, Instruction cb, BasicBlock tb) { if ((cb.operator() != INT_IFCMP) && (cb.operator() != REF_IFCMP)) { return false; } // make sure this is the last branch in the block if (cb.nextInstructionInCodeOrder().operator() != BBEND) { return false; } Operand val1 = IfCmp.getVal1(cb); Operand val2 = IfCmp.getVal2(cb); ConditionOperand condition = IfCmp.getCond(cb); // "not taken" path BasicBlock fb = cb.getBasicBlock().getNotTakenNextBlock(); // make sure it's a diamond if (tb.getNumberOfNormalOut() != 1) { return false; } if (fb.getNumberOfNormalOut() != 1) { return false; } BasicBlock jb = fb.getNormalOut().nextElement(); // join block // make sure it's a diamond if (!tb.pointsOut(jb)) { return false; } Instruction ti = tb.firstRealInstruction(); Instruction fi = fb.firstRealInstruction(); // make sure the instructions in target blocks are either both moves // or both returns if (ti == null || fi == null) { return false; } if (ti.operator() != fi.operator()) { return false; } if (ti.operator != RETURN && ti.operator() != INT_MOVE) { return false; } // // WARNING: This code is currently NOT exercised! // if (ti.operator() == RETURN) { // make sure each of the target blocks contains only one instruction if (ti != tb.lastRealInstruction()) { return false; } if (fi != fb.lastRealInstruction()) { return false; } Operand tr = Return.getVal(ti); Operand fr = Return.getVal(fi); // make sure we're returning constants if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) { return false; } int tv = ((IntConstantOperand) tr).value; int fv = ((IntConstantOperand) fr).value; if (!((tv == 1 && fv == 0) || (tv == 1 && fv == 0))) { return false; } RegisterOperand t = ir.regpool.makeTemp(TypeReference.Boolean); // Cases 1) and 2) if (tv == 0) { condition = condition.flipCode(); } booleanCompareHelper(cb, t, val1.copy(), val2.copy(), condition); cb.insertAfter(Return.create(RETURN, t.copyD2U())); } else { // (ti.operator() == INT_MOVE) // make sure each of the target blocks only does the move if (ti != tb.lastRealInstruction() && ti.nextInstructionInCodeOrder().operator() != GOTO) { return false; } if (fi != fb.lastRealInstruction() && fi.nextInstructionInCodeOrder().operator() != GOTO) { return false; } RegisterOperand t = Move.getResult(ti); // make sure both moves are to the same register if (t.getRegister() != Move.getResult(fi).getRegister()) { return false; } Operand tr = Move.getVal(ti); Operand fr = Move.getVal(fi); // make sure we're assigning constants if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) { return false; } int tv = ((IntConstantOperand) tr).value; int fv = ((IntConstantOperand) fr).value; if (!((tv == 1 && fv == 0) || (tv == 0 && fv == 1))) { return false; } // Cases 3) and 4) if (tv == 0) { condition = condition.flipCode(); } booleanCompareHelper(cb, t.copyRO(), val1.copy(), val2.copy(), condition); Instruction next = cb.nextInstructionInCodeOrder(); if (next.operator() == GOTO) { Goto.setTarget(next, jb.makeJumpTarget()); } else { cb.insertAfter(jb.makeGOTO()); } } // fixup CFG bb.deleteOut(tb); bb.deleteOut(fb); bb.insertOut(jb); // Note: if we processed returns, // jb is the exit node. return true; }