Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -483,6 +483,9 @@ LLVM_NODISCARD AttributeList addAttributesAtIndex(LLVMContext &C, unsigned Index, const AttrBuilder &B) const; + LLVM_NODISCARD AttributeList addAttributesAtIndex(LLVMContext &C, + unsigned Index, + AttributeSet AS) const; /// Add a function attribute to the list. Returns a new list because /// attribute lists are immutable. @@ -512,6 +515,11 @@ return addAttributesAtIndex(C, FunctionIndex, B); } + LLVM_NODISCARD AttributeList addFnAttributes(LLVMContext &C, + AttributeSet AS) const { + return addAttributesAtIndex(C, FunctionIndex, AS); + } + /// Add a return value attribute to the list. Returns a new list because /// attribute lists are immutable. LLVM_NODISCARD AttributeList addRetAttribute(LLVMContext &C, @@ -532,6 +540,10 @@ const AttrBuilder &B) const { return addAttributesAtIndex(C, ReturnIndex, B); } + LLVM_NODISCARD AttributeList addRetAttributes(LLVMContext &C, + AttributeSet AS) const { + return addAttributesAtIndex(C, ReturnIndex, AS); + } /// Add an argument attribute to the list. Returns a new list because /// attribute lists are immutable. @@ -561,6 +573,11 @@ const AttrBuilder &B) const { return addAttributesAtIndex(C, ArgNo + FirstArgIndex, B); } + LLVM_NODISCARD AttributeList addParamAttributes(LLVMContext &C, + unsigned ArgNo, + AttributeSet AS) const { + return addAttributesAtIndex(C, ArgNo + FirstArgIndex, AS); + } /// Remove the specified attribute at the specified index from this /// attribute list. Returns a new list because attribute lists are immutable. @@ -947,12 +964,11 @@ AttrBuilder(const AttrBuilder &) = delete; AttrBuilder(AttrBuilder &&) = default; - AttrBuilder(const Attribute &A) { - addAttribute(A); - } + explicit AttrBuilder(const Attribute &A) { addAttribute(A); } + + explicit AttrBuilder(AttributeSet AS); AttrBuilder(AttributeList AS, unsigned Idx); - AttrBuilder(AttributeSet AS); void clear(); @@ -978,15 +994,24 @@ /// Remove the attributes from the builder. AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex); + /// Remove the attributes from the builder. + AttrBuilder &removeAttributes(AttributeSet AS); + /// Remove the target-dependent attribute to the builder. AttrBuilder &removeAttribute(StringRef A); /// Add the attributes from the builder. AttrBuilder &merge(const AttrBuilder &B); + /// Add the attributes from the builder. + AttrBuilder &merge(AttributeSet AS); + /// Remove the attributes from the builder. AttrBuilder &remove(const AttrBuilder &B); + /// Remove the attribute from the builder. + AttrBuilder &remove(Attribute A); + /// Return true if the builder has any attribute that's in the /// specified builder. bool overlaps(const AttrBuilder &B) const; Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -1264,6 +1264,29 @@ return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); } +AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C, + unsigned Index, + AttributeSet AS) const { + if (!AS.hasAttributes()) + return *this; + + if (!pImpl) + return AttributeList::get(C, {{Index, AS}}); + +#ifndef NDEBUG + // FIXME it is not obvious how this should work for alignment. For now, say + // we can't change a known alignment. + const MaybeAlign OldAlign = getAttributes(Index).getAlignment(); + const MaybeAlign NewAlign = AS.getAlignment(); + assert((!OldAlign || !NewAlign || OldAlign == NewAlign) && + "Attempt to change alignment!"); +#endif + + AttrBuilder Merged(getAttributes(Index)); + Merged.merge(AS); + return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); +} + AttributeList AttributeList::addParamAttribute(LLVMContext &C, ArrayRef ArgNos, Attribute A) const { @@ -1617,7 +1640,13 @@ } AttrBuilder &AttrBuilder::removeAttributes(AttributeList A, uint64_t Index) { - remove(A.getAttributes(Index)); + removeAttributes(A.getAttributes(Index)); + return *this; +} + +AttrBuilder &AttrBuilder::removeAttributes(AttributeSet AS) { + for (Attribute A : AS) + remove(A); return *this; } @@ -1760,6 +1789,12 @@ return *this; } +AttrBuilder &AttrBuilder::merge(AttributeSet AS) { + for(Attribute A : AS) + addAttribute(A); + return *this; +} + AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) { // FIXME: What if both have an int/type attribute, but they don't match?! for (unsigned Index = 0; Index < Attribute::NumIntAttrKinds; ++Index) @@ -1778,6 +1813,13 @@ return *this; } +AttrBuilder &AttrBuilder::remove(Attribute A) { + if (A.isStringAttribute()) + return removeAttribute(A.getKindAsString()); + else + return removeAttribute(A.getKindAsEnum()); +} + bool AttrBuilder::overlaps(const AttrBuilder &B) const { // First check if any of the target independent attributes overlap. if ((Attrs & B.Attrs).any()) Index: llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1377,7 +1377,7 @@ return AL; // Remove the readonly, readnone, and statepoint function attributes. - AttrBuilder FnAttrs = AL.getFnAttrs(); + AttrBuilder FnAttrs(AL.getFnAttrs()); for (auto Attr : FnAttrsToStrip) FnAttrs.removeAttribute(Attr); @@ -1387,8 +1387,7 @@ } // Just skip parameter and return attributes for now - return AttributeList::get(Ctx, AttributeList::FunctionIndex, - AttributeSet::get(Ctx, FnAttrs)); + return AttributeList::get(Ctx, AttributeList::FunctionIndex, FnAttrs); } /// Helper function to place all gc relocates necessary for the given Index: llvm/unittests/IR/AttributesTest.cpp =================================================================== --- llvm/unittests/IR/AttributesTest.cpp +++ llvm/unittests/IR/AttributesTest.cpp @@ -55,7 +55,7 @@ AttributeList SetA = AttributeList::get(C, ASs); AttributeList SetB = - SetA.removeParamAttributes(C, 0, ASs[1].getParamAttrs(0)); + SetA.removeParamAttributes(C, 0, AttrBuilder(ASs[1].getParamAttrs(0))); EXPECT_NE(SetA, SetB); }