/** Evaluate the cost of a basic block, in number of real instructions. */
 private int evaluateCost(BasicBlock bb) {
   int result = 0;
   for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) {
     Instruction s = e.nextElement();
     if (!s.isBranch()) result++;
   }
   return result;
 }
  /**
   * For each real non-branch instruction s in bb,
   *
   * <ul>
   *   <li>Copy s to s', and store s' in the returned array
   *   <li>Insert the function s->s' in the map
   * </ul>
   */
  private Instruction[] copyAndMapInstructions(
      BasicBlock bb, HashMap<Instruction, Instruction> map) {
    if (bb == null) return new Instruction[0];

    int count = 0;
    // first count the number of instructions
    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) {
      Instruction s = e.nextElement();
      if (s.isBranch()) continue;
      count++;
    }
    // now copy.
    Instruction[] result = new Instruction[count];
    int i = 0;
    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) {
      Instruction s = e.nextElement();
      if (s.isBranch()) continue;
      Instruction sprime = s.copyWithoutLinks();
      result[i++] = sprime;
      map.put(s, sprime);
    }
    return result;
  }
예제 #3
0
  /**
   * Walks through the IR. For each StackLocationOperand, replace the operand with the appropriate
   * MemoryOperand.
   */
  private void rewriteStackLocations() {
    // ESP is initially WORDSIZE above where the framepointer is going to be.
    ESPOffset = getFrameFixedSize() + WORDSIZE;
    Register ESP = ((PhysicalRegisterSet) ir.regpool.getPhysicalRegisterSet()).getESP();

    boolean seenReturn = false;
    for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) {
      Instruction s = e.nextElement();

      if (s.isReturn()) {
        seenReturn = true;
        continue;
      }

      if (s.isBranch()) {
        // restore ESP to home location at end of basic block.
        moveESPBefore(s, 0);
        continue;
      }

      if (s.operator() == BBEND) {
        if (seenReturn) {
          // at a return ESP will be at FrameFixedSize,
          seenReturn = false;
          ESPOffset = 0;
        } else {
          moveESPBefore(s, 0);
        }
        continue;
      }

      if (s.operator() == ADVISE_ESP) {
        ESPOffset = MIR_UnaryNoRes.getVal(s).asIntConstant().value;
        continue;
      }

      if (s.operator() == REQUIRE_ESP) {
        // ESP is required to be at the given offset from the bottom of the frame
        moveESPBefore(s, MIR_UnaryNoRes.getVal(s).asIntConstant().value);
        continue;
      }

      if (s.operator() == YIELDPOINT_PROLOGUE
          || s.operator() == YIELDPOINT_BACKEDGE
          || s.operator() == YIELDPOINT_EPILOGUE) {
        moveESPBefore(s, 0);
        continue;
      }

      if (s.operator() == IA32_MOV) {
        rewriteMoveInstruction(s);
      }

      // pop computes the effective address of its operand after ESP
      // is incremented.  Therefore update ESPOffset before rewriting
      // stacklocation and memory operands.
      if (s.operator() == IA32_POP) {
        ESPOffset += WORDSIZE;
      }

      for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements(); ) {
        Operand op = ops.nextElement();
        if (op instanceof StackLocationOperand) {
          StackLocationOperand sop = (StackLocationOperand) op;
          int offset = sop.getOffset();
          if (sop.isFromTop()) {
            offset = FPOffset2SPOffset(offset);
          }
          offset -= ESPOffset;
          byte size = sop.getSize();
          MemoryOperand M =
              MemoryOperand.BD(
                  new RegisterOperand(ESP, PRIMITIVE_TYPE_FOR_WORD),
                  Offset.fromIntSignExtend(offset),
                  size,
                  null,
                  null);
          s.replaceOperand(op, M);
        } else if (op instanceof MemoryOperand) {
          MemoryOperand M = op.asMemory();
          if ((M.base != null && M.base.getRegister() == ESP)
              || (M.index != null && M.index.getRegister() == ESP)) {
            M.disp = M.disp.minus(ESPOffset);
          }
        }
      }

      // push computes the effective address of its operand after ESP
      // is decremented.  Therefore update ESPOffset after rewriting
      // stacklocation and memory operands.
      if (s.operator() == IA32_PUSH) {
        ESPOffset -= WORDSIZE;
      }
    }
  }
  /**
   * Do any of the instructions in a basic block preclude eliminating the basic block with
   * conditional moves?
   */
  private boolean hasCMTaboo(BasicBlock bb) {

    if (bb == null) return false;

    // Note: it is taboo to assign more than once to any register in the
    // block.
    HashSet<Register> defined = new HashSet<Register>();

    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) {
      Instruction s = e.nextElement();
      if (s.isBranch()) continue;
      // for now, only the following opcodes are legal.
      switch (s.operator.opcode) {
        case INT_MOVE_opcode:
        case REF_MOVE_opcode:
        case DOUBLE_MOVE_opcode:
        case FLOAT_MOVE_opcode:
        case INT_ADD_opcode:
        case REF_ADD_opcode:
        case FLOAT_ADD_opcode:
        case DOUBLE_ADD_opcode:
        case INT_SUB_opcode:
        case REF_SUB_opcode:
        case FLOAT_SUB_opcode:
        case DOUBLE_SUB_opcode:
        case INT_MUL_opcode:
        case FLOAT_MUL_opcode:
        case DOUBLE_MUL_opcode:
        case INT_NEG_opcode:
        case FLOAT_NEG_opcode:
        case DOUBLE_NEG_opcode:
        case REF_SHL_opcode:
        case INT_SHL_opcode:
        case REF_SHR_opcode:
        case INT_SHR_opcode:
        case REF_USHR_opcode:
        case INT_USHR_opcode:
        case REF_AND_opcode:
        case INT_AND_opcode:
        case REF_OR_opcode:
        case INT_OR_opcode:
        case REF_XOR_opcode:
        case INT_XOR_opcode:
        case REF_NOT_opcode:
        case INT_NOT_opcode:
        case INT_2BYTE_opcode:
        case INT_2USHORT_opcode:
        case INT_2SHORT_opcode:
        case FLOAT_2DOUBLE_opcode:
        case DOUBLE_2FLOAT_opcode:
          // these are OK.
          break;
        default:
          return true;
      }

      // make sure no register is defined more than once in this block.
      for (Enumeration<Operand> defs = s.getDefs(); defs.hasMoreElements(); ) {
        Operand def = defs.nextElement();
        if (VM.VerifyAssertions) VM._assert(def.isRegister());
        Register r = def.asRegister().getRegister();
        if (defined.contains(r)) return true;
        defined.add(r);
      }
    }

    return false;
  }
  /**
   * Perform the transformation to replace conditional branch with a sequence using conditional
   * moves.
   *
   * @param ir governing IR
   * @param diamond the IR diamond structure to replace
   * @param cb conditional branch instruction at the head of the diamond
   */
  private void doCondMove(IR ir, Diamond diamond, Instruction cb) {
    BasicBlock taken = diamond.getTaken();
    BasicBlock notTaken = diamond.getNotTaken();

    // for each non-branch instruction s in the diamond,
    // copy s to a new instruction s'
    // and store a mapping from s to s'
    HashMap<Instruction, Instruction> takenInstructions = new HashMap<Instruction, Instruction>();
    Instruction[] takenInstructionList = copyAndMapInstructions(taken, takenInstructions);

    HashMap<Instruction, Instruction> notTakenInstructions =
        new HashMap<Instruction, Instruction>();
    Instruction[] notTakenInstructionList = copyAndMapInstructions(notTaken, notTakenInstructions);

    // Extract the values and condition from the conditional branch.
    Operand val1 = IfCmp.getVal1(cb);
    Operand val2 = IfCmp.getVal2(cb);
    ConditionOperand cond = IfCmp.getCond(cb);

    // Copy val1 and val2 to temporaries, just in case they're defined in
    // the diamond.  If they're not defined in the diamond, copy prop
    // should clean these moves up.
    RegisterOperand tempVal1 = ir.regpool.makeTemp(val1);
    Operator op = IRTools.getMoveOp(tempVal1.getType());
    cb.insertBefore(Move.create(op, tempVal1.copyRO(), val1.copy()));
    RegisterOperand tempVal2 = ir.regpool.makeTemp(val2);
    op = IRTools.getMoveOp(tempVal2.getType());
    cb.insertBefore(Move.create(op, tempVal2.copyRO(), val2.copy()));

    // For each instruction in each temporary set, rewrite it to def a new
    // temporary, and insert it before the branch.
    rewriteWithTemporaries(takenInstructionList, ir);
    rewriteWithTemporaries(notTakenInstructionList, ir);
    insertBefore(takenInstructionList, cb);
    insertBefore(notTakenInstructionList, cb);

    // For each register defined in the TAKEN branch, save a mapping to
    // the corresponding conditional move.
    HashMap<Register, Instruction> takenMap = new HashMap<Register, Instruction>();

    // Now insert conditional moves to replace each instruction in the diamond.
    // First handle the taken branch.
    if (taken != null) {
      for (Enumeration<Instruction> e = taken.forwardRealInstrEnumerator(); e.hasMoreElements(); ) {
        Instruction s = e.nextElement();
        if (s.isBranch()) continue;
        Operand def = s.getDefs().nextElement();
        // if the register does not span a basic block, it is a temporary
        // that will now be dead
        if (def.asRegister().getRegister().spansBasicBlock()) {
          Instruction tempS = takenInstructions.get(s);
          RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();
          op = IRTools.getCondMoveOp(def.asRegister().getType());
          Instruction cmov =
              CondMove.create(
                  op,
                  def.asRegister(),
                  tempVal1.copy(),
                  tempVal2.copy(),
                  cond.copy().asCondition(),
                  temp.copy(),
                  def.copy());
          takenMap.put(def.asRegister().getRegister(), cmov);
          cb.insertBefore(cmov);
        }
        s.remove();
      }
    }
    // For each register defined in the NOT-TAKEN branch, save a mapping to
    // the corresponding conditional move.
    HashMap<Register, Instruction> notTakenMap = new HashMap<Register, Instruction>();
    // Next handle the not taken branch.
    if (notTaken != null) {
      for (Enumeration<Instruction> e = notTaken.forwardRealInstrEnumerator();
          e.hasMoreElements(); ) {
        Instruction s = e.nextElement();
        if (s.isBranch()) continue;
        Operand def = s.getDefs().nextElement();
        // if the register does not span a basic block, it is a temporary
        // that will now be dead
        if (def.asRegister().getRegister().spansBasicBlock()) {
          Instruction tempS = notTakenInstructions.get(s);
          RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();

          Instruction prevCmov = takenMap.get(def.asRegister().getRegister());
          if (prevCmov != null) {
            // if this register was also defined in the taken branch, change
            // the previous cmov with a different 'False' Value
            CondMove.setFalseValue(prevCmov, temp.copy());
            notTakenMap.put(def.asRegister().getRegister(), prevCmov);
          } else {
            // create a new cmov instruction
            op = IRTools.getCondMoveOp(def.asRegister().getType());
            Instruction cmov =
                CondMove.create(
                    op,
                    def.asRegister(),
                    tempVal1.copy(),
                    tempVal2.copy(),
                    cond.copy().asCondition(),
                    def.copy(),
                    temp.copy());
            cb.insertBefore(cmov);
            notTakenMap.put(def.asRegister().getRegister(), cmov);
          }
        }
        s.remove();
      }
    }

    // Mutate the conditional branch into a GOTO.
    BranchOperand target = diamond.getBottom().makeJumpTarget();
    Goto.mutate(cb, GOTO, target);

    // Delete a potential GOTO after cb.
    Instruction next = cb.nextInstructionInCodeOrder();
    if (next.operator != BBEND) {
      next.remove();
    }

    // Recompute the CFG.
    diamond.getTop().recomputeNormalOut(ir); // fix the CFG
  }