<div dir="ltr">r303693<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 23, 2017 at 1:59 PM, Galina Kistanova <span dir="ltr"><<a href="mailto:gkistanova@gmail.com" target="_blank">gkistanova@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello Reid,<br><br>It look like this commit broke one of our builders:<br><br><a href="http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/2524" target="_blank">http://lab.llvm.org:8011/<wbr>builders/llvm-clang-x86_64-<wbr>expensive-checks-win/builds/<wbr>2524</a><br><br>Please have a look at this?<br><br>Thanks<span class="HOEnZb"><font color="#888888"><br><br>Galina<br><br></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 23, 2017 at 10:01 AM, Reid Kleckner via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rnk<br>
Date: Tue May 23 12:01:48 2017<br>
New Revision: 303654<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=303654&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=303654&view=rev</a><br>
Log:<br>
[IR] Switch AttributeList to use an array for O(1) access<br>
<br>
Summary:<br>
Before this change, AttributeLists stored a pair of index and<br>
AttributeSet. This is memory efficient if most arguments do not have<br>
attributes. However, it requires doing a search over the pairs to test<br>
an argument or function attribute. Profiling shows that this loop was<br>
0.76% of the time in 'opt -O2' of sqlite3.c, because LLVM constantly<br>
tests values for nullability.<br>
<br>
This was worth about 2.5% of mid-level optimization cycles on the<br>
sqlite3 amalgamation. Here are the full perf results:<br>
<a href="https://reviews.llvm.org/P7995" rel="noreferrer" target="_blank">https://reviews.llvm.org/P7995</a><br>
<br>
Here are just the before and after cycle counts:<br>
```<br>
$ perf stat -r 5 ./opt_before -O2 sqlite3.bc -o /dev/null<br>
    13,274,181,184      cycles                    #    3.047 GHz                      ( +-  0.28% )<br>
$ perf stat -r 5 ./opt_after -O2 sqlite3.bc -o /dev/null<br>
    12,906,927,263      cycles                    #    3.043 GHz                      ( +-  0.51% )<br>
```<br>
<br>
This patch *does not* change the indices used to query attributes, as<br>
requested by reviewers. Tracking whether an index is usable for array<br>
indexing is a huge pain that affects many of the internal APIs, so it<br>
would be good to come back later and do a cleanup to remove this<br>
internal adjustment.<br>
<br>
Reviewers: pete, chandlerc<br>
<br>
Subscribers: javed.absar, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D32819" rel="noreferrer" target="_blank">https://reviews.llvm.org/D3281<wbr>9</a><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/IR/Att<wbr>ributes.h<br>
    llvm/trunk/lib/Bitcode/Writer/<wbr>BitcodeWriter.cpp<br>
    llvm/trunk/lib/Bitcode/Writer/<wbr>ValueEnumerator.cpp<br>
    llvm/trunk/lib/IR/AttributeImp<wbr>l.h<br>
    llvm/trunk/lib/IR/Attributes.c<wbr>pp<br>
    llvm/trunk/lib/IR/Instructions<wbr>.cpp<br>
    llvm/trunk/lib/IR/Verifier.cpp<br>
    llvm/trunk/lib/Transforms/Util<wbr>s/FunctionComparator.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/IR/Att<wbr>ributes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.h?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/include/llvm/<wbr>IR/Attributes.h?rev=303654&r1=<wbr>303653&r2=303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/IR/Att<wbr>ributes.h (original)<br>
+++ llvm/trunk/include/llvm/IR/Att<wbr>ributes.h Tue May 23 12:01:48 2017<br>
@@ -322,7 +322,7 @@ template <> struct DenseMapInfo<Attribut<br>
 /// the AttributeList object. The function attributes are at index<br>
 /// `AttributeList::FunctionIndex'<wbr>, the return value is at index<br>
 /// `AttributeList::ReturnIndex', and the attributes for the parameters start at<br>
-/// index `1'.<br>
+/// index `AttributeList::FirstArgIndex'<wbr>.<br>
 class AttributeList {<br>
 public:<br>
   enum AttrIndex : unsigned {<br>
@@ -347,8 +347,8 @@ public:<br>
   /// \brief Create an AttributeList with the specified parameters in it.<br>
   static AttributeList get(LLVMContext &C,<br>
                            ArrayRef<std::pair<unsigned, Attribute>> Attrs);<br>
-  static AttributeList<br>
-  get(LLVMContext &C, ArrayRef<std::pair<unsigned, AttributeSet>> Attrs);<br>
+  static AttributeList get(LLVMContext &C,<br>
+                           ArrayRef<std::pair<unsigned, AttributeSet>> Attrs);<br>
<br>
   /// \brief Create an AttributeList from attribute sets for a function, its<br>
   /// return value, and all of its arguments.<br>
@@ -356,13 +356,11 @@ public:<br>
                            AttributeSet RetAttrs,<br>
                            ArrayRef<AttributeSet> ArgAttrs);<br>
<br>
-  static AttributeList<br>
-  getImpl(LLVMContext &C,<br>
-          ArrayRef<std::pair<unsigned, AttributeSet>> Attrs);<br>
-<br>
 private:<br>
   explicit AttributeList(AttributeListImp<wbr>l *LI) : pImpl(LI) {}<br>
<br>
+  static AttributeList getImpl(LLVMContext &C, ArrayRef<AttributeSet> AttrSets);<br>
+<br>
 public:<br>
   AttributeList() = default;<br>
<br>
@@ -521,39 +519,31 @@ public:<br>
   /// \brief Return the attributes at the index as a string.<br>
   std::string getAsString(unsigned Index, bool InAttrGrp = false) const;<br>
<br>
-  using iterator = ArrayRef<Attribute>::iterator;<br>
+  //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
+  // AttributeList Introspection<br>
+  //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
<br>
-  iterator begin(unsigned Slot) const;<br>
-  iterator end(unsigned Slot) const;<br>
+  typedef const AttributeSet *iterator;<br>
+  iterator begin() const;<br>
+  iterator end() const;<br>
+<br>
+  unsigned getNumAttrSets() const;<br>
+<br>
+  /// Use these to iterate over the valid attribute indices.<br>
+  unsigned index_begin() const { return AttributeList::FunctionIndex; }<br>
+  unsigned index_end() const { return getNumAttrSets() - 1; }<br>
<br>
   /// operator==/!= - Provide equality predicates.<br>
   bool operator==(const AttributeList &RHS) const { return pImpl == RHS.pImpl; }<br>
   bool operator!=(const AttributeList &RHS) const { return pImpl != RHS.pImpl; }<br>
<br>
-  //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
-  // AttributeList Introspection<br>
-  //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
-<br>
   /// \brief Return a raw pointer that uniquely identifies this attribute list.<br>
   void *getRawPointer() const {<br>
     return pImpl;<br>
   }<br>
<br>
   /// \brief Return true if there are no attributes.<br>
-  bool isEmpty() const {<br>
-    return getNumSlots() == 0;<br>
-  }<br>
-<br>
-  /// \brief Return the number of slots used in this attribute list.  This is<br>
-  /// the number of arguments that have an attribute set on them (including the<br>
-  /// function itself).<br>
-  unsigned getNumSlots() const;<br>
-<br>
-  /// \brief Return the index for the given slot.<br>
-  unsigned getSlotIndex(unsigned Slot) const;<br>
-<br>
-  /// \brief Return the attributes at the given slot.<br>
-  AttributeSet getSlotAttributes(unsigned Slot) const;<br>
+  bool isEmpty() const { return pImpl == nullptr; }<br>
<br>
   void dump() const;<br>
 };<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Writer/<wbr>BitcodeWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Bitcode/<wbr>Writer/BitcodeWriter.cpp?rev=<wbr>303654&r1=303653&r2=303654&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Bitcode/Writer/<wbr>BitcodeWriter.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Writer/<wbr>BitcodeWriter.cpp Tue May 23 12:01:48 2017<br>
