From: Reid Kleckner Date: Thu, 13 Apr 2017 00:58:09 +0000 (+0000) Subject: [IR] Take func, ret, and arg attrs separately in AttributeList::get X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9a46bf123cf40748eb8381b98420c35f3224ccc;p=llvm [IR] Take func, ret, and arg attrs separately in AttributeList::get This seems like a much more natural API, based on Derek Schuff's comments on r300015. It further hides the implementation detail of AttributeList that function attributes come last and appear at index ~0U, which is easy for the user to screw up. git diff says it saves code as well: 97 insertions(+), 137 deletions(-) This also makes it easier to change the implementation, which I want to do next. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300153 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 56f0f7715fe..3fdb9d8b7f9 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -307,13 +307,11 @@ public: static AttributeList get(LLVMContext &C, ArrayRef> Attrs); - /// \brief Create an AttributeList from a vector of AttributeSetNodes. The - /// index of each set is implied by its position in the array \p Attrs: - /// 0 : Return attributes - /// 1 to n-1 : Argument attributes - /// n : Function attributes - /// Any element that has no entries should be left null. - static AttributeList get(LLVMContext &C, ArrayRef Attrs); + /// \brief Create an AttributeList from attribute sets for a function, its + /// return value, and all of its arguments. + static AttributeList get(LLVMContext &C, AttributeSet FnAttrs, + AttributeSet RetAttrs, + ArrayRef ArgAttrs); static AttributeList getImpl(LLVMContext &C, diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 68d448ed7e0..58ea9296afd 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -4764,16 +4764,14 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { std::vector ParamTypeList; SmallVector Attrs; - Attrs.push_back(AttributeSet::get(Context, RetAttrs)); - for (unsigned i = 0, e = ArgList.size(); i != e; ++i) { ParamTypeList.push_back(ArgList[i].Ty); Attrs.push_back(ArgList[i].Attrs); } - Attrs.push_back(AttributeSet::get(Context, FuncAttrs)); - - AttributeList PAL = AttributeList::get(Context, Attrs); + AttributeList PAL = + AttributeList::get(Context, AttributeSet::get(Context, FuncAttrs), + AttributeSet::get(Context, RetAttrs), Attrs); if (PAL.hasAttribute(1, Attribute::StructRet) && !RetType->isVoidTy()) return Error(RetTypeLoc, "functions with 'sret' argument must return void"); @@ -5383,10 +5381,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { return true; // Set up the Attribute for the function. - SmallVector Attrs; - Attrs.push_back(AttributeSet::get(Context, RetAttrs)); - - SmallVector Args; + SmallVector Args; + SmallVector ArgAttrs; // Loop through FunctionType's arguments and ensure they are specified // correctly. Also, gather any parameter attributes. @@ -5404,7 +5400,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { return Error(ArgList[i].Loc, "argument is not of expected type '" + getTypeString(ExpectedTy) + "'"); Args.push_back(ArgList[i].V); - Attrs.push_back(ArgList[i].Attrs); + ArgAttrs.push_back(ArgList[i].Attrs); } if (I != E) @@ -5413,10 +5409,10 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { if (FnAttrs.hasAlignmentAttr()) return Error(CallLoc, "invoke instructions may not have an alignment"); - Attrs.push_back(AttributeSet::get(Context, FnAttrs)); - // Finish off the Attribute and check them - AttributeList PAL = AttributeList::get(Context, Attrs); + AttributeList PAL = + AttributeList::get(Context, AttributeSet::get(Context, FnAttrs), + AttributeSet::get(Context, RetAttrs), ArgAttrs); InvokeInst *II = InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args, BundleList); @@ -5978,7 +5974,6 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, // Set up the Attribute for the function. SmallVector Attrs; - Attrs.push_back(AttributeSet::get(Context, RetAttrs)); SmallVector Args; @@ -6007,10 +6002,10 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, if (FnAttrs.hasAlignmentAttr()) return Error(CallLoc, "call instructions may not have an alignment"); - Attrs.push_back(AttributeSet::get(Context, FnAttrs)); - // Finish off the Attribute and check them - AttributeList PAL = AttributeList::get(Context, Attrs); + AttributeList PAL = + AttributeList::get(Context, AttributeSet::get(Context, FnAttrs), + AttributeSet::get(Context, RetAttrs), Attrs); CallInst *CI = CallInst::Create(Ty, Callee, Args, BundleList); CI->setTailCallKind(TCK); diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 7faac60208f..2e3d7bdf709 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -778,7 +778,7 @@ AttributeList AttributeList::getImpl( #ifndef NDEBUG unsigned LastIndex = 0; bool IsFirst = true; - for (const auto &AttrPair : Attrs) { + for (auto &&AttrPair : Attrs) { assert((IsFirst || LastIndex < AttrPair.first) && "unsorted or duplicate AttributeList indices"); assert(AttrPair.second.hasAttributes() && "pointless AttributeList slot"); @@ -855,20 +855,20 @@ AttributeList::get(LLVMContext &C, return getImpl(C, Attrs); } -AttributeList AttributeList::get(LLVMContext &C, ArrayRef Attrs) { - assert(Attrs.size() >= 2 && - "should always have function and return attr slots"); +AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, + AttributeSet RetAttrs, + ArrayRef ArgAttrs) { SmallVector, 8> AttrPairs; - size_t Index = 0; - for (AttributeSet AS : Attrs) { - if (AS.hasAttributes()) { - // If this is the last AttributeSetNode, it's for the function. - if (Index == Attrs.size() - 1) - Index = AttributeList::FunctionIndex; + if (RetAttrs.hasAttributes()) + AttrPairs.emplace_back(ReturnIndex, RetAttrs); + size_t Index = 1; + for (AttributeSet AS : ArgAttrs) { + if (AS.hasAttributes()) AttrPairs.emplace_back(Index, AS); - } ++Index; } + if (FnAttrs.hasAttributes()) + AttrPairs.emplace_back(FunctionIndex, FnAttrs); if (AttrPairs.empty()) return AttributeList(); return getImpl(C, AttrPairs); diff --git a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index e1b2f79c81c..6af7d107934 100644 --- a/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -435,22 +435,20 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) { // Because we added the pointer to the callee as first argument, all // argument attribute indices have to be incremented by one. - SmallVector AttributesVec; + SmallVector ArgAttributes; const AttributeList &InvokeAL = CI->getAttributes(); - // Add any return attributes. - AttributesVec.push_back(InvokeAL.getRetAttributes()); // No attributes for the callee pointer. - AttributesVec.push_back(AttributeSet()); + ArgAttributes.push_back(AttributeSet()); // Copy the argument attributes from the original for (unsigned i = 1, e = CI->getNumArgOperands(); i <= e; ++i) { - AttributesVec.push_back(InvokeAL.getParamAttributes(i)); + ArgAttributes.push_back(InvokeAL.getParamAttributes(i)); } - // Add any function attributes. - AttributesVec.push_back(InvokeAL.getFnAttributes()); // Reconstruct the AttributesList based on the vector we constructed. - AttributeList NewCallAL = AttributeList::get(C, AttributesVec); + AttributeList NewCallAL = + AttributeList::get(C, InvokeAL.getFnAttributes(), + InvokeAL.getRetAttributes(), ArgAttributes); NewCall->setAttributes(NewCallAL); CI->replaceAllUsesWith(NewCall); diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index c43557b4e1a..00235d46dc5 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -102,11 +102,8 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, // Attribute - Keep track of the parameter attributes for the arguments // that we are *not* promoting. For the ones that we do promote, the parameter // attributes are lost - SmallVector AttributesVec; - const AttributeList &PAL = F->getAttributes(); - - // Add any return attributes. - AttributesVec.push_back(PAL.getRetAttributes()); + SmallVector ArgAttrVec; + AttributeList PAL = F->getAttributes(); // First, determine the new argument list unsigned ArgIndex = 1; @@ -117,13 +114,13 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, Type *AgTy = cast(I->getType())->getElementType(); StructType *STy = cast(AgTy); Params.insert(Params.end(), STy->element_begin(), STy->element_end()); - AttributesVec.insert(AttributesVec.end(), STy->getNumElements(), - AttributeSet()); + ArgAttrVec.insert(ArgAttrVec.end(), STy->getNumElements(), + AttributeSet()); ++NumByValArgsPromoted; } else if (!ArgsToPromote.count(&*I)) { // Unchanged argument Params.push_back(I->getType()); - AttributesVec.push_back(PAL.getParamAttributes(ArgIndex)); + ArgAttrVec.push_back(PAL.getParamAttributes(ArgIndex)); } else if (I->use_empty()) { // Dead argument (which are always marked as promotable) ++NumArgumentsDead; @@ -168,7 +165,7 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, Params.push_back(GetElementPtrInst::getIndexedType( cast(I->getType()->getScalarType())->getElementType(), ArgIndex.second)); - AttributesVec.push_back(AttributeSet()); + ArgAttrVec.push_back(AttributeSet()); assert(Params.back()); } @@ -179,9 +176,6 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, } } - // Add any function attributes. - AttributesVec.push_back(PAL.getFnAttributes()); - Type *RetTy = FTy->getReturnType(); // Construct the new function type using the new arguments. @@ -200,8 +194,9 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, // Recompute the parameter attributes list based on the new arguments for // the function. - NF->setAttributes(AttributeList::get(F->getContext(), AttributesVec)); - AttributesVec.clear(); + NF->setAttributes(AttributeList::get(F->getContext(), PAL.getFnAttributes(), + PAL.getRetAttributes(), ArgAttrVec)); + ArgAttrVec.clear(); F->getParent()->getFunctionList().insert(F->getIterator(), NF); NF->takeName(F); @@ -216,9 +211,6 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, Instruction *Call = CS.getInstruction(); const AttributeList &CallPAL = CS.getAttributes(); - // Add any return attributes. - AttributesVec.push_back(CallPAL.getRetAttributes()); - // Loop over the operands, inserting GEP and loads in the caller as // appropriate. CallSite::arg_iterator AI = CS.arg_begin(); @@ -227,7 +219,7 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, ++I, ++AI, ++ArgIndex) if (!ArgsToPromote.count(&*I) && !ByValArgsToTransform.count(&*I)) { Args.push_back(*AI); // Unmodified argument - AttributesVec.push_back(CallPAL.getAttributes(ArgIndex)); + ArgAttrVec.push_back(CallPAL.getAttributes(ArgIndex)); } else if (ByValArgsToTransform.count(&*I)) { // Emit a GEP and load for each element of the struct. Type *AgTy = cast(I->getType())->getElementType(); @@ -240,7 +232,7 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, STy, *AI, Idxs, (*AI)->getName() + "." + Twine(i), Call); // TODO: Tell AA about the new values? Args.push_back(new LoadInst(Idx, Idx->getName() + ".val", Call)); - AttributesVec.push_back(AttributeSet()); + ArgAttrVec.push_back(AttributeSet()); } } else if (!I->use_empty()) { // Non-dead argument: insert GEPs and loads as appropriate. @@ -283,48 +275,43 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, newLoad->setAAMetadata(AAInfo); Args.push_back(newLoad); - AttributesVec.push_back(AttributeSet()); + ArgAttrVec.push_back(AttributeSet()); } } // Push any varargs arguments on the list. for (; AI != CS.arg_end(); ++AI, ++ArgIndex) { Args.push_back(*AI); - AttributesVec.push_back(CallPAL.getAttributes(ArgIndex)); + ArgAttrVec.push_back(CallPAL.getAttributes(ArgIndex)); } - // Add any function attributes. - AttributesVec.push_back(CallPAL.getFnAttributes()); - SmallVector OpBundles; CS.getOperandBundlesAsDefs(OpBundles); - Instruction *New; + CallSite NewCS; if (InvokeInst *II = dyn_cast(Call)) { - New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), + NewCS = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles, "", Call); - cast(New)->setCallingConv(CS.getCallingConv()); - cast(New)->setAttributes( - AttributeList::get(II->getContext(), AttributesVec)); } else { - New = CallInst::Create(NF, Args, OpBundles, "", Call); - cast(New)->setCallingConv(CS.getCallingConv()); - cast(New)->setAttributes( - AttributeList::get(New->getContext(), AttributesVec)); - cast(New)->setTailCallKind( - cast(Call)->getTailCallKind()); + auto *NewCall = CallInst::Create(NF, Args, OpBundles, "", Call); + NewCall->setTailCallKind(cast(Call)->getTailCallKind()); + NewCS = NewCall; } - New->setDebugLoc(Call->getDebugLoc()); + NewCS.setCallingConv(CS.getCallingConv()); + NewCS.setAttributes( + AttributeList::get(F->getContext(), CallPAL.getFnAttributes(), + CallPAL.getRetAttributes(), ArgAttrVec)); + NewCS->setDebugLoc(Call->getDebugLoc()); Args.clear(); - AttributesVec.clear(); + ArgAttrVec.clear(); // Update the callgraph to know that the callsite has been transformed. if (ReplaceCallSite) - (*ReplaceCallSite)(CS, CallSite(New)); + (*ReplaceCallSite)(CS, NewCS); if (!Call->use_empty()) { - Call->replaceAllUsesWith(New); - New->takeName(Call); + Call->replaceAllUsesWith(NewCS.getInstruction()); + NewCS->takeName(Call); } // Finally, remove the old call from the program, reducing the use-count of diff --git a/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp index 66eb33f246a..2fd0b567705 100644 --- a/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -685,13 +685,9 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) { bool HasLiveReturnedArg = false; // Set up to build a new list of parameter attributes. - SmallVector AttributesVec; + SmallVector ArgAttrVec; const AttributeList &PAL = F->getAttributes(); - // Reserve an empty slot for the return value attributes, which we will - // compute last. - AttributesVec.push_back(AttributeSet()); - // Remember which arguments are still alive. SmallVector ArgAlive(FTy->getNumParams(), false); // Construct the new parameter list from non-dead arguments. Also construct @@ -704,7 +700,7 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) { if (LiveValues.erase(Arg)) { Params.push_back(I->getType()); ArgAlive[i] = true; - AttributesVec.push_back(PAL.getParamAttributes(i + 1)); + ArgAttrVec.push_back(PAL.getParamAttributes(i + 1)); HasLiveReturnedArg |= PAL.hasAttribute(i + 1, Attribute::Returned); } else { ++NumArgumentsEliminated; @@ -791,14 +787,12 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) { assert(!RAttrs.overlaps(AttributeFuncs::typeIncompatible(NRetTy)) && "Return attributes no longer compatible?"); - AttributesVec[0] = AttributeSet::get(F->getContext(), RAttrs); - - // Transfer the function attributes, if any. - AttributesVec.push_back(PAL.getFnAttributes()); + AttributeSet RetAttrs = AttributeSet::get(F->getContext(), RAttrs); // Reconstruct the AttributesList based on the vector we constructed. - assert(AttributesVec.size() == Params.size() + 2); - AttributeList NewPAL = AttributeList::get(F->getContext(), AttributesVec); + assert(ArgAttrVec.size() == Params.size()); + AttributeList NewPAL = AttributeList::get( + F->getContext(), PAL.getFnAttributes(), RetAttrs, ArgAttrVec); // Create the new function type based on the recomputed parameters. FunctionType *NFTy = FunctionType::get(NRetTy, Params, FTy->isVarArg()); @@ -825,14 +819,14 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) { CallSite CS(F->user_back()); Instruction *Call = CS.getInstruction(); - AttributesVec.clear(); + ArgAttrVec.clear(); const AttributeList &CallPAL = CS.getAttributes(); // Adjust the call return attributes in case the function was changed to // return void. AttrBuilder RAttrs(CallPAL.getRetAttributes()); RAttrs.remove(AttributeFuncs::typeIncompatible(NRetTy)); - AttributesVec.push_back(AttributeSet::get(F->getContext(), RAttrs)); + AttributeSet RetAttrs = AttributeSet::get(F->getContext(), RAttrs); // Declare these outside of the loops, so we can reuse them for the second // loop, which loops the varargs. @@ -851,26 +845,25 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) { // call sites keep the return value alive just like 'returned' // attributes on function declaration but it's less clearly a win and // this is not an expected case anyway - AttributesVec.push_back(AttributeSet::get( + ArgAttrVec.push_back(AttributeSet::get( F->getContext(), AttrBuilder(Attrs).removeAttribute(Attribute::Returned))); } else { // Otherwise, use the original attributes. - AttributesVec.push_back(Attrs); + ArgAttrVec.push_back(Attrs); } } // Push any varargs arguments on the list. Don't forget their attributes. for (CallSite::arg_iterator E = CS.arg_end(); I != E; ++I, ++i) { Args.push_back(*I); - AttributesVec.push_back(CallPAL.getParamAttributes(i + 1)); + ArgAttrVec.push_back(CallPAL.getParamAttributes(i + 1)); } - AttributesVec.push_back(CallPAL.getFnAttributes()); - // Reconstruct the AttributesList based on the vector we constructed. - AttributeList NewCallPAL = - AttributeList::get(F->getContext(), AttributesVec); + assert(ArgAttrVec.size() == Args.size()); + AttributeList NewCallPAL = AttributeList::get( + F->getContext(), CallPAL.getFnAttributes(), RetAttrs, ArgAttrVec); SmallVector OpBundles; CS.getOperandBundlesAsDefs(OpBundles); diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index cdae9571851..814f5933a58 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4232,16 +4232,13 @@ InstCombiner::transformCallThroughTrampoline(CallSite CS, if (NestTy) { Instruction *Caller = CS.getInstruction(); std::vector NewArgs; - std::vector NewAttrs; + std::vector NewArgAttrs; NewArgs.reserve(CS.arg_size() + 1); - NewAttrs.reserve(CS.arg_size() + 2); + NewArgAttrs.reserve(CS.arg_size()); // Insert the nest argument into the call argument list, which may // mean appending it. Likewise for attributes. - // Add any result attributes. - NewAttrs.push_back(Attrs.getRetAttributes()); - { unsigned Idx = 1; CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); @@ -4252,7 +4249,7 @@ InstCombiner::transformCallThroughTrampoline(CallSite CS, if (NestVal->getType() != NestTy) NestVal = Builder->CreateBitCast(NestVal, NestTy, "nest"); NewArgs.push_back(NestVal); - NewAttrs.push_back(NestAttr); + NewArgAttrs.push_back(NestAttr); } if (I == E) @@ -4260,16 +4257,13 @@ InstCombiner::transformCallThroughTrampoline(CallSite CS, // Add the original argument and attributes. NewArgs.push_back(*I); - NewAttrs.push_back(Attrs.getParamAttributes(Idx)); + NewArgAttrs.push_back(Attrs.getParamAttributes(Idx)); ++Idx; ++I; } while (true); } - // Add any function attributes. - NewAttrs.push_back(Attrs.getFnAttributes()); - // The trampoline may have been bitcast to a bogus type (FTy). // Handle this by synthesizing a new function type, equal to FTy // with the chain parameter inserted. @@ -4308,7 +4302,9 @@ InstCombiner::transformCallThroughTrampoline(CallSite CS, NestF->getType() == PointerType::getUnqual(NewFTy) ? NestF : ConstantExpr::getBitCast(NestF, PointerType::getUnqual(NewFTy)); - AttributeList NewPAL = AttributeList::get(FTy->getContext(), NewAttrs); + AttributeList NewPAL = + AttributeList::get(FTy->getContext(), Attrs.getFnAttributes(), + Attrs.getRetAttributes(), NewArgAttrs); SmallVector OpBundles; CS.getOperandBundlesAsDefs(OpBundles); diff --git a/lib/Transforms/Utils/CloneFunction.cpp b/lib/Transforms/Utils/CloneFunction.cpp index ae58d6133d9..05770268a0a 100644 --- a/lib/Transforms/Utils/CloneFunction.cpp +++ b/lib/Transforms/Utils/CloneFunction.cpp @@ -103,23 +103,20 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, TypeMapper, Materializer)); - SmallVector AttrVec(NewFunc->arg_size() + 2); + SmallVector NewArgAttrs(NewFunc->arg_size()); AttributeList OldAttrs = OldFunc->getAttributes(); - // Copy the return attributes. - AttrVec[0] = OldAttrs.getRetAttributes(); - // Clone any argument attributes that are present in the VMap. - for (const Argument &OldArg : OldFunc->args()) + for (const Argument &OldArg : OldFunc->args()) { if (Argument *NewArg = dyn_cast(VMap[&OldArg])) { - AttrVec[NewArg->getArgNo() + 1] = + NewArgAttrs[NewArg->getArgNo()] = OldAttrs.getParamAttributes(OldArg.getArgNo() + 1); } + } - // Copy any function attributes. - AttrVec.back() = OldAttrs.getFnAttributes(); - - NewFunc->setAttributes(AttributeList::get(NewFunc->getContext(), AttrVec)); + NewFunc->setAttributes( + AttributeList::get(NewFunc->getContext(), OldAttrs.getFnAttributes(), + OldAttrs.getRetAttributes(), NewArgAttrs)); SmallVector, 1> MDs; OldFunc->getAllMetadata(MDs);