use of org.jikesrvm.compilers.opt.ir.BasicBlock 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.BasicBlock in project JikesRVM by JikesRVM.
the class ReorderingPhase method exileInfrequentBlocks.
// ///////////////////////
// Code for trivial algorithm
// ///////////////////////
/**
* Select a new basic block ordering via a simple heuristic
* that moves all infrequent basic blocks to the end.
* @param ir the IR object to reorder
*/
private void exileInfrequentBlocks(IR ir) {
// (1) Look to see if there are infrequent blocks
// Also count how many blocks there are.
int numBlocks = 0;
boolean foundSome = false;
for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements(); ) {
BasicBlock bb = e.nextElement();
numBlocks++;
foundSome |= bb.getInfrequent();
}
// Nothing to do
if (!foundSome)
return;
// Reorder the blocks to exile the infrequent blocks.
// Relative order within the set of frequent and infrequent is unchanged.
BasicBlock[] newOrdering = new BasicBlock[numBlocks];
int idx = 0;
// First append frequent blocks to newOrdering
for (BasicBlock bb = ir.cfg.firstInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
if (!bb.getInfrequent()) {
newOrdering[idx++] = bb;
}
}
// Next append infrequent blocks to newOrdering
for (BasicBlock bb = ir.cfg.firstInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
if (bb.getInfrequent()) {
newOrdering[idx++] = bb;
}
}
// don't lose blocks!
if (VM.VerifyAssertions)
VM._assert(idx == numBlocks);
if (VM.VerifyAssertions)
VM._assert(ir.cfg.entry() == newOrdering[0]);
// Add/remove unconditional goto's as needed.
for (int i = 0; i < newOrdering.length; i++) {
Instruction lastInstr = newOrdering[i].lastRealInstruction();
// Append a GOTO if needed to maintain old fallthrough semantics.
BasicBlock fallthroughBlock = newOrdering[i].getFallThroughBlock();
if (fallthroughBlock != null) {
if (i == newOrdering.length - 1 || fallthroughBlock != newOrdering[i + 1]) {
// Add unconditional goto to preserve old fallthrough semantics
newOrdering[i].appendInstruction(fallthroughBlock.makeGOTO());
}
}
// (Only possible if newOrdering[i] is not the last basic block.)
if (i < newOrdering.length - 1 && lastInstr != null && lastInstr.operator() == GOTO) {
BranchOperand op = Goto.getTarget(lastInstr);
if (op.target.getBasicBlock() == newOrdering[i + 1]) {
// unconditional goto is redundant in new ordering
lastInstr.remove();
}
}
}
// Re-insert all basic blocks according to new ordering
ir.cfg.clearCodeOrder();
for (BasicBlock bb : newOrdering) {
ir.cfg.addLastInCodeOrder(bb);
}
}
use of org.jikesrvm.compilers.opt.ir.BasicBlock in project JikesRVM by JikesRVM.
the class ReorderingPhase method doPettisHansenAlgo2.
// ///////////////////////
// Code for P&H Algo2
// ///////////////////////
/**
* Reorder code using Algo2 (Bottom-Up Positioning) from
* Pettis and Hansen PLDI'90.
* @param ir the IR to reorder.
*/
private void doPettisHansenAlgo2(IR ir) {
// (1) Setup:
// (a) Count the blocks
// (b) Create a sorted set of CFG edges
// (c) Create a set of blocks
// (d) Make fallthroughs explict by adding GOTOs
int numBlocks = 0;
TreeSet<Edge> edges = new TreeSet<Edge>();
LinkedHashSet<BasicBlock> chainHeads = new LinkedHashSet<BasicBlock>();
HashMap<BasicBlock, BasicBlock> associatedChain = new HashMap<BasicBlock, BasicBlock>();
BasicBlock entry = ir.cfg.entry();
if (VM.VerifyAssertions)
VM._assert(ir.cfg.entry() == ir.cfg.firstInCodeOrder());
for (BasicBlock bb = entry; bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
numBlocks++;
chainHeads.add(bb);
associatedChain.put(bb, bb);
BasicBlock ft = bb.getFallThroughBlock();
if (ft != null) {
bb.appendInstruction(Goto.create(GOTO, ft.makeJumpTarget()));
}
float bw = bb.getExecutionFrequency();
for (WeightedBranchTargets wbt = new WeightedBranchTargets(bb); wbt.hasMoreElements(); wbt.advance()) {
edges.add(new Edge(bb, wbt.curBlock(), wbt.curWeight() * bw));
}
}
if (DEBUG)
VM.sysWriteln("Edges = " + edges);
// (2) Build chains
ir.cfg.clearCodeOrder();
for (Edge e : edges) {
// then merge the chains.
if (DEBUG)
VM.sysWriteln("Processing edge " + e);
if (e.target == entry) {
if (DEBUG)
VM.sysWriteln("\tCan't put entry block in interior of chain");
continue;
}
if (e.source.nextBasicBlockInCodeOrder() != null) {
if (DEBUG)
VM.sysWriteln("\tSource is not at end of a chain");
continue;
}
if (e.target.prevBasicBlockInCodeOrder() != null) {
if (DEBUG)
VM.sysWriteln("\tTarget is not at start of a chain");
continue;
}
BasicBlock sourceChain = associatedChain.get(e.source);
BasicBlock targetChain = associatedChain.get(e.target);
if (sourceChain == targetChain) {
if (DEBUG)
VM.sysWriteln("\tSource and target are in same chain");
continue;
}
if (DEBUG)
VM.sysWriteln("\tMerging chains");
chainHeads.remove(e.target);
ir.cfg.linkInCodeOrder(e.source, e.target);
// Yuck....we should really use near-linear time union find here
// Doing this crappy thing makes us O(N^2) in the worst case.
BasicBlock newChain = sourceChain;
for (BasicBlock ptr = e.target; ptr != null; ptr = ptr.nextBasicBlockInCodeOrder()) {
associatedChain.put(ptr, newChain);
}
}
if (DEBUG)
VM.sysWriteln("Chains constructed ");
LinkedHashMap<BasicBlock, ChainInfo> chainInfo = new LinkedHashMap<BasicBlock, ChainInfo>();
for (BasicBlock head : chainHeads) {
if (DEBUG)
dumpChain(head);
chainInfo.put(head, new ChainInfo(head));
}
// (3) Summarize inter-chain edges.
for (Edge e : edges) {
BasicBlock sourceChain = associatedChain.get(e.source);
BasicBlock targetChain = associatedChain.get(e.target);
if (sourceChain != targetChain) {
ChainInfo sourceInfo = chainInfo.get(sourceChain);
ChainInfo targetInfo = chainInfo.get(targetChain);
if (DEBUG)
VM.sysWriteln("Inter-chain edge " + sourceChain + "->" + targetChain + " (" + e.weight + ")");
Float value = sourceInfo.outWeights.get(targetInfo);
float weight = e.weight;
if (value != null) {
weight += value;
}
sourceInfo.outWeights.put(targetInfo, weight);
targetInfo.inWeight += e.weight;
if (DEBUG)
VM.sysWriteln("\t" + targetInfo + "," + sourceInfo.outWeights.get(targetInfo));
}
}
if (DEBUG)
VM.sysWriteln("Chain Info " + chainInfo);
// (4) Construct a total order of the chains, guided by the interchain edge weights.
// Constructing an optimal order is NP-Hard, so we apply the following heuristic.
// The chain that starts with the entry node is placed first.
// At each step, pick the chain with the maximal placedWeight (incoming edges from chains
// that are already placed) and minimal inWeight (incoming edges from chains that are not
// already placed). Prefer a node with non-zero placedWeight and inWeight to one that has
// zeros for both. (A node with both zero placedWeight and zero inWeight is something that
// the profile data predicts is not reachable via normal control flow from the entry node).
BasicBlock lastNode = null;
ChainInfo nextChoice = chainInfo.get(entry);
int numPlaced = 0;
ir.cfg.setFirstNode(entry);
while (true) {
if (DEBUG)
VM.sysWriteln("Placing chain " + nextChoice);
// Append nextChoice to the previous chain
if (lastNode != null)
ir.cfg.linkInCodeOrder(lastNode, nextChoice.head);
for (BasicBlock ptr = nextChoice.head; ptr != null; ptr = ptr.nextBasicBlockInCodeOrder()) {
numPlaced++;
lastNode = ptr;
}
// update ChainInfo
chainInfo.remove(nextChoice.head);
// no chains left to place.
if (chainInfo.isEmpty())
break;
for (ChainInfo target : nextChoice.outWeights.keySet()) {
if (DEBUG)
VM.sysWrite("\toutedge " + target);
float weight = nextChoice.outWeights.get(target);
if (DEBUG)
VM.sysWriteln(" = " + weight);
target.placedWeight += weight;
target.inWeight -= weight;
}
if (DEBUG)
VM.sysWriteln("Chain Info " + chainInfo);
// Find the next chain to append.
nextChoice = null;
for (ChainInfo cand : chainInfo.values()) {
if (cand.placedWeight > 0f) {
if (nextChoice == null) {
if (DEBUG)
VM.sysWriteln("First reachable candidate " + cand);
nextChoice = cand;
} else if (cand.inWeight > nextChoice.inWeight || (cand.inWeight == nextChoice.inWeight && cand.placedWeight > nextChoice.placedWeight)) {
if (DEBUG)
VM.sysWriteln(cand + " is a better choice than " + nextChoice);
nextChoice = cand;
}
}
}
if (nextChoice != null)
continue;
// Pick one with minimal inWeight and continue.
for (ChainInfo cand : chainInfo.values()) {
if (nextChoice == null) {
if (DEBUG)
VM.sysWriteln("First candidate " + cand);
nextChoice = cand;
} else if (cand.inWeight < nextChoice.inWeight) {
if (DEBUG)
VM.sysWriteln(cand + " is a better choice than " + nextChoice);
nextChoice = cand;
}
}
}
// Don't lose blocks!!
if (VM.VerifyAssertions)
VM._assert(numPlaced == numBlocks);
ir.cfg.setLastNode(lastNode);
}
use of org.jikesrvm.compilers.opt.ir.BasicBlock in project JikesRVM by JikesRVM.
the class ReorderingPhase method dumpChain.
private void dumpChain(BasicBlock head) {
VM.sysWrite("{" + head);
for (BasicBlock next = head.nextBasicBlockInCodeOrder(); next != null; next = next.nextBasicBlockInCodeOrder()) {
VM.sysWrite(", " + next);
}
VM.sysWriteln("}");
}
use of org.jikesrvm.compilers.opt.ir.BasicBlock in project JikesRVM by JikesRVM.
the class StaticSplitting method splitCandidate.
/**
* Splits a node where we can safely not
* replicate the on-branch in the cloned node.
* @param ci description of the split candidate.
* @param ir the governing IR
*/
private void splitCandidate(CandInfo ci, IR ir) {
BasicBlock cand = ci.candBB;
BasicBlock prev = ci.prevBB;
BasicBlock succ = ci.succBB;
BasicBlock clone = cand.copyWithoutLinks(ir);
// Redirect clone to always stay on cold path.
Instruction s = clone.lastRealInstruction();
while (s.isBranch()) {
s = s.remove();
}
clone.appendInstruction(Goto.create(GOTO, succ.makeJumpTarget()));
// inject clone in code order;
// force prev to go to clone instead of cand.
prev.redirectOuts(cand, clone, ir);
clone.recomputeNormalOut(ir);
ir.cfg.addLastInCodeOrder(clone);
clone.setInfrequent();
}
Aggregations