/**
  * Replace a Load instruction s with a load from a scalar register r TODO: factor this
  * functionality out elsewhere
  */
 static void replaceLoadWithMove(Register r, Instruction load) {
   RegisterOperand dest = ResultCarrier.getResult(load);
   RegisterOperand rop = new RegisterOperand(r, dest.getType());
   load.replace(Move.create(IRTools.getMoveOp(dest.getType()), dest, rop));
 }
 /**
  * Perform scalar replacement actions for a Def of a heap variable. NOTE: Even loads can def a
  * heap variable.
  *
  * @param UseRepSet stores the uses(loads) that have been eliminated
  * @param registers mapping from valueNumber -> temporary register
  */
 static void replaceDefs(IR ir, UseRecordSet UseRepSet, HashMap<UseRecord, Register> registers) {
   SSADictionary ssa = ir.HIRInfo.dictionary;
   for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) {
     Instruction s = e.nextElement();
     if (!GetField.conforms(s)
         && !GetStatic.conforms(s)
         && !PutField.conforms(s)
         && !PutStatic.conforms(s)
         && !ALoad.conforms(s)
         && !AStore.conforms(s)) {
       continue;
     }
     if (!ssa.defsHeapVariable(s)) {
       continue;
     }
     // this instruction is a DEF of heap variable H.
     // Check if UseRepSet needs the scalar assigned by this def
     HeapOperand<?>[] H = ssa.getHeapDefs(s);
     if (H.length != 1) {
       throw new OptimizingCompilerException(
           "LoadElimination: encountered a store with more than one def? " + s);
     }
     int valueNumber = -1;
     Object index = null;
     if (AStore.conforms(s)) {
       Object address = AStore.getArray(s);
       index = AStore.getIndex(s);
       valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
     } else if (GetField.conforms(s)) {
       Object address = GetField.getRef(s);
       valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
     } else if (PutField.conforms(s)) {
       Object address = PutField.getRef(s);
       valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
     } else if (GetStatic.conforms(s)) {
       valueNumber = 0;
     } else if (PutStatic.conforms(s)) {
       valueNumber = 0;
     } else if (ALoad.conforms(s)) {
       Object address = ALoad.getArray(s);
       valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
       index = ALoad.getIndex(s);
     }
     if (index == null) {
       // Load/Store
       if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), valueNumber)) {
         Operand value = null;
         if (PutField.conforms(s)) {
           value = PutField.getValue(s);
         } else if (PutStatic.conforms(s)) {
           value = PutStatic.getValue(s);
         } else if (GetField.conforms(s) || GetStatic.conforms(s)) {
           value = ResultCarrier.getResult(s);
         }
         TypeReference type = value.getType();
         Register r =
             findOrCreateRegister(H[0].getHeapType(), valueNumber, registers, ir.regpool, type);
         appendMove(r, value, s);
       }
     } else {
       // ALoad / AStore
       int v1 = valueNumber;
       int v2 = ir.HIRInfo.valueNumbers.getValueNumber(index);
       if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), v1, v2)) {
         Operand value = null;
         if (AStore.conforms(s)) {
           value = AStore.getValue(s);
         } else if (ALoad.conforms(s)) {
           value = ALoad.getResult(s);
         }
         TypeReference type = value.getType();
         Register r =
             findOrCreateRegister(H[0].getHeapType(), v1, v2, registers, ir.regpool, type);
         appendMove(r, value, s);
       }
     }
   }
 }
  /**
   * Walk over each instruction. If its a USE (load) of a heap variable and the value is available,
   * then replace the load with a move from a register.
   *
   * <p>POSTCONDITION: sets up the mapping 'registers' from value number to temporary register
   *
   * @param ir the IR
   * @param available information on which values are available
   * @param registers a place to store information about temp registers
   */
  static UseRecordSet replaceLoads(
      IR ir, DF_Solution available, HashMap<UseRecord, Register> registers) {
    UseRecordSet result = new UseRecordSet();
    SSADictionary ssa = ir.HIRInfo.dictionary;
    GlobalValueNumberState valueNumbers = ir.HIRInfo.valueNumbers;
    for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) {
      Instruction s = e.nextElement();
      if (!GetField.conforms(s) && !GetStatic.conforms(s) && !ALoad.conforms(s)) {
        continue;
      }
      // this instruction is a USE of heap variable H.
      // get the lattice cell that holds the available indices
      // for this heap variable
      HeapOperand<?>[] H = ssa.getHeapUses(s);
      if (H == null) {
        // this case can happen due to certain magics that insert
        // INT_LOAD instructions in HIR
        // TODO: clean up HIR representation of these magics
        continue;
      }
      if (H.length != 1) {
        throw new OptimizingCompilerException(
            "LoadElimination: load with wrong number of heap uses");
      }
      if (GetField.conforms(s) || GetStatic.conforms(s)) {
        int valueNumber = -1;
        if (GetField.conforms(s)) {
          Object address = GetField.getRef(s);
          valueNumber = valueNumbers.getValueNumber(address);
        } else {
          // for getStatic, always use the value number 0
          valueNumber = 0;
        }
        ObjectCell cell = (ObjectCell) available.lookup(H[0].getHeapVariable());
        if (cell == null) {
          continue; // nothing available
        }

        // .. if H{valueNumber} is available ...
        if (cell.contains(valueNumber)) {
          result.add(H[0].getHeapVariable(), valueNumber);
          TypeReference type = ResultCarrier.getResult(s).getType();
          Register r =
              findOrCreateRegister(H[0].getHeapType(), valueNumber, registers, ir.regpool, type);
          if (DEBUG) {
            System.out.println("ELIMINATING LOAD " + s);
          }
          replaceLoadWithMove(r, s);
        }
      } else { // ALoad.conforms(s)
        Object array = ALoad.getArray(s);
        Object index = ALoad.getIndex(s);
        ArrayCell cell = (ArrayCell) available.lookup(H[0].getHeapVariable());
        if (cell == null) {
          continue; // nothing available
        }
        int v1 = valueNumbers.getValueNumber(array);
        int v2 = valueNumbers.getValueNumber(index);
        // .. if H{<v1,v2>} is available ...
        if (cell.contains(v1, v2)) {
          result.add(H[0].getHeapVariable(), v1, v2);
          TypeReference type = ALoad.getResult(s).getType();
          Register r =
              findOrCreateRegister(
                  H[0].getHeapVariable().getHeapType(), v1, v2, registers, ir.regpool, type);
          if (DEBUG) {
            System.out.println("ELIMINATING LOAD " + s);
          }
          replaceLoadWithMove(r, s);
        }
      }
    }
    return result;
  }