/** Applies the optimization. */
  private void run() {
    int regSz = ssaMeth.getRegCount();

    ArrayList<TypedConstant> constantList = getConstsSortedByCountUse();

    int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);

    SsaBasicBlock start = ssaMeth.getEntryBlock();

    // Constant to new register containing the constant
    HashMap<TypedConstant, RegisterSpec> newRegs =
        new HashMap<TypedConstant, RegisterSpec>(toCollect);

    for (int i = 0; i < toCollect; i++) {
      TypedConstant cst = constantList.get(i);
      RegisterSpec result = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);

      Rop constRop = Rops.opConst(cst);

      if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
        start.addInsnToHead(
            new PlainCstInsn(
                Rops.opConst(cst), SourcePosition.NO_INFO, result, RegisterSpecList.EMPTY, cst));
      } else {
        // We need two new basic blocks along with the new insn
        SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
        SsaBasicBlock successorBlock = entryBlock.getPrimarySuccessor();

        // Insert a block containing the const insn.
        SsaBasicBlock constBlock = entryBlock.insertNewSuccessor(successorBlock);

        constBlock.replaceLastInsn(
            new ThrowingCstInsn(
                constRop, SourcePosition.NO_INFO, RegisterSpecList.EMPTY, StdTypeList.EMPTY, cst));

        // Insert a block containing the move-result-pseudo insn.

        SsaBasicBlock resultBlock = constBlock.insertNewSuccessor(successorBlock);
        PlainInsn insn =
            new PlainInsn(
                Rops.opMoveResultPseudo(result.getTypeBearer()),
                SourcePosition.NO_INFO,
                result,
                RegisterSpecList.EMPTY);

        resultBlock.addInsnToHead(insn);
      }

      newRegs.put(cst, result);
    }

    updateConstUses(newRegs, regSz);
  }
  /**
   * Tries to replace an instruction with a const instruction. The given instruction must have a
   * constant result for it to be replaced.
   *
   * @param insn {@code non-null;} instruction to try to replace
   * @return true if the instruction was replaced
   */
  private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
    Insn originalRopInsn = insn.getOriginalRopInsn();
    Rop opcode = originalRopInsn.getOpcode();
    RegisterSpec result = insn.getResult();

    if (result != null && !ssaMeth.isRegALocal(result) && opcode.getOpcode() != RegOps.CONST) {
      TypeBearer type = insn.getResult().getTypeBearer();
      if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
        // Replace the instruction with a constant
        replacePlainInsn(insn, RegisterSpecList.EMPTY, RegOps.CONST, (Constant) type);

        // Remove the source as well if this is a move-result-pseudo
        if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
          int pred = insn.getBlock().getPredecessors().nextSetBit(0);
          ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
          NormalSsaInsn sourceInsn = (NormalSsaInsn) predInsns.get(predInsns.size() - 1);
          replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY, RegOps.GOTO, null);
        }
        return true;
      }
    }
    return false;
  }