use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class LoadElimination method getCandidates.
/**
* Do a quick pass over the IR, and return types that are candidates
* for redundant load elimination.<p>
*
* Algorithm: return those types T where
* <ul>
* <li>there's a load L(i) of type T
* <li>there's another load or store M(j) of type T, M!=L and V(i) == V(j)
* </ul>
* <p>
* The result contains objects of type RVMField and TypeReference, whose
* narrowest common ancestor is Object.
*
* @param ir the governing IR
*
* @return the types that are candidates for redundant load elimination
*/
@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 (Enumeration<Instruction> e = bb.forwardInstrEnumerator(); e.hasMoreElements(); ) {
Instruction s = e.nextElement();
switch(s.getOpcode()) {
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;
}
}
}
}
// 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;
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class LoadElimination method replaceLoads.
/**
* 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
* @return mapping from heap variables to value numbers
*/
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) {
// 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) {
// nothing available
continue;
}
// .. 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) {
// nothing available
continue;
}
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;
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class LoopVersioning method generatePhiNodes.
/**
* Generate into a new block phi nodes that define the original
* register defined by the loop and use two newly created
* registers.
* @param loop the loop to process
* @param registers - vector to which defined registers need to be
* created registers.x used in creating phi nodes
* @param types - vector of corresponding types of registers.
* @param phiInstructions - created phi instructions
* @param subOptimalRegMap - mapping of orignal destination to the
* newly created destination for the unoptimized loop
* @param optimalRegMap - mapping of orignal destination to the
* newly created destination for the optimized loop
*/
private void generatePhiNodes(AnnotatedLSTNode loop, ArrayList<Register> registers, ArrayList<TypeReference> types, ArrayList<Instruction> phiInstructions, HashMap<Register, Register> subOptimalRegMap, HashMap<Register, Register> optimalRegMap) {
// Get the carried loop iterator's register
Register carriedLoopIteratorRegister = ((RegisterOperand) loop.getCarriedLoopIterator()).getRegister();
for (int i = 0; i < registers.size(); i++) {
Register register = registers.get(i);
TypeReference type = types.get(i);
Instruction phi = Phi.create(PHI, new RegisterOperand(register, type), 2);
phi.setBytecodeIndex(SYNTH_LOOP_VERSIONING_BCI);
// new operand for optimized loop
Operand op0 = ir.regpool.makeTemp(type);
Phi.setValue(phi, OPTIMIZED_LOOP_OPERAND, op0);
optimalRegMap.put(register, op0.asRegister().getRegister());
// new operand for unoptimized loop
Operand op1 = ir.regpool.makeTemp(type);
Phi.setValue(phi, UNOPTIMIZED_LOOP_OPERAND, op1);
subOptimalRegMap.put(register, op1.asRegister().getRegister());
// internal set to mark the optimized loops
if (register == carriedLoopIteratorRegister) {
setOptimizedLoop(op0.asRegister().getRegister());
setOptimizedLoop(op1.asRegister().getRegister());
}
phiInstructions.add(phi);
}
// rename any optimized inner loops registers
renameOptimizedLoops(subOptimalRegMap, optimalRegMap);
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class LoopVersioning method findLoopToOptimise.
// -oO Optimisation routines Oo-
/**
* Find an outermost loop to optimise and optimise it. Focus on
* annotated regular loops, LICM should handle possible
* optimisation for the non-regular loops
*
* @param loop Loop to search
* @return was optimisation performed
*/
private boolean findLoopToOptimise(AnnotatedLSTNode loop) {
// Has this loop already been optimised?
Operand carriedLoopIterator = loop.getCarriedLoopIterator();
if ((carriedLoopIterator instanceof RegisterOperand) && (isOptimizedLoop(carriedLoopIterator.asRegister().getRegister()))) {
return false;
}
// Process inner loops first
Enumeration<GraphNode> innerLoops = loop.outNodes();
// Iterate over loops
while (innerLoops.hasMoreElements()) {
AnnotatedLSTNode nestedLoop = (AnnotatedLSTNode) innerLoops.nextElement();
// Try to optimise inner loops first
if (findLoopToOptimise(nestedLoop)) {
// Exit early if inner loop optimisation succeeded
return true;
}
}
// Don't try to optimise irregular loops
if (loop.isNonRegularLoop()) {
return false;
}
if (DEBUG) {
report("LoopFissionOfArrayGuards: found loop in " + ir.getMethod());
VM.sysWriteln("dominator tree:");
VM.sysWriteln(ir.HIRInfo.dominatorTree.toString());
}
// 1) Determine the bound and null checks to be eliminated. The
// bound checks are the ones that operate on the loop iterator. If
// no checks can be eliminated, stop optimising this loop.
ArrayList<Instruction> checksToEliminate = new ArrayList<Instruction>();
getListOfChecksToEliminate(loop, checksToEliminate);
if (checksToEliminate.isEmpty()) {
return false;
} else {
// We found instructions to eliminate
if (DEBUG) {
VM.sysWriteln("Loop being optimised:");
VM.sysWriteln(loop.toString());
VM.sysWriteln("Checks to eliminate:");
for (Instruction instruction : checksToEliminate) {
VM.sysWriteln(instruction.toString());
}
}
// 2) Determine the registers defined in the loop.
ArrayList<Register> registersDefinedInOriginalLoop = new ArrayList<Register>();
ArrayList<TypeReference> typesOfRegistersDefinedInOriginalLoop = new ArrayList<TypeReference>();
ArrayList<Instruction> definingInstructionsInOriginalLoop = new ArrayList<Instruction>();
getRegistersDefinedInLoop(loop, registersDefinedInOriginalLoop, typesOfRegistersDefinedInOriginalLoop, definingInstructionsInOriginalLoop);
if (DEBUG) {
VM.sysWrite("Registers in original loop:\n{");
for (int i = 0; i < registersDefinedInOriginalLoop.size(); i++) {
VM.sysWrite(registersDefinedInOriginalLoop.get(i).toString());
if (definingInstructionsInOriginalLoop.get(i) != null) {
VM.sysWrite("(escapes),");
} else {
VM.sysWrite(",");
}
}
VM.sysWriteln("}");
}
// 3) Generate phi nodes that define the original register
// defined by the loop and use two newly created registers.
ArrayList<Instruction> phiInstructions = new ArrayList<Instruction>();
HashMap<Register, Register> subOptimalRegMap = new HashMap<Register, Register>();
HashMap<Register, Register> optimalRegMap = new HashMap<Register, Register>();
generatePhiNodes(loop, registersDefinedInOriginalLoop, typesOfRegistersDefinedInOriginalLoop, phiInstructions, subOptimalRegMap, optimalRegMap);
if (DEBUG) {
VM.sysWriteln("subOptimalRegMap");
VM.sysWriteln(subOptimalRegMap.toString());
VM.sysWriteln("optimalRegMap");
VM.sysWriteln(optimalRegMap.toString());
}
// 4) Create a version of the original loop that uses the first of
// the newly created registers instead of the original
// registers.
HashMap<Register, BasicBlock> regToUnoptimizedBlockMap = new HashMap<Register, BasicBlock>();
HashMap<BasicBlock, BasicBlock> unoptimizedLoopMap = createCloneLoop(loop, subOptimalRegMap, regToUnoptimizedBlockMap);
if (DEBUG) {
VM.sysWriteln("subOptimalLoopMap");
VM.sysWriteln(unoptimizedLoopMap.toString());
}
// 5) Create a second version, this time with the result of the
// eliminated checks set to explicit test guards.
HashMap<Register, BasicBlock> regToOptimizedBlockMap = new HashMap<Register, BasicBlock>();
HashMap<BasicBlock, BasicBlock> optimizedLoopMap = createOptimizedLoop(loop, optimalRegMap, checksToEliminate, regToOptimizedBlockMap);
if (DEBUG) {
VM.sysWriteln("optimalLoopMap");
VM.sysWriteln(optimizedLoopMap.toString());
}
// 6) Work out what the maximum value for all the bounds checks
// are and create branches to optimal or suboptimal loops - with
// the unoptimized loop possibly being unreachable
BasicBlock firstBranchBlock = loop.header.createSubBlock(SYNTH_LOOP_VERSIONING_BCI, ir);
BasicBlock temp = (BasicBlock) loop.header.prev;
ir.cfg.breakCodeOrder(temp, loop.header);
ir.cfg.linkInCodeOrder(temp, firstBranchBlock);
ir.cfg.linkInCodeOrder(firstBranchBlock, loop.header);
temp.redirectOuts(loop.header, firstBranchBlock, ir);
boolean isUnoptimizedLoopReachable = createBranchBlocks(loop, firstBranchBlock, checksToEliminate, unoptimizedLoopMap.get(loop.predecessor), optimizedLoopMap.get(loop.predecessor), optimalRegMap);
// 7) Fix up the phi node predecessors
fixUpPhiPredecessors(phiInstructions, isUnoptimizedLoopReachable ? unoptimizedLoopMap.get(loop.exit) : null, optimizedLoopMap.get(loop.exit));
// 8) Remove the unoptimized loop if its redundant
if (!isUnoptimizedLoopReachable) {
removeUnoptimizedLoop(loop, unoptimizedLoopMap);
}
// 9) Replace register definitions in the original
// loop with phi instructions
modifyOriginalLoop(loop, phiInstructions, definingInstructionsInOriginalLoop, subOptimalRegMap, optimalRegMap);
// 10) Compact node numbering so that CFG number of nodes
// reflects that some basic blocks may have been deleted
ir.cfg.compactNodeNumbering();
return true;
}
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class RewriteMemoryOperandsWithOversizedDisplacements method disp64MemOperandConversion.
private static void disp64MemOperandConversion(IR ir, Instruction inst, MemoryOperand mo) {
if (!mo.disp.isZero() && !Bits.fits(mo.disp, 32)) {
RegisterOperand effectiveAddress = ir.regpool.makeTempLong();
RegisterOperand temp = null;
inst.insertBefore(MIR_Move.create(IMMQ_MOV, effectiveAddress, LC(mo.disp.toLong())));
if (mo.index != null) {
if (mo.scale != 0) {
temp = ir.regpool.makeTempLong();
TypeReference indexType = mo.index.getType();
if (indexType.isLongType() || indexType.isWordLikeType()) {
inst.insertBefore(MIR_Move.create(IA32_MOV, temp, mo.index.copy()));
} else if (indexType.isIntType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXDQ, temp, mo.index.copy()));
} else if (indexType.isByteType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__B, temp, mo.index.copy()));
} else if (indexType.isShortType() || indexType.isCharType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__W, temp, mo.index.copy()));
} else {
String msg = "Unhandled type: " + indexType;
if (VM.VerifyAssertions)
VM._assert(VM.NOT_REACHED, msg);
}
inst.insertBefore(MIR_BinaryAcc.create(IA32_SHL, temp.copy(), IC(mo.scale)));
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), temp.copy()));
} else {
TypeReference indexType = mo.index.getType();
if (indexType.isLongType() || indexType.isWordLikeType()) {
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), mo.index.copy()));
} else {
temp = ir.regpool.makeTempLong();
if (indexType.isIntType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXDQ, temp, mo.index.copy()));
} else if (indexType.isByteType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__B, temp, mo.index.copy()));
} else if (indexType.isShortType() || indexType.isCharType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__W, temp, mo.index.copy()));
} else {
String msg = "Unhandled type: " + indexType;
if (VM.VerifyAssertions)
VM._assert(VM.NOT_REACHED, msg);
}
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), temp.copy()));
}
}
}
if (mo.base != null) {
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), mo.base.copy()));
}
MemoryOperand newMo = MemoryOperand.I(effectiveAddress.copy().asRegister(), mo.size, null != mo.loc ? (LocationOperand) mo.loc.copy() : null, mo.guard != null ? mo.guard.copy() : null);
inst.replaceOperand(mo, newMo);
}
}
Aggregations