use of org.jikesrvm.compilers.opt.ir.Register in project JikesRVM by JikesRVM.
the class SpillLocationManager method getSpillPreference.
/**
* Given the current state of the register allocator, compute the
* available spill location to which ci has the highest preference.
*
* @param ci the interval to spill
* @param spillSize the size of spill location needed
* @param type the physical register's type
* @return the interval to spill to. null if no preference found.
*/
SpillLocationInterval getSpillPreference(CompoundInterval ci, int spillSize, int type) {
// a mapping from SpillLocationInterval to Integer
// (spill location to weight);
HashMap<SpillLocationInterval, Integer> map = new HashMap<SpillLocationInterval, Integer>();
Register r = ci.getRegister();
CoalesceGraph graph = ir.stackManager.getPreferences().getGraph();
SpaceEffGraphNode node = graph.findNode(r);
// Return null if no affinities.
if (node == null)
return null;
RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState;
// location affinity
for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements(); ) {
CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement();
CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from();
Register neighbor = src.getRegister();
if (neighbor.isSymbolic() && neighbor.isSpilled()) {
int spillOffset = regAllocState.getSpill(neighbor);
// if this is a candidate interval, update its weight
for (SpillLocationInterval s : freeIntervals) {
if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) {
int w = edge.getWeight();
Integer oldW = map.get(s);
if (oldW == null) {
map.put(s, w);
} else {
map.put(s, oldW + w);
}
break;
}
}
}
}
// location affinity
for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements(); ) {
CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement();
CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to();
Register neighbor = dest.getRegister();
if (neighbor.isSymbolic() && neighbor.isSpilled()) {
int spillOffset = regAllocState.getSpill(neighbor);
// if this is a candidate interval, update its weight
for (SpillLocationInterval s : freeIntervals) {
if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) {
int w = edge.getWeight();
Integer oldW = map.get(s);
if (oldW == null) {
map.put(s, w);
} else {
map.put(s, oldW + w);
}
break;
}
}
}
}
// OK, now find the highest preference.
SpillLocationInterval result = null;
int weight = -1;
for (Map.Entry<SpillLocationInterval, Integer> entry : map.entrySet()) {
int w = entry.getValue();
if (w > weight) {
weight = w;
result = entry.getKey();
}
}
return result;
}
use of org.jikesrvm.compilers.opt.ir.Register in project JikesRVM by JikesRVM.
the class UpdateGCMaps1 method perform.
/**
* Iterate over the IR-based GC map collection and for each entry
* replace the symbolic reg with the real reg or spill it was allocated
* @param ir the IR
*/
@Override
public void perform(IR ir) {
RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState;
for (GCIRMapElement GCelement : ir.MIRInfo.gcIRMap) {
if (LinearScan.GC_DEBUG) {
VM.sysWrite("GCelement " + GCelement);
}
for (RegSpillListElement elem : GCelement.regSpillList()) {
Register symbolic = elem.getSymbolicReg();
if (LinearScan.GC_DEBUG) {
VM.sysWriteln("get location for " + symbolic);
}
if (symbolic.isAllocated()) {
Register ra = regAllocState.getMapping(symbolic);
elem.setRealReg(ra);
if (LinearScan.GC_DEBUG) {
VM.sysWriteln(ra.toString());
}
} else if (symbolic.isSpilled()) {
int spill = ir.MIRInfo.regAllocState.getSpill(symbolic);
elem.setSpill(spill);
if (LinearScan.GC_DEBUG) {
VM.sysWriteln(Integer.toString(spill));
}
} else {
OptimizingCompilerException.UNREACHABLE("LinearScan", "register not alive:", symbolic.toString());
}
}
}
}
use of org.jikesrvm.compilers.opt.ir.Register in project JikesRVM by JikesRVM.
the class UpdateGCMaps2 method perform.
/**
* @param ir the IR
*/
@Override
public void perform(IR ir) {
GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
ScratchMap scratchMap = ir.stackManager.getScratchMap();
RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState;
if (LinearScan.GC_DEBUG) {
System.out.println("SCRATCH MAP:");
System.out.println();
System.out.println(scratchMap);
}
if (scratchMap.isEmpty())
return;
// Walk over each instruction that has a GC point.
for (GCIRMapElement GCelement : ir.MIRInfo.gcIRMap) {
// new elements to add to the gc map
HashSet<RegSpillListElement> newElements = new HashSet<RegSpillListElement>();
Instruction GCinst = GCelement.getInstruction();
int dfn = regAllocState.getDFN(GCinst);
if (LinearScan.GC_DEBUG) {
VM.sysWrite("GCelement at " + dfn + " , " + GCelement);
}
// a set of elements to delete from the GC Map
HashSet<RegSpillListElement> toDelete = new HashSet<RegSpillListElement>(3);
// For each element in the GC Map ...
for (RegSpillListElement elem : GCelement.regSpillList()) {
if (LinearScan.GC_DEBUG) {
VM.sysWriteln("Update " + elem);
}
if (elem.isSpill()) {
// check if the spilled value currently is cached in a scratch
// register
Register r = elem.getSymbolicReg();
Register scratch = scratchMap.getScratch(r, dfn);
if (scratch != null) {
if (LinearScan.GC_DEBUG) {
VM.sysWriteln("cached in scratch register " + scratch);
}
// we will add a new element noting that the scratch register
// also must be including in the GC map
RegSpillListElement newElem = new RegSpillListElement(r);
newElem.setRealReg(scratch);
newElements.add(newElem);
// valid value
if (scratchMap.isDirty(GCinst, r)) {
toDelete.add(elem);
}
}
} else {
// check if the physical register is currently spilled.
int n = elem.getRealRegNumber();
Register r = phys.get(n);
if (scratchMap.isScratch(r, dfn)) {
// spilled.
if (LinearScan.GC_DEBUG) {
VM.sysWriteln("CHANGE to spill location " + regAllocState.getSpill(r));
}
elem.setSpill(regAllocState.getSpill(r));
}
}
}
// delete all obsolete elements
for (RegSpillListElement deadElem : toDelete) {
GCelement.deleteRegSpillElement(deadElem);
}
// add each new Element to the gc map
for (RegSpillListElement newElem : newElements) {
GCelement.addRegSpillElement(newElem);
}
}
}
use of org.jikesrvm.compilers.opt.ir.Register in project JikesRVM by JikesRVM.
the class CallingConvention method expandPrologue.
private static void expandPrologue(IR ir) {
boolean useDU = ir.options.getOptLevel() >= 1;
if (useDU) {
// set up register lists for dead code elimination.
DefUse.computeDU(ir);
}
Instruction p = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder();
if (VM.VerifyAssertions)
VM._assert(p.operator() == IR_PROLOGUE);
Instruction start = p.nextInstructionInCodeOrder();
PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet().asIA32();
int gprIndex = 0;
int fprIndex = 0;
int paramByteOffset = ir.incomingParameterBytes() + 2 * WORDSIZE;
// count the number of FPR params in a pre-pass
int FPRRegisterParams = countFPRParamsInPrologue(p);
FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
ir.MIRInfo.fpStackHeight = Math.max(ir.MIRInfo.fpStackHeight, FPRRegisterParams);
// deal with each parameter
for (Enumeration<Operand> e = p.getDefs(); e.hasMoreElements(); ) {
RegisterOperand symbOp = (RegisterOperand) e.nextElement();
TypeReference rType = symbOp.getType();
if (rType.isFloatingPointType()) {
int size;
if (rType.isFloatType()) {
size = BYTES_IN_FLOAT;
paramByteOffset -= WORDSIZE;
} else {
size = BYTES_IN_DOUBLE;
paramByteOffset -= 2 * WORDSIZE;
}
// if optimizing, only define the register if it has uses
if (!useDU || symbOp.getRegister().useList != null) {
if (fprIndex < PhysicalRegisterSet.getNumberOfFPRParams()) {
// the 2nd goes in F(k-2), etc...
if (SSE2_FULL) {
Register param = phys.getFPRParam(fprIndex);
if (rType.isFloatType()) {
start.insertBefore(MIR_Move.create(IA32_MOVSS, symbOp.copyRO(), F(param)));
} else {
start.insertBefore(MIR_Move.create(IA32_MOVSD, symbOp.copyRO(), D(param)));
}
} else {
Register param = phys.getFPRParam(FPRRegisterParams - fprIndex - 1);
start.insertBefore(MIR_Move.create(IA32_FMOV, symbOp.copyRO(), D(param)));
}
} else {
Operand M = new StackLocationOperand(true, paramByteOffset, size);
if (SSE2_FULL) {
if (rType.isFloatType()) {
start.insertBefore(MIR_Move.create(IA32_MOVSS, symbOp.copyRO(), M));
} else {
start.insertBefore(MIR_Move.create(IA32_MOVSD, symbOp.copyRO(), M));
}
} else {
start.insertBefore(MIR_Move.create(IA32_FMOV, symbOp.copyRO(), M));
}
}
}
fprIndex++;
} else {
// if optimizing, only define the register if it has uses
paramByteOffset -= WORDSIZE;
if (paramIsNativeLongOn64Bit(symbOp)) {
paramByteOffset -= WORDSIZE;
}
if (!useDU || symbOp.getRegister().useList != null) {
// t is object, 1/2 of a long, int, short, char, byte, or boolean
if (gprIndex < PhysicalRegisterSet.getNumberOfGPRParams()) {
// to give the register allocator more freedom, we
// insert two move instructions to get the physical into
// the symbolic. First a move from the physical to a fresh temp
// before start and second a move from the temp to the
// 'real' parameter symbolic after start.
RegisterOperand tmp = ir.regpool.makeTemp(rType);
Register param = phys.getGPRParam(gprIndex);
RegisterOperand pOp = new RegisterOperand(param, rType);
start.insertBefore(PhysicalRegisterTools.makeMoveInstruction(tmp, pOp));
Instruction m2 = PhysicalRegisterTools.makeMoveInstruction(symbOp.copyRO(), tmp.copyD2U());
start.insertBefore(m2);
start = m2;
} else {
int stackLocSize = WORDSIZE;
if (VM.BuildFor64Addr && rType.getMemoryBytes() <= BYTES_IN_INT) {
stackLocSize = BYTES_IN_INT;
}
Operand M = new StackLocationOperand(true, paramByteOffset, stackLocSize);
start.insertBefore(MIR_Move.create(IA32_MOV, symbOp.copyRO(), M));
}
}
gprIndex++;
}
}
if (VM.VerifyAssertions && paramByteOffset != 2 * WORDSIZE) {
String msg = "pb = " + paramByteOffset + "; expected " + 2 * WORDSIZE;
VM._assert(VM.NOT_REACHED, msg);
}
removeDefsFromPrologue(p);
}
use of org.jikesrvm.compilers.opt.ir.Register in project JikesRVM by JikesRVM.
the class CallingConvention method expandParametersToSysCall.
/**
* Explicitly copy parameters to a system call into the appropriate physical
* registers as defined by the calling convention. Note that for a system
* call (ie., a call to C), the order of parameters on the stack is
* <em> reversed </em> compared to the normal RVM calling convention<p>
*
* Note: Assumes that ESP points to the word before the slot where the
* first parameter should be stored.<p>
*
* TODO: much of this code is exactly the same as in expandParametersToCall().
* factor out the common code.
*
* @param call the call instruction
* @param ir the IR that contains the call
* @return the number of bytes necessary to hold the parameters
*/
private static int expandParametersToSysCall(Instruction call, IR ir) {
int nGPRParams = 0;
int nFPRParams = 0;
int parameterBytes = 0;
int numParams = MIR_Call.getNumberOfParams(call);
if (VM.BuildFor32Addr) {
// NOTE: All params to syscall are passed on the stack!
for (int i = numParams - 1; i >= 0; i--) {
Operand param = MIR_Call.getClearParam(call, i);
MIR_Call.setParam(call, i, null);
TypeReference paramType = param.getType();
if (paramType.isFloatingPointType()) {
nFPRParams++;
int size;
if (paramType.isFloatType()) {
size = BYTES_IN_FLOAT;
parameterBytes -= WORDSIZE;
} else {
size = BYTES_IN_DOUBLE;
parameterBytes -= 2 * WORDSIZE;
}
Operand M = new StackLocationOperand(false, parameterBytes, size);
if (SSE2_FULL) {
if (paramType.isFloatType()) {
call.insertBefore(MIR_Move.create(IA32_MOVSS, M, param));
} else {
call.insertBefore(MIR_Move.create(IA32_MOVSD, M, param));
}
} else {
call.insertBefore(MIR_Move.create(IA32_FMOV, M, param));
}
} else {
nGPRParams++;
parameterBytes -= WORDSIZE;
call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes + WORDSIZE)));
call.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, param));
}
}
return parameterBytes;
} else {
if (VM.VerifyAssertions)
VM._assert(SSE2_FULL, "x64 builds must have SSE2_FULL enabled");
PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet().asIA32();
// count the number FPR parameters in a pre-pass
int FPRRegisterParams = countFPRParams(call);
FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfNativeFPRParams());
// offset, in bytes, from the SP, for the next parameter slot on the
// stack
parameterBytes = -2 * WORDSIZE;
RegisterOperand fpCount = new RegisterOperand(phys.getEAX(), TypeReference.Int);
// Save count of vector parameters (= XMM) in EAX as defined by
// the ABI for varargs convention
call.insertBefore(MIR_Move.create(IA32_MOV, fpCount, IC(FPRRegisterParams)));
// Save volatiles to non-volatiles that are currently not used
call.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(phys.getGPR(R14), TypeReference.Long), new RegisterOperand(phys.getESI(), TypeReference.Long)));
call.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(phys.getGPR(R13), TypeReference.Long), new RegisterOperand(phys.getEDI(), TypeReference.Long)));
// Restore volatiles from non-volatiles
call.insertAfter(MIR_Move.create(IA32_MOV, new RegisterOperand(phys.getESI(), TypeReference.Long), new RegisterOperand(phys.getGPR(R14), TypeReference.Long)));
call.insertAfter(MIR_Move.create(IA32_MOV, new RegisterOperand(phys.getEDI(), TypeReference.Long), new RegisterOperand(phys.getGPR(R13), TypeReference.Long)));
if (VM.BuildFor64Addr) {
// Add a marker instruction. When processing x64 syscalls, the block of the syscall
// needs to be split up to copy the code for the call. Copying has to occur
// to be able to ensure stack alignment for the x64 ABI. This instruction
// marks the border for the copy: everything before this instruction isn't duplicated.
call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(MARKER)));
}
// Require ESP to be at bottom of frame before a call,
call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(0)));
// Determine if a parameter is in a register or not
boolean[] inRegister = new boolean[numParams];
nFPRParams = 0;
nGPRParams = 0;
for (int i = 0; i < numParams; i++) {
Operand param = MIR_Call.getParam(call, i);
TypeReference paramType = param.getType();
if (paramType.isFloatingPointType()) {
nFPRParams++;
inRegister[i] = nFPRParams <= PhysicalRegisterSet.getNumberOfNativeFPRParams();
} else {
nGPRParams++;
inRegister[i] = nGPRParams <= PhysicalRegisterSet.getNumberOfNativeGPRParams();
}
}
// Walk over non-register parameters from right-to-left and assign stack slots
int[] stackSlot = new int[numParams];
for (int i = numParams - 1; i >= 0; i--) {
if (!inRegister[i]) {
parameterBytes -= BYTES_IN_STACKSLOT;
stackSlot[i] = parameterBytes;
}
}
// Pass stack slot parameters from right-to-left
for (int i = numParams - 1; i >= 0; i--) {
if (!inRegister[i]) {
Operand param = MIR_Call.getClearParam(call, i);
TypeReference paramType = param.getType();
if (paramType.isFloatingPointType()) {
// pass the FP parameter on the stack
Operand M = new StackLocationOperand(false, stackSlot[i], BYTES_IN_STACKSLOT);
if (paramType.isFloatType()) {
call.insertBefore(MIR_Move.create(IA32_MOVSS, M, param));
} else {
call.insertBefore(MIR_Move.create(IA32_MOVSD, M, param));
}
} else {
// Write the parameter into the appropriate stack frame location.
call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(stackSlot[i] + BYTES_IN_STACKSLOT)));
call.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, param));
}
}
}
// Pass register parameters from left-to-right
int nParamsInRegisters = 0;
nFPRParams = 0;
nGPRParams = 0;
for (int i = 0; i < numParams; i++) {
if (inRegister[i]) {
Operand param = MIR_Call.getClearParam(call, i);
TypeReference paramType = param.getType();
if (paramType.isFloatingPointType()) {
// Pass the parameter in a register.
RegisterOperand real = new RegisterOperand(phys.getNativeFPRParam(nFPRParams), paramType);
nFPRParams++;
if (paramType.isFloatType()) {
call.insertBefore(MIR_Move.create(IA32_MOVSS, real, param));
} else {
call.insertBefore(MIR_Move.create(IA32_MOVSD, real, param));
}
// Record that the call now has a use of the real register.
MIR_Call.setParam(call, nParamsInRegisters++, real.copy());
} else {
Register phy = phys.getNativeGPRParam(nGPRParams);
nGPRParams++;
RegisterOperand real = new RegisterOperand(phy, paramType);
call.insertBefore(MIR_Move.create(IA32_MOV, real, param));
// Record that the call now has a use of the real register.
MIR_Call.setParam(call, nParamsInRegisters++, real.copy());
}
}
}
return parameterBytes;
}
}
Aggregations