Example #1
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();
  }