serge-sans-paille created this revision.
serge-sans-paille added reviewers: nikic, dblaikie, rnk.
Herald added subscribers: dexonsmith, jdoerfert, mgrang, hiraditya.
serge-sans-paille requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

This class can only add / remove Attributes, but it does it relatively
efficiently compared to existing AttrBuilder, providing a consistent 
compile-time
speedup according to https://llvm-compile-time-tracker.com/

Internally it maintains two SmallVector of sorted Attributes, which turns out to
be more efficient than temporary hashmap and bitfields as used by AttrBuilder.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115798

Files:
  clang/include/clang/CodeGen/CodeGenABITypes.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CodeGenABITypes.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenModule.h
  llvm/include/llvm/IR/Attributes.h
  llvm/include/llvm/IR/Function.h
  llvm/lib/IR/AttributeImpl.h
  llvm/lib/IR/Attributes.cpp
  llvm/lib/IR/Function.cpp
  llvm/lib/Transforms/Utils/InlineFunction.cpp
  llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
===================================================================
--- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -602,7 +602,8 @@
     Align MemSetAlign =
         CI->getAttributes().getParamAttrs(0).getAlignment().valueOrOne();
     CallInst *NewCI = B.CreateMemSet(Dst, B.getInt8('\0'), Size, MemSetAlign);
-    AttrBuilder ArgAttrs(CI->getAttributes().getParamAttrs(0));
+    SmallAttrBuilder ArgAttrs(CI->getContext(),
+                              CI->getAttributes().getParamAttrs(0));
     NewCI->setAttributes(NewCI->getAttributes().addParamAttributes(
         CI->getContext(), 0, ArgAttrs));
     copyFlags(*CI, NewCI);
Index: llvm/lib/Transforms/Utils/InlineFunction.cpp
===================================================================
--- llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1183,12 +1183,13 @@
       Begin->getIterator(), End->getIterator(), InlinerAttributeWindow + 1);
 }
 
-static AttrBuilder IdentifyValidAttributes(CallBase &CB) {
+static SmallAttrBuilder IdentifyValidAttributes(CallBase &CB) {
 
   AttrBuilder AB(CB.getAttributes(), AttributeList::ReturnIndex);
-  if (AB.empty())
-    return AB;
-  AttrBuilder Valid;
+  SmallAttrBuilder Valid(CB.getContext());
+  if (AB.empty()) {
+    return Valid;
+  }
   // Only allow these white listed attributes to be propagated back to the
   // callee. This is because other attributes may only be valid on the call
   // itself, i.e. attributes such as signext and zeroext.
@@ -1207,7 +1208,7 @@
   if (!UpdateReturnAttributes)
     return;
 
-  AttrBuilder Valid = IdentifyValidAttributes(CB);
+  SmallAttrBuilder Valid = IdentifyValidAttributes(CB);
   if (Valid.empty())
     return;
   auto *CalledFunction = CB.getCalledFunction();
@@ -1252,6 +1253,7 @@
     // existing attribute value (i.e. attributes such as dereferenceable,
     // dereferenceable_or_null etc). See AttrBuilder::merge for more details.
     AttributeList AL = NewRetVal->getAttributes();
+
     AttributeList NewAL = AL.addRetAttributes(Context, Valid);
     NewRetVal->setAttributes(NewAL);
   }
Index: llvm/lib/IR/Function.cpp
===================================================================
--- llvm/lib/IR/Function.cpp
+++ llvm/lib/IR/Function.cpp
@@ -549,6 +549,10 @@
   AttributeSets = AttributeSets.addFnAttributes(getContext(), Attrs);
 }
 
+void Function::addFnAttrs(const SmallAttrBuilder &Attrs) {
+  AttributeSets = AttributeSets.addFnAttributes(getContext(), Attrs);
+}
+
 void Function::addRetAttr(Attribute::AttrKind Kind) {
   AttributeSets = AttributeSets.addRetAttribute(getContext(), Kind);
 }
@@ -593,6 +597,10 @@
   AttributeSets = AttributeSets.removeFnAttributes(getContext(), Attrs);
 }
 
+void Function::removeFnAttrs(const SmallAttrBuilder &Attrs) {
+  AttributeSets = AttributeSets.removeFnAttributes(getContext(), Attrs);
+}
+
 void Function::removeRetAttr(Attribute::AttrKind Kind) {
   AttributeSets = AttributeSets.removeRetAttribute(getContext(), Kind);
 }
Index: llvm/lib/IR/Attributes.cpp
===================================================================
--- llvm/lib/IR/Attributes.cpp
+++ llvm/lib/IR/Attributes.cpp
@@ -600,6 +600,10 @@
   return AttributeSet(AttributeSetNode::get(C, B));
 }
 
