mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 02:31:09 +00:00
Update inliner to handle functions that return multiple values.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48020 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0fdaa0b8f1
commit
12a466b9d0
@ -503,65 +503,74 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG, const TargetData *TD) {
|
||||
// Now that the function is correct, make it a little bit nicer. In
|
||||
// particular, move the basic blocks inserted from the end of the function
|
||||
// into the space made by splitting the source basic block.
|
||||
//
|
||||
Caller->getBasicBlockList().splice(AfterCallBB, Caller->getBasicBlockList(),
|
||||
FirstNewBlock, Caller->end());
|
||||
|
||||
// Handle all of the return instructions that we just cloned in, and eliminate
|
||||
// any users of the original call/invoke instruction.
|
||||
if (Returns.size() > 1) {
|
||||
if (!Returns.empty()) {
|
||||
// The PHI node should go at the front of the new basic block to merge all
|
||||
// possible incoming values.
|
||||
//
|
||||
PHINode *PHI = 0;
|
||||
SmallVector<PHINode *, 4> PHIs;
|
||||
if (!TheCall->use_empty()) {
|
||||
PHI = new PHINode(CalledFunc->getReturnType(),
|
||||
TheCall->getName(), AfterCallBB->begin());
|
||||
|
||||
// Anything that used the result of the function call should now use the
|
||||
// PHI node as their operand.
|
||||
//
|
||||
TheCall->replaceAllUsesWith(PHI);
|
||||
const Type *RTy = CalledFunc->getReturnType();
|
||||
if (const StructType *STy = dyn_cast<StructType>(RTy)) {
|
||||
unsigned NumRetVals = STy->getNumElements();
|
||||
// Create new phi nodes such that phi node number in the PHIs vector
|
||||
// match corresponding return value operand number.
|
||||
for (unsigned i = 0; i < NumRetVals; ++i) {
|
||||
PHINode *PHI = new PHINode(STy->getElementType(i),
|
||||
TheCall->getName(), AfterCallBB->begin());
|
||||
PHIs.push_back(PHI);
|
||||
}
|
||||
// TheCall results are used by GetResult instructions.
|
||||
while (!TheCall->use_empty()) {
|
||||
GetResultInst *GR = cast<GetResultInst>(TheCall->use_back());
|
||||
GR->replaceAllUsesWith(PHIs[GR->getIndex()]);
|
||||
GR->eraseFromParent();
|
||||
}
|
||||
} else {
|
||||
PHINode *PHI = new PHINode(RTy, TheCall->getName(), AfterCallBB->begin());
|
||||
PHIs.push_back(PHI);
|
||||
// Anything that used the result of the function call should now use the
|
||||
// PHI node as their operand.
|
||||
TheCall->replaceAllUsesWith(PHI);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over all of the return instructions, turning them into unconditional
|
||||
// branches to the merge point now, and adding entries to the PHI node as
|
||||
// Loop over all of the return instructions adding entries to the PHI node as
|
||||
// appropriate.
|
||||
if (!PHIs.empty()) {
|
||||
const Type *RTy = CalledFunc->getReturnType();
|
||||
if (const StructType *STy = dyn_cast<StructType>(RTy)) {
|
||||
unsigned NumRetVals = STy->getNumElements();
|
||||
for (unsigned j = 0; j < NumRetVals; ++j) {
|
||||
PHINode *PHI = PHIs[j];
|
||||
// Each PHI node will receive one value from each return instruction.
|
||||
for(unsigned i = 0, e = Returns.size(); i != e; ++i) {
|
||||
ReturnInst *RI = Returns[i];
|
||||
PHI->addIncoming(RI->getReturnValue(j /*PHI number matches operand number*/),
|
||||
RI->getParent());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0, e = Returns.size(); i != e; ++i) {
|
||||
ReturnInst *RI = Returns[i];
|
||||
assert(PHIs.size() == 1 && "Invalid number of PHI nodes");
|
||||
assert(RI->getReturnValue() && "Ret should have value!");
|
||||
assert(RI->getReturnValue()->getType() == PHIs[0]->getType() &&
|
||||
"Ret value not consistent in function!");
|
||||
PHIs[0]->addIncoming(RI->getReturnValue(), RI->getParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a branch to the merge points and remove retrun instructions.
|
||||
for (unsigned i = 0, e = Returns.size(); i != e; ++i) {
|
||||
ReturnInst *RI = Returns[i];
|
||||
|
||||
if (PHI) {
|
||||
assert(RI->getReturnValue() && "Ret should have value!");
|
||||
assert(RI->getReturnValue()->getType() == PHI->getType() &&
|
||||
"Ret value not consistent in function!");
|
||||
PHI->addIncoming(RI->getReturnValue(), RI->getParent());
|
||||
}
|
||||
|
||||
// Add a branch to the merge point where the PHI node lives if it exists.
|
||||
new BranchInst(AfterCallBB, RI);
|
||||
|
||||
// Delete the return instruction now
|
||||
RI->getParent()->getInstList().erase(RI);
|
||||
}
|
||||
|
||||
} else if (!Returns.empty()) {
|
||||
// Otherwise, if there is exactly one return value, just replace anything
|
||||
// using the return value of the call with the computed value.
|
||||
if (!TheCall->use_empty())
|
||||
TheCall->replaceAllUsesWith(Returns[0]->getReturnValue());
|
||||
|
||||
// Splice the code from the return block into the block that it will return
|
||||
// to, which contains the code that was after the call.
|
||||
BasicBlock *ReturnBB = Returns[0]->getParent();
|
||||
AfterCallBB->getInstList().splice(AfterCallBB->begin(),
|
||||
ReturnBB->getInstList());
|
||||
|
||||
// Update PHI nodes that use the ReturnBB to use the AfterCallBB.
|
||||
ReturnBB->replaceAllUsesWith(AfterCallBB);
|
||||
|
||||
// Delete the return instruction now and empty ReturnBB now.
|
||||
Returns[0]->eraseFromParent();
|
||||
ReturnBB->eraseFromParent();
|
||||
} else if (!TheCall->use_empty()) {
|
||||
// No returns, but something is using the return value of the call. Just
|
||||
// nuke the result.
|
||||
|
46
test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll
Normal file
46
test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll
Normal file
@ -0,0 +1,46 @@
|
||||
; RUN: llvm-as < %s | opt -inline -sretpromotion -disable-output
|
||||
%struct.Demand = type { double, double }
|
||||
%struct.branch = type { %struct.Demand, double, double, double, double, %struct.branch*, [12 x %struct.leaf*] }
|
||||
%struct.leaf = type { %struct.Demand, double, double }
|
||||
@P = external global double ; <double*> [#uses=1]
|
||||
|
||||
define %struct.leaf* @build_leaf() nounwind {
|
||||
entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
define void @Compute_Branch(%struct.Demand* sret %agg.result, %struct.branch* %br, double %theta_R, double %theta_I, double %pi_R, double %pi_I) nounwind {
|
||||
entry:
|
||||
%a2 = alloca %struct.Demand ; <%struct.Demand*> [#uses=2]
|
||||
br i1 false, label %bb46, label %bb
|
||||
|
||||
bb: ; preds = %entry
|
||||
ret void
|
||||
|
||||
bb46: ; preds = %entry
|
||||
br label %bb72
|
||||
|
||||
bb49: ; preds = %bb72
|
||||
call void @Compute_Leaf( %struct.Demand* sret %a2, %struct.leaf* null, double 0.000000e+00, double 0.000000e+00 ) nounwind
|
||||
%tmp66 = getelementptr %struct.Demand* %a2, i32 0, i32 1 ; <double*> [#uses=0]
|
||||
br label %bb72
|
||||
|
||||
bb72: ; preds = %bb49, %bb46
|
||||
br i1 false, label %bb49, label %bb77
|
||||
|
||||
bb77: ; preds = %bb72
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Compute_Leaf(%struct.Demand* sret %agg.result, %struct.leaf* %l, double %pi_R, double %pi_I) nounwind {
|
||||
entry:
|
||||
%tmp10 = load double* @P, align 8 ; <double> [#uses=1]
|
||||
%tmp11 = fcmp olt double %tmp10, 0.000000e+00 ; <i1> [#uses=1]
|
||||
br i1 %tmp11, label %bb, label %bb13
|
||||
|
||||
bb: ; preds = %entry
|
||||
br label %bb13
|
||||
|
||||
bb13: ; preds = %bb, %entry
|
||||
ret void
|
||||
}
|
46
test/Transforms/SRETPromotion/2008-03-07-Inline.ll
Normal file
46
test/Transforms/SRETPromotion/2008-03-07-Inline.ll
Normal file
@ -0,0 +1,46 @@
|
||||
; RUN: llvm-as < %s | opt -inline -sretpromotion -disable-output
|
||||
%struct.Demand = type { double, double }
|
||||
%struct.branch = type { %struct.Demand, double, double, double, double, %struct.branch*, [12 x %struct.leaf*] }
|
||||
%struct.leaf = type { %struct.Demand, double, double }
|
||||
@P = external global double ; <double*> [#uses=1]
|
||||
|
||||
define %struct.leaf* @build_leaf() nounwind {
|
||||
entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
define void @Compute_Branch(%struct.Demand* sret %agg.result, %struct.branch* %br, double %theta_R, double %theta_I, double %pi_R, double %pi_I) nounwind {
|
||||
entry:
|
||||
%a2 = alloca %struct.Demand ; <%struct.Demand*> [#uses=2]
|
||||
br i1 false, label %bb46, label %bb
|
||||
|
||||
bb: ; preds = %entry
|
||||
ret void
|
||||
|
||||
bb46: ; preds = %entry
|
||||
br label %bb72
|
||||
|
||||
bb49: ; preds = %bb72
|
||||
call void @Compute_Leaf( %struct.Demand* sret %a2, %struct.leaf* null, double 0.000000e+00, double 0.000000e+00 ) nounwind
|
||||
%tmp66 = getelementptr %struct.Demand* %a2, i32 0, i32 1 ; <double*> [#uses=0]
|
||||
br label %bb72
|
||||
|
||||
bb72: ; preds = %bb49, %bb46
|
||||
br i1 false, label %bb49, label %bb77
|
||||
|
||||
bb77: ; preds = %bb72
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Compute_Leaf(%struct.Demand* sret %agg.result, %struct.leaf* %l, double %pi_R, double %pi_I) nounwind {
|
||||
entry:
|
||||
%tmp10 = load double* @P, align 8 ; <double> [#uses=1]
|
||||
%tmp11 = fcmp olt double %tmp10, 0.000000e+00 ; <i1> [#uses=1]
|
||||
br i1 %tmp11, label %bb, label %bb13
|
||||
|
||||
bb: ; preds = %entry
|
||||
ret void
|
||||
|
||||
bb13: ; preds = %entry
|
||||
ret void
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user