Fix arg promotion to propagate the correct attrs on the calls to
authorChris Lattner <sabre@nondot.org>
Thu, 17 Jan 2008 01:17:03 +0000 (01:17 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 17 Jan 2008 01:17:03 +0000 (01:17 +0000)
promoted functions.  This is important for varargs calls in
particular.  Thanks to duncan for providing a great testcase.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@46108 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/ArgumentPromotion.cpp
test/Transforms/ArgumentPromotion/attrs.ll [new file with mode: 0644]

index 073d752af0f9d98a6aab10765ef9a1995907ebe7..3ac1c7bb2b23af4c457aa67c99892bdbeb65747b 100644 (file)
@@ -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/test/Transforms/ArgumentPromotion/attrs.ll b/test/Transforms/ArgumentPromotion/attrs.ll
new file mode 100644 (file)
index 0000000..0fb38be
--- /dev/null
@@ -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
+}