+AttributeSet AttributeSet::get(LLVMContext &C, const SmallAttrBuilder &B) {
+  return AttributeSet(AttributeSetNode::get(C, B));
+}
+
 AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {
   return AttributeSet(AttributeSetNode::get(C, Attrs));
 }
@@ -607,14 +611,14 @@
 AttributeSet AttributeSet::addAttribute(LLVMContext &C,
                                         Attribute::AttrKind Kind) const {
   if (hasAttribute(Kind)) return *this;
-  AttrBuilder B;
+  SmallAttrBuilder B(C);
   B.addAttribute(Kind);
   return addAttributes(C, AttributeSet::get(C, B));
 }
 
 AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
                                         StringRef Value) const {
-  AttrBuilder B;
+  SmallAttrBuilder B(C);
   B.addAttribute(Kind, Value);
   return addAttributes(C, AttributeSet::get(C, B));
 }
@@ -627,7 +631,7 @@
   if (!AS.hasAttributes())
     return *this;
 
-  AttrBuilder B(AS);
+  SmallAttrBuilder B(C, AS);
   for (const auto &I : *this)
     B.addAttribute(I);
 
@@ -637,16 +641,18 @@
 AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
                                              Attribute::AttrKind Kind) const {
   if (!hasAttribute(Kind)) return *this;
-  AttrBuilder B(*this);
-  B.removeAttribute(Kind);
+  SmallAttrBuilder B(C, make_filter_range(*this, [Kind](Attribute Attr) {
+                       return !Attr.hasAttribute(Kind);
+                     }));
   return get(C, B);
 }
 
 AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
-                                             StringRef Kind) const {
+                                           StringRef Kind) const {
   if (!hasAttribute(Kind)) return *this;
-  AttrBuilder B(*this);
-  B.removeAttribute(Kind);
+  SmallAttrBuilder B(C, make_filter_range(*this, [Kind](Attribute Attr) {
+                       return !Attr.hasAttribute(Kind);
+                     }));
   return get(C, B);
 }
 
@@ -661,6 +667,18 @@
   return get(C, B);
 }
 
+AttributeSet
+AttributeSet::removeAttributes(LLVMContext &C,
+                               const SmallAttrBuilder &Attrs) const {
+  SmallAttrBuilder B(C, *this);
+  auto AttrsPair = Attrs.uniquify();
+  for (Attribute A : AttrsPair.first)
+    B.removeEnumAttribute(A);
+  for (Attribute A : AttrsPair.second)
+    B.removeStringAttribute(A);
+  return get(C, B);
+}
+
 unsigned AttributeSet::getNumAttributes() const {
   return SetNode ? SetNode->getNumAttributes() : 0;
 }
@@ -779,6 +797,18 @@
   }
 }
 
+AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> EAttrs,
+                                   ArrayRef<Attribute> SAttrs)
+    : NumAttrs(EAttrs.size() + SAttrs.size()) {
+  // There's memory after the node where we can store the entries in.
+  llvm::copy(SAttrs, llvm::copy(EAttrs, getTrailingObjects<Attribute>()));
+
+  for (const auto &A : SAttrs)
+    StringAttrs.insert({A.getKindAsString(), A});
+  for (const auto &A : EAttrs)
+    AvailableAttrs.addAttribute(A.getKindAsEnum());
+}
+
 AttributeSetNode *AttributeSetNode::get(LLVMContext &C,
                                         ArrayRef<Attribute> Attrs) {
   SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end());
@@ -841,6 +871,41 @@
   return getSorted(C, Attrs);
 }
 
+AttributeSetNode *AttributeSetNode::get(LLVMContext &C,
+                                        const SmallAttrBuilder &B) {
+  if (!B.hasAttributes())
+    return nullptr;
+
+  // Build a key to look up the existing attributes.
+  LLVMContextImpl *pImpl = C.pImpl;
+  FoldingSetNodeID ID;
+
+  auto AttrsPair = B.uniquify();
+
+  assert(llvm::is_sorted(AttrsPair.first) && "Expected sorted attributes!");
+  for (const auto &Attr : AttrsPair.first)
+    Attr.Profile(ID);
+  assert(llvm::is_sorted(AttrsPair.second) && "Expected sorted attributes!");
+  for (const auto &Attr : AttrsPair.second)
+    Attr.Profile(ID);
+
+  void *InsertPoint;
+  AttributeSetNode *PA =
+      pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint);
+
+  // If we didn't find any existing attributes of the same shape then create a
+  // new one and insert it.
+  if (!PA) {
+    // Coallocate entries after the AttributeSetNode itself.
+    void *Mem = ::operator new(totalSizeToAlloc<Attribute>(B.size()));
+    PA = new (Mem) AttributeSetNode(AttrsPair.first, AttrsPair.second);
+    pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint);
+  }
+
+  // Return the AttributeSetNode that we found or created.
+  return PA;
+}
+
 bool AttributeSetNode::hasAttribute(StringRef Kind) const {
   return StringAttrs.count(Kind);
 }
