aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2008-01-17 01:17:03 +0000
committerChris Lattner <sabre@nondot.org>2008-01-17 01:17:03 +0000
commit5630c4f2171055329fe68564a3783228367637ee (patch)
treee0d610f2d899d7852a1ad61c91f9671538690d64
parent15051b4cafcfe7dcc8e832ac0754b34108216a2d (diff)
downloadllvm-5630c4f2171055329fe68564a3783228367637ee.zip
llvm-5630c4f2171055329fe68564a3783228367637ee.tar.gz
llvm-5630c4f2171055329fe68564a3783228367637ee.tar.bz2
Fix arg promotion to propagate the correct attrs on the calls to
promoted functions. This is important for varargs calls in particular. Thanks to duncan for providing a great testcase. llvm-svn: 46108
-rw-r--r--llvm/lib/Transforms/IPO/ArgumentPromotion.cpp39
-rw-r--r--llvm/test/Transforms/ArgumentPromotion/attrs.ll25
2 files changed, 50 insertions, 14 deletions
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index 073d752..3ac1c7b 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -404,9 +404,9 @@ Function *ArgPromotion::DoPromotion(Function *F,
ParamAttrsVector ParamAttrsVec;
const ParamAttrsList *PAL = F->getParamAttrs();
- unsigned index = 1;
+ unsigned ArgIndex = 1;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
- ++I, ++index) {
+ ++I, ++ArgIndex) {
if (ByValArgsToTransform.count(I)) {
// Just add all the struct element types.
const Type *AgTy = cast<PointerType>(I->getType())->getElementType();
@@ -416,7 +416,7 @@ Function *ArgPromotion::DoPromotion(Function *F,
++NumByValArgsPromoted;
} else if (!ArgsToPromote.count(I)) {
Params.push_back(I->getType());
- if (unsigned attrs = PAL ? PAL->getParamAttrs(index) : 0)
+ if (unsigned attrs = PAL ? PAL->getParamAttrs(ArgIndex) : 0)
ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Params.size(), attrs));
} else if (I->use_empty()) {
++NumArgumentsDead;
@@ -454,10 +454,6 @@ Function *ArgPromotion::DoPromotion(Function *F,
const Type *RetTy = FTy->getReturnType();
- // Recompute the parameter attributes list based on the new arguments for
- // the function.
- PAL = ParamAttrsList::get(ParamAttrsVec);
-
// Work around LLVM bug PR56: the CWriter cannot emit varargs functions which
// have zero fixed arguments.
bool ExtraArgHack = false;
@@ -472,7 +468,12 @@ Function *ArgPromotion::DoPromotion(Function *F,
// Create the new function body and insert it into the module...
Function *NF = new Function(NFTy, F->getLinkage(), F->getName());
NF->setCallingConv(F->getCallingConv());
- NF->setParamAttrs(PAL);
+
+ // Recompute the parameter attributes list based on the new arguments for
+ // the function.
+ NF->setParamAttrs(ParamAttrsList::get(ParamAttrsVec));
+ ParamAttrsVec.clear(); PAL = 0;
+
if (F->hasCollector())
NF->setCollector(F->getCollector());
F->getParent()->getFunctionList().insert(F, NF);
@@ -484,18 +485,24 @@ Function *ArgPromotion::DoPromotion(Function *F,
// Loop over all of the callers of the function, transforming the call sites
// to pass in the loaded pointers.
//
- std::vector<Value*> Args;
+ SmallVector<Value*, 16> Args;
while (!F->use_empty()) {
CallSite CS = CallSite::get(F->use_back());
Instruction *Call = CS.getInstruction();
-
+ PAL = CS.getParamAttrs();
+
// Loop over the operands, inserting GEP and loads in the caller as
// appropriate.
CallSite::arg_iterator AI = CS.arg_begin();
+ ArgIndex = 1;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
- I != E; ++I, ++AI)
+ I != E; ++I, ++AI, ++ArgIndex)
if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) {
Args.push_back(*AI); // Unmodified argument
+
+ if (unsigned Attrs = PAL ? PAL->getParamAttrs(ArgIndex) : 0)
+ ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Args.size(), Attrs));
+
} else if (ByValArgsToTransform.count(I)) {
// Emit a GEP and load for each element of the struct.
const Type *AgTy = cast<PointerType>(I->getType())->getElementType();
@@ -530,23 +537,27 @@ Function *ArgPromotion::DoPromotion(Function *F,
Args.push_back(Constant::getNullValue(Type::Int32Ty));
// Push any varargs arguments on the list
- for (; AI != CS.arg_end(); ++AI)
+ for (; AI != CS.arg_end(); ++AI, ++ArgIndex) {
Args.push_back(*AI);
+ if (unsigned Attrs = PAL ? PAL->getParamAttrs(ArgIndex) : 0)
+ ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Args.size(), Attrs));
+ }
Instruction *New;
if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
New = new InvokeInst(NF, II->getNormalDest(), II->getUnwindDest(),
Args.begin(), Args.end(), "", Call);
cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
- cast<InvokeInst>(New)->setParamAttrs(PAL);
+ cast<InvokeInst>(New)->setParamAttrs(ParamAttrsList::get(ParamAttrsVec));
} else {
New = new CallInst(NF, Args.begin(), Args.end(), "", Call);
cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
- cast<CallInst>(New)->setParamAttrs(PAL);
+ cast<CallInst>(New)->setParamAttrs(ParamAttrsList::get(ParamAttrsVec));
if (cast<CallInst>(Call)->isTailCall())
cast<CallInst>(New)->setTailCall();
}
Args.clear();
+ ParamAttrsVec.clear();
// Update the alias analysis implementation to know that we are replacing
// the old call with a new one.
diff --git a/llvm/test/Transforms/ArgumentPromotion/attrs.ll b/llvm/test/Transforms/ArgumentPromotion/attrs.ll
new file mode 100644
index 0000000..0fb38be
--- /dev/null
+++ b/llvm/test/Transforms/ArgumentPromotion/attrs.ll
@@ -0,0 +1,25 @@
+; RUN: llvm-as < %s | opt -argpromotion | llvm-dis | grep zeroext
+
+ %struct.ss = type { i32, i64 }
+
+define internal void @f(%struct.ss* byval %b, i32* byval %X, i32 %i) nounwind {
+entry:
+ %tmp = getelementptr %struct.ss* %b, i32 0, i32 0
+ %tmp1 = load i32* %tmp, align 4
+ %tmp2 = add i32 %tmp1, 1
+ store i32 %tmp2, i32* %tmp, align 4
+
+ store i32 0, i32* %X
+ ret void
+}
+
+define i32 @test(i32* %X) {
+entry:
+ %S = alloca %struct.ss ; <%struct.ss*> [#uses=4]
+ %tmp1 = getelementptr %struct.ss* %S, i32 0, i32 0 ; <i32*> [#uses=1]
+ store i32 1, i32* %tmp1, align 8
+ %tmp4 = getelementptr %struct.ss* %S, i32 0, i32 1 ; <i64*> [#uses=1]
+ store i64 2, i64* %tmp4, align 4
+ call void @f( %struct.ss* byval %S, i32* byval %X, i32 zeroext 0)
+ ret i32 0
+}