/**
  * Update the value graph to account for a given instruction.
  *
  * @param s the instruction in question
  */
 private void processInstruction(Instruction s) {
   // TODO: support all necessary types of instructions
   if (s.isDynamicLinkingPoint()) {
     processCall(s);
   } else if (Move.conforms(s)) {
     processMove(s);
   } else if (s.operator == PI) {
     processPi(s);
   } else if (New.conforms(s)) {
     processNew(s);
   } else if (NewArray.conforms(s)) {
     processNewArray(s);
   } else if (Unary.conforms(s)) {
     processUnary(s);
   } else if (GuardedUnary.conforms(s)) {
     processGuardedUnary(s);
   } else if (NullCheck.conforms(s)) {
     processNullCheck(s);
   } else if (ZeroCheck.conforms(s)) {
     processZeroCheck(s);
   } else if (Binary.conforms(s)) {
     processBinary(s);
   } else if (GuardedBinary.conforms(s)) {
     processGuardedBinary(s);
   } else if (InlineGuard.conforms(s)) {
     processInlineGuard(s);
   } else if (IfCmp.conforms(s)) {
     processIfCmp(s);
   } else if (Call.conforms(s)) {
     processCall(s);
   } else if (MonitorOp.conforms(s)) {
     processCall(s);
   } else if (Prepare.conforms(s)) {
     processCall(s);
   } else if (Attempt.conforms(s)) {
     processCall(s);
   } else if (CacheOp.conforms(s)) {
     processCall(s);
   } else if (ALoad.conforms(s)) {
     processALoad(s);
   } else if (PutField.conforms(s)) {
     processPutField(s);
   } else if (PutStatic.conforms(s)) {
     processPutStatic(s);
   } else if (AStore.conforms(s)) {
     processAStore(s);
   } else if (Phi.conforms(s)) {
     processPhi(s);
   } else if (s.operator() == IR_PROLOGUE) {
     processPrologue(s);
   }
 }
  /**
   * Do a quick pass over the IR, and return types that are candidates for redundant load
   * elimination. Algorithm: return those types T where 1) there's a load L(i) of type T 2) there's
   * another load or store M(j) of type T, M!=L and V(i) == V(j)
   *
   * <p>The result contains objects of type RVMField and TypeReference, whose narrowest common
   * ancestor is Object.
   */
  @SuppressWarnings("unchecked")
  public static HashSet<Object> getCandidates(IR ir) {
    GlobalValueNumberState valueNumbers = ir.HIRInfo.valueNumbers;
    // which types have we seen loads for?
    HashSet<Object> seenLoad = new HashSet<Object>(10);
    // which static fields have we seen stores for?
    HashSet<RVMField> seenStore = new HashSet<RVMField>(10);
    HashSet<Object> resultSet = new HashSet<Object>(10);
    HashSet<FieldReference> forbidden = new HashSet<FieldReference>(10);
    // for each type T, indices(T) gives the set of value number (pairs)
    // that identify the indices seen in memory accesses to type T.
    HashMap indices = new HashMap(10);

    for (Enumeration be = ir.getBasicBlocks(); be.hasMoreElements(); ) {
      BasicBlock bb = (BasicBlock) be.nextElement();
      if (!ir.options.FREQ_FOCUS_EFFORT || !bb.getInfrequent()) {
        for (InstructionEnumeration e = bb.forwardInstrEnumerator(); e.hasMoreElements(); ) {
          Instruction s = e.next();
          switch (s.operator().opcode) {
            case GETFIELD_opcode:
              {
                Operand ref = GetField.getRef(s);
                FieldReference fr = GetField.getLocation(s).getFieldRef();
                RVMField f = fr.peekResolvedField();
                if (f == null) {
                  forbidden.add(fr);
                } else {
                  HashSet<Integer> numbers = findOrCreateIndexSet(indices, f);
                  int v = valueNumbers.getValueNumber(ref);
                  Integer V = v;
                  if (numbers.contains(V)) {
                    resultSet.add(f);
                  } else {
                    numbers.add(V);
                  }
                  seenLoad.add(f);
                }
              }
              break;
            case PUTFIELD_opcode:
              {
                Operand ref = PutField.getRef(s);
                FieldReference fr = PutField.getLocation(s).getFieldRef();
                RVMField f = fr.peekResolvedField();
                if (f == null) {
                  forbidden.add(fr);
                } else {
                  HashSet<Integer> numbers = findOrCreateIndexSet(indices, f);
                  int v = valueNumbers.getValueNumber(ref);
                  Integer V = v;
                  if (numbers.contains(V)) {
                    if (seenLoad.contains(f)) {
                      resultSet.add(f);
                    }
                  } else {
                    numbers.add(V);
                  }
                }
              }
              break;
            case GETSTATIC_opcode:
              {
                FieldReference fr = GetStatic.getLocation(s).getFieldRef();
                RVMField f = fr.peekResolvedField();
                if (f == null) {
                  forbidden.add(fr);
                } else {
                  if (seenLoad.contains(f) || seenStore.contains(f)) {
                    resultSet.add(f);
                  }
                  seenLoad.add(f);
                }
              }
              break;
            case PUTSTATIC_opcode:
              {
                FieldReference fr = PutStatic.getLocation(s).getFieldRef();
                RVMField f = fr.peekResolvedField();
                if (f == null) {
                  forbidden.add(fr);
                } else {
                  if (seenLoad.contains(f)) {
                    resultSet.add(f);
                  }
                  seenStore.add(f);
                }
              }
              break;
            case INT_ALOAD_opcode:
            case LONG_ALOAD_opcode:
            case FLOAT_ALOAD_opcode:
            case DOUBLE_ALOAD_opcode:
            case REF_ALOAD_opcode:
            case BYTE_ALOAD_opcode:
            case UBYTE_ALOAD_opcode:
            case USHORT_ALOAD_opcode:
            case SHORT_ALOAD_opcode:
              {
                Operand ref = ALoad.getArray(s);
                TypeReference type = ref.getType();
                if (type.isArrayType()) {
                  if (!type.getArrayElementType().isPrimitiveType()) {
                    type = TypeReference.JavaLangObjectArray;
                  }
                }
                Operand index = ALoad.getIndex(s);

                HashSet<ValueNumberPair> numbers = findOrCreateIndexSet(indices, type);
                int v1 = valueNumbers.getValueNumber(ref);
                int v2 = valueNumbers.getValueNumber(index);
                ValueNumberPair V = new ValueNumberPair(v1, v2);
                if (numbers.contains(V)) {
                  resultSet.add(type);
                } else {
                  numbers.add(V);
                }
                seenLoad.add(type);
              }

              break;

            case INT_ASTORE_opcode:
            case LONG_ASTORE_opcode:
            case FLOAT_ASTORE_opcode:
            case DOUBLE_ASTORE_opcode:
            case REF_ASTORE_opcode:
            case BYTE_ASTORE_opcode:
            case SHORT_ASTORE_opcode:
              {
                Operand ref = AStore.getArray(s);
                TypeReference type = ref.getType();
                if (type.isArrayType()) {
                  if (!type.getArrayElementType().isPrimitiveType()) {
                    type = TypeReference.JavaLangObjectArray;
                  }
                }
                Operand index = AStore.getIndex(s);

                HashSet<ValueNumberPair> numbers = findOrCreateIndexSet(indices, type);
                int v1 = valueNumbers.getValueNumber(ref);
                int v2 = valueNumbers.getValueNumber(index);
                ValueNumberPair V = new ValueNumberPair(v1, v2);

                if (numbers.contains(V)) {
                  if (seenLoad.contains(type)) {
                    resultSet.add(type);
                  }
                } else {
                  numbers.add(V);
                }
              }
              break;

            default:
              break;
          }
        }
      }
    }

    // If we have found an unresolved field reference, then conservatively
    // remove all fields that it might refer to from the resultSet.
    for (final FieldReference fieldReference : forbidden) {
      for (Iterator i2 = resultSet.iterator(); i2.hasNext(); ) {
        Object it = i2.next();
        if (it instanceof RVMField) {
          final RVMField field = (RVMField) it;
          if (!fieldReference.definitelyDifferent(field.getMemberRef().asFieldReference())) {
            i2.remove();
          }
        }
      }
    }

    return resultSet;
  }
 /**
  * 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);
       }
     }
   }
 }
 /**
  * Update the value graph to account for a given PUTFIELD instruction.
  *
  * <p><b>PRECONDITION:</b> <code> PutField.conforms(s); </code> Make sure we have value graph
  * nodes for a constant value
  *
  * @param s the instruction in question
  */
 private void processPutField(Instruction s) {
   Operand value = PutField.getValue(s);
   if (value.isConstant()) {
     findOrCreateVertex((ConstantOperand) value);
   }
 }