Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -288,6 +288,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); @@ -485,6 +486,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. @@ -514,6 +518,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, @@ -534,6 +543,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. @@ -563,6 +576,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. @@ -1052,12 +1070,24 @@ /// Remove the attributes from the builder. AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex); + /// Remove the attributes from the builder. + AttrBuilder &removeAttributes(AttributeSet AS); + /// 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 AttributeMask &AM); + /// 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 AttributeMask &AM) const; Index: llvm/lib/IR/AttributeImpl.h =================================================================== --- llvm/lib/IR/AttributeImpl.h +++ 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; } Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ 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(C); - 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(C); - 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(C, 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(C); - 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(C); - B.addAttribute(A); - return addAttributesAtIndex(C, Index, B); + AttrBuilder B(C, 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(C, getAttributes(Index)); + Merged.merge(AS); + return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); +} + AttributeList AttributeList::addParamAttribute(LLVMContext &C, ArrayRef ArgNos, Attribute A) const { @@ -1616,11 +1679,6 @@ return addAttribute(Attribute::get(Ctx, A, V)); } -AttrBuilder &AttrBuilder::removeAttributes(AttributeList AL, uint64_t Index) { - remove(AttributeMask(AL.getAttributes(Index))); - return *this; -} - AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); Attrs[Val] = false; @@ -1633,6 +1691,17 @@ return *this; } +AttrBuilder &AttrBuilder::removeAttributes(AttributeList A, uint64_t Index) { + removeAttributes(A.getAttributes(Index)); + return *this; +} + +AttrBuilder &AttrBuilder::removeAttributes(AttributeSet AS) { + for (Attribute A : AS) + remove(A); + return *this; +} + AttrBuilder &AttrBuilder::removeAttribute(StringRef A) { auto It = lower_bound(TargetDepAttrs, A, StringAttributeComparator()); if (It != TargetDepAttrs.end() && It->hasAttribute(A)) @@ -1775,7 +1844,35 @@ return *this; } +AttrBuilder &AttrBuilder::merge(AttributeSet AS) { + for (Attribute A : AS) + merge(A); + return *this; +} + +AttrBuilder &AttrBuilder::merge(Attribute A) { + if (A.isStringAttribute()) { + auto It = lower_bound(TargetDepAttrs, A, StringAttributeComparator()); + if (It != TargetDepAttrs.end() && It->hasAttribute(A.getKindAsString())) + std::swap(*It, A); + else + TargetDepAttrs.insert(It, A); + } 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 AttributeMask &AM) { + // FIXME: What if both have an int/type attribute, but they don't match?! for (unsigned Index = 0; Index < Attribute::NumIntAttrKinds; ++Index) if (AM.contains((Attribute::AttrKind)Index)) IntAttrs[Index] = 0; @@ -1792,6 +1889,13 @@ return *this; } +AttrBuilder &AttrBuilder::remove(Attribute A) { + if (A.isStringAttribute()) + return removeAttribute(A.getKindAsString()); + else + return removeAttribute(A.getKindAsEnum()); +} + bool AttrBuilder::overlaps(const AttributeMask &AM) const { // First check if any of the target independent attributes overlap. if ((Attrs & AM.attrs()).any()) Index: llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1377,8 +1377,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, AttributeMask(ASs[1].getParamAttrs(0))); EXPECT_NE(SetA, SetB); }