@@ -1144,6 +1209,15 @@
   AttrSets[Index] = AttributeSet::get(C, B);
   return getImpl(C, AttrSets);
 }
+AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
+                                 const SmallAttrBuilder &B) {
+  if (!B.hasAttributes())
+    return {};
+  Index = attrIdxToArrayIdx(Index);
+  SmallVector<AttributeSet, 8> AttrSets(Index + 1);
+  AttrSets[Index] = AttributeSet::get(C, B);
+  return getImpl(C, AttrSets);
+}
 
 AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
                                  ArrayRef<Attribute::AttrKind> Kinds) {
@@ -1213,14 +1287,14 @@
 AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
                                                  StringRef Kind,
                                                  StringRef Value) const {
-  AttrBuilder B;
+  SmallAttrBuilder B(C);
   B.addAttribute(Kind, Value);
   return addAttributesAtIndex(C, Index, B);
 }
 
 AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
                                                  Attribute A) const {
-  AttrBuilder B;
+  SmallAttrBuilder B(C);
   B.addAttribute(A);
   return addAttributesAtIndex(C, Index, B);
 }
@@ -1259,6 +1333,20 @@
   return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));
 }
 
+AttributeList
+AttributeList::addAttributesAtIndex(LLVMContext &C, unsigned Index,
+                                    const SmallAttrBuilder &B) const {
+  if (!B.hasAttributes())
+    return *this;
+
+  if (!pImpl)
+    return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}});
+
+  SmallAttrBuilder Merged(C, getAttributes(Index));
+  Merged.merge(B);
+  return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));
+}
+
 AttributeList AttributeList::addParamAttribute(LLVMContext &C,
                                                ArrayRef<unsigned> ArgNos,
                                                Attribute A) const {
@@ -1320,6 +1408,17 @@
   return setAttributesAtIndex(C, Index, NewAttrs);
 }
 
+AttributeList AttributeList::removeAttributesAtIndex(
+    LLVMContext &C, unsigned Index,
+    const SmallAttrBuilder &AttrsToRemove) const {
+  AttributeSet Attrs = getAttributes(Index);
+  AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
+  // If nothing was removed, return the original list.
+  if (Attrs == NewAttrs)
+    return *this;
+  return setAttributesAtIndex(C, Index, NewAttrs);
+}
+
 AttributeList
 AttributeList::removeAttributesAtIndex(LLVMContext &C,
                                        unsigned WithoutIndex) const {
@@ -1649,6 +1748,15 @@
   return unpackVScaleRangeArgs(getRawIntAttr(Attribute::VScaleRange)).second;
 }
 
+SmallAttrBuilder &SmallAttrBuilder::addAlignmentAttr(MaybeAlign Align) {
+  if (!Align)
+    return *this;
+
+  assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");
+  return addAttribute(
+      Attribute::get(Ctxt, Attribute::Alignment, Align->value()));
+}
+
 AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) {
   if (!Align)
     return *this;
@@ -1666,11 +1774,25 @@
   return addRawIntAttr(Attribute::StackAlignment, Align->value());
 }
 
+SmallAttrBuilder &SmallAttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
+  if (Bytes == 0)
+    return *this;
+  return addAttribute(Attribute::get(Ctxt, Attribute::Dereferenceable, Bytes));
+}
+
 AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
   if (Bytes == 0) return *this;
 
   return addRawIntAttr(Attribute::Dereferenceable, Bytes);
 }
+SmallAttrBuilder &
+SmallAttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
+  if (Bytes == 0)
+    return *this;
+
+  return addAttribute(
+      Attribute::get(Ctxt, Attribute::DereferenceableOrNull, Bytes));
+}
 
 AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
   if (Bytes == 0)
@@ -1679,6 +1801,13 @@
   return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes);
 }
 
+SmallAttrBuilder &
+SmallAttrBuilder::addAllocSizeAttr(unsigned ElemSize,
+                                   const Optional<unsigned> &NumElems) {
+  return addAttribute(Attribute::get(Ctxt, Attribute::AllocSize,
+                                     packAllocSizeArgs(ElemSize, NumElems)));
+}
+
 AttrBuilder &AttrBuilder::addAllocSizeAttr(unsigned ElemSize,
                                            const Optional<unsigned> &NumElems) {
   return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));
@@ -1716,11 +1845,17 @@
   TypeAttrs[*TypeIndex] = Ty;
   return *this;
 }
+SmallAttrBuilder &SmallAttrBuilder::addByValAttr(Type *Ty) {
+  return addAttribute(Attribute::get(Ctxt, Attribute::ByVal, Ty));
+}
 
 AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
   return addTypeAttr(Attribute::ByVal, Ty);
 }
 
