use of org.jikesrvm.compilers.opt.ir.operand.MemoryOperand in project JikesRVM by JikesRVM.
the class CallingConvention method callExpand.
/**
* Expands the calling convention for a particular call instruction.
*
* @param call the call instruction
* @param ir the IR that contains the call instruction
*/
private static void callExpand(Instruction call, IR ir) {
boolean isSysCall = call.operator() == IA32_SYSCALL;
// 0. Handle the parameters
int parameterBytes = isSysCall ? expandParametersToSysCall(call, ir) : expandParametersToCall(call, ir);
// 1. Clear the floating-point stack if dirty.
if (!SSE2_FULL) {
if (!call.operator().isCallSaveVolatile()) {
int FPRRegisterParams = countFPRParams(call);
FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
call.insertBefore(MIR_UnaryNoRes.create(IA32_FCLEAR, IC(FPRRegisterParams)));
}
}
// 2. Move the return value into a register
expandResultOfCall(call, isSysCall, ir);
// in the processor object to hold the interface signature id.
if (VM.BuildForIMTInterfaceInvocation) {
if (MIR_Call.hasMethod(call)) {
MethodOperand mo = MIR_Call.getMethod(call);
if (mo.isInterface()) {
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(mo.getMemberRef());
MemoryOperand M = MemoryOperand.BD(ir.regpool.makeTROp(), ArchEntrypoints.hiddenSignatureIdField.getOffset(), (byte) WORDSIZE, null, null);
call.insertBefore(MIR_Move.create(IA32_MOV, M, IC(sig.getId())));
}
}
}
// 4. ESP must be parameterBytes before call, will be at either parameterBytes
// or 0 afterwards depending on whether or it is an RVM method or a sysCall.
Instruction requireESP = MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes));
call.insertBefore(requireESP);
Instruction adviseESP = MIR_UnaryNoRes.create(ADVISE_ESP, IC(isSysCall ? parameterBytes : 0));
call.insertAfter(adviseESP);
// by 16 at the call.
if (VM.BuildFor64Addr && isSysCall) {
alignStackForX64SysCall(call, ir, parameterBytes, requireESP, adviseESP);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.MemoryOperand in project JikesRVM by JikesRVM.
the class CallingConvention method expandResultOfCall.
/**
* Explicitly copy the result of a call instruction from the result
* register to the appropriate symbolic register,
* as defined by the calling convention.
*
* @param call the call instruction
* @param isSysCall whether the call is a SysCall
* @param ir the IR that contains the call
*/
private static void expandResultOfCall(Instruction call, boolean isSysCall, IR ir) {
PhysicalRegisterSet phys = (PhysicalRegisterSet) ir.regpool.getPhysicalRegisterSet();
// copy the first result parameter
if (MIR_Call.hasResult(call)) {
RegisterOperand result1 = MIR_Call.getClearResult(call);
if (result1.getType().isFloatType() || result1.getType().isDoubleType()) {
if (VM.BuildFor32Addr && SSE2_FULL && isSysCall) {
byte size = (byte) (result1.getType().isFloatType() ? 4 : 8);
RegisterOperand st0 = new RegisterOperand(phys.getST0(), result1.getType());
// result is in st0, set it to avoid extending the live range of st0
MIR_Call.setResult(call, st0);
RegisterOperand pr = ir.regpool.makeTROp();
MemoryOperand scratch = new MemoryOperand(pr, null, (byte) 0, Entrypoints.scratchStorageField.getOffset(), size, new LocationOperand(Entrypoints.scratchStorageField), null);
Instruction pop = MIR_Move.create(IA32_FSTP, scratch, st0.copyRO());
call.insertAfter(pop);
if (result1.getType().isFloatType()) {
pop.insertAfter(MIR_Move.create(IA32_MOVSS, result1, scratch.copy()));
} else {
if (VM.VerifyAssertions)
VM._assert(result1.getType().isDoubleType());
pop.insertAfter(MIR_Move.create(IA32_MOVSD, result1, scratch.copy()));
}
} else {
Register r = phys.getReturnFPR();
RegisterOperand physical = new RegisterOperand(r, result1.getType());
// result is in physical, set it to avoid extending its live range
MIR_Call.setResult(call, physical.copyRO());
Instruction tmp;
if (SSE2_FULL) {
if (result1.getType().isFloatType()) {
tmp = MIR_Move.create(IA32_MOVSS, result1, physical);
} else {
tmp = MIR_Move.create(IA32_MOVSD, result1, physical);
}
} else {
tmp = MIR_Move.create(IA32_FMOV, result1, physical);
}
call.insertAfter(tmp);
}
} else {
// first GPR result register
Register r = phys.getFirstReturnGPR();
RegisterOperand physical = new RegisterOperand(r, result1.getType());
Instruction tmp = MIR_Move.create(IA32_MOV, result1, physical);
call.insertAfter(tmp);
// result is in physical, set it to avoid extending its live range
MIR_Call.setResult(call, physical.copyRO());
}
}
// copy the second result parameter
if (MIR_Call.hasResult2(call)) {
if (VM.VerifyAssertions)
VM._assert(VM.BuildFor32Addr);
RegisterOperand result2 = MIR_Call.getClearResult2(call);
// second GPR result register
Register r = phys.getSecondReturnGPR();
RegisterOperand physical = new RegisterOperand(r, result2.getType());
Instruction tmp = MIR_Move.create(IA32_MOV, result2, physical);
call.insertAfter(tmp);
// result is in physical, set it to avoid extending its live range
MIR_Call.setResult2(call, physical.copyRO());
}
}
use of org.jikesrvm.compilers.opt.ir.operand.MemoryOperand in project JikesRVM by JikesRVM.
the class BlockCountSpillCost method calculate.
@Override
void calculate(IR ir) {
final double moveFactor = ir.options.REGALLOC_SIMPLE_SPILL_COST_MOVE_FACTOR;
final double memoryOperandFactor = ir.options.REGALLOC_SIMPLE_SPILL_COST_MEMORY_OPERAND_FACTOR;
for (Enumeration<BasicBlock> blocks = ir.getBasicBlocks(); blocks.hasMoreElements(); ) {
BasicBlock bb = blocks.nextElement();
float freq = bb.getExecutionFrequency();
for (Enumeration<Instruction> e = bb.forwardInstrEnumerator(); e.hasMoreElements(); ) {
Instruction s = e.nextElement();
double factor = freq;
if (s.isMove())
factor *= moveFactor;
double baseFactor = factor;
if (SimpleSpillCost.hasBadSizeMemoryOperand(s)) {
baseFactor *= memoryOperandFactor;
}
// first deal with non-memory operands
for (Enumeration<Operand> e2 = s.getRootOperands(); e2.hasMoreElements(); ) {
Operand op = e2.nextElement();
if (op.isRegister()) {
Register r = op.asRegister().getRegister();
if (r.isSymbolic()) {
update(r, baseFactor);
}
}
}
// now handle memory operands
factor *= memoryOperandFactor;
for (Enumeration<Operand> e2 = s.getMemoryOperands(); e2.hasMoreElements(); ) {
MemoryOperand M = (MemoryOperand) e2.nextElement();
if (M.base != null) {
Register r = M.base.getRegister();
if (r.isSymbolic()) {
update(r, factor);
}
}
if (M.index != null) {
Register r = M.index.getRegister();
if (r.isSymbolic()) {
update(r, factor);
}
}
}
}
}
}
use of org.jikesrvm.compilers.opt.ir.operand.MemoryOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method EMIT_Compare.
/**
* Gives the MIR condition operator appropriate for the given condition
* @param s the comparison instruction
* @param cond the condition
* @param val1 first operand for the compare
* @param val2 second operand for the compare
*/
protected void EMIT_Compare(Instruction s, ConditionOperand cond, Operand val1, Operand val2) {
// Swap operands for non-commutative operators
if (getCMP_needsSwap(cond)) {
Operand temp = val1;
val2 = val1;
val1 = temp;
}
switch(cond.value) {
case ConditionOperand.CARRY_FROM_ADD:
case ConditionOperand.NO_CARRY_FROM_ADD:
case ConditionOperand.OVERFLOW_FROM_ADD:
case ConditionOperand.NO_OVERFLOW_FROM_ADD:
{
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, temp.copyRO(), val2));
break;
}
case ConditionOperand.BIT_TEST:
case ConditionOperand.NO_BIT_TEST:
case ConditionOperand.RBIT_TEST:
case ConditionOperand.NO_RBIT_TEST:
if (val2 instanceof MemoryOperand) {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2.copy())));
val2 = temp;
}
EMIT(MIR_Compare.mutate(s, IA32_BT, val1.copy(), val2.copy()));
break;
case ConditionOperand.OVERFLOW_FROM_MUL:
case ConditionOperand.NO_OVERFLOW_FROM_MUL:
{
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_IMUL2, temp.copyRO(), val2));
break;
}
default:
EMIT(MIR_Compare.mutate(s, IA32_CMP, val1.copy(), val2.copy()));
break;
}
}
use of org.jikesrvm.compilers.opt.ir.operand.MemoryOperand in project JikesRVM by JikesRVM.
the class ComplexLIR2MIRExpansion method float_2long.
private static Instruction float_2long(Instruction s, IR ir) {
Instruction nextInstr = s.nextInstructionInCodeOrder();
while (Label.conforms(nextInstr) || BBend.conforms(nextInstr)) {
nextInstr = nextInstr.nextInstructionInCodeOrder();
}
if (VM.BuildFor32Addr) {
// we need 6 basic blocks (in code order)
// 1: the current block that does a test to see if this is a regular f2l or
// branches to the maxint/NaN case
// 2: a block to perform a regular f2l
// 3: a block to test for NaN
// 4: a block to perform give maxint
// 5: a block to perform NaN
// 6: the next basic block
BasicBlock testBB = s.getBasicBlock();
BasicBlock nextBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, nextBB);
BasicBlock nanBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, nanBB);
BasicBlock maxintBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, maxintBB);
BasicBlock nanTestBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, nanTestBB);
BasicBlock f2lBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, f2lBB);
// Move the maxlongFloat value and the value into x87 registers and compare and
// branch if they are <= or unordered.
RegisterOperand resultHi = Unary.getResult(s).copyRO();
resultHi.setType(TypeReference.Int);
RegisterOperand resultLo = new RegisterOperand(ir.regpool.getSecondReg(resultHi.getRegister()), TypeReference.Int);
RegisterOperand value = Unary.getVal(s).asRegister().copyRO();
RegisterOperand cw = ir.regpool.makeTempInt();
MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(ir, Entrypoints.maxlongFloatField.getOffset(), (byte) 4);
RegisterOperand st0 = new RegisterOperand(phys(ir).getST0(), TypeReference.Float);
RegisterOperand st1 = new RegisterOperand(phys(ir).getST1(), TypeReference.Float);
int offset = -ir.stackManager.allocateSpaceForConversion();
StackLocationOperand slLo = new StackLocationOperand(true, offset, 4);
StackLocationOperand slHi = new StackLocationOperand(true, offset + 4, 4);
StackLocationOperand sl = new StackLocationOperand(true, offset, 8);
MemoryOperand scratchLo = new MemoryOperand(ir.regpool.makeTROp(), null, (byte) 0, Entrypoints.scratchStorageField.getOffset(), (byte) 4, new LocationOperand(Entrypoints.scratchStorageField), null);
MemoryOperand scratchHi = new MemoryOperand(ir.regpool.makeTROp(), null, (byte) 0, Entrypoints.scratchStorageField.getOffset().plus(4), (byte) 4, new LocationOperand(Entrypoints.scratchStorageField), null);
s.insertBefore(CPOS(s, MIR_Move.create(IA32_MOVSS, slLo, value)));
s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0, slLo.copy())));
s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0.copyRO(), maxlong)));
MIR_Compare.mutate(s, IA32_FUCOMIP, st0.copyRO(), st1);
testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.LLE(), nanTestBB.makeJumpTarget(), BranchProfileOperand.unlikely())));
testBB.insertOut(f2lBB);
testBB.insertOut(nanTestBB);
// Convert float to long knowing that if the value is < min long the Intel
// unspecified result is min long
// TODO: this would be a lot simpler and faster with SSE3's FISTTP instruction
f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FNSTCW, scratchLo.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_MOVZX__W, cw, scratchLo.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR, cw.copyRO(), IC(0xC00))));
f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, scratchHi, cw.copyRO())));
f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchHi.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FISTP, sl, st0.copyRO())));
f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchLo.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultLo, slLo.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultHi, slHi)));
f2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP, nextBB.makeJumpTarget())));
f2lBB.insertOut(nextBB);
// Did the compare find a NaN or a maximum integer?
nanTestBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FSTP, st0.copyRO(), st0.copyRO())));
nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.PE(), nanBB.makeJumpTarget(), BranchProfileOperand.unlikely())));
nanTestBB.insertOut(nanBB);
nanTestBB.insertOut(maxintBB);
// Value was >= max long
maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultLo.copyRO(), IC((int) Long.MAX_VALUE))));
maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultHi.copyRO(), IC((int) (Long.MAX_VALUE >>> 32)))));
maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP, nextBB.makeJumpTarget())));
maxintBB.insertOut(nextBB);
// In case of NaN result is 0
nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultLo.copyRO(), IC(0))));
nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultHi.copyRO(), IC(0))));
nanBB.insertOut(nextBB);
} else {
// we need 4 basic blocks (in code order)
// 1: the current block which includes a test for NaN
// 2: a block to perform regular f2l
// 3: a block to handle NaN (which gives a result of 0)
// 4: the next basic block
BasicBlock testBB = s.getBasicBlock();
BasicBlock nextBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, nextBB);
BasicBlock nanBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, nanBB);
BasicBlock f2lBB = testBB.splitNodeAt(s, ir);
ir.cfg.linkInCodeOrder(testBB, f2lBB);
RegisterOperand result = Unary.getResult(s).copyRO();
RegisterOperand value = Unary.getVal(s).asRegister().copyRO();
RegisterOperand adjustment = ir.regpool.makeTempInt();
testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, adjustment.copy(), IC(0))));
MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(ir, Entrypoints.maxlongFloatField.getOffset(), (byte) 4);
MIR_Compare.mutate(s, IA32_UCOMISS, value.copy(), maxlong);
testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.PE(), nanBB.makeJumpTarget(), BranchProfileOperand.unlikely())));
testBB.insertOut(f2lBB);
testBB.insertOut(nanBB);
f2lBB.appendInstruction(CPOS(s, MIR_Set.create(IA32_SET__B, adjustment.copy(), IA32ConditionOperand.LGE())));
f2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_CVTTSS2SI, result.copy(), value.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copy(), adjustment.copy())));
f2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP, nextBB.makeJumpTarget())));
f2lBB.insertOut(nextBB);
// In case of NaN result is 0.
nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, result.copyRO(), LC(0))));
nanBB.insertOut(nextBB);
}
return nextInstr;
}
Aggregations