mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-11 13:46:13 +00:00
Simplify code a bit, and fix bug CodeExtractor/2004-03-14-NoSwitchSupport.ll
This also implements a two minor improvements: * Don't insert live-out stores IN the region, insert them on the code path that exits the region * If the region is exited to the same block from multiple paths, share the switch statement entry, live-out store code, and the basic block. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12401 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0e06674287
commit
12f390e9c0
@ -336,11 +336,10 @@ Function *CodeExtractor::constructFunction(const Values &inputs,
|
||||
return newFunction;
|
||||
}
|
||||
|
||||
void CodeExtractor::moveCodeToFunction(Function *newFunction)
|
||||
{
|
||||
void CodeExtractor::moveCodeToFunction(Function *newFunction) {
|
||||
Function *oldFunc = (*BlocksToExtract.begin())->getParent();
|
||||
Function::BasicBlockListType &oldBlocks = oldFunc->getBasicBlockList();
|
||||
Function::BasicBlockListType &newBlocks = newFunction->getBasicBlockList();
|
||||
Function::BasicBlockListType &newBlocks = newFunction->getBasicBlockList();
|
||||
|
||||
for (std::set<BasicBlock*>::const_iterator i = BlocksToExtract.begin(),
|
||||
e = BlocksToExtract.end(); i != e; ++i) {
|
||||
@ -390,6 +389,7 @@ CodeExtractor::emitCallAndSwitchStatement(Function *newFunction,
|
||||
params.push_back(*i);
|
||||
}
|
||||
}
|
||||
|
||||
CallInst *call = new CallInst(newFunction, params, "targetBlock");
|
||||
codeReplacer->getInstList().push_back(call);
|
||||
codeReplacer->getInstList().push_back(new BranchInst(codeReplacerTail));
|
||||
@ -405,70 +405,42 @@ CodeExtractor::emitCallAndSwitchStatement(Function *newFunction,
|
||||
codeReplacerTail);
|
||||
|
||||
// Since there may be multiple exits from the original region, make the new
|
||||
// function return an unsigned, switch on that number
|
||||
// function return an unsigned, switch on that number. This loop iterates
|
||||
// over all of the blocks in the extracted region, updating any terminator
|
||||
// instructions in the to-be-extracted region that branch to blocks that are
|
||||
// not in the region to be extracted.
|
||||
std::map<BasicBlock*, BasicBlock*> ExitBlockMap;
|
||||
|
||||
unsigned switchVal = 0;
|
||||
for (std::set<BasicBlock*>::const_iterator i = BlocksToExtract.begin(),
|
||||
e = BlocksToExtract.end(); i != e; ++i) {
|
||||
BasicBlock *BB = *i;
|
||||
TerminatorInst *TI = (*i)->getTerminator();
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
if (!BlocksToExtract.count(TI->getSuccessor(i))) {
|
||||
BasicBlock *OldTarget = TI->getSuccessor(i);
|
||||
// add a new basic block which returns the appropriate value
|
||||
BasicBlock *&NewTarget = ExitBlockMap[OldTarget];
|
||||
if (!NewTarget) {
|
||||
// If we don't already have an exit stub for this non-extracted
|
||||
// destination, create one now!
|
||||
NewTarget = new BasicBlock(OldTarget->getName() + ".exitStub",
|
||||
newFunction);
|
||||
|
||||
// rewrite the terminator of the original BasicBlock
|
||||
Instruction *term = BB->getTerminator();
|
||||
if (BranchInst *brInst = dyn_cast<BranchInst>(term)) {
|
||||
ConstantUInt *brVal = ConstantUInt::get(Type::UShortTy, switchVal++);
|
||||
ReturnInst *NTRet = new ReturnInst(brVal, NewTarget);
|
||||
|
||||
// Restore values just before we exit
|
||||
// FIXME: Use a GetElementPtr to bunch the outputs in a struct
|
||||
for (unsigned outIdx = 0, outE = outputs.size(); outIdx != outE; ++outIdx)
|
||||
new StoreInst(outputs[outIdx],
|
||||
getFunctionArg(newFunction, outIdx),
|
||||
brInst);
|
||||
// Update the switch instruction.
|
||||
switchInst->addCase(brVal, OldTarget);
|
||||
|
||||
// Rewrite branches into exits which return a value based on which
|
||||
// exit we take from this function
|
||||
if (brInst->isUnconditional()) {
|
||||
if (!BlocksToExtract.count(brInst->getSuccessor(0))) {
|
||||
ConstantUInt *brVal = ConstantUInt::get(Type::UShortTy, switchVal);
|
||||
ReturnInst *newRet = new ReturnInst(brVal);
|
||||
// add a new target to the switch
|
||||
switchInst->addCase(brVal, brInst->getSuccessor(0));
|
||||
++switchVal;
|
||||
// rewrite the branch with a return
|
||||
BasicBlock::iterator ii(brInst);
|
||||
ReplaceInstWithInst(BB->getInstList(), ii, newRet);
|
||||
delete brInst;
|
||||
}
|
||||
} else {
|
||||
// Replace the conditional branch to branch
|
||||
// to two new blocks, each of which returns a different code.
|
||||
for (unsigned idx = 0; idx < 2; ++idx) {
|
||||
BasicBlock *oldTarget = brInst->getSuccessor(idx);
|
||||
if (!BlocksToExtract.count(oldTarget)) {
|
||||
// add a new basic block which returns the appropriate value
|
||||
BasicBlock *newTarget = new BasicBlock("newTarget", newFunction);
|
||||
ConstantUInt *brVal = ConstantUInt::get(Type::UShortTy, switchVal);
|
||||
ReturnInst *newRet = new ReturnInst(brVal);
|
||||
newTarget->getInstList().push_back(newRet);
|
||||
// rewrite the original branch instruction with this new target
|
||||
brInst->setSuccessor(idx, newTarget);
|
||||
// the switch statement knows what to do with this value
|
||||
switchInst->addCase(brVal, oldTarget);
|
||||
++switchVal;
|
||||
}
|
||||
// Restore values just before we exit
|
||||
// FIXME: Use a GetElementPtr to bunch the outputs in a struct
|
||||
for (unsigned out = 0, e = outputs.size(); out != e; ++out)
|
||||
new StoreInst(outputs[out], getFunctionArg(newFunction, out),NTRet);
|
||||
}
|
||||
|
||||
// rewrite the original branch instruction with this new target
|
||||
TI->setSuccessor(i, NewTarget);
|
||||
}
|
||||
} else if (SwitchInst *swTerm = dyn_cast<SwitchInst>(term)) {
|
||||
|
||||
assert(0 && "Cannot handle switch instructions just yet.");
|
||||
|
||||
} else if (ReturnInst *retTerm = dyn_cast<ReturnInst>(term)) {
|
||||
assert(0 && "Cannot handle return instructions just yet.");
|
||||
// FIXME: what if the terminator is a return!??!
|
||||
// Need to rewrite: add new basic block, move the return there
|
||||
// treat the original as an unconditional branch to that basicblock
|
||||
} else if (InvokeInst *invInst = dyn_cast<InvokeInst>(term)) {
|
||||
assert(0 && "Cannot handle invoke instructions just yet.");
|
||||
} else {
|
||||
assert(0 && "Unrecognized terminator, or badly-formed BasicBlock.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user