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