/**
   * Adds {@code regV} to the live-in list for this block. This is called by the liveness analyzer.
   *
   * @param regV register that is live-in for this block.
   */
  public void addLiveIn(int regV) {
    if (liveIn == null) {
      liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
    }

    liveIn.add(regV);
  }
  /** 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);
  }
  /**
   * Does the extraction.
   *
   * @return {@code non-null;} the extracted information
   */
  private LocalVariableInfo doit() {

    // FIXME why is this needed here?
    if (method.getRegCount() > 0) {
      for (int bi = method.getEntryBlockIndex(); bi >= 0; bi = workSet.nextSetBit(0)) {
        workSet.clear(bi);
        processBlock(bi);
      }
    }

    resultInfo.setImmutable();
    return resultInfo;
  }
 /**
  * Returns the set of live-out registers. Valid after register interference graph has been
  * generated, otherwise empty.
  *
  * @return {@code non-null;} live-out register set
  */
 public IntSet getLiveOutRegs() {
   if (liveOut == null) {
     liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
   }
   return liveOut;
 }
  /**
   * Ensures that all move operations in this block occur such that reads of any register happen
   * before writes to that register. NOTE: caller is expected to returnSpareRegisters()! TODO: See
   * Briggs, et al "Practical Improvements to the Construction and Destruction of Static Single
   * Assignment Form" section 5. a) This can be done in three passes.
   *
   * @param toSchedule List of instructions. Must consist only of moves.
   */
  private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) {
    BitSet regsUsedAsSources = new BitSet(parent.getRegCount());

    // TODO: Get rid of this.
    BitSet regsUsedAsResults = new BitSet(parent.getRegCount());

    int sz = toSchedule.size();

    int insertPlace = 0;

    while (insertPlace < sz) {
      int oldInsertPlace = insertPlace;

      // Record all registers used as sources in this block.
      for (int i = insertPlace; i < sz; i++) {
        setRegsUsed(regsUsedAsSources, toSchedule.get(i).getSources().get(0));

        setRegsUsed(regsUsedAsResults, toSchedule.get(i).getResult());
      }

      /*
       * If there are no circular dependencies, then there exists n
       * instructions where n > 1 whose result is not used as a source.
       */
      for (int i = insertPlace; i < sz; i++) {
        SsaInsn insn = toSchedule.get(i);

        /*
         * Move these n registers to the front, since they overwrite
         * nothing.
         */
        if (!checkRegUsed(regsUsedAsSources, insn.getResult())) {
          Collections.swap(toSchedule, i, insertPlace++);
        }
      }

      /*
       * If we've made no progress in this iteration, there's a circular
       * dependency. Split it using the temp reg.
       */
      if (oldInsertPlace == insertPlace) {

        SsaInsn insnToSplit = null;

        // Find an insn whose result is used as a source.
        for (int i = insertPlace; i < sz; i++) {
          SsaInsn insn = toSchedule.get(i);
          if (checkRegUsed(regsUsedAsSources, insn.getResult())
              && checkRegUsed(regsUsedAsResults, insn.getSources().get(0))) {

            insnToSplit = insn;
            /*
             * We're going to split this insn; move it to the front.
             */
            Collections.swap(toSchedule, insertPlace, i);
            break;
          }
        }

        // At least one insn will be set above.

        RegisterSpec result = insnToSplit.getResult();
        RegisterSpec tempSpec = result.withReg(parent.borrowSpareRegister(result.getCategory()));

        NormalSsaInsn toAdd =
            new NormalSsaInsn(
                new PlainInsn(
                    Rops.opMove(result.getType()),
                    SourcePosition.NO_INFO,
                    tempSpec,
                    insnToSplit.getSources()),
                this);

        toSchedule.add(insertPlace++, toAdd);

        RegisterSpecList newSources = RegisterSpecList.make(tempSpec);

        NormalSsaInsn toReplace =
            new NormalSsaInsn(
                new PlainInsn(
                    Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, newSources),
                this);

        toSchedule.set(insertPlace, toReplace);

        // The size changed.
        sz = toSchedule.size();
      }

      regsUsedAsSources.clear();
      regsUsedAsResults.clear();
    }
  }
  /**
   * Gets all of the collectable constant values used in this method, sorted by most used first.
   * Skips non-collectable consts, such as non-string object constants
   *
   * @return {@code non-null;} list of constants in most-to-least used order
   */
  private ArrayList<TypedConstant> getConstsSortedByCountUse() {
    int regSz = ssaMeth.getRegCount();

    final HashMap<TypedConstant, Integer> countUses = new HashMap<TypedConstant, Integer>();

    /*
     * Each collected constant can be used by just one local (used only if
     * COLLECT_ONE_LOCAL is true).
     */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();

    // Count how many times each const value is used.
    for (int i = 0; i < regSz; i++) {
      SsaInsn insn = ssaMeth.getDefinitionForRegister(i);

      if (insn == null || insn.getOpcode() == null) continue;

      RegisterSpec result = insn.getResult();
      TypeBearer typeBearer = result.getTypeBearer();

      if (!typeBearer.isConstant()) continue;

      TypedConstant cst = (TypedConstant) typeBearer;

      // Find defining instruction for move-result-pseudo instructions
      if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
        int pred = insn.getBlock().getPredecessors().nextSetBit(0);
        ArrayList<SsaInsn> predInsns;
        predInsns = ssaMeth.getBlocks().get(pred).getInsns();
        insn = predInsns.get(predInsns.size() - 1);
      }

      if (insn.canThrow()) {
        /*
         * Don't move anything other than strings -- the risk of
         * changing where an exception is thrown is too high.
         */
        if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
          continue;
        }
        /*
         * We can't move any throwable const whose throw will be caught,
         * so don't count them.
         */
        if (insn.getBlock().getSuccessors().cardinality() > 1) {
          continue;
        }
      }

      /*
       * TODO: Might be nice to try and figure out which local wins most
       * when collected.
       */
      if (ssaMeth.isRegALocal(result)) {
        if (!COLLECT_ONE_LOCAL) {
          continue;
        } else {
          if (usedByLocal.contains(cst)) {
            // Count one local usage only.
            continue;
          } else {
            usedByLocal.add(cst);
          }
        }
      }

      Integer has = countUses.get(cst);
      if (has == null) {
        countUses.put(cst, 1);
      } else {
        countUses.put(cst, has + 1);
      }
    }

    // Collect constants that have been reused.
    ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
    for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
      if (entry.getValue() > 1) {
        constantList.add(entry.getKey());
      }
    }

    // Sort by use, with most used at the beginning of the list.
    Collections.sort(
        constantList,
        new Comparator<Constant>() {

          public int compare(Constant a, Constant b) {
            int ret;
            ret = countUses.get(b) - countUses.get(a);

            if (ret == 0) {
              /*
               * Provide sorting determinisim for constants with same
               * usage count.
               */
              ret = a.compareTo(b);
            }

            return ret;
          }

          @Override
          public boolean equals(Object obj) {
            return obj == this;
          }
        });

    return constantList;
  }