+SmallAttrBuilder &SmallAttrBuilder::addStructRetAttr(Type *Ty) {
+  return addAttribute(Attribute::get(Ctxt, Attribute::StructRet, Ty));
+}
 AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {
   return addTypeAttr(Attribute::StructRet, Ty);
 }
@@ -1737,6 +1872,20 @@
   return addTypeAttr(Attribute::InAlloca, Ty);
 }
 
+SmallAttrBuilder &SmallAttrBuilder::merge(const SmallAttrBuilder &B) {
+  {
+    auto Start = EnumAttrs.begin();
+    for (auto A : B.EnumAttrs)
+      Start = addEnumAttributeHelper(A, Start);
+  }
+  {
+    auto Start = StringAttrs.begin();
+    for (auto A : B.StringAttrs)
+      Start = addStringAttributeHelper(A, Start);
+  }
+
+  return *this;
+}
 AttrBuilder &AttrBuilder::merge(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)
Index: llvm/lib/IR/AttributeImpl.h
===================================================================
--- llvm/lib/IR/AttributeImpl.h
+++ llvm/lib/IR/AttributeImpl.h
@@ -220,10 +220,12 @@
   DenseMap<StringRef, Attribute> StringAttrs;
 
   AttributeSetNode(ArrayRef<Attribute> Attrs);
+  AttributeSetNode(ArrayRef<Attribute> EnumAttrs,
+                   ArrayRef<Attribute> StringAttrs);
 
+  Optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const;
   static AttributeSetNode *getSorted(LLVMContext &C,
                                      ArrayRef<Attribute> SortedAttrs);
-  Optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const;
 
 public:
   // AttributesSetNode is uniqued, these should not be available.
@@ -233,6 +235,7 @@
   void operator delete(void *p) { ::operator delete(p); }
 
   static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B);
+  static AttributeSetNode *get(LLVMContext &C, const SmallAttrBuilder &B);
 
   static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs);
 
Index: llvm/include/llvm/IR/Function.h
===================================================================
--- llvm/include/llvm/IR/Function.h
+++ llvm/include/llvm/IR/Function.h
@@ -333,6 +333,7 @@
 
   /// Add function attributes to this function.
   void addFnAttrs(const AttrBuilder &Attrs);
+  void addFnAttrs(const SmallAttrBuilder &Attrs);
 
   /// Add return value attributes to this function.
   void addRetAttr(Attribute::AttrKind Kind);
@@ -365,6 +366,7 @@
   void removeFnAttr(StringRef Kind);
 
   void removeFnAttrs(const AttrBuilder &Attrs);
+  void removeFnAttrs(const SmallAttrBuilder &Attrs);
 
   /// removes the attribute from the return value list of attributes.
   void removeRetAttr(Attribute::AttrKind Kind);
Index: llvm/include/llvm/IR/Attributes.h
===================================================================
--- llvm/include/llvm/IR/Attributes.h
+++ llvm/include/llvm/IR/Attributes.h
@@ -34,6 +34,7 @@
 namespace llvm {
 
 class AttrBuilder;
+class SmallAttrBuilder;
 class AttributeImpl;
 class AttributeListImpl;
 class AttributeSetNode;
@@ -287,6 +288,7 @@
   ~AttributeSet() = default;
 
   static AttributeSet get(LLVMContext &C, const AttrBuilder &B);
+  static AttributeSet get(LLVMContext &C, const SmallAttrBuilder &B);
   static AttributeSet get(LLVMContext &C, ArrayRef<Attribute> Attrs);
 
   bool operator==(const AttributeSet &O) const { return SetNode == O.SetNode; }
@@ -321,6 +323,8 @@
   /// attribute sets are immutable.
   LLVM_NODISCARD AttributeSet
   removeAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const;
+  LLVM_NODISCARD AttributeSet
+  removeAttributes(LLVMContext &C, const SmallAttrBuilder &AttrsToRemove) const;
 
   /// Return the number of attributes in this set.
   unsigned getNumAttributes() const;
@@ -457,6 +461,8 @@
                            ArrayRef<StringRef> Kind);
   static AttributeList get(LLVMContext &C, unsigned Index,
                            const AttrBuilder &B);
+  static AttributeList get(LLVMContext &C, unsigned Index,
+                           const SmallAttrBuilder &B);
 
   // TODO: remove non-AtIndex versions of these methods.
   /// Add an attribute to the attribute set at the given index.
@@ -481,6 +487,8 @@
   LLVM_NODISCARD AttributeList addAttributesAtIndex(LLVMContext &C,
                                                     unsigned Index,
                                                     const AttrBuilder &B) const;
