Example #1
0
  /**
   * Adds a move instruction after the phi insn block.
   *
   * @param result move destination
   * @param source move source
   */
  public void addMoveToBeginning(RegisterSpec result, RegisterSpec source) {
    if (result.getReg() == source.getReg()) {
      // Sometimes we end up with no-op moves. Ignore them here.
      return;
    }

    RegisterSpecList sources = RegisterSpecList.make(source);
    NormalSsaInsn toAdd =
        new NormalSsaInsn(
            new PlainInsn(Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, sources),
            this);

    insns.add(getCountPhiInsns(), toAdd);
    movesFromPhisAtBeginning++;
  }
Example #2
0
  /**
   * Adds a move instruction to the end of this basic block, just before the last instruction. If
   * the result of the final instruction is the source in question, then the move is placed at the
   * beginning of the primary successor block. This is for unversioned registers.
   *
   * @param result move destination
   * @param source move source
   */
  public void addMoveToEnd(RegisterSpec result, RegisterSpec source) {

    if (result.getReg() == source.getReg()) {
      // Sometimes we end up with no-op moves. Ignore them here.
      return;
    }

    /*
     * The last Insn has to be a normal SSA insn: a phi can't branch or
     * return or cause an exception, etc.
     */
    NormalSsaInsn lastInsn;
    lastInsn = (NormalSsaInsn) insns.get(insns.size() - 1);

    if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) {
      /*
       * The final insn in this block has a source or result register, and
       * the moves we may need to place and schedule may interfere. We
       * need to insert this instruction at the beginning of the primary
       * successor block instead. We know this is safe, because when we
       * edge-split earlier, we ensured that each successor has only us as
       * a predecessor.
       */

      for (int i = successors.nextSetBit(0); i >= 0; i = successors.nextSetBit(i + 1)) {

        SsaBasicBlock succ;

        succ = parent.getBlocks().get(i);
        succ.addMoveToBeginning(result, source);
      }
    } else {
      /*
       * We can safely add a move to the end of the block just before the
       * last instruction, because the final insn does not assign to
       * anything.
       */
      RegisterSpecList sources = RegisterSpecList.make(source);
      NormalSsaInsn toAdd =
          new NormalSsaInsn(
              new PlainInsn(Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, sources),
              this);

      insns.add(insns.size() - 1, toAdd);

      movesFromPhisAtEnd++;
    }
  }
Example #3
0
  /** {@inheritDoc} */
  @Override
  public boolean isCompatible(DalvInsn insn) {
    if (!(insn instanceof CstInsn)) {
      return false;
    }

    RegisterSpecList regs = insn.getRegisters();
    RegisterSpec reg;

    switch (regs.size()) {
      case 1:
        {
          reg = regs.get(0);
          break;
        }
      case 2:
        {
          /*
           * This format is allowed for ops that are effectively
           * 2-arg but where the two args are identical.
           */
          reg = regs.get(0);
          if (reg.getReg() != regs.get(1).getReg()) {
            return false;
          }
          break;
        }
      default:
        {
          return false;
        }
    }

    if (!unsignedFitsInByte(reg.getReg())) {
      return false;
    }

    CstInsn ci = (CstInsn) insn;
    int cpi = ci.getIndex();

    if (!unsignedFitsInShort(cpi)) {
      return false;
    }

    Constant cst = ci.getConstant();
    return (cst instanceof CstType) || (cst instanceof CstFieldRef) || (cst instanceof CstString);
  }
Example #4
0
  /**
   * Inserts mark-locals if necessary when changing a register. If the definition of {@code origReg}
   * is associated with a local variable, then insert a mark-local for {@code newReg} just below it.
   * We expect the definition of {@code origReg} to ultimately be removed by the dead code
   * eliminator
   *
   * @param origReg {@code non-null;} original register
   * @param newReg {@code non-null;} new register that will replace {@code origReg}
   */
  private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) {
    for (SsaInsn use : ssaMeth.getUseListForRegister(origReg.getReg())) {
      RegisterSpec localAssignment = use.getLocalAssignment();
      if (localAssignment == null) {
        continue;
      }

      if (use.getResult() == null) {
        /*
         * This is a mark-local. it will be updated when all uses are
         * updated.
         */
        continue;
      }

      LocalItem local = localAssignment.getLocalItem();

      // Un-associate original use.
      use.setResultLocal(null);

      // Now add a mark-local to the new reg immediately after.
      newReg = newReg.withLocalItem(local);

      SsaInsn newInsn =
          SsaInsn.makeFromRop(
              new PlainInsn(
                  Rops.opMarkLocal(newReg),
                  SourcePosition.NO_INFO,
                  null,
                  RegisterSpecList.make(newReg)),
              use.getBlock());

      ArrayList<SsaInsn> insns = use.getBlock().getInsns();

      insns.add(insns.indexOf(use) + 1, newInsn);
    }
  }
Example #5
0
  /**
   * Processes a single block.
   *
   * @param blockIndex {@code >= 0;} block index of the block to process
   */
  private void processBlock(int blockIndex) {
    RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex);
    SsaBasicBlock block = blocks.get(blockIndex);
    List<SsaInsn> insns = block.getInsns();
    int insnSz = insns.size();

    // The exit block has no insns and no successors
    if (blockIndex == method.getExitBlockIndex()) {
      return;
    }

    /*
     * We may have to treat the last instruction specially: If it
     * can (but doesn't always) throw, and the exception can be
     * caught within the same method, then we need to use the
     * state *before* executing it to be what is merged into
     * exception targets.
     */
    SsaInsn lastInsn = insns.get(insnSz - 1);
    boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0;
    boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null);
    int freezeSecondaryStateAt = insnSz - 1;
    RegisterSpecSet secondaryState = primaryState;

    /*
     * Iterate over the instructions, adding information for each place
     * that the active variable set changes.
     */

    for (int i = 0; i < insnSz; i++) {
      if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
        // Until this point, primaryState == secondaryState.
        primaryState.setImmutable();
        primaryState = primaryState.mutableCopy();
      }

      SsaInsn insn = insns.get(i);
      RegisterSpec result;

      result = insn.getLocalAssignment();

      if (result == null) {
        // We may be nuking an existing local

        result = insn.getResult();

        if (result != null && primaryState.get(result.getReg()) != null) {
          primaryState.remove(primaryState.get(result.getReg()));
        }
        continue;
      }

      result = result.withSimpleType();

      RegisterSpec already = primaryState.get(result);
      /*
       * The equals() check ensures we only add new info if
       * the instruction causes a change to the set of
       * active variables.
       */
      if (!result.equals(already)) {
        /*
         * If this insn represents a local moving from one register
         * to another, remove the association between the old register
         * and the local.
         */
        RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem());

        if (previous != null && (previous.getReg() != result.getReg())) {

          primaryState.remove(previous);
        }

        resultInfo.addAssignment(insn, result);
        primaryState.put(result);
      }
    }

    primaryState.setImmutable();

    /*
     * Merge this state into the start state for each successor,
     * and update the work set where required (that is, in cases
     * where the start state for a block changes).
     */

    IntList successors = block.getSuccessorList();
    int succSz = successors.size();
    int primarySuccessor = block.getPrimarySuccessorIndex();

    for (int i = 0; i < succSz; i++) {
      int succ = successors.get(i);
      RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState;

      if (resultInfo.mergeStarts(succ, state)) {
        workSet.set(succ);
      }
    }
  }
Example #6
0
  /**
   * Checks to see if the register is used in a bitset, taking into account its category/width.
   *
   * @param regsUsed set, indexed by register number
   * @param rs register to mark as used
   * @return true if register is fully or partially (for the case of wide registers) used.
   */
  private static boolean checkRegUsed(BitSet regsUsed, RegisterSpec rs) {
    int reg = rs.getReg();
    int category = rs.getCategory();

    return regsUsed.get(reg) || (category == 2 ? regsUsed.get(reg + 1) : false);
  }
Example #7
0
 /**
  * Sets the register as used in a bitset, taking into account its category/width.
  *
  * @param regsUsed set, indexed by register number
  * @param rs register to mark as used
  */
 private static void setRegsUsed(BitSet regsUsed, RegisterSpec rs) {
   regsUsed.set(rs.getReg());
   if (rs.getCategory() > 1) {
     regsUsed.set(rs.getReg() + 1);
   }
 }
Example #8
0
  /**
   * Updates all uses of various consts to use the values in the newly assigned registers.
   *
   * @param newRegs {@code non-null;} mapping between constant and new reg
   * @param origRegCount {@code >=0;} original SSA reg count, not including newly added constant
   *     regs
   */
  private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs, int origRegCount) {

    /*
     * set of constants associated with a local variable; used only if
     * COLLECT_ONE_LOCAL is true.
     */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();

    final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();

    for (int i = 0; i < origRegCount; i++) {
      SsaInsn insn = ssaMeth.getDefinitionForRegister(i);

      if (insn == null) {
        continue;
      }

      final RegisterSpec origReg = insn.getResult();
      TypeBearer typeBearer = insn.getResult().getTypeBearer();

      if (!typeBearer.isConstant()) continue;

      TypedConstant cst = (TypedConstant) typeBearer;
      final RegisterSpec newReg = newRegs.get(cst);

      if (newReg == null) {
        continue;
      }

      if (ssaMeth.isRegALocal(origReg)) {
        if (!COLLECT_ONE_LOCAL) {
          continue;
        } else {
          /*
           * TODO: If the same local gets the same cst multiple times,
           * it would be nice to reuse the register.
           */
          if (usedByLocal.contains(cst)) {
            continue;
          } else {
            usedByLocal.add(cst);
            fixLocalAssignment(origReg, newRegs.get(cst));
          }
        }
      }

      // maps an original const register to the new collected register
      RegisterMapper mapper =
          new RegisterMapper() {

            @Override
            public int getNewRegisterCount() {
              return ssaMeth.getRegCount();
            }

            @Override
            public RegisterSpec map(RegisterSpec registerSpec) {
              if (registerSpec.getReg() == origReg.getReg()) {
                return newReg.withLocalItem(registerSpec.getLocalItem());
              }

              return registerSpec;
            }
          };

      for (SsaInsn use : useList[origReg.getReg()]) {
        if (use.canThrow() && use.getBlock().getSuccessors().cardinality() > 1) {
          continue;
        }
        use.mapSourceRegisters(mapper);
      }
    }
  }