summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/Utils/InlineFunction.cpp95
-rw-r--r--test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll46
-rw-r--r--test/Transforms/SRETPromotion/2008-03-07-Inline.ll46
3 files changed, 144 insertions, 43 deletions
diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp
index 6862ec6dfd..64e6056b73 100644
--- a/lib/Transforms/Utils/InlineFunction.cpp
+++ b/lib/Transforms/Utils/InlineFunction.cpp
@@ -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.
- 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());
+ 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 point where the PHI node lives if it exists.
+ // 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];
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.
diff --git a/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll b/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll
new file mode 100644
index 0000000000..4aceea4f09
--- /dev/null
+++ b/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll
@@ -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
+}
diff --git a/test/Transforms/SRETPromotion/2008-03-07-Inline.ll b/test/Transforms/SRETPromotion/2008-03-07-Inline.ll
new file mode 100644
index 0000000000..b04c5a9580
--- /dev/null
+++ b/test/Transforms/SRETPromotion/2008-03-07-Inline.ll
@@ -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
+}