+  LLVM_NODISCARD AttributeList addAttributesAtIndex(
+      LLVMContext &C, unsigned Index, const SmallAttrBuilder &B) const;
 
   /// Add a function attribute to the list. Returns a new list because
   /// attribute lists are immutable.
@@ -509,6 +517,10 @@
                                                const AttrBuilder &B) const {
     return addAttributesAtIndex(C, FunctionIndex, B);
   }
+  LLVM_NODISCARD AttributeList
+  addFnAttributes(LLVMContext &C, const SmallAttrBuilder &B) const {
+    return addAttributesAtIndex(C, FunctionIndex, B);
+  }
 
   /// Add a return value attribute to the list. Returns a new list because
   /// attribute lists are immutable.
@@ -530,6 +542,10 @@
                                                 const AttrBuilder &B) const {
     return addAttributesAtIndex(C, ReturnIndex, B);
   }
+  LLVM_NODISCARD AttributeList
+  addRetAttributes(LLVMContext &C, const SmallAttrBuilder &B) const {
+    return addAttributesAtIndex(C, ReturnIndex, B);
+  }
 
   /// Add an argument attribute to the list. Returns a new list because
   /// attribute lists are immutable.
@@ -559,6 +575,10 @@
                                                   const AttrBuilder &B) const {
     return addAttributesAtIndex(C, ArgNo + FirstArgIndex, B);
   }
+  LLVM_NODISCARD AttributeList addParamAttributes(
+      LLVMContext &C, unsigned ArgNo, const SmallAttrBuilder &B) const {
+    return addAttributesAtIndex(C, ArgNo + FirstArgIndex, B);
+  }
 
   /// Remove the specified attribute at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
@@ -579,6 +599,9 @@
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeAttributesAtIndex(
       LLVMContext &C, unsigned Index, const AttrBuilder &AttrsToRemove) const;
+  LLVM_NODISCARD AttributeList
+  removeAttributesAtIndex(LLVMContext &C, unsigned Index,
+                          const SmallAttrBuilder &AttrsToRemove) const;
 
   /// Remove all attributes at the specified index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
@@ -605,6 +628,10 @@
   removeFnAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const {
     return removeAttributesAtIndex(C, FunctionIndex, AttrsToRemove);
   }
+  LLVM_NODISCARD AttributeList removeFnAttributes(
+      LLVMContext &C, const SmallAttrBuilder &AttrsToRemove) const {
+    return removeAttributesAtIndex(C, FunctionIndex, AttrsToRemove);
+  }
 
   /// Remove the attributes at the function index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
@@ -632,6 +659,10 @@
   removeRetAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const {
     return removeAttributesAtIndex(C, ReturnIndex, AttrsToRemove);
   }
+  LLVM_NODISCARD AttributeList removeRetAttributes(
+      LLVMContext &C, const SmallAttrBuilder &AttrsToRemove) const {
+    return removeAttributesAtIndex(C, ReturnIndex, AttrsToRemove);
+  }
 
   /// Remove the specified attribute at the specified arg index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
@@ -654,6 +685,11 @@
       LLVMContext &C, unsigned ArgNo, const AttrBuilder &AttrsToRemove) const {
     return removeAttributesAtIndex(C, ArgNo + FirstArgIndex, AttrsToRemove);
   }
+  LLVM_NODISCARD AttributeList
+  removeParamAttributes(LLVMContext &C, unsigned ArgNo,
+                        const SmallAttrBuilder &AttrsToRemove) const {
+    return removeAttributesAtIndex(C, ArgNo + FirstArgIndex, AttrsToRemove);
+  }
 
   /// Remove all attributes at the specified arg index from this
   /// attribute list. Returns a new list because attribute lists are immutable.
@@ -927,6 +963,173 @@
 
 //===----------------------------------------------------------------------===//
 /// \class
