use of org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand in project JikesRVM by JikesRVM.
the class AssemblerBase method operandCost.
private int operandCost(Operand op, boolean shortFormImmediate) {
if (op instanceof MemoryOperand) {
MemoryOperand mop = (MemoryOperand) op;
// If it's a 2byte mem location, we're going to need an override prefix
int prefix = mop.size == 2 ? 1 : 0;
// Deal with EBP wierdness
if (mop.base != null && mop.base.getRegister() == EBP) {
if (mop.index != null) {
// forced into SIB + 32 bit displacement no matter what disp is
return prefix + 5;
}
if (fits(mop.disp, 8)) {
return prefix + 1;
} else {
return prefix + 4;
}
}
if (mop.index != null && mop.index.getRegister() == EBP) {
// forced into SIB + 32 bit displacement no matter what disp is
return prefix + 5;
}
// Deal with ESP wierdness -- requires SIB byte even when index is null
if (mop.base != null && mop.base.getRegister() == ESP) {
if (fits(mop.disp, 8)) {
return prefix + 2;
} else {
return prefix + 5;
}
}
if (mop.index == null) {
// just displacement to worry about
if (mop.disp.isZero()) {
return prefix + 0;
} else if (fits(mop.disp, 8)) {
return prefix + 1;
} else {
return prefix + 4;
}
} else {
// have a SIB
if (mop.base == null && mop.scale != 0) {
// forced to 32 bit displacement even if it would fit in 8
return prefix + 5;
} else {
if (mop.disp.isZero()) {
return prefix + 1;
} else if (fits(mop.disp, 8)) {
return prefix + 2;
} else {
return prefix + 5;
}
}
}
} else if (op instanceof IntConstantOperand) {
if (shortFormImmediate && fits(((IntConstantOperand) op).value, 8)) {
return 1;
} else {
return 4;
}
} else {
return 0;
}
}
use of org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand 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.IntConstantOperand in project JikesRVM by JikesRVM.
the class Inliner method execute.
/**
* Return a generation context that represents the
* execution of inlDec in the context <code><parent,ebag></code> for
* the call instruction callSite.
* <p> PRECONDITION: inlDec.isYes()
* <p> POSTCONDITIONS:
* Let gc be the returned generation context.
* <ul>
* <li> gc.cfg.firstInCodeOrder is the entry to the inlined context
* <li>gc.cfg.lastInCodeOrder is the exit from the inlined context
* <li> GenerationContext.transferState(parent, child) has been called.
* </ul>
*
* @param inlDec the inlining decision to execute
* @param parent the caller generation context
* @param ebag exception handler scope for the caller
* @param callSite the callsite to execute
* @return a generation context that represents the execution of the
* inline decision in the given context
*/
public static GenerationContext execute(InlineDecision inlDec, GenerationContext parent, ExceptionHandlerBasicBlockBag ebag, Instruction callSite) {
if (inlDec.needsGuard()) {
// Step 1: create the synthetic generation context we'll
// return to our caller.
GenerationContext container = GenerationContext.createSynthetic(parent, ebag);
container.getCfg().breakCodeOrder(container.getPrologue(), container.getEpilogue());
// Step 2: (a) Print a message (optional)
// (b) Generate the child GC for each target
RVMMethod[] targets = inlDec.getTargets();
byte[] guards = inlDec.getGuards();
GenerationContext[] children = new GenerationContext[targets.length];
for (int i = 0; i < targets.length; i++) {
NormalMethod callee = (NormalMethod) targets[i];
// (a)
if (parent.getOptions().PRINT_INLINE_REPORT) {
String guard = guards[i] == OptOptions.INLINE_GUARD_CLASS_TEST ? " (class test) " : " (method test) ";
VM.sysWriteln("\tGuarded inline" + guard + " " + callee + " into " + callSite.position().getMethod() + " at bytecode " + callSite.getBytecodeIndex());
}
// (b)
children[i] = parent.createChildContext(ebag, callee, callSite);
BC2IR.generateHIR(children[i]);
children[i].transferStateToParent();
}
// special purpose coding wrapping the calls to Operand.meet.
if (Call.hasResult(callSite)) {
Register reg = Call.getResult(callSite).getRegister();
container.setResult(children[0].getResult());
for (int i = 1; i < targets.length; i++) {
if (children[i].getResult() != null) {
container.setResult((container.getResult() == null) ? children[i].getResult() : Operand.meet(container.getResult(), children[i].getResult(), reg));
}
}
if (!inlDec.OSRTestFailed()) {
// Account for the non-predicted case as well...
RegisterOperand failureCaseResult = Call.getResult(callSite).copyRO();
container.setResult((container.getResult() == null) ? failureCaseResult : Operand.meet(container.getResult(), failureCaseResult, reg));
}
}
// Step 4: Create a block to contain a copy of the original call or an OSR_Yieldpoint
// to cover the case that all predictions fail.
BasicBlock testFailed = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
testFailed.setExceptionHandlers(ebag);
if (COUNT_FAILED_GUARDS && Controller.options.INSERT_DEBUGGING_COUNTERS) {
// Get a dynamic count of how many times guards fail at runtime.
// Need a name for the event to count. In this example, a
// separate counter for each method by using the method name
// as the event name. You could also have used just the string
// "Guarded inline failed" to keep only one counter.
String eventName = "Guarded inline failed: " + callSite.position().getMethod().toString();
// Create instruction that will increment the counter
// corresponding to the named event.
Instruction counterInst = AOSDatabase.debuggingCounterData.getCounterInstructionForEvent(eventName);
testFailed.appendInstruction(counterInst);
}
if (inlDec.OSRTestFailed()) {
// note where we're storing the osr barrier instruction
Instruction lastOsrBarrier = parent.getOSRBarrierFromInst(callSite);
Instruction s = BC2IR._osrHelper(lastOsrBarrier, parent);
s.copyPosition(callSite);
testFailed.appendInstruction(s);
testFailed.insertOut(parent.getExit());
} else {
Instruction call = callSite.copyWithoutLinks();
Call.getMethod(call).setIsGuardedInlineOffBranch(true);
call.copyPosition(callSite);
testFailed.appendInstruction(call);
testFailed.insertOut(container.getEpilogue());
// BC2IR.maybeInlineMethod).
if (ebag != null) {
for (Enumeration<BasicBlock> e = ebag.enumerator(); e.hasMoreElements(); ) {
BasicBlock handler = e.nextElement();
testFailed.insertOut(handler);
}
}
testFailed.setCanThrowExceptions();
testFailed.setMayThrowUncaughtException();
}
container.getCfg().linkInCodeOrder(testFailed, container.getEpilogue());
testFailed.setInfrequent();
// Step 5: Patch together all the callees by generating guard blocks
BasicBlock firstIfBlock = testFailed;
// Note: We know that receiver must be a register
// operand (and not a string constant) because we are doing a
// guarded inlining....if it was a string constant we'd have
// been able to inline without a guard.
Operand receiver = Call.getParam(callSite, 0);
MethodOperand mo = Call.getMethod(callSite);
boolean isInterface = mo.isInterface();
if (isInterface) {
if (VM.BuildForIMTInterfaceInvocation) {
RVMType interfaceType = mo.getTarget().getDeclaringClass();
TypeReference recTypeRef = receiver.getType();
RVMClass recType = (RVMClass) recTypeRef.peekType();
// Attempt to avoid inserting the check by seeing if the
// known static type of the receiver implements the interface.
boolean requiresImplementsTest = true;
if (recType != null && recType.isResolved() && !recType.isInterface()) {
byte doesImplement = ClassLoaderProxy.includesType(interfaceType.getTypeRef(), recTypeRef);
requiresImplementsTest = doesImplement != YES;
}
if (requiresImplementsTest) {
RegisterOperand checkedReceiver = parent.getTemps().makeTemp(receiver);
Instruction dtc = TypeCheck.create(MUST_IMPLEMENT_INTERFACE, checkedReceiver, receiver.copy(), new TypeOperand(interfaceType), Call.getGuard(callSite).copy());
dtc.copyPosition(callSite);
checkedReceiver.refine(interfaceType.getTypeRef());
Call.setParam(callSite, 0, checkedReceiver.copyRO());
testFailed.prependInstruction(dtc);
}
}
}
// "logical" test and to share test insertion for interfaces/virtuals.
for (int i = children.length - 1; i >= 0; i--, testFailed = firstIfBlock) {
firstIfBlock = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
firstIfBlock.setExceptionHandlers(ebag);
BasicBlock lastIfBlock = firstIfBlock;
RVMMethod target = children[i].getMethod();
Instruction tmp;
if (isInterface) {
RVMClass callDeclClass = mo.getTarget().getDeclaringClass();
if (!callDeclClass.isInterface()) {
// the entire compilation.
throw new OptimizingCompilerException("Attempted guarded inline of invoke interface when decl class of target method may not be an interface");
}
// We potentially have to generate IR to perform two tests here:
// (1) Does the receiver object implement callDeclClass?
// (2) Given that it does, is target the method that would
// be invoked for this receiver?
// It is quite common to be able to answer (1) "YES" at compile
// time, in which case we only have to generate IR to establish
// (2) at runtime.
byte doesImplement = ClassLoaderProxy.includesType(callDeclClass.getTypeRef(), target.getDeclaringClass().getTypeRef());
if (doesImplement != YES) {
// implements the interface).
if (parent.getOptions().PRINT_INLINE_REPORT) {
VM.sysWriteln("\t\tRequired additional instanceof " + callDeclClass + " test");
}
firstIfBlock = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
firstIfBlock.setExceptionHandlers(ebag);
RegisterOperand instanceOfResult = parent.getTemps().makeTempInt();
tmp = InstanceOf.create(INSTANCEOF_NOTNULL, instanceOfResult, new TypeOperand(callDeclClass), receiver.copy(), Call.getGuard(callSite));
tmp.copyPosition(callSite);
firstIfBlock.appendInstruction(tmp);
tmp = IfCmp.create(INT_IFCMP, parent.getTemps().makeTempValidation(), instanceOfResult.copyD2U(), new IntConstantOperand(0), ConditionOperand.EQUAL(), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
tmp.copyPosition(callSite);
firstIfBlock.appendInstruction(tmp);
firstIfBlock.insertOut(testFailed);
firstIfBlock.insertOut(lastIfBlock);
container.getCfg().linkInCodeOrder(firstIfBlock, lastIfBlock);
}
}
if (guards[i] == OptOptions.INLINE_GUARD_CLASS_TEST) {
tmp = InlineGuard.create(IG_CLASS_TEST, receiver.copy(), Call.getGuard(callSite).copy(), new TypeOperand(target.getDeclaringClass()), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
} else if (guards[i] == OptOptions.INLINE_GUARD_METHOD_TEST) {
// declaring class.
if (isInterface) {
RegisterOperand t = parent.getTemps().makeTempInt();
Instruction test = InstanceOf.create(INSTANCEOF_NOTNULL, t, new TypeOperand(target.getDeclaringClass().getTypeRef()), receiver.copy());
test.copyPosition(callSite);
lastIfBlock.appendInstruction(test);
Instruction cmp = IfCmp.create(INT_IFCMP, parent.getTemps().makeTempValidation(), t.copyD2U(), new IntConstantOperand(0), ConditionOperand.EQUAL(), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
cmp.copyPosition(callSite);
lastIfBlock.appendInstruction(cmp);
BasicBlock subclassTest = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
lastIfBlock.insertOut(testFailed);
lastIfBlock.insertOut(subclassTest);
container.getCfg().linkInCodeOrder(lastIfBlock, subclassTest);
lastIfBlock = subclassTest;
}
tmp = InlineGuard.create(IG_METHOD_TEST, receiver.copy(), Call.getGuard(callSite).copy(), MethodOperand.VIRTUAL(target.getMemberRef().asMethodReference(), target), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
} else {
tmp = InlineGuard.create(IG_PATCH_POINT, receiver.copy(), Call.getGuard(callSite).copy(), MethodOperand.VIRTUAL(target.getMemberRef().asMethodReference(), target), testFailed.makeJumpTarget(), inlDec.OSRTestFailed() ? BranchProfileOperand.never() : BranchProfileOperand.unlikely());
}
tmp.copyPosition(callSite);
lastIfBlock.appendInstruction(tmp);
lastIfBlock.insertOut(testFailed);
lastIfBlock.insertOut(children[i].getPrologue());
container.getCfg().linkInCodeOrder(lastIfBlock, children[i].getCfg().firstInCodeOrder());
if (children[i].getEpilogue() != null) {
children[i].getEpilogue().appendInstruction(container.getEpilogue().makeGOTO());
children[i].getEpilogue().insertOut(container.getEpilogue());
}
container.getCfg().linkInCodeOrder(children[i].getCfg().lastInCodeOrder(), testFailed);
}
// Step 6: finish by linking container.prologue & testFailed
container.getPrologue().insertOut(testFailed);
container.getCfg().linkInCodeOrder(container.getPrologue(), testFailed);
return container;
} else {
if (VM.VerifyAssertions)
VM._assert(inlDec.getNumberOfTargets() == 1);
NormalMethod callee = (NormalMethod) inlDec.getTargets()[0];
if (parent.getOptions().PRINT_INLINE_REPORT) {
VM.sysWriteln("\tInline " + callee + " into " + callSite.position().getMethod() + " at bytecode " + callSite.getBytecodeIndex());
}
GenerationContext child = parent.createChildContext(ebag, callee, callSite);
BC2IR.generateHIR(child);
child.transferStateToParent();
return child;
}
}
use of org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand in project JikesRVM by JikesRVM.
the class LoopUnrolling method unrollLeaf.
boolean unrollLeaf(LSTNode t, IR ir) {
int instructionsInLoop = 0;
BasicBlock exitBlock = null, backEdgeBlock = null, succBlock = null, predBlock = null;
BitVector nloop = t.getLoop();
BasicBlock header = t.header;
Instruction tmp;
if (ir.hasReachableExceptionHandlers()) {
report("0 IR may have exception handlers");
return false;
}
// determine loop structure by looking at its blocks
Enumeration<BasicBlock> loopBlocks = ir.getBasicBlocks(nloop);
int blocks = 0;
while (loopBlocks.hasMoreElements()) {
BasicBlock b = loopBlocks.nextElement();
blocks++;
// check for size
instructionsInLoop += b.getNumberOfRealInstructions();
if (instructionsInLoop > MaxInstructions) {
report("1 is too big");
return false;
}
// look at the in edges. We want the header to be the only
// block with out of loop incoming edges.
Enumeration<BasicBlock> e = b.getIn();
if (b != header) {
while (e.hasMoreElements()) {
BasicBlock o = e.nextElement();
if (!CFGTransformations.inLoop(o, nloop)) {
report("2 interior pointers.");
return true;
}
}
} else {
// check the headers predecessors: there should be
// one out of loop input and one backedge.
// We can extend this for loops with several backedges,
// if they all have the same conditions.
int inEdges = 0;
while (e.hasMoreElements()) {
inEdges++;
BasicBlock o = e.nextElement();
if (!CFGTransformations.inLoop(o, nloop)) {
if (predBlock == null) {
predBlock = o;
} else {
report("3 multi entry header.");
return true;
}
} else {
if (backEdgeBlock == null) {
backEdgeBlock = o;
} else {
report("4 multiple back edges.");
return true;
}
}
}
}
// look at the out edges to find loop exits
e = b.getOut();
while (e.hasMoreElements()) {
BasicBlock out = e.nextElement();
if (!CFGTransformations.inLoop(out, nloop)) {
if (exitBlock == null) {
exitBlock = b;
} else {
report("5 multiple exit blocks.");
return true;
}
}
}
}
// exitBlock must equal backEdgeBlock
if (exitBlock == null) {
report("6 no exit block found...infinite loop?");
return true;
}
if (exitBlock != backEdgeBlock) {
report("7 exit block is not immediate predecessor of loop head");
return true;
}
// exitBlock must exit (skip over pads in critical edges)
while (exitBlock.getNumberOfOut() == 1 && exitBlock.getNumberOfIn() == 1) {
exitBlock = exitBlock.getIn().nextElement();
}
if (exitBlock == header && blocks > 1) {
report("6 while loop? (" + blocks + ")");
return true;
}
// So far, so good. Examine the exit test.
Instruction origBranch = exitBlock.firstBranchInstruction();
if (origBranch != exitBlock.lastRealInstruction()) {
Instruction aGoto = origBranch.nextInstructionInCodeOrder();
if (aGoto.getOpcode() != GOTO_opcode) {
report("7 too complex exit");
return true;
}
succBlock = Label.getBlock(Goto.getTarget(aGoto).target).block;
if (VM.VerifyAssertions) {
VM._assert(aGoto == exitBlock.lastRealInstruction());
}
} else {
succBlock = exitBlock.getFallThroughBlock();
}
if (origBranch.getOpcode() != INT_IFCMP_opcode) {
report("8 branch isn't int_ifcmp: " + origBranch.operator() + ".");
return true;
}
// examine operands:
Operand op1 = follow(IfCmp.getVal1(origBranch));
Operand op2 = follow(IfCmp.getVal2(origBranch));
ConditionOperand cond = (ConditionOperand) IfCmp.getCond(origBranch).copy();
RegisterOperand ifcmpGuard = IfCmp.getGuardResult(origBranch);
float backBranchProbability = IfCmp.getBranchProfile(origBranch).takenProbability;
if (!loopInvariant(op2, nloop, 4)) {
if (loopInvariant(op1, nloop, 4)) {
Operand op = op1;
op1 = op2;
op2 = op;
cond.flipOperands();
} else {
if (DEBUG) {
printDefs(op1, nloop, 4);
printDefs(op2, nloop, 4);
VM.sysWriteln(origBranch.toString());
}
report("8a op1 and op2 may not be loop invariant");
return true;
}
}
BasicBlock target = Label.getBlock(IfCmp.getTarget(origBranch).target).block;
if (!(op1 instanceof RegisterOperand)) {
report("9 op1 of ifcmp isn't a register");
return true;
}
RegisterOperand rop1 = (RegisterOperand) op1;
Register reg = rop1.getRegister();
if (reg.isPhysical()) {
report("10 loops over physical register");
return false;
}
if (succBlock == header && !CFGTransformations.inLoop(target, nloop)) {
succBlock = target;
target = header;
cond.flipCode();
}
if (target != header) {
report("11 ifcmp doesn't jump to header");
return true;
}
Instruction iterator = null;
Enumeration<Operand> defs = new RealDefs(rop1);
while (defs.hasMoreElements()) {
Operand def = defs.nextElement();
Instruction inst = def.instruction;
BasicBlock block = inst.getBasicBlock();
// VM.sysWriteln(block + ": " + inst);
if (CFGTransformations.inLoop(block, nloop)) {
if (iterator == null) {
iterator = inst;
} else {
report("12 iterator not unique.");
return true;
}
}
}
if (iterator == null) {
report("15 iterator not found.");
return true;
}
if (iterator.getOpcode() != INT_ADD_opcode) {
// dumpIR (ir, "malformed");
report("16 iterator is no addition: " + iterator.operator());
return true;
}
if (!rop1.similar(follow(Binary.getVal1(iterator)))) {
// dumpIR (ir, "malformed");
report("17 malformed iterator.\n" + iterator);
return true;
}
Operand strideOp = follow(Binary.getVal2(iterator));
if (!(strideOp instanceof IntConstantOperand)) {
report("18 stride not constant");
return true;
}
int stride = ((IntConstantOperand) strideOp).value;
if (stride != 1 && stride != -1) {
report("18b stride != +/-1 (" + stride + ")");
return true;
}
if ((stride == 1 && ((cond.value != ConditionOperand.LESS) && cond.value != ConditionOperand.LESS_EQUAL && cond.value != ConditionOperand.NOT_EQUAL)) || (stride == -1 && ((cond.value != ConditionOperand.GREATER) && cond.value != ConditionOperand.GREATER_EQUAL && cond.value != ConditionOperand.NOT_EQUAL))) {
report("19 unexpected condition: " + cond + "\n" + iterator + "\n" + origBranch);
return true;
}
RegisterOperand outerGuard;
BasicBlock outer = predBlock;
while (outer.getNumberOfOut() == 1 && outer.getNumberOfIn() == 1) {
outer = outer.getIn().nextElement();
}
if (outer.getNumberOfIn() > 0 && outer.getNumberOfOut() < 2) {
report("23 no suitable outer guard found.");
return true;
}
tmp = outer.firstBranchInstruction();
if (tmp != null && GuardResultCarrier.conforms(tmp)) {
outerGuard = GuardResultCarrier.getGuardResult(tmp);
} else {
outerGuard = ir.regpool.makeTempValidation();
}
// //////////
// transfom
// transform this:
//
// Orig:
// B
// if i CC b goto Orig
// else goto exit
//
// exit:
//
// into this:
//
//
// stride == 1: common: stride == -1:
// --------------------------------------------------------------------------
// guard0:
// limit = b;
// if a > b goto Orig if b > a goto Orig
// else guard1
//
//
// guard 1:
// remainder = b - a; remainder = a - b;
// if cond == '<=' if cond == '>='
// remainder++; remainder++;
// remainder = remainder & 3
// limit = a + remainder limit = a - remainder
// if cond == '<=' if cond == '>='
// limit--; limit++;
// if remainder == 0 goto mllp
// goto Orig
//
// Orig:
// LOOP;
// if i CC limit goto Orig
// else guard2
//
// guard2: if i CC b goto mllp
// else exit
//
// mllp: // landing pad
// goto ml
//
// ml:
// LOOP;LOOP;LOOP;LOOP;
// if i CC b goto ml
// else exit
//
// exit:
// --------------------------------------------------------------------------
report("...transforming.");
if (DEBUG && ir.options.hasMETHOD_TO_PRINT() && ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
dumpIR(ir, "before unroll");
}
CFGTransformations.killFallThroughs(ir, nloop);
BasicBlock[] handles = makeSomeCopies(unrollFactor, ir, nloop, blocks, header, exitBlock, exitBlock);
BasicBlock mainHeader = handles[0];
BasicBlock mainExit = handles[1];
// test block for well formed bounds
BasicBlock guardBlock0 = header.createSubBlock(header.firstInstruction().getBytecodeIndex(), ir);
predBlock.redirectOuts(header, guardBlock0, ir);
// test block for iteration alignemnt
BasicBlock guardBlock1 = header.createSubBlock(header.firstInstruction().getBytecodeIndex(), ir);
// landing pad for orig loop
BasicBlock olp = header.createSubBlock(header.firstInstruction().getBytecodeIndex(), ir);
olp.setLandingPad();
BasicBlock predSucc = predBlock.nextBasicBlockInCodeOrder();
if (predSucc != null) {
ir.cfg.breakCodeOrder(predBlock, predSucc);
ir.cfg.linkInCodeOrder(olp, predSucc);
}
ir.cfg.linkInCodeOrder(predBlock, guardBlock0);
ir.cfg.linkInCodeOrder(guardBlock0, guardBlock1);
ir.cfg.linkInCodeOrder(guardBlock1, olp);
// guard block for main loop
BasicBlock guardBlock2 = header.createSubBlock(header.firstInstruction().getBytecodeIndex(), ir);
// landing pad for main loop
BasicBlock landingPad = header.createSubBlock(header.firstInstruction().getBytecodeIndex(), ir);
landingPad.setLandingPad();
BasicBlock mainLoop = exitBlock.nextBasicBlockInCodeOrder();
ir.cfg.breakCodeOrder(exitBlock, mainLoop);
ir.cfg.linkInCodeOrder(exitBlock, guardBlock2);
ir.cfg.linkInCodeOrder(guardBlock2, landingPad);
ir.cfg.linkInCodeOrder(landingPad, mainLoop);
RegisterOperand remainder = ir.regpool.makeTemp(rop1.getType());
RegisterOperand limit = ir.regpool.makeTemp(rop1.getType());
// test whether a <= b for stride == 1 and a >= b for stride == -1
tmp = guardBlock0.lastInstruction();
tmp.insertBefore(Move.create(INT_MOVE, limit, op2.copy()));
ConditionOperand g0cond = ConditionOperand.GREATER_EQUAL();
if (stride == -1)
g0cond = ConditionOperand.LESS_EQUAL();
tmp.insertBefore(IfCmp.create(INT_IFCMP, outerGuard.copyD2D(), rop1.copyD2U(), op2.copy(), g0cond, olp.makeJumpTarget(), BranchProfileOperand.unlikely()));
tmp.insertBefore(Goto.create(GOTO, guardBlock1.makeJumpTarget()));
// align the loop iterations
tmp = guardBlock1.lastInstruction();
if (stride == 1) {
tmp.insertBefore(Binary.create(INT_SUB, remainder, op2.copy(), rop1.copyD2U()));
} else {
tmp.insertBefore(Binary.create(INT_SUB, remainder, rop1.copyD2U(), op2.copy()));
}
if (cond.isGREATER_EQUAL() || cond.isLESS_EQUAL()) {
tmp.insertBefore(Binary.create(INT_ADD, remainder.copyD2D(), remainder.copyD2U(), new IntConstantOperand(1)));
}
tmp.insertBefore(Binary.create(INT_ADD, remainder.copyD2D(), remainder.copyD2U(), new IntConstantOperand(-1)));
tmp.insertBefore(Binary.create(INT_AND, remainder.copyD2D(), remainder.copyD2U(), new IntConstantOperand(unrollFactor - 1)));
tmp.insertBefore(Binary.create(INT_ADD, remainder.copyD2D(), remainder.copyD2U(), new IntConstantOperand(1)));
if (stride == 1) {
tmp.insertBefore(Binary.create(INT_ADD, limit.copyD2U(), op1.copy(), remainder.copyD2U()));
} else {
tmp.insertBefore(Binary.create(INT_SUB, limit.copyD2U(), op1.copy(), remainder.copyD2U()));
}
if (cond.isLESS_EQUAL()) {
tmp.insertBefore(Binary.create(INT_ADD, limit.copyD2D(), limit.copyD2U(), new IntConstantOperand(-1)));
}
if (cond.isGREATER_EQUAL()) {
tmp.insertBefore(Binary.create(INT_ADD, limit.copyD2D(), limit.copyD2U(), new IntConstantOperand(1)));
}
tmp.insertBefore(Goto.create(GOTO, olp.makeJumpTarget()));
// build landing pad for original loop
tmp = olp.lastInstruction();
tmp.insertBefore(Goto.create(GOTO, header.makeJumpTarget()));
// change the back branch in the original loop
deleteBranches(exitBlock);
tmp = exitBlock.lastInstruction();
tmp.insertBefore(IfCmp.create(INT_IFCMP, outerGuard.copyD2D(), rop1.copyU2U(), limit.copyD2U(), (ConditionOperand) cond.copy(), header.makeJumpTarget(), new BranchProfileOperand(1.0f - 1.0f / (unrollFactor / 2))));
tmp.insertBefore(Goto.create(GOTO, guardBlock2.makeJumpTarget()));
// only enter main loop if iterations left
tmp = guardBlock2.lastInstruction();
tmp.insertBefore(IfCmp.create(INT_IFCMP, outerGuard.copyD2D(), rop1.copyU2U(), op2.copy(), (ConditionOperand) cond.copy(), landingPad.makeJumpTarget(), new BranchProfileOperand(backBranchProbability)));
tmp.insertBefore(Goto.create(GOTO, succBlock.makeJumpTarget()));
// landing pad jumps to mainHeader
tmp = landingPad.lastInstruction();
tmp.insertBefore(Goto.create(GOTO, mainHeader.makeJumpTarget()));
// repair back edge in mainExit
if (VM.VerifyAssertions)
VM._assert(mainExit != null);
tmp = mainExit.lastInstruction();
if (VM.VerifyAssertions) {
VM._assert((mainExit.lastRealInstruction() == null) || !mainExit.lastRealInstruction().isBranch());
}
tmp.insertBefore(IfCmp.create(INT_IFCMP, ifcmpGuard.copyU2U(), rop1.copyU2U(), op2.copy(), (ConditionOperand) cond.copy(), mainHeader.makeJumpTarget(), new BranchProfileOperand(1.0f - (1.0f - backBranchProbability) * unrollFactor)));
tmp.insertBefore(Goto.create(GOTO, succBlock.makeJumpTarget()));
// recompute normal outs
guardBlock0.recomputeNormalOut(ir);
guardBlock1.recomputeNormalOut(ir);
olp.recomputeNormalOut(ir);
guardBlock2.recomputeNormalOut(ir);
exitBlock.recomputeNormalOut(ir);
landingPad.recomputeNormalOut(ir);
mainExit.recomputeNormalOut(ir);
if (DEBUG && ir.options.hasMETHOD_TO_PRINT() && ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
dumpIR(ir, "after unroll");
}
return false;
}
use of org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand 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);
}
}
Aggregations