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 @@ -286,6 +286,7 @@ AttributeSet(const AttributeSet &) = default; ~AttributeSet() = default; + static AttributeSet get(LLVMContext &C, Attribute A); static AttributeSet get(LLVMContext &C, const AttrBuilder &B); static AttributeSet get(LLVMContext &C, ArrayRef Attrs); @@ -483,6 +484,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 +516,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 +541,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 +574,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 +965,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 +995,27 @@ /// 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); + + /// Add the attributes from the builder. + AttrBuilder &merge(Attribute A); + /// 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/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -221,8 +221,6 @@ AttributeSetNode(ArrayRef Attrs); - static AttributeSetNode *getSorted(LLVMContext &C, - ArrayRef SortedAttrs); Optional findEnumAttribute(Attribute::AttrKind Kind) const; public: @@ -232,10 +230,15 @@ void operator delete(void *p) { ::operator delete(p); } + static AttributeSetNode *get(LLVMContext &C, Attribute A); + static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B); static AttributeSetNode *get(LLVMContext &C, ArrayRef Attrs); + static AttributeSetNode *getSorted(LLVMContext &C, + ArrayRef SortedAttrs); + /// Return the number of attributes this AttributeList contains. unsigned getNumAttributes() const { return NumAttrs; } 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 @@ -596,6 +596,10 @@ // AttributeSet Definition //===----------------------------------------------------------------------===// +AttributeSet AttributeSet::get(LLVMContext &C, Attribute A) { + return AttributeSet(AttributeSetNode::get(C, A)); +} + AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) { return AttributeSet(AttributeSetNode::get(C, B)); } @@ -607,16 +611,12 @@ AttributeSet AttributeSet::addAttribute(LLVMContext &C, Attribute::AttrKind Kind) const { if (hasAttribute(Kind)) return *this; - AttrBuilder B; - B.addAttribute(Kind); - return addAttributes(C, AttributeSet::get(C, B)); + return addAttributes(C, AttributeSet::get(C, Attribute::get(C, Kind))); } AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind, StringRef Value) const { - AttrBuilder B; - B.addAttribute(Kind, Value); - return addAttributes(C, AttributeSet::get(C, B)); + return addAttributes(C, AttributeSet::get(C, Attribute::get(C, Kind, Value))); } AttributeSet AttributeSet::addAttributes(LLVMContext &C, @@ -627,11 +627,51 @@ if (!AS.hasAttributes()) return *this; - AttrBuilder B(AS); - for (const auto &I : *this) - B.addAttribute(I); + // It is more efficient to merge the two sorted Attribute array we have at + // that point rather than creating an AttrBuilder to to the merge. + + SmallVector SortedAttrs; + auto SelfIter = begin(), SelfEnd = end(); + auto OtherIter = AS.begin(), OtherEnd = AS.end(); + + // Comparator that only compares key and treat Attribute with the same key but + // different value as equivalent. + auto Cmp = [](Attribute A0, Attribute A1) { + if (A0.isStringAttribute()) { + if (A1.isStringAttribute()) + return strcmp(A0.getKindAsString().data(), A1.getKindAsString().data()); + else + return +1; + } else { + if (A1.isStringAttribute()) + return -1; + else + return (int)A0.getKindAsEnum() - (int)A1.getKindAsEnum(); + } + }; - return get(C, B); + // This is close to std::set_union + std::unique in a row. + while (OtherIter < OtherEnd && SelfIter < SelfEnd) { + int C = Cmp(*OtherIter, *SelfIter); + if (C < 0) { + SortedAttrs.push_back(*OtherIter); + ++OtherIter; + } else if (C == 0) { + // In case of equality, the new version is honored. + SortedAttrs.push_back(*OtherIter); + ++OtherIter; + ++SelfIter; + } else { + SortedAttrs.push_back(*SelfIter); + ++SelfIter; + } + } + if (OtherIter < OtherEnd) + SortedAttrs.append(OtherIter, OtherEnd); + else + SortedAttrs.append(SelfIter, SelfEnd); + + return AttributeSet(AttributeSetNode::getSorted(C, SortedAttrs)); } AttributeSet AttributeSet::removeAttribute(LLVMContext &C, @@ -765,6 +805,9 @@ //===----------------------------------------------------------------------===// // AttributeSetNode Definition //===----------------------------------------------------------------------===// +AttributeSetNode *AttributeSetNode::get(LLVMContext &C, Attribute A) { + return getSorted(C, {A}); +} AttributeSetNode::AttributeSetNode(ArrayRef Attrs) : NumAttrs(Attrs.size()) { @@ -1208,26 +1251,23 @@ Attribute::AttrKind Kind) const { if (hasAttributeAtIndex(Index, Kind)) return *this; + AttributeSet Attrs = getAttributes(Index); - // TODO: Insert at correct position and avoid sort. - SmallVector NewAttrs(Attrs.begin(), Attrs.end()); - NewAttrs.push_back(Attribute::get(C, Kind)); - return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs)); + return setAttributesAtIndex(C, Index, Attrs.addAttribute(C, Kind)); } AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, StringRef Kind, StringRef Value) const { - AttrBuilder B; - B.addAttribute(Kind, Value); - return addAttributesAtIndex(C, Index, B); + return addAttributeAtIndex(C, Index, Attribute::get(C, Kind, Value)); } AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, Attribute A) const { - AttrBuilder B; - B.addAttribute(A); - return addAttributesAtIndex(C, Index, B); + AttrBuilder B(getAttributes(Index)); + B.merge(A); + getAttributes(Index); + return setAttributesAtIndex(C, Index, AttributeSet::get(C, B)); } AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C, @@ -1264,6 +1304,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 +1680,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 +1829,29 @@ return *this; } +AttrBuilder &AttrBuilder::merge(AttributeSet AS) { + for (Attribute A : AS) + merge(A); + return *this; +} + +AttrBuilder &AttrBuilder::merge(Attribute A) { + if (A.isStringAttribute()) { + TargetDepAttrs[A.getKindAsString()] = A.getValueAsString(); + } else { + auto Kind = A.getKindAsEnum(); + if (!Attrs[Kind]) { + Attrs[Kind] = true; + if (A.isIntAttribute()) { + IntAttrs[*kindToIntIndex(Kind)] = A.getValueAsInt(); + } else if (A.isTypeAttribute()) { + TypeAttrs[*kindToTypeIndex(Kind)] = A.getValueAsType(); + } + } + } + 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 +1870,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); }