+/// This class aggregates add/remove attribute requests in order to efficiently
+/// build new AttributeSet. Unlike AttrBuilder, it is not suited to query the
+/// state of attributes.
+
+class SmallAttrBuilder {
+  LLVMContext &Ctxt;
+
+  SmallVector<Attribute> EnumAttrs;
+  SmallVector<Attribute> StringAttrs;
+
+  struct StringAttributeComparator {
+    bool operator()(Attribute A0, Attribute A1) const {
+      return A0.getKindAsString() < A1.getKindAsString();
+    }
+    bool operator()(Attribute A0, StringRef Kind) const {
+      return A0.getKindAsString() < Kind;
+    }
+  };
+  struct EnumAttributeComparator {
+    bool operator()(Attribute A0, Attribute A1) const {
+      return A0.getKindAsEnum() < A1.getKindAsEnum();
+    }
+    bool operator()(Attribute A0, Attribute::AttrKind Kind) const {
+      return A0.getKindAsEnum() < Kind;
+    }
+  };
+  iterator addStringAttributeHelper(Attribute A, iterator Iter) {
+    auto R = std::lower_bound(Iter, StringAttrs.end(), A,
+                              StringAttributeComparator{});
+    if (R == StringAttrs.end()) {
+      StringAttrs.push_back(A);
+      return StringAttrs.end();
+    } else if (R->hasAttribute(A.getKindAsString())) {
+      std::swap(*R, A);
+      return R;
+    } else {
+      return StringAttrs.insert(R, A);
+    }
+  }
+  iterator addEnumAttributeHelper(Attribute A, iterator Iter) {
+    auto R =
+        std::lower_bound(Iter, EnumAttrs.end(), A, EnumAttributeComparator{});
+    if (R == EnumAttrs.end()) {
+      EnumAttrs.push_back(A);
+      return EnumAttrs.end();
+    } else if (R->hasAttribute(A.getKindAsEnum()))
+      return R;
+    else {
+      return EnumAttrs.insert(R, A);
+    }
+  }
+  iterator addAttributeHelper(Attribute A, iterator Iter) {
+    if (A.isStringAttribute()) {
+      return addStringAttributeHelper(A, Iter);
+    } else {
+      return addEnumAttributeHelper(A, Iter);
+    }
+  }
+
+public:
+  using iterator = typename SmallVector<Attribute>::iterator;
+
+  SmallAttrBuilder(LLVMContext &Ctxt) : Ctxt(Ctxt) {}
+  SmallAttrBuilder(LLVMContext &Ctxt, AttributeList AL, unsigned Idx)
+      : SmallAttrBuilder(Ctxt, AL.getAttributes(Idx)) {}
+  template <class Range>
+  SmallAttrBuilder(LLVMContext &Ctxt, Range &&R) : Ctxt(Ctxt) {
+    for (Attribute A : R)
+      if (A.isStringAttribute())
+        StringAttrs.push_back(A);
+      else
+        EnumAttrs.push_back(A);
+    llvm::sort(StringAttrs, StringAttributeComparator());
+    llvm::sort(EnumAttrs, EnumAttributeComparator());
+  }
+
+  SmallAttrBuilder &addAttribute(Attribute::AttrKind Val) {
+    Attribute A = Attribute::get(Ctxt, Val);
+    auto R = std::lower_bound(EnumAttrs.begin(), EnumAttrs.end(), A,
+                              EnumAttributeComparator{});
+    if (R != EnumAttrs.end() && R->hasAttribute(Val))
+      return *this;
+    else
+      EnumAttrs.insert(R, A);
+    return *this;
+  }
+  SmallAttrBuilder &addAttribute(StringRef K, StringRef V = StringRef()) {
+    Attribute A = Attribute::get(Ctxt, K, V);
+    auto R = std::lower_bound(StringAttrs.begin(), StringAttrs.end(), A,
+                              StringAttributeComparator{});
+    if (R != StringAttrs.end() && R->hasAttribute(K))
+      std::swap(*R, A);
+    else
+      StringAttrs.insert(R, A);
+    return *this;
+  }
+  SmallAttrBuilder &addAttribute(Attribute A) {
+    if (A.isStringAttribute())
+      addStringAttributeHelper(A, StringAttrs.begin());
+    else
+      addEnumAttributeHelper(A, EnumAttrs.begin());
+    return *this;
+  }
+  SmallAttrBuilder &merge(const SmallAttrBuilder &B);
+
+  bool hasAttributes() const {
+    return !EnumAttrs.empty() || !StringAttrs.empty();
+  }
+
+  SmallAttrBuilder &removeAttribute(StringRef Val) {
+    auto R = std::lower_bound(StringAttrs.begin(), StringAttrs.end(), Val,
+                              StringAttributeComparator{});
+    if (R != StringAttrs.end() && R->hasAttribute(Val)) {
+      StringAttrs.erase(R);
+    }
+    return *this;
+  }
+
+  SmallAttrBuilder &removeAttribute(Attribute::AttrKind Val) {
+    auto R = std::lower_bound(EnumAttrs.begin(), EnumAttrs.end(), Val,
+                              EnumAttributeComparator{});
+    if (R != EnumAttrs.end() && R->hasAttribute(Val)) {
+      EnumAttrs.erase(R);
+    }
+    return *this;
+  }
+  SmallAttrBuilder &removeStringAttribute(Attribute A) {
+    return removeAttribute(A.getKindAsString());
+  }
+  SmallAttrBuilder &removeEnumAttribute(Attribute A) {
+    return removeAttribute(A.getKindAsEnum());
+  }
+
+  SmallAttrBuilder &removeAttribute(Attribute A) {
+    if (A.isStringAttribute())
+      return removeStringAttribute(A);
+    else
+      return removeEnumAttribute(A);
+  }
+
+  unsigned size() const { return EnumAttrs.size() + StringAttrs.size(); }
+
+  bool empty() const { return EnumAttrs.empty(); }
+
+  void clear() {
+    EnumAttrs.clear();
+    StringAttrs.clear();
+  }
+  std::pair<ArrayRef<Attribute>, ArrayRef<Attribute>> uniquify() const {
+    return std::make_pair(ArrayRef<Attribute>(EnumAttrs),
+                          ArrayRef<Attribute>(StringAttrs));
+  }
+
+  SmallAttrBuilder &addAllocSizeAttr(unsigned ElemSize,
+                                     const Optional<unsigned> &NumElems);
+  SmallAttrBuilder &addDereferenceableAttr(uint64_t Bytes);
+  SmallAttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes);
+  SmallAttrBuilder &addAlignmentAttr(MaybeAlign Align);
+  SmallAttrBuilder &addAlignmentAttr(unsigned Align) {
+    return addAlignmentAttr(MaybeAlign(Align));
+  }
+  SmallAttrBuilder &addStructRetAttr(Type *Ty);
+  SmallAttrBuilder &addByValAttr(Type *Ty);
+};
+
+//===----------------------------------------------------------------------===//
+/// \class
 /// This class is used in conjunction with the Attribute::get method to
 /// create an Attribute object. The object itself is uniquified. The Builder's
 /// value, however, is not. So this can be used as a quick way to test for
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1223,7 +1223,7 @@
 
   /// Like the overload taking a `Function &`, but intended specifically
   /// for frontends that want to build on Clang's target-configuration logic.