@@ -660,10 +660,12 @@ void ModuleBitcodeWriter::writeAttr<wbr>ibute<br>
<br>
   SmallVector<uint64_t, 64> Record;<br>
   for (unsigned i = 0, e = Attrs.size(); i != e; ++i) {<br>
-    const AttributeList &A = Attrs[i];<br>
-    for (unsigned i = 0, e = A.getNumSlots(); i != e; ++i)<br>
-      Record.push_back(<br>
-          VE.getAttributeGroupID({A.getS<wbr>lotIndex(i), A.getSlotAttributes(i)}));<br>
+    AttributeList AL = Attrs[i];<br>
+    for (unsigned i = AL.index_begin(), e = AL.index_end(); i != e; ++i) {<br>
+      AttributeSet AS = AL.getAttributes(i);<br>
+      if (AS.hasAttributes())<br>
+        Record.push_back(VE.getAttribu<wbr>teGroupID({i, AS}));<br>
+    }<br>
<br>
     Stream.EmitRecord(bitc::PARAM<wbr>ATTR_CODE_ENTRY, Record);<br>
     Record.clear();<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Writer/<wbr>ValueEnumerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Bitcode/<wbr>Writer/ValueEnumerator.cpp?<wbr>rev=303654&r1=303653&r2=<wbr>303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Bitcode/Writer/<wbr>ValueEnumerator.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Writer/<wbr>ValueEnumerator.cpp Tue May 23 12:01:48 2017<br>
@@ -902,8 +902,11 @@ void ValueEnumerator::EnumerateAttr<wbr>ibute<br>
   }<br>
<br>
   // Do lookups for all attribute groups.<br>
