use of org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand in project JikesRVM by JikesRVM.
the class FinalMIRExpansion method expand.
/**
* @param ir the IR to expand
* @return return value is garbage for IA32
*/
public static int expand(IR ir) {
PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet().asIA32();
MachineCodeOffsets mcOffsets = ir.MIRInfo.mcOffsets;
for (Instruction next, p = ir.firstInstructionInCodeOrder(); p != null; p = next) {
next = p.nextInstructionInCodeOrder();
mcOffsets.setMachineCodeOffset(p, -1);
switch(p.getOpcode()) {
case IA32_MOVAPS_opcode:
// a reg-reg move turned into a memory move where we can't guarantee alignment
if (MIR_Move.getResult(p).isMemory() || MIR_Move.getValue(p).isMemory()) {
MIR_Move.mutate(p, IA32_MOVSS, MIR_Move.getClearResult(p), MIR_Move.getClearValue(p));
}
break;
case IA32_MOVAPD_opcode:
// a reg-reg move turned into a memory move where we can't guarantee alignment
if (MIR_Move.getResult(p).isMemory() || MIR_Move.getValue(p).isMemory()) {
MIR_Move.mutate(p, IA32_MOVSD, MIR_Move.getClearResult(p), MIR_Move.getClearValue(p));
}
break;
case IA32_TEST_opcode:
// must be first; we can just commute it here.
if (MIR_Test.getVal2(p).isMemory()) {
Operand tmp = MIR_Test.getClearVal1(p);
MIR_Test.setVal1(p, MIR_Test.getClearVal2(p));
MIR_Test.setVal2(p, tmp);
}
break;
case NULL_CHECK_opcode:
{
// mutate this into a TRAPIF, and then fall through to the the
// TRAP_IF case.
Operand ref = NullCheck.getRef(p);
MIR_TrapIf.mutate(p, IA32_TRAPIF, null, ref.copy(), IC(0), IA32ConditionOperand.EQ(), TrapCodeOperand.NullPtr());
}
// There is no break statement here on purpose!
case IA32_TRAPIF_opcode:
{
// split the basic block right before the IA32_TRAPIF
BasicBlock thisBlock = p.getBasicBlock();
BasicBlock trap = thisBlock.createSubBlock(p.getBytecodeIndex(), ir, 0f);
thisBlock.insertOut(trap);
BasicBlock nextBlock = thisBlock.splitNodeWithLinksAt(p, ir);
thisBlock.insertOut(trap);
TrapCodeOperand tc = MIR_TrapIf.getClearTrapCode(p);
p.remove();
mcOffsets.setMachineCodeOffset(nextBlock.firstInstruction(), -1);
// add code to thisBlock to conditionally jump to trap
Instruction cmp = MIR_Compare.create(IA32_CMP, MIR_TrapIf.getVal1(p).copy(), MIR_TrapIf.getVal2(p).copy());
if (p.isMarkedAsPEI()) {
// The trap if was explictly marked, which means that it has
// a memory operand into which we've folded a null check.
// Actually need a GC map for both the compare and the INT.
cmp.markAsPEI();
cmp.copyPosition(p);
ir.MIRInfo.gcIRMap.insertTwin(p, cmp);
}
thisBlock.appendInstruction(cmp);
thisBlock.appendInstruction(MIR_CondBranch.create(IA32_JCC, (IA32ConditionOperand) MIR_TrapIf.getCond(p).copy(), trap.makeJumpTarget(), null));
// add block at end to hold trap instruction, and
// insert trap sequence
ir.cfg.addLastInCodeOrder(trap);
if (tc.isArrayBounds()) {
// attempt to store index expression in processor object for
// C trap handler
Operand index = MIR_TrapIf.getVal2(p);
if (!(index instanceof RegisterOperand || index instanceof IntConstantOperand)) {
// index was spilled, and
index = IC(0xdeadbeef);
// we can't get it back here.
}
MemoryOperand mo = MemoryOperand.BD(ir.regpool.makeTROp(), ArchEntrypoints.arrayIndexTrapParamField.getOffset(), (byte) 4, null, null);
trap.appendInstruction(MIR_Move.create(IA32_MOV, mo, index.copy()));
}
// NOTE: must make p the trap instruction: it is the GC point!
// IMPORTANT: must also inform the GCMap that the instruction has
// been moved!!!
trap.appendInstruction(MIR_Trap.mutate(p, IA32_INT, null, tc));
ir.MIRInfo.gcIRMap.moveToEnd(p);
if (tc.isStackOverflow()) {
// only stackoverflow traps resume at next instruction.
trap.appendInstruction(MIR_Branch.create(IA32_JMP, nextBlock.makeJumpTarget()));
}
}
break;
case IA32_FMOV_ENDING_LIVE_RANGE_opcode:
{
Operand result = MIR_Move.getResult(p);
Operand value = MIR_Move.getValue(p);
if (result.isRegister() && value.isRegister()) {
if (result.similar(value)) {
// eliminate useless move
p.remove();
} else {
int i = PhysicalRegisterSet.getFPRIndex(result.asRegister().getRegister());
int j = PhysicalRegisterSet.getFPRIndex(value.asRegister().getRegister());
if (i == 0) {
MIR_XChng.mutate(p, IA32_FXCH, result, value);
} else if (j == 0) {
MIR_XChng.mutate(p, IA32_FXCH, value, result);
} else {
expandFmov(p, phys);
}
}
} else {
expandFmov(p, phys);
}
break;
}
case DUMMY_DEF_opcode:
case DUMMY_USE_opcode:
case REQUIRE_ESP_opcode:
case ADVISE_ESP_opcode:
p.remove();
break;
case IA32_FMOV_opcode:
expandFmov(p, phys);
break;
case IA32_MOV_opcode:
// Convert 0L to 0 to allow optimization into XOR.
if (MIR_Move.getResult(p).isRegister() && MIR_Move.getValue(p).isLongConstant() && MIR_Move.getValue(p).asLongConstant().value == 0L) {
MIR_Move.setValue(p, IC(0));
}
// Replace result = IA32_MOV 0 with result = IA32_XOR result, result
if (MIR_Move.getResult(p).isRegister() && MIR_Move.getValue(p).isIntConstant() && MIR_Move.getValue(p).asIntConstant().value == 0) {
// Calculate what flags are defined in coming instructions before a use of a flag or BBend
Instruction x = next;
int futureDefs = 0;
while (!BBend.conforms(x) && !PhysicalDefUse.usesEFLAGS(x.operator())) {
futureDefs |= x.operator().implicitDefs;
x = x.nextInstructionInCodeOrder();
}
// If the flags will be destroyed prior to use or we reached the end of the basic block
if (BBend.conforms(x) || (futureDefs & PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) == PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) {
Operand result = MIR_Move.getClearResult(p);
MIR_BinaryAcc.mutate(p, IA32_XOR, result, result.copy());
}
}
break;
case IA32_SET__B_opcode:
// Replace <cmp>, set__b, movzx__b with xor, <cmp>, set__b
if (MIR_Set.getResult(p).isRegister() && MIR_Unary.conforms(next) && (next.operator() == IA32_MOVZX__B) && MIR_Unary.getResult(next).isRegister() && MIR_Unary.getVal(next).similar(MIR_Unary.getResult(next)) && MIR_Unary.getVal(next).similar(MIR_Set.getResult(p))) {
// Find instruction in this basic block that defines flags
Instruction x = p.prevInstructionInCodeOrder();
Operand result = MIR_Unary.getResult(next);
boolean foundCmp = false;
outer: while (!Label.conforms(x)) {
Enumeration<Operand> e = x.getUses();
while (e.hasMoreElements()) {
// used by the <cmp> or intervening instruction
if (e.nextElement().similar(result)) {
break outer;
}
}
if (PhysicalDefUse.definesEFLAGS(x.operator()) && !PhysicalDefUse.usesEFLAGS(x.operator())) {
// we found a <cmp> that doesn't use the result or the flags
// that would be clobbered by the xor
foundCmp = true;
break outer;
}
x = x.prevInstructionInCodeOrder();
}
if (foundCmp) {
// We found the <cmp>, mutate the movzx__b into an xor and insert it before the <cmp>
next.remove();
MIR_BinaryAcc.mutate(next, IA32_XOR, result, MIR_Unary.getVal(next));
x.insertBefore(next);
// get ready for the next instruction
next = p.nextInstructionInCodeOrder();
}
}
break;
case IA32_LEA_opcode:
{
// Sometimes we're over eager in BURS in using LEAs and after register
// allocation we can simplify to the accumulate form
// replace reg1 = LEA [reg1 + reg2] with reg1 = reg1 + reg2
// replace reg1 = LEA [reg1 + c1] with reg1 = reg1 + c1
// replace reg1 = LEA [reg1 << c1] with reg1 = reg1 << c1
MemoryOperand value = MIR_Lea.getValue(p);
RegisterOperand result = MIR_Lea.getResult(p);
if ((value.base != null && value.base.getRegister() == result.getRegister()) || (value.index != null && value.index.getRegister() == result.getRegister())) {
// Calculate what flags are defined in coming instructions before a use of a flag or BBend
Instruction x = next;
int futureDefs = 0;
while (!BBend.conforms(x) && !PhysicalDefUse.usesEFLAGS(x.operator())) {
futureDefs |= x.operator().implicitDefs;
x = x.nextInstructionInCodeOrder();
}
// If the flags will be destroyed prior to use or we reached the end of the basic block
if (BBend.conforms(x) || (futureDefs & PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) == PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) {
if (value.base != null && value.index != null && value.index.getRegister() == result.getRegister() && value.disp.isZero() && value.scale == 0) {
// reg1 = lea [base + reg1] -> add reg1, base
MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.base);
} else if (value.base != null && value.base.getRegister() == result.getRegister() && value.index != null && value.disp.isZero() && value.scale == 0) {
// reg1 = lea [reg1 + index] -> add reg1, index
MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.index);
} else if (value.base != null && value.base.getRegister() == result.getRegister() && value.index == null) {
if (VM.VerifyAssertions)
VM._assert(fits(value.disp, 32));
// reg1 = lea [reg1 + disp] -> add reg1, disp
MIR_BinaryAcc.mutate(p, IA32_ADD, result, IC(value.disp.toInt()));
} else if (value.base == null && value.index != null && value.index.getRegister() == result.getRegister() && value.scale == 0) {
if (VM.VerifyAssertions)
VM._assert(fits(value.disp, 32));
// reg1 = lea [reg1 + disp] -> add reg1, disp
MIR_BinaryAcc.mutate(p, IA32_ADD, result, IC(value.disp.toInt()));
} else if (value.base == null && value.index != null && value.index.getRegister() == result.getRegister() && value.disp.isZero()) {
// reg1 = lea [reg1 << scale] -> shl reg1, scale
if (value.scale == 0) {
p.remove();
} else if (value.scale == 1) {
MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.index);
} else {
MIR_BinaryAcc.mutate(p, IA32_SHL, result, IC(value.scale));
}
}
}
}
}
break;
case IA32_FCLEAR_opcode:
expandFClear(p, ir);
break;
case IA32_JCC2_opcode:
p.insertBefore(MIR_CondBranch.create(IA32_JCC, MIR_CondBranch2.getClearCond1(p), MIR_CondBranch2.getClearTarget1(p), MIR_CondBranch2.getClearBranchProfile1(p)));
MIR_CondBranch.mutate(p, IA32_JCC, MIR_CondBranch2.getClearCond2(p), MIR_CondBranch2.getClearTarget2(p), MIR_CondBranch2.getClearBranchProfile2(p));
break;
case CALL_SAVE_VOLATILE_opcode:
p.changeOperatorTo(IA32_CALL);
break;
case IA32_LOCK_CMPXCHG_opcode:
p.insertBefore(MIR_Empty.create(IA32_LOCK));
p.changeOperatorTo(IA32_CMPXCHG);
break;
case IA32_LOCK_CMPXCHG8B_opcode:
p.insertBefore(MIR_Empty.create(IA32_LOCK));
p.changeOperatorTo(IA32_CMPXCHG8B);
break;
case YIELDPOINT_PROLOGUE_opcode:
expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromPrologueMethod, IA32ConditionOperand.NE());
break;
case YIELDPOINT_EPILOGUE_opcode:
expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromEpilogueMethod, IA32ConditionOperand.NE());
break;
case YIELDPOINT_BACKEDGE_opcode:
expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromBackedgeMethod, IA32ConditionOperand.GT());
break;
case YIELDPOINT_OSR_opcode:
// must yield, does not check threadSwitch request
expandUnconditionalYieldpoint(p, ir, Entrypoints.optThreadSwitchFromOsrOptMethod);
break;
}
}
return 0;
}
use of org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method TRAP_IF_IMM.
/**
* Take the generic LIR trap_if and coerce into the limited
* vocabulary understood by the C trap handler on PPC. See
* TrapConstants.java. Also see ConvertToLowLevelIR.java
* which generates most of these TRAP_IFs.
*
* @param s the instruction to expand
* @param longConstant is the argument a long constant?
*/
protected final void TRAP_IF_IMM(Instruction s, boolean longConstant) {
RegisterOperand gRes = TrapIf.getClearGuardResult(s);
RegisterOperand v1 = (RegisterOperand) TrapIf.getClearVal1(s);
ConditionOperand cond = TrapIf.getClearCond(s);
TrapCodeOperand tc = TrapIf.getClearTCode(s);
switch(tc.getTrapCode()) {
case RuntimeEntrypoints.TRAP_ARRAY_BOUNDS:
{
IntConstantOperand v2 = (IntConstantOperand) TrapIf.getClearVal2(s);
if (cond.isLOWER_EQUAL()) {
EMIT(MIR_Trap.mutate(s, PPC_TWI, gRes, new PowerPCTrapOperand(cond), v1, v2, tc));
} else if (cond.isHIGHER_EQUAL()) {
// have flip the operands and use non-immediate so trap handler can recognize.
RegisterOperand tmp = regpool.makeTempInt();
IntConstant(tmp.getRegister(), v2.value);
EMIT(MIR_Trap.mutate(s, PPC_TW, gRes, new PowerPCTrapOperand(cond.flipOperands()), tmp, v1, tc));
} else {
throw new OptimizingCompilerException("Unexpected case of trap_if" + s);
}
}
break;
case RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO:
{
ConstantOperand v2 = (ConstantOperand) TrapIf.getClearVal2(s);
if (VM.VerifyAssertions) {
if (longConstant) {
long val = ((LongConstantOperand) v2).value;
boolean caseMatchesExpected = val == 0L && cond.isEQUAL();
if (!caseMatchesExpected) {
String msg = "Unexpected case of trap_if" + s;
VM._assert(VM.NOT_REACHED, msg);
}
} else {
int val = ((IntConstantOperand) v2).value;
boolean caseMatchesExpected = val == 0L && cond.isEQUAL();
if (!caseMatchesExpected) {
String msg = "Unexpected case of trap_if" + s;
VM._assert(VM.NOT_REACHED, msg);
}
}
}
if (longConstant) {
if (VM.BuildFor32Addr) {
// A slightly ugly matter, but we need to deal with combining
// the two pieces of a long register from a LONG_ZERO_CHECK.
// A little awkward, but probably the easiest workaround...
RegisterOperand rr = regpool.makeTempInt();
EMIT(MIR_Binary.create(PPC_OR, rr, v1, I(regpool.getSecondReg(v1.getRegister()))));
v1 = rr.copyD2U();
v2 = IC(0);
EMIT(MIR_Trap.mutate(s, PPC_TWI, gRes, new PowerPCTrapOperand(cond), v1, v2, tc));
} else {
EMIT(MIR_Trap.mutate(s, PPC64_TDI, gRes, new PowerPCTrapOperand(cond), v1, v2, tc));
}
} else {
EMIT(MIR_Trap.mutate(s, PPC_TWI, gRes, new PowerPCTrapOperand(cond), v1, v2, tc));
}
}
break;
default:
throw new OptimizingCompilerException("Unexpected case of trap_if" + s);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method TRAP_IF.
// Take the generic LIR trap_if and coerce into the limited vocabulary
// understand by C trap handler on PPC. See TrapConstants.java.
// Also see ConvertToLowLevelIR.java which generates most of these TRAP_IFs.
protected final void TRAP_IF(Instruction s) {
RegisterOperand gRes = TrapIf.getClearGuardResult(s);
RegisterOperand v1 = (RegisterOperand) TrapIf.getClearVal1(s);
RegisterOperand v2 = (RegisterOperand) TrapIf.getClearVal2(s);
ConditionOperand cond = TrapIf.getClearCond(s);
TrapCodeOperand tc = TrapIf.getClearTCode(s);
switch(tc.getTrapCode()) {
case RuntimeEntrypoints.TRAP_ARRAY_BOUNDS:
{
if (cond.isLOWER_EQUAL()) {
EMIT(MIR_Trap.mutate(s, PPC_TW, gRes, new PowerPCTrapOperand(cond), v1, v2, tc));
} else {
throw new OptimizingCompilerException("Unexpected case of trap_if" + s);
}
}
break;
default:
throw new OptimizingCompilerException("Unexpected case of trap_if" + s);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method TRAP_IF_IMM.
/**
* Expansion of TRAP_IF, with an int constant as the second value.
*
* @param s the instruction to expand
* @param longConstant is the argument a long constant?
*/
protected final void TRAP_IF_IMM(Instruction s, boolean longConstant) {
RegisterOperand gRes = TrapIf.getGuardResult(s);
RegisterOperand v1 = (RegisterOperand) TrapIf.getVal1(s);
ConstantOperand v2 = (ConstantOperand) TrapIf.getVal2(s);
ConditionOperand cond = TrapIf.getCond(s);
TrapCodeOperand tc = TrapIf.getTCode(s);
// A little awkward, but probably the easiest workaround...
if (VM.BuildFor32Addr && longConstant) {
if (VM.VerifyAssertions) {
opt_assert((tc.getTrapCode() == RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO) && (((LongConstantOperand) v2).value == 0L));
}
RegisterOperand vr = v1.copyRO();
vr.setType(TypeReference.Int);
RegisterOperand rr = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, rr, vr)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, rr.copy(), new RegisterOperand(regpool.getSecondReg(v1.getRegister()), TypeReference.Int))));
v1 = rr.copyD2U();
v2 = IC(0);
}
// emit the trap instruction
EMIT(MIR_TrapIf.mutate(s, IA32_TRAPIF, gRes, v1, v2, COND(cond), tc));
}
use of org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand in project JikesRVM by JikesRVM.
the class Simple method codeAfterTrapIsUnreachable.
private static boolean codeAfterTrapIsUnreachable(Instruction trap) {
TrapCodeOperand trapCodeOp = Trap.getTCode(trap);
int trapCode = trapCodeOp.getTrapCode();
switch(trapCode) {
// code in the same basic block after the instruction is unreachable
case TRAP_NULL_POINTER:
case TRAP_ARRAY_BOUNDS:
case TRAP_CHECKCAST:
case TRAP_DIVIDE_BY_ZERO:
case TRAP_MUST_IMPLEMENT:
case TRAP_STORE_CHECK:
return true;
// code in the same basic block after the instruction might be reachable
case TRAP_STACK_OVERFLOW:
case TRAP_REGENERATE:
case TRAP_JNI_STACK:
case TRAP_UNKNOWN:
return false;
default:
if (VM.VerifyAssertions) {
throw new OptimizingCompilerException("Unhandled trap code in dead code elimination " + trapCode);
}
return false;
}
}
Aggregations