-  void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs);
+  void addDefaultFunctionDefinitionAttributes(llvm::SmallAttrBuilder &attrs);
 
   StringRef getMangledName(GlobalDecl GD);
   StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
@@ -1483,7 +1483,7 @@
                         ForDefinition_t IsForDefinition = NotForDefinition);
 
   bool GetCPUAndFeaturesAttributes(GlobalDecl GD,
-                                   llvm::AttrBuilder &AttrBuilder);
+                                   llvm::SmallAttrBuilder &AttrBuilder);
   void setNonAliasAttributes(GlobalDecl GD, llvm::GlobalObject *GO);
 
   /// Set function attributes for a function declaration.
@@ -1623,7 +1623,7 @@
   /// attributes to add to a function with the given properties.
   void getDefaultFunctionAttributes(StringRef Name, bool HasOptnone,
                                     bool AttrOnCallSite,
-                                    llvm::AttrBuilder &FuncAttrs);
+                                    llvm::SmallAttrBuilder &FuncAttrs);
 
   llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
                                                StringRef Suffix);
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -1819,7 +1819,7 @@
 
 void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
                                                            llvm::Function *F) {
-  llvm::AttrBuilder B;
+  llvm::SmallAttrBuilder B(getLLVMContext());
 
   if (CodeGenOpts.UnwindTables)
     B.addAttribute(llvm::Attribute::UWTable);
@@ -1982,9 +1982,7 @@
 void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
                                                   llvm::Function *F) {
   if (D->hasAttr<StrictFPAttr>()) {
-    llvm::AttrBuilder FuncAttrs;
-    FuncAttrs.addAttribute("strictfp");
-    F->addFnAttrs(FuncAttrs);
+    F->addFnAttr("strictfp");
   }
 }
 
@@ -2007,7 +2005,7 @@
 }
 
 bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
