/** * 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); } }