-  for (unsigned i = 0, e = PAL.getNumSlots(); i != e; ++i) {<br>
-    IndexAndAttrSet Pair = {PAL.getSlotIndex(i), PAL.getSlotAttributes(i)};<br>
+  for (unsigned i = PAL.index_begin(), e = PAL.index_end(); i != e; ++i) {<br>
+    AttributeSet AS = PAL.getAttributes(i);<br>
+    if (!AS.hasAttributes())<br>
+      continue;<br>
+    IndexAndAttrSet Pair = {i, AS};<br>
     unsigned &Entry = AttributeGroupMap[Pair];<br>
     if (Entry == 0) {<br>
       AttributeGroups.push_back(Pai<wbr>r);<br>
<br>
Modified: llvm/trunk/lib/IR/AttributeImp<wbr>l.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AttributeImpl.h?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/IR/Attrib<wbr>uteImpl.h?rev=303654&r1=303653<wbr>&r2=303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/AttributeImp<wbr>l.h (original)<br>
+++ llvm/trunk/lib/IR/AttributeImp<wbr>l.h Tue May 23 12:01:48 2017<br>
@@ -212,27 +212,21 @@ using IndexAttrPair = std::pair<unsigned<br>
 /// return type, and parameters.<br>
 class AttributeListImpl final<br>
     : public FoldingSetNode,<br>
-      private TrailingObjects<AttributeListI<wbr>mpl, IndexAttrPair> {<br>
+      private TrailingObjects<AttributeListI<wbr>mpl, AttributeSet> {<br>
   friend class AttributeList;<br>
   friend TrailingObjects;<br>
<br>
 private:<br>
-  LLVMContext &Context;<br>
-  unsigned NumSlots; ///< Number of entries in this set.<br>
   /// Bitset with a bit for each available attribute Attribute::AttrKind.<br>
   uint64_t AvailableFunctionAttrs;<br>
+  LLVMContext &Context;<br>
+  unsigned NumAttrSets; ///< Number of entries in this set.<br>
<br>
   // Helper fn for TrailingObjects class.<br>
-  size_t numTrailingObjects(OverloadTok<wbr>en<IndexAttrPair>) { return NumSlots; }<br>
-<br>
-  /// \brief Return a pointer to the IndexAttrPair for the specified slot.<br>
-  const IndexAttrPair *getSlotPair(unsigned Slot) const {<br>
-    return getTrailingObjects<IndexAttrPa<wbr>ir>() + Slot;<br>
-  }<br>
+  size_t numTrailingObjects(OverloadTok<wbr>en<AttributeSet>) { return NumAttrSets; }<br>
<br>
 public:<br>
-  AttributeListImpl(LLVMContext &C,<br>
-                    ArrayRef<std::pair<unsigned, AttributeSet>> Slots);<br>
+  AttributeListImpl(LLVMContext &C, ArrayRef<AttributeSet> Sets);<br>
<br>
   // AttributesSetImpt is uniqued, these should not be available.<br>
   AttributeListImpl(const AttributeListImpl &) = delete;<br>
@@ -243,41 +237,18 @@ public:<br>
   /// \brief Get the context that created this AttributeListImpl.<br>
   LLVMContext &getContext() { return Context; }<br>
<br>
-  /// \brief Return the number of slots used in this attribute list. This is<br>
-  /// the number of arguments that have an attribute set on them (including the<br>
-  /// function itself).<br>
-  unsigned getNumSlots() const { return NumSlots; }<br>
-<br>
-  /// \brief Get the index of the given "slot" in the AttrNodes list. This index<br>
-  /// is the index of the return, parameter, or function object that the<br>
-  /// attributes are applied to, not the index into the AttrNodes list where the<br>
-  /// attributes reside.<br>
-  unsigned getSlotIndex(unsigned Slot) const {<br>
-    return getSlotPair(Slot)->first;<br>
-  }<br>
-<br>
-  /// \brief Retrieve the attribute set node for the given "slot" in the<br>
-  /// AttrNode list.<br>
-  AttributeSet getSlotAttributes(unsigned Slot) const {<br>
-    return getSlotPair(Slot)->second;<br>
-  }<br>
-<br>
   /// \brief Return true if the AttributeSet or the FunctionIndex has an<br>
   /// enum attribute of the given kind.<br>
   bool hasFnAttribute(Attribute::Attr<wbr>Kind Kind) const {<br>
     return AvailableFunctionAttrs & ((uint64_t)1) << Kind;<br>
   }<br>
<br>
-  using iterator = AttributeSet::iterator;<br>
-<br>
-  iterator begin(unsigned Slot) const {<br>
-    return getSlotAttributes(Slot).begin(<wbr>);<br>
-  }<br>
-  iterator end(unsigned Slot) const { return getSlotAttributes(Slot).end(); }<br>
+  typedef const AttributeSet *iterator;<br>
+  iterator begin() const { return getTrailingObjects<AttributeSe<wbr>t>(); }<br>
+  iterator end() const { return begin() + NumAttrSets; }<br>
<br>
   void Profile(FoldingSetNodeID &ID) const;<br>
-  static void Profile(FoldingSetNodeID &ID,<br>
-                      ArrayRef<std::pair<unsigned, AttributeSet>> Nodes);<br>
+  static void Profile(FoldingSetNodeID &ID, ArrayRef<AttributeSet> Nodes);<br>
<br>
   void dump() const;<br>
 };<br>
<br>
Modified: llvm/trunk/lib/IR/Attributes.c<wbr>pp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/IR/Attrib<wbr>utes.cpp?rev=303654&r1=303653&<wbr>r2=303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/Attributes.c<wbr>pp (original)<br>
+++ llvm/trunk/lib/IR/Attributes.c<wbr>pp Tue May 23 12:01:48 2017<br>
@@ -507,7 +507,7 @@ AttributeSet AttributeSet::get(LLVMConte<br>
 }<br>
<br>
 AttributeSet AttributeSet::addAttribute(LLV<wbr>MContext &C,<br>
-                          Attribute::AttrKind Kind) const {<br>
+                                        Attribute::AttrKind Kind) const {<br>
   if (hasAttribute(Kind)) return *this;<br>
   AttrBuilder B;<br>
   B.addAttribute(Kind);<br>
@@ -515,7 +515,7 @@ AttributeSet AttributeSet::addAttribute(<br>
 }<br>
<br>
 AttributeSet AttributeSet::addAttribute(LLV<wbr>MContext &C, StringRef Kind,<br>
-                          StringRef Value) const {<br>
+                                        StringRef Value) const {<br>
   AttrBuilder B;<br>
   B.addAttribute(Kind, Value);<br>
   return addAttributes(C, AttributeSet::get(C, B));<br>
@@ -788,48 +788,42 @@ std::string AttributeSetNode::getAsStrin<br>
 // AttributeListImpl Definition<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
<br>
-AttributeListImpl::AttributeL<wbr>istImpl(<br>
-    LLVMContext &C, ArrayRef<std::pair<unsigned, AttributeSet>> Slots)<br>
-    : Context(C), NumSlots(Slots.size()), AvailableFunctionAttrs(0) {<br>
-#ifndef NDEBUG<br>
-  assert(!Slots.empty() && "pointless AttributeListImpl");<br>
-  if (Slots.size() >= 2) {<br>
-    auto &PrevPair = Slots.front();<br>
-    for (auto &CurPair : Slots.drop_front()) {<br>
-      assert(PrevPair.first <= CurPair.first && "Attribute set not ordered!");<br>
-    }<br>
-  }<br>
-#endif<br>
+/// Map from AttributeList index to the internal array index. Adding one works:<br>
+///   FunctionIndex: ~0U -> 0<br>
+///   ReturnIndex:    0  -> 1<br>
+///   FirstArgIndex: 1.. -> 2..<br>
+static constexpr unsigned attrIdxToArrayIdx(unsigned Index) {<br>
+  return Index + 1;<br>
+}<br>
+<br>
+AttributeListImpl::AttributeL<wbr>istImpl(LLVMContext &C,<br>
+                                     ArrayRef<AttributeSet> Sets)<br>
+    : AvailableFunctionAttrs(0), Context(C), NumAttrSets(Sets.size()) {<br>
+  assert(!Sets.empty() && "pointless AttributeListImpl");<br>
<br>
   // There's memory after the node where we can store the entries in.<br>
-  std::copy(Slots.begin(), Slots.end(), getTrailingObjects<IndexAttrPa<wbr>ir>());<br>
+  std::copy(Sets.begin(), Sets.end(), getTrailingObjects<AttributeSe<wbr>t>());<br>
<br>
   // Initialize AvailableFunctionAttrs summary bitset.<br>
   static_assert(Attribute::EndA<wbr>ttrKinds <=<br>
                     sizeof(<wbr>AvailableFunctionAttrs) * CHAR_BIT,<br>
                 "Too many attributes");<br>
-  static_assert(AttributeList::F<wbr>unctionIndex == ~0u,<br>
-                "FunctionIndex should be biggest possible index");<br>
-  const auto &Last = Slots.back();<br>
-  if (Last.first == AttributeList::FunctionIndex) {<br>
-    AttributeSet Node = Last.second;<br>
-    for (Attribute I : Node) {<br>
-      if (!I.isStringAttribute())<br>
-        AvailableFunctionAttrs |= ((uint64_t)1) << I.getKindAsEnum();<br>
-    }<br>
+  static_assert(attrIdxToArrayId<wbr>x(AttributeList::<wbr>FunctionIndex) == 0U,<br>
+                "function should be stored in slot 0");<br>
+  for (Attribute I : Sets[0]) {<br>
+    if (!I.isStringAttribute())<br>
+      AvailableFunctionAttrs |= 1ULL << I.getKindAsEnum();<br>
   }<br>
 }<br>
<br>
 void AttributeListImpl::Profile(Fol<wbr>dingSetNodeID &ID) const {<br>
-  Profile(ID, makeArrayRef(getSlotPair(0), getNumSlots()));<br>
+  Profile(ID, makeArrayRef(begin(), end()));<br>
 }<br>
<br>
-void AttributeListImpl::Profile(<br>
-    FoldingSetNodeID &ID, ArrayRef<std::pair<unsigned, AttributeSet>> Nodes) {<br>
-  for (const auto &Node : Nodes) {<br>
-    ID.AddInteger(Node.first);<br>
-    ID.AddPointer(Node.second.SetN<wbr>ode);<br>
-  }<br>
+void AttributeListImpl::Profile(Fol<wbr>dingSetNodeID &ID,<br>
+                                ArrayRef<AttributeSet> Sets) {<br>
+  for (const auto &Set : Sets)<br>
+    ID.AddPointer(Set.SetNode);<br>
 }<br>
<br>
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)<br>
@@ -842,24 +836,13 @@ LLVM_DUMP_METHOD void AttributeListImpl:<br>
 // AttributeList Construction and Mutation Methods<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
<br>
-AttributeList AttributeList::getImpl(<br>
-    LLVMContext &C, ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {<br>
-  assert(!Attrs.empty() && "creating pointless AttributeList");<br>
-#ifndef NDEBUG<br>
-  unsigned LastIndex = 0;<br>
-  bool IsFirst = true;<br>
-  for (auto &&AttrPair : Attrs) {<br>
-    assert((IsFirst || LastIndex < AttrPair.first) &&<br>
-           "unsorted or duplicate AttributeList indices");<br>
-    assert(AttrPair.second.hasAttr<wbr>ibutes() && "pointless AttributeList slot");<br>
-    LastIndex = AttrPair.first;<br>
-    IsFirst = false;<br>
-  }<br>
-#endif<br>
+AttributeList AttributeList::getImpl(LLVMCon<wbr>text &C,<br>
+                                     ArrayRef<AttributeSet> AttrSets) {<br>
+  assert(!AttrSets.empty() && "pointless AttributeListImpl");<br>
<br>
   LLVMContextImpl *pImpl = C.pImpl;<br>
   FoldingSetNodeID ID;<br>
-  AttributeListImpl::Profile(ID, Attrs);<br>
+  AttributeListImpl::Profile(ID, AttrSets);<br>
<br>
   void *InsertPoint;<br>
   AttributeListImpl *PA =<br>
@@ -870,8 +853,8 @@ AttributeList AttributeList::getImpl(<br>
   if (!PA) {<br>
     // Coallocate entries after the AttributeListImpl itself.<br>
     void *Mem = ::operator new(<br>
-        AttributeListImpl::totalSizeTo<wbr>Alloc<IndexAttrPair>(Attrs.<wbr>size()));<br>
-    PA = new (Mem) AttributeListImpl(C, Attrs);<br>
+        AttributeListImpl::totalSizeTo<wbr>Alloc<AttributeSet>(AttrSets.<wbr>size()));<br>
+    PA = new (Mem) AttributeListImpl(C, AttrSets);<br>
     pImpl->AttrsLists.InsertNode(<wbr>PA, InsertPoint);<br>
   }<br>
<br>
@@ -912,7 +895,7 @@ AttributeList::get(LLVMContext &C,<br>
     AttrPairVec.emplace_back(Inde<wbr>x, AttributeSet::get(C, AttrVec));<br>
   }<br>
<br>
-  return getImpl(C, AttrPairVec);<br>
+  return get(C, AttrPairVec);<br>
 }<br>
<br>
 AttributeList<br>
@@ -922,35 +905,76 @@ AttributeList::get(LLVMContext &C,<br>
   if (Attrs.empty())<br>
     return AttributeList();<br>
<br>
-  return getImpl(C, Attrs);<br>
+  assert(std::is_sorted(Attrs.be<wbr>gin(), Attrs.end(),<br>
+                        [](const std::pair<unsigned, AttributeSet> &LHS,<br>
+                           const std::pair<unsigned, AttributeSet> &RHS) {<br>
+                          return LHS.first < RHS.first;<br>
+                        }) &&<br>
+         "Misordered Attributes list!");<br>
+  assert(none_of(Attrs,<br>
+                 [](const std::pair<unsigned, AttributeSet> &Pair) {<br>
+                   return !Pair.second.hasAttributes();<br>
+                 }) &&<br>
+         "Pointless attribute!");<br>
+<br>
+  unsigned MaxIndex = Attrs.back().first;<br>
+<br>
+  SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxI<wbr>ndex) + 1);<br>
+  for (auto Pair : Attrs)<br>
+    AttrVec[attrIdxToArrayIdx(Pair<wbr>.first)] = Pair.second;<br>
+<br>
+  return getImpl(C, AttrVec);<br>
 }<br>
<br>
 AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs,<br>
                                  AttributeSet RetAttrs,<br>
                                  ArrayRef<AttributeSet> ArgAttrs) {<br>
-  SmallVector<std::pair<unsigned<wbr>, AttributeSet>, 8> AttrPairs;<br>
-  if (RetAttrs.hasAttributes())<br>
-    AttrPairs.emplace_back(ReturnI<wbr>ndex, RetAttrs);<br>
-  size_t Index = 1;<br>
-  for (AttributeSet AS : ArgAttrs) {<br>
-    if (AS.hasAttributes())<br>
-      AttrPairs.emplace_back(Index, AS);<br>
-    ++Index;<br>
-  }<br>
-  if (FnAttrs.hasAttributes())<br>
-    AttrPairs.emplace_back(Functio<wbr>nIndex, FnAttrs);<br>
-  if (AttrPairs.empty())<br>
+  // Scan from the end to find the last argument with attributes.  Most<br>
+  // arguments don't have attributes, so it's nice if we can have fewer unique<br>
+  // AttributeListImpls by dropping empty attribute sets at the end of the list.<br>
+  unsigned NumSets = 0;<br>
+  for (size_t I = ArgAttrs.size(); I != 0; --I) {<br>
+    if (ArgAttrs[I - 1].hasAttributes()) {<br>
+      NumSets = I + 2;<br>
+      break;<br>
+    }<br>
+  }<br>
+  if (NumSets == 0) {<br>
+    // Check function and return attributes if we didn't have argument<br>
+    // attributes.<br>
+    if (RetAttrs.hasAttributes())<br>
+      NumSets = 2;<br>
+    else if (FnAttrs.hasAttributes())<br>
+      NumSets = 1;<br>
+  }<br>
+<br>
+  // If all attribute sets were empty, we can use the empty attribute list.<br>
+  if (NumSets == 0)<br>
     return AttributeList();<br>
-  return getImpl(C, AttrPairs);<br>
+<br>
+  SmallVector<AttributeSet, 8> AttrSets;<br>
+  AttrSets.reserve(NumSets);<br>
+  // If we have any attributes, we always have function attributes.<br>
+  AttrSets.push_back(FnAttrs);<br>
+  if (NumSets > 1)<br>
+    AttrSets.push_back(RetAttrs);<br>
+  if (NumSets > 2) {<br>
+    // Drop the empty argument attribute sets at the end.<br>
+    ArgAttrs = ArgAttrs.take_front(NumSets - 2);<br>
+    AttrSets.insert(AttrSets.end()<wbr>, ArgAttrs.begin(), ArgAttrs.end());<br>
+  }<br>
+<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::get(LLVMContext &C, unsigned Index,<br>
                                  const AttrBuilder &B) {<br>
   if (!B.hasAttributes())<br>
     return AttributeList();<br>
-  AttributeSet AS = AttributeSet::get(C, B);<br>
-  std::pair<unsigned, AttributeSet> Arr[1] = {{Index, AS}};<br>
-  return getImpl(C, Arr);<br>
+  Index = attrIdxToArrayIdx(Index);<br>
+  SmallVector<AttributeSet, 8> AttrSets(Index + 1);<br>
+  AttrSets[Index] = AttributeSet::get(C, B);<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::get(LLVMContext &C, unsigned Index,<br>
@@ -973,32 +997,22 @@ AttributeList AttributeList::get(LLVMCon<br>
                                  ArrayRef<AttributeList> Attrs) {<br>
   if (Attrs.empty())<br>
     return AttributeList();<br>
-  if (Attrs.size() == 1) return Attrs[0];<br>
+  if (Attrs.size() == 1)<br>
+    return Attrs[0];<br>
<br>
-  SmallVector<std::pair<unsigned<wbr>, AttributeSet>, 8> AttrNodeVec;<br>
-  AttributeListImpl *A0 = Attrs[0].pImpl;<br>
-  if (A0)<br>
-    AttrNodeVec.append(A0->getSlot<wbr>Pair(0), A0->getSlotPair(A0->getNumSlot<wbr>s()));<br>
-  // Copy all attributes from Attrs into AttrNodeVec while keeping AttrNodeVec<br>
-  // ordered by index.  Because we know that each list in Attrs is ordered by<br>
-  // index we only need to merge each successive list in rather than doing a<br>
-  // full sort.<br>
-  for (unsigned I = 1, E = Attrs.size(); I != E; ++I) {<br>
-    AttributeListImpl *ALI = Attrs[I].pImpl;<br>
-    if (!ALI) continue;<br>
-    SmallVector<std::pair<unsigned<wbr>, AttributeSet>, 8>::iterator<br>
-      ANVI = AttrNodeVec.begin(), ANVE;<br>
-    for (const IndexAttrPair *AI = ALI->getSlotPair(0),<br>
-                             *AE = ALI->getSlotPair(ALI->getNumSl<wbr>ots());<br>
-         AI != AE; ++AI) {<br>
-      ANVE = AttrNodeVec.end();<br>
-      while (ANVI != ANVE && ANVI->first <= AI->first)<br>
-        ++ANVI;<br>
-      ANVI = AttrNodeVec.insert(ANVI, *AI) + 1;<br>
-    }<br>
+  unsigned MaxSize = 0;<br>
+  for (AttributeList List : Attrs)<br>
+    MaxSize = std::max(MaxSize, List.getNumAttrSets());<br>
+<br>
+  SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);<br>
+  for (unsigned I = 0; I < MaxSize; ++I) {<br>
+    AttrBuilder CurBuilder;<br>
+    for (AttributeList List : Attrs)<br>
+      CurBuilder.merge(List.getAttri<wbr>butes(I - 1));<br>
+    NewAttrSets[I] = AttributeSet::get(C, CurBuilder);<br>
   }<br>
<br>
-  return getImpl(C, AttrNodeVec);<br>
+  return getImpl(C, NewAttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::addAttribute(LL<wbr>VMContext &C, unsigned Index,<br>
@@ -1022,29 +1036,19 @@ AttributeList AttributeList::addAttribut<br>
                                           Attribute A) const {<br>
   assert(std::is_sorted(<wbr>Indices.begin(), Indices.end()));<br>
<br>
-  unsigned I = 0, E = pImpl ? pImpl->getNumSlots() : 0;<br>
-  SmallVector<IndexAttrPair, 4> AttrVec;<br>
+  SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());<br>
+  unsigned MaxIndex = attrIdxToArrayIdx(Indices.back<wbr>());<br>
+  if (MaxIndex >= AttrSets.size())<br>
+    AttrSets.resize(MaxIndex + 1);<br>
+<br>
   for (unsigned Index : Indices) {<br>
-    // Add all attribute slots before the current index.<br>
-    for (; I < E && getSlotIndex(I) < Index; ++I)<br>
-      AttrVec.emplace_back(getSlotIn<wbr>dex(I), pImpl->getSlotAttributes(I));<br>
-<br>
-    // Add the attribute at this index. If we already have attributes at this<br>
-    // index, merge them into a new set.<br>
-    AttrBuilder B;<br>
-    if (I < E && getSlotIndex(I) == Index) {<br>
-      B.merge(AttrBuilder(pImpl->get<wbr>SlotAttributes(I)));<br>
-      ++I;<br>
-    }<br>
+    Index = attrIdxToArrayIdx(Index);<br>
+    AttrBuilder B(AttrSets[Index]);<br>
     B.addAttribute(A);<br>
-    AttrVec.emplace_back(Index, AttributeSet::get(C, B));<br>
+    AttrSets[Index] = AttributeSet::get(C, B);<br>
   }<br>
<br>
-  // Add remaining attributes.<br>
-  for (; I < E; ++I)<br>
-    AttrVec.emplace_back(getSlotIn<wbr>dex(I), pImpl->getSlotAttributes(I));<br>
-<br>
-  return get(C, AttrVec);<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::addAttributes(L<wbr>LVMContext &C, unsigned Index,<br>
@@ -1064,33 +1068,16 @@ AttributeList AttributeList::addAttribut<br>
          "Attempt to change alignment!");<br>
 #endif<br>
<br>
-  SmallVector<IndexAttrPair, 4> AttrVec;<br>
-  uint64_t NumAttrs = pImpl->getNumSlots();<br>
-  unsigned I;<br>
-<br>
-  // Add all the attribute slots before the one we need to merge.<br>
-  for (I = 0; I < NumAttrs; ++I) {<br>
-    if (getSlotIndex(I) >= Index)<br>
-      break;<br>
-    AttrVec.emplace_back(getSlotIn<wbr>dex(I), pImpl->getSlotAttributes(I));<br>
-  }<br>
+  Index = attrIdxToArrayIdx(Index);<br>
+  SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());<br>
+  if (Index >= AttrSets.size())<br>
+    AttrSets.resize(Index + 1);<br>
+<br>
+  AttrBuilder Merged(AttrSets[Index]);<br>
+  Merged.merge(B);<br>
+  AttrSets[Index] = AttributeSet::get(C, Merged);<br>
<br>
-  AttrBuilder NewAttrs;<br>
-  if (I < NumAttrs && getSlotIndex(I) == Index) {<br>
-    // We need to merge the attribute sets.<br>
-    NewAttrs.merge(pImpl->getSlotA<wbr>ttributes(I));<br>
-    ++I;<br>
-  }<br>
-  NewAttrs.merge(B);<br>
-<br>
-  // Add the new or merged attribute set at this index.<br>
-  AttrVec.emplace_back(Index, AttributeSet::get(C, NewAttrs));<br>
-<br>
-  // Add the remaining entries.<br>
-  for (; I < NumAttrs; ++I)<br>
-    AttrVec.emplace_back(getSlotIn<wbr>dex(I), pImpl->getSlotAttributes(I));<br>
-<br>
-  return get(C, AttrVec);<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::removeAttribute<wbr>(LLVMContext &C, unsigned Index,<br>
@@ -1109,54 +1096,38 @@ AttributeList AttributeList::removeAttri<br>
   return removeAttributes(C, Index, B);<br>
 }<br>
<br>
-AttributeList AttributeList::removeAttribute<wbr>s(LLVMContext &C, unsigned Index,<br>
-                                              const AttrBuilder &Attrs) const {<br>
+AttributeList<br>
+AttributeList::removeAttribut<wbr>es(LLVMContext &C, unsigned Index,<br>
+                                const AttrBuilder &AttrsToRemove) const {<br>
   if (!pImpl)<br>
     return AttributeList();<br>
<br>
   // FIXME it is not obvious how this should work for alignment.<br>
   // For now, say we can't pass in alignment, which no current use does.<br>
-  assert(!Attrs.hasAlignmentAttr<wbr>() && "Attempt to change alignment!");<br>
+  assert(!AttrsToRemove.hasAlign<wbr>mentAttr() && "Attempt to change alignment!");<br>
<br>
-  // Add the attribute slots before the one we're trying to add.<br>
-  SmallVector<IndexAttrPair, 4> AttrSets;<br>
-  uint64_t NumAttrs = pImpl->getNumSlots();<br>
-  AttrBuilder B;<br>
-  uint64_t LastIndex = 0;<br>
-  for (unsigned I = 0, E = NumAttrs; I != E; ++I) {<br>
-    if (getSlotIndex(I) >= Index) {<br>
-      if (getSlotIndex(I) == Index)<br>
-        B = AttrBuilder(getSlotAttributes(<wbr>LastIndex++));<br>
-      break;<br>
-    }<br>
-    LastIndex = I + 1;<br>
-    AttrSets.push_back({getSlotInd<wbr>ex(I), getSlotAttributes(I)});<br>
-  }<br>
-<br>
-  // Remove the attributes from the existing set and add them.<br>
-  B.remove(Attrs);<br>
-  if (B.hasAttributes())<br>
-    AttrSets.push_back({Index, AttributeSet::get(C, B)});<br>
-<br>
-  // Add the remaining attribute slots.<br>
-  for (unsigned I = LastIndex, E = NumAttrs; I < E; ++I)<br>
-    AttrSets.push_back({getSlotInd<wbr>ex(I), getSlotAttributes(I)});<br>
+  Index = attrIdxToArrayIdx(Index);<br>
+  SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());<br>
+  if (Index >= AttrSets.size())<br>
+    AttrSets.resize(Index + 1);<br>
+<br>
+  AttrBuilder B(AttrSets[Index]);<br>
+  B.remove(AttrsToRemove);<br>
+  AttrSets[Index] = AttributeSet::get(C, B);<br>
<br>
-  return get(C, AttrSets);<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::removeAttribute<wbr>s(LLVMContext &C,<br>
                                               unsigned WithoutIndex) const {<br>
   if (!pImpl)<br>
     return AttributeList();<br>
-<br>
-  SmallVector<std::pair<unsigned<wbr>, AttributeSet>, 4> AttrSet;<br>
-  for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) {<br>
-    unsigned Index = getSlotIndex(I);<br>
-    if (Index != WithoutIndex)<br>
-      AttrSet.push_back({Index, pImpl->getSlotAttributes(I)});<br>
-  }<br>
-  return get(C, AttrSet);<br>
+  WithoutIndex = attrIdxToArrayIdx(WithoutIndex<wbr>);<br>
+  if (WithoutIndex >= getNumAttrSets())<br>
+    return *this;<br>
+  SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());<br>
+  AttrSets[WithoutIndex] = AttributeSet();<br>
+  return getImpl(C, AttrSets);<br>
 }<br>
<br>
 AttributeList AttributeList::addDereferencea<wbr>bleAttr(LLVMContext &C,<br>
@@ -1225,20 +1196,20 @@ bool AttributeList::hasFnAttribute(<wbr>Strin<br>
<br>
 bool AttributeList::hasParamAttribu<wbr>te(unsigned ArgNo,<br>
                                       Attribute::AttrKind Kind) const {<br>
-  return hasAttribute(ArgNo + 1, Kind);<br>
+  return hasAttribute(ArgNo + FirstArgIndex, Kind);<br>
 }<br>
<br>
 bool AttributeList::hasAttrSomewher<wbr>e(Attribute::AttrKind Attr,<br>
                                      unsigned *Index) const {<br>
   if (!pImpl) return false;<br>
<br>
-  for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I)<br>
-    for (AttributeListImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I);<br>
-         II != IE; ++II)<br>
-      if (II->hasAttribute(Attr)) {<br>
-        if (Index) *Index = pImpl->getSlotIndex(I);<br>
-        return true;<br>
-      }<br>
+  for (unsigned I = index_begin(), E = index_end(); I != E; ++I) {<br>
+    if (hasAttribute(I, Attr)) {<br>
+      if (Index)<br>
+        *Index = I;<br>
+      return true;<br>
+    }<br>
+  }<br>
<br>
   return false;<br>
 }<br>
@@ -1282,60 +1253,35 @@ std::string AttributeList::getAsString(u<br>
 }<br>
<br>
 AttributeSet AttributeList::getAttributes(u<wbr>nsigned Index) const {<br>
-  if (!pImpl) return AttributeSet();<br>
-<br>
-  // Loop through to find the attribute node we want.<br>
-  for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I)<br>
-    if (pImpl->getSlotIndex(I) == Index)<br>
-      return pImpl->getSlotAttributes(I);<br>
-<br>
-  return AttributeSet();<br>
+  Index = attrIdxToArrayIdx(Index);<br>
+  if (!pImpl || Index >= getNumAttrSets())<br>
+    return AttributeSet();<br>
+  return pImpl->begin()[Index];<br>
 }<br>
<br>
-AttributeList::iterator AttributeList::begin(unsigned Slot) const {<br>
-  if (!pImpl)<br>
-    return ArrayRef<Attribute>().begin();<br>
-  return pImpl->begin(Slot);<br>
+AttributeList::iterator AttributeList::begin() const {<br>
+  return pImpl ? pImpl->begin() : nullptr;<br>
 }<br>
<br>
-AttributeList::iterator AttributeList::end(unsigned Slot) const {<br>
-  if (!pImpl)<br>
-    return ArrayRef<Attribute>().end();<br>
-  return pImpl->end(Slot);<br>
+AttributeList::iterator AttributeList::end() const {<br>
+  return pImpl ? pImpl->end() : nullptr;<br>
 }<br>
<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
 // AttributeList Introspection Methods<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
<br>
-unsigned AttributeList::getNumSlots() const {<br>
-  return pImpl ? pImpl->getNumSlots() : 0;<br>
-}<br>
-<br>
-unsigned AttributeList::getSlotIndex(un<wbr>signed Slot) const {<br>
-  assert(pImpl && Slot < pImpl->getNumSlots() &&<br>
-         "Slot # out of range!");<br>
-  return pImpl->getSlotIndex(Slot);<br>
-}<br>
-<br>
-AttributeSet AttributeList::getSlotAttribut<wbr>es(unsigned Slot) const {<br>
-  assert(pImpl && Slot < pImpl->getNumSlots() &&<br>
-         "Slot # out of range!");<br>
-  return pImpl->getSlotAttributes(Slot)<wbr>;<br>
+unsigned AttributeList::getNumAttrSets(<wbr>) const {<br>
+  return pImpl ? pImpl->NumAttrSets : 0;<br>
 }<br>
<br>
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)<br>
 LLVM_DUMP_METHOD void AttributeList::dump() const {<br>
   dbgs() << "PAL[\n";<br>
<br>
-  for (unsigned i = 0, e = getNumSlots(); i < e; ++i) {<br>
-    uint64_t Index = getSlotIndex(i);<br>
-    dbgs() << "  { ";<br>
-    if (Index == ~0U)<br>
-      dbgs() << "~0U";<br>
-    else<br>
-      dbgs() << Index;<br>
-    dbgs() << " => " << getAsString(Index) << " }\n";<br>
+  for (unsigned i = index_begin(), e = index_end(); i != e; ++i) {<br>
+    if (getAttributes(i).hasAttribute<wbr>s())<br>
+      dbgs() << "  { " << i << " => " << getAsString(i) << " }\n";<br>
   }<br>
<br>
   dbgs() << "]\n";<br>
@@ -1346,26 +1292,16 @@ LLVM_DUMP_METHOD void AttributeList::dum<br>
 // AttrBuilder Method Implementations<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
<br>
+// FIXME: Remove this ctor, use AttributeSet.<br>
 AttrBuilder::AttrBuilder(Attr<wbr>ibuteList AL, unsigned Index) {<br>
-  AttributeListImpl *pImpl = AL.pImpl;<br>
-  if (!pImpl) return;<br>
-<br>
-  for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) {<br>
-    if (pImpl->getSlotIndex(I) != Index) continue;<br>
-<br>
-    for (AttributeListImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I);<br>
-         II != IE; ++II)<br>
-      addAttribute(*II);<br>
-<br>
-    break;<br>
-  }<br>
+  AttributeSet AS = AL.getAttributes(Index);<br>
+  for (const Attribute &A : AS)<br>
+    addAttribute(A);<br>
 }<br>
<br>
 AttrBuilder::AttrBuilder(Attr<wbr>ibuteSet AS) {<br>
-  if (AS.hasAttributes()) {<br>
-    for (const Attribute &A : AS)<br>
-      addAttribute(A);<br>
-  }<br>
+  for (const Attribute &A : AS)<br>
+    addAttribute(A);<br>
 }<br>
<br>
 void AttrBuilder::clear() {<br>
<br>
Modified: llvm/trunk/lib/IR/Instructions<wbr>.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Instructions.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/IR/Instru<wbr>ctions.cpp?rev=303654&r1=<wbr>303653&r2=303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/Instructions<wbr>.cpp (original)<br>
+++ llvm/trunk/lib/IR/Instructions<wbr>.cpp Tue May 23 12:01:48 2017<br>
@@ -454,6 +454,9 @@ bool CallInst::dataOperandHasImplie<wbr>dAttr<br>
   // question is a call argument; or be indirectly implied by the kind of its<br>
   // containing operand bundle, if the operand is a bundle operand.<br>
<br>
+  if (i == Attribute::ReturnIndex)<br>
+    return hasRetAttr(Kind);<br>
+<br>
   // FIXME: Avoid these i - 1 calculations and update the API to use zero-based<br>
   // indices.<br>
   if (i < (getNumArgOperands() + 1))<br>
@@ -779,6 +782,9 @@ bool InvokeInst::dataOperandHasImpl<wbr>iedAt<br>
   // question is an invoke argument; or be indirectly implied by the kind of its<br>
   // containing operand bundle, if the operand is a bundle operand.<br>
<br>
+  if (i == Attribute::ReturnIndex)<br>
+    return hasRetAttr(Kind);<br>
+<br>
   // FIXME: Avoid these i - 1 calculations and update the API to use zero-based<br>
   // indices.<br>
   if (i < (getNumArgOperands() + 1))<br>
<br>
Modified: llvm/trunk/lib/IR/Verifier.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/IR/Verifi<wbr>er.cpp?rev=303654&r1=303653&<wbr>r2=303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/Verifier.cpp (original)<br>
+++ llvm/trunk/lib/IR/Verifier.cpp Tue May 23 12:01:48 2017<br>
@@ -1736,17 +1736,9 @@ void Verifier::visitConstantExpr(co<wbr>nst C<br>
 }<br>
<br>
 bool Verifier::verifyAttributeCount<wbr>(AttributeList Attrs, unsigned Params) {<br>
-  if (Attrs.getNumSlots() == 0)<br>
-    return true;<br>
-<br>
-  unsigned LastSlot = Attrs.getNumSlots() - 1;<br>
-  unsigned LastIndex = Attrs.getSlotIndex(LastSlot);<br>
-  if (LastIndex <= Params ||<br>
-      (LastIndex == AttributeList::FunctionIndex &&<br>
-       (LastSlot == 0 || Attrs.getSlotIndex(LastSlot - 1) <= Params)))<br>
-    return true;<br>
-<br>
-  return false;<br>
+  // There shouldn't be more attribute sets than there are parameters plus the<br>
+  // function and return value.<br>
+  return Attrs.getNumAttrSets() <= Params + 2;<br>
 }<br>
<br>
 /// Verify that statepoint intrinsic is well formed.<br>
<br>
Modified: llvm/trunk/lib/Transforms/Util<wbr>s/FunctionComparator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/FunctionComparator.cpp?rev=303654&r1=303653&r2=303654&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Transform<wbr>s/Utils/FunctionComparator.<wbr>cpp?rev=303654&r1=303653&r2=<wbr>303654&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Transforms/Util<wbr>s/FunctionComparator.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Util<wbr>s/FunctionComparator.cpp Tue May 23 12:01:48 2017<br>
@@ -76,12 +76,14 @@ int FunctionComparator::cmpMem(Str<wbr>ingRef<br>
<br>
 int FunctionComparator::cmpAttrs(c<wbr>onst AttributeList L,<br>
                                  const AttributeList R) const {<br>
-  if (int Res = cmpNumbers(L.getNumSlots(), R.getNumSlots()))<br>
+  if (int Res = cmpNumbers(L.getNumAttrSets(), R.getNumAttrSets()))<br>
     return Res;<br>
<br>
-  for (unsigned i = 0, e = L.getNumSlots(); i != e; ++i) {<br>
-    AttributeList::iterator LI = L.begin(i), LE = L.end(i), RI = R.begin(i),<br>
-                            RE = R.end(i);<br>
+  for (unsigned i = L.index_begin(), e = L.index_end(); i != e; ++i) {<br>
+    AttributeSet LAS = L.getAttributes(i);<br>
+    AttributeSet RAS = R.getAttributes(i);<br>
+    AttributeSet::iterator LI = LAS.begin(), LE = LAS.end();<br>
+    AttributeSet::iterator RI = RAS.begin(), RE = RAS.end();<br>
     for (; LI != LE && RI != RE; ++LI, ++RI) {<br>
       Attribute LA = *LI;<br>
       Attribute RA = *RI;<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>