-                                                llvm::AttrBuilder &Attrs) {
+                                                llvm::SmallAttrBuilder &Attrs) {
   // Add target-cpu and target-features attributes to functions. If
   // we have a decl for the function and it has a target attribute then
   // parse that and add it to the feature set.
@@ -2092,12 +2090,12 @@
         if (!D->getAttr<SectionAttr>())
           F->addFnAttr("implicit-section-name", SA->getName());
 
-      llvm::AttrBuilder Attrs;
+      llvm::SmallAttrBuilder Attrs(getLLVMContext());
       if (GetCPUAndFeaturesAttributes(GD, Attrs)) {
         // We know that GetCPUAndFeaturesAttributes will always have the
         // newest set, since it has the newest possible FunctionDecl, so the
         // new ones should replace the old.
-        llvm::AttrBuilder RemoveAttrs;
+        llvm::SmallAttrBuilder RemoveAttrs(getLLVMContext());
         RemoveAttrs.addAttribute("target-cpu");
         RemoveAttrs.addAttribute("target-features");
         RemoveAttrs.addAttribute("tune-cpu");
@@ -3785,7 +3783,8 @@
   if (D)
     SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
   if (ExtraAttrs.hasFnAttrs()) {
-    llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
+    llvm::SmallAttrBuilder B(getLLVMContext(), ExtraAttrs,
+                             llvm::AttributeList::FunctionIndex);
     F->addFnAttrs(B);
   }
 
Index: clang/lib/CodeGen/CodeGenABITypes.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenABITypes.cpp
+++ clang/lib/CodeGen/CodeGenABITypes.cpp
@@ -27,8 +27,8 @@
 using namespace clang;
 using namespace CodeGen;
 
-void CodeGen::addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM,
-                                                     llvm::AttrBuilder &attrs) {
+void CodeGen::addDefaultFunctionDefinitionAttributes(
+    CodeGenModule &CGM, llvm::SmallAttrBuilder &attrs) {
   CGM.addDefaultFunctionDefinitionAttributes(attrs);
 }
 
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1736,9 +1736,10 @@
   return GetFunctionType(GD);
 }
 
-static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
-                                               llvm::AttrBuilder &FuncAttrs,
-                                               const FunctionProtoType *FPT) {
+static void
+AddAttributesFromFunctionProtoType(ASTContext &Ctx,
+                                   llvm::SmallAttrBuilder &FuncAttrs,
+                                   const FunctionProtoType *FPT) {
   if (!FPT)
     return;
 
@@ -1747,7 +1748,7 @@
     FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
 }
 
-static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
+static void AddAttributesFromAssumes(llvm::SmallAttrBuilder &FuncAttrs,
                                      const Decl *Callee) {
   if (!Callee)
     return;
@@ -1774,10 +1775,9 @@
   return ReturnType.isTriviallyCopyableType(Context);
 }
 
-void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
-                                                 bool HasOptnone,
-                                                 bool AttrOnCallSite,
-                                               llvm::AttrBuilder &FuncAttrs) {
+void CodeGenModule::getDefaultFunctionAttributes(
+    StringRef Name, bool HasOptnone, bool AttrOnCallSite,
+    llvm::SmallAttrBuilder &FuncAttrs) {
   // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
   if (!HasOptnone) {
     if (CodeGenOpts.OptimizeSize)
@@ -1898,7 +1898,7 @@
 }
 
 void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) {
-  llvm::AttrBuilder FuncAttrs;
+  llvm::SmallAttrBuilder FuncAttrs(F.getContext());
   getDefaultFunctionAttributes(F.getName(), F.hasOptNone(),
                                /* AttrOnCallSite = */ false, FuncAttrs);
   // TODO: call GetCPUAndFeaturesAttributes?
@@ -1906,13 +1906,13 @@
 }
 
 void CodeGenModule::addDefaultFunctionDefinitionAttributes(
-                                                   llvm::AttrBuilder &attrs) {
+    llvm::SmallAttrBuilder &attrs) {
   getDefaultFunctionAttributes(/*function name*/ "", /*optnone*/ false,
                                /*for call*/ false, attrs);
   GetCPUAndFeaturesAttributes(GlobalDecl(), attrs);
 }
 
-static void addNoBuiltinAttributes(llvm::AttrBuilder &FuncAttrs,
+static void addNoBuiltinAttributes(llvm::SmallAttrBuilder &FuncAttrs,
                                    const LangOptions &LangOpts,
                                    const NoBuiltinAttr *NBA = nullptr) {
   auto AddNoBuiltinAttr = [&FuncAttrs](StringRef BuiltinName) {
@@ -2020,8 +2020,8 @@
                                            llvm::AttributeList &AttrList,
                                            unsigned &CallingConv,
                                            bool AttrOnCallSite, bool IsThunk) {
-  llvm::AttrBuilder FuncAttrs;
-  llvm::AttrBuilder RetAttrs;
+  llvm::SmallAttrBuilder FuncAttrs(getLLVMContext());
+  llvm::SmallAttrBuilder RetAttrs(getLLVMContext());
 
   // Collect function IR attributes from the CC lowering.
   // We'll collect the paramete and result attributes later.
Index: clang/include/clang/CodeGen/CodeGenABITypes.h
===================================================================
--- clang/include/clang/CodeGen/CodeGenABITypes.h
+++ clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -30,7 +30,7 @@
 #include "llvm/IR/BasicBlock.h"
 
 namespace llvm {
-class AttrBuilder;
+class SmallAttrBuilder;
 class Constant;
 class DataLayout;
 class Module;
@@ -129,7 +129,7 @@
 /// This function assumes that the caller is not defining a function that
 /// requires special no-builtin treatment.
 void addDefaultFunctionDefinitionAttributes(CodeGenModule &CGM,
-                                            llvm::AttrBuilder &attrs);
+                                            llvm::SmallAttrBuilder &attrs);
 
 /// Returns the default constructor for a C struct with non-trivially copyable
 /// fields, generating it if necessary. The returned function uses the `cdecl`
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to