/**
   * 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);
 }