diff options
-rw-r--r-- | llvm/lib/Transforms/Utils/InlineFunction.cpp | 95 | ||||
-rw-r--r-- | llvm/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll | 46 | ||||
-rw-r--r-- | llvm/test/Transforms/SRETPromotion/2008-03-07-Inline.ll | 46 |
3 files changed, 144 insertions, 43 deletions
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index 6862ec6dfd2..64e6056b73f 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/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/llvm/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll b/llvm/test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll new file mode 100644 index 00000000000..4aceea4f099 --- /dev/null +++ b/llvm/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/llvm/test/Transforms/SRETPromotion/2008-03-07-Inline.ll b/llvm/test/Transforms/SRETPromotion/2008-03-07-Inline.ll new file mode 100644 index 00000000000..b04c5a95801 --- /dev/null +++ b/llvm/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 +} |