diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -450,6 +450,8 @@ static AttributeList get(LLVMContext &C, ArrayRef Attrs); static AttributeList get(LLVMContext &C, unsigned Index, ArrayRef Kinds); + static AttributeList get(LLVMContext &C, unsigned Index, + AttributeSet AS); static AttributeList get(LLVMContext &C, unsigned Index, ArrayRef Kinds, ArrayRef Values); @@ -481,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. @@ -510,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, @@ -530,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. @@ -559,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. @@ -943,12 +962,13 @@ public: AttrBuilder() = default; - AttrBuilder(const Attribute &A) { + explicit AttrBuilder(const Attribute &A) { addAttribute(A); } + explicit AttrBuilder(AttributeSet AS); + AttrBuilder(AttributeList AS, unsigned Idx); - AttrBuilder(AttributeSet AS); void clear(); @@ -974,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; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -1145,6 +1145,16 @@ return getImpl(C, AttrSets); } +AttributeList AttributeList::get(LLVMContext &C, unsigned Index, + AttributeSet AS) { + if (!AS.hasAttributes()) + return {}; + Index = attrIdxToArrayIdx(Index); + SmallVector AttrSets(Index + 1); + AttrSets[Index] = AS; + return getImpl(C, AttrSets); +} + AttributeList AttributeList::get(LLVMContext &C, unsigned Index, ArrayRef Kinds) { SmallVector, 8> Attrs; @@ -1259,6 +1269,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 { @@ -1612,7 +1645,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; } @@ -1755,6 +1794,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) @@ -1773,6 +1818,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()) diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/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 diff --git a/llvm/unittests/IR/AttributesTest.cpp b/llvm/unittests/IR/AttributesTest.cpp --- a/llvm/unittests/IR/AttributesTest.cpp +++ b/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); }