Пример #1
0
  /**
   * Replaces an old successor with a new successor. This will throw RuntimeException if {@code
   * oldIndex} was not a successor.
   *
   * @param oldIndex index of old successor block
   * @param newIndex index of new successor block
   */
  public void replaceSuccessor(int oldIndex, int newIndex) {
    if (oldIndex == newIndex) {
      return;
    }

    // Update us.
    successors.set(newIndex);

    if (primarySuccessor == oldIndex) {
      primarySuccessor = newIndex;
    }

    for (int i = successorList.size() - 1; i >= 0; i--) {
      if (successorList.get(i) == oldIndex) {
        successorList.set(i, newIndex);
      }
    }

    successors.clear(oldIndex);

    // Update new successor.
    parent.getBlocks().get(newIndex).predecessors.set(index);

    // Update old successor.
    parent.getBlocks().get(oldIndex).predecessors.clear(index);
  }
Пример #2
0
  /**
   * Inserts a new empty GOTO block as a predecessor to this block. All previous predecessors will
   * be predecessors to the new block.
   *
   * @return {@code non-null;} an appropriately-constructed instance
   */
  public SsaBasicBlock insertNewPredecessor() {
    SsaBasicBlock newPred = parent.makeNewGotoBlock();

    // Update the new block.
    newPred.predecessors = predecessors;
    newPred.successors.set(index);
    newPred.successorList.add(index);
    newPred.primarySuccessor = index;

    // Update us.
    predecessors = new BitSet(parent.getBlocks().size());
    predecessors.set(newPred.index);

    // Update our (soon-to-be) old predecessors.
    for (int i = newPred.predecessors.nextSetBit(0);
        i >= 0;
        i = newPred.predecessors.nextSetBit(i + 1)) {

      SsaBasicBlock predBlock = parent.getBlocks().get(i);

      predBlock.replaceSuccessor(index, newPred.index);
    }

    return newPred;
  }
Пример #3
0
  /**
   * Creates a new SSA basic block from a ROP form basic block.
   *
   * @param rmeth original method
   * @param basicBlockIndex index this block will have
   * @param parent method of this block predecessor set will be updated
   * @return new instance
   */
  public static SsaBasicBlock newFromRop(
      RopMethod rmeth, int basicBlockIndex, final SsaMethod parent) {
    BasicBlockList ropBlocks = rmeth.getBlocks();
    BasicBlock bb = ropBlocks.get(basicBlockIndex);
    SsaBasicBlock result = new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
    InsnList ropInsns = bb.getInsns();

    result.insns.ensureCapacity(ropInsns.size());

    for (int i = 0, sz = ropInsns.size(); i < sz; i++) {
      result.insns.add(new NormalSsaInsn(ropInsns.get(i), result));
    }

    result.predecessors =
        SsaMethod.bitSetFromLabelList(ropBlocks, rmeth.labelToPredecessors(bb.getLabel()));

    result.successors = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors());

    result.successorList = SsaMethod.indexListFromLabelList(ropBlocks, bb.getSuccessors());

    if (result.successorList.size() != 0) {
      int primarySuccessor = bb.getPrimarySuccessor();

      result.primarySuccessor =
          (primarySuccessor < 0) ? -1 : ropBlocks.indexOfLabel(primarySuccessor);
    }

    return result;
  }
Пример #4
0
  /**
   * Creates a new empty basic block.
   *
   * @param basicBlockIndex index this block will have
   * @param ropLabel original rop-form label
   * @param parent method of this block
   */
  public SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent) {
    this.parent = parent;
    this.index = basicBlockIndex;
    this.insns = new ArrayList<SsaInsn>();
    this.ropLabel = ropLabel;

    this.predecessors = new BitSet(parent.getBlocks().size());
    this.successors = new BitSet(parent.getBlocks().size());
    this.successorList = new IntList();

    domChildren = new ArrayList<SsaBasicBlock>();
  }
Пример #5
0
  /** 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);
  }
Пример #6
0
  /**
   * 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;
  }
Пример #7
0
  /**
   * Replaces the last insn in this block. The provided insn must have some branchingness.
   *
   * @param insn {@code non-null;} rop-form insn to add, which must branch.
   */
  public void replaceLastInsn(Insn insn) {
    if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
      throw new IllegalArgumentException("last insn must branch");
    }

    SsaInsn oldInsn = insns.get(insns.size() - 1);
    SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);

    insns.set(insns.size() - 1, newInsn);

    parent.onInsnRemoved(oldInsn);
    parent.onInsnAdded(newInsn);
  }
Пример #8
0
  /**
   * Constructs and inserts a new empty GOTO block {@code Z} between this block ({@code A}) and a
   * current successor block ({@code B}). The new block will replace B as A's successor and A as B's
   * predecessor. A and B will no longer be directly connected. If B is listed as a successor
   * multiple times, all references are replaced.
   *
   * @param other current successor (B)
   * @return {@code non-null;} an appropriately-constructed instance
   */
  public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
    SsaBasicBlock newSucc = parent.makeNewGotoBlock();

    if (!successors.get(other.index)) {
      throw new RuntimeException(
          "Block " + other.getRopLabelString() + " not successor of " + getRopLabelString());
    }

    // Update the new block.
    newSucc.predecessors.set(this.index);
    newSucc.successors.set(other.index);
    newSucc.successorList.add(other.index);
    newSucc.primarySuccessor = other.index;

    // Update us.
    for (int i = successorList.size() - 1; i >= 0; i--) {
      if (successorList.get(i) == other.index) {
        successorList.set(i, newSucc.index);
      }
    }

    if (primarySuccessor == other.index) {
      primarySuccessor = newSucc.index;
    }
    successors.clear(other.index);
    successors.set(newSucc.index);

    // Update "other".
    other.predecessors.set(newSucc.index);
    other.predecessors.set(index, successors.get(other.index));

    return newSucc;
  }
Пример #9
0
 /** @return {@code null-ok;} the primary successor block or {@code null} if there is none */
 public SsaBasicBlock getPrimarySuccessor() {
   if (primarySuccessor < 0) {
     return null;
   } else {
     return parent.getBlocks().get(primarySuccessor);
   }
 }
Пример #10
0
  /**
   * 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);
  }
Пример #11
0
  /** @return successor list of rop labels */
  public IntList getRopLabelSuccessorList() {
    IntList result = new IntList(successorList.size());

    int sz = successorList.size();

    for (int i = 0; i < sz; i++) {
      result.add(parent.blockIndexToRopLabel(successorList.get(i)));
    }
    return result;
  }
Пример #12
0
  /**
   * Constructs an instance. This method is private. Use {@link #extract}.
   *
   * @param method {@code non-null;} the method to extract from
   */
  private LocalVariableExtractor(SsaMethod method) {
    if (method == null) {
      throw new NullPointerException("method == null");
    }

    ArrayList<SsaBasicBlock> blocks = method.getBlocks();

    this.method = method;
    this.blocks = blocks;
    this.resultInfo = new LocalVariableInfo(method);
    this.workSet = new BitSet(blocks.size());
  }
Пример #13
0
  /** Run the literal op upgrader */
  private void run() {
    final TranslationAdvice advice = Optimizer.getAdvice();

    ssaMeth.forEachInsn(
        new SsaInsn.Visitor() {
          public void visitMoveInsn(NormalSsaInsn insn) {
            // do nothing
          }

          public void visitPhiInsn(PhiInsn insn) {
            // do nothing
          }

          public void visitNonMoveInsn(NormalSsaInsn insn) {

            Insn originalRopInsn = insn.getOriginalRopInsn();
            Rop opcode = originalRopInsn.getOpcode();
            RegisterSpecList sources = insn.getSources();

            // Replace insns with constant results with const insns
            if (tryReplacingWithConstant(insn)) return;

            if (sources.size() != 2) {
              // We're only dealing with two-source insns here.
              return;
            }

            if (opcode.getBranchingness() == Rop.BRANCH_IF) {
              /*
               * An if instruction can become an if-*z instruction.
               */
              if (isConstIntZeroOrKnownNull(sources.get(0))) {
                replacePlainInsn(
                    insn, sources.withoutFirst(), RegOps.flippedIfOpcode(opcode.getOpcode()), null);
              } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
                replacePlainInsn(insn, sources.withoutLast(), opcode.getOpcode(), null);
              }
            } else if (advice.hasConstantOperation(opcode, sources.get(0), sources.get(1))) {
              insn.upgradeToLiteral();
            } else if (opcode.isCommutative()
                && advice.hasConstantOperation(opcode, sources.get(1), sources.get(0))) {
              /*
               * An instruction can be commuted to a literal operation
               */

              insn.setNewSources(RegisterSpecList.make(sources.get(1), sources.get(0)));

              insn.upgradeToLiteral();
            }
          }
        });
  }
Пример #14
0
  /**
   * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The new PlainInsn is
   * constructed with a new RegOp and new sources.
   *
   * <p>TODO move this somewhere else.
   *
   * @param insn {@code non-null;} an SsaInsn containing a PlainInsn
   * @param newSources {@code non-null;} new sources list for new insn
   * @param newOpcode A RegOp from {@link RegOps}
   * @param cst {@code null-ok;} constant for new instruction, if any
   */
  private void replacePlainInsn(
      NormalSsaInsn insn, RegisterSpecList newSources, int newOpcode, Constant cst) {

    Insn originalRopInsn = insn.getOriginalRopInsn();
    Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst);
    Insn newRopInsn;
    if (cst == null) {
      newRopInsn =
          new PlainInsn(newRop, originalRopInsn.getPosition(), insn.getResult(), newSources);
    } else {
      newRopInsn =
          new PlainCstInsn(
              newRop, originalRopInsn.getPosition(), insn.getResult(), newSources, cst);
    }
    NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());

    List<SsaInsn> insns = insn.getBlock().getInsns();

    ssaMeth.onInsnRemoved(insn);
    insns.set(insns.lastIndexOf(insn), newInsn);
    ssaMeth.onInsnAdded(newInsn);
  }
Пример #15
0
  /**
   * 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;
  }
Пример #16
0
  /**
   * Removes a successor from this block's successor list.
   *
   * @param oldIndex index of successor block to remove
   */
  public void removeSuccessor(int oldIndex) {
    int removeIndex = 0;

    for (int i = successorList.size() - 1; i >= 0; i--) {
      if (successorList.get(i) == oldIndex) {
        removeIndex = i;
      } else {
        primarySuccessor = successorList.get(i);
      }
    }

    successorList.removeIndex(removeIndex);
    successors.clear(oldIndex);
    parent.getBlocks().get(oldIndex).predecessors.clear(index);
  }
Пример #17
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++;
    }
  }
Пример #18
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);
    }
  }
Пример #19
0
  /**
   * 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;
  }
Пример #20
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);
      }
    }
  }
Пример #21
0
 /**
  * Adds an insn to the head of this basic block, just after any phi insns.
  *
  * @param insn {@code non-null;} rop-form insn to add
  */
 public void addInsnToHead(Insn insn) {
   SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
   insns.add(getCountPhiInsns(), newInsn);
   parent.onInsnAdded(newInsn);
 }
Пример #22
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);
      }
    }
  }
Пример #23
0
 /** @return rop label of primary successor */
 public int getPrimarySuccessorRopLabel() {
   return parent.blockIndexToRopLabel(primarySuccessor);
 }
Пример #24
0
  /**
   * Sorts move instructions added via {@code addMoveToEnd} during phi removal so that results don't
   * overwrite sources that are used. For use after all phis have been removed and all calls to
   * addMoveToEnd() have been made.
   *
   * <p>This is necessary because copy-propogation may have left us in a state where the same basic
   * block has the same register as a phi operand and a result. In this case, the register in the
   * phi operand always refers value before any other phis have executed.
   */
  public void scheduleMovesFromPhis() {
    if (movesFromPhisAtBeginning > 1) {
      List<SsaInsn> toSchedule;

      toSchedule = insns.subList(0, movesFromPhisAtBeginning);

      scheduleUseBeforeAssigned(toSchedule);

      SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning);

      /*
       * TODO: It's actually possible that this case never happens,
       * because a move-exception block, having only one predecessor in
       * SSA form, perhaps is never on a dominance frontier.
       */
      if (firstNonPhiMoveInsn.isMoveException()) {
        if (true) {
          /*
           * We've yet to observe this case, and if it can occur the
           * code written to handle it probably does not work.
           */
          throw new RuntimeException("Unexpected: moves from " + "phis before move-exception");
        } else {
          /*
           * A move-exception insn must be placed first in this block
           * We need to move it there, and deal with possible
           * interference.
           */
          boolean moveExceptionInterferes = false;

          int moveExceptionResult = firstNonPhiMoveInsn.getResult().getReg();

          /*
           * Does the move-exception result reg interfere with the phi
           * moves?
           */
          for (SsaInsn insn : toSchedule) {
            if (insn.isResultReg(moveExceptionResult) || insn.isRegASource(moveExceptionResult)) {
              moveExceptionInterferes = true;
              break;
            }
          }

          if (!moveExceptionInterferes) {
            // This is the easy case.
            insns.remove(movesFromPhisAtBeginning);
            insns.add(0, firstNonPhiMoveInsn);
          } else {
            /*
             * We need to move the result to a spare reg and move it
             * back.
             */
            RegisterSpec originalResultSpec = firstNonPhiMoveInsn.getResult();
            int spareRegister = parent.borrowSpareRegister(originalResultSpec.getCategory());

            // We now move it to a spare register.
            firstNonPhiMoveInsn.changeResultReg(spareRegister);
            RegisterSpec tempSpec = firstNonPhiMoveInsn.getResult();

            insns.add(0, firstNonPhiMoveInsn);

            // And here we move it back.

            NormalSsaInsn toAdd =
                new NormalSsaInsn(
                    new PlainInsn(
                        Rops.opMove(tempSpec.getType()),
                        SourcePosition.NO_INFO,
                        originalResultSpec,
                        RegisterSpecList.make(tempSpec)),
                    this);

            /*
             * Place it immediately after the phi-moves, overwriting
             * the move-exception that was there.
             */
            insns.set(movesFromPhisAtBeginning + 1, toAdd);
          }
        }
      }
    }

    if (movesFromPhisAtEnd > 1) {
      scheduleUseBeforeAssigned(
          insns.subList(insns.size() - movesFromPhisAtEnd - 1, insns.size() - 1));
    }

    // Return registers borrowed here and in scheduleUseBeforeAssigned().
    parent.returnSpareRegisters();
  }
Пример #25
0
 /**
  * Returns true if this block was last calculated to be reachable. Recalculates reachability if
  * value has never been computed.
  *
  * @return {@code true} if reachable
  */
 public boolean isReachable() {
   if (reachable == -1) {
     parent.computeReachability();
   }
   return (reachable == 1);
 }
Пример #26
0
 /** @return true if this is the one-and-only exit block for this method */
 public boolean isExitBlock() {
   return index == parent.getExitBlockIndex();
 }
Пример #27
0
 /**
  * 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;
 }
Пример #28
0
  /**
   * 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();
    }
  }