Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -284,9 +284,9 @@ class AttributeList { public: enum AttrIndex : unsigned { - ReturnIndex = 0U, - FunctionIndex = ~0U, - FirstArgIndex = 1, + FunctionIndex = 0, + ReturnIndex = 1, + FirstArgIndex = 2, }; private: @@ -305,8 +305,8 @@ /// \brief Create an AttributeList with the specified parameters in it. static AttributeList get(LLVMContext &C, ArrayRef> Attrs); - static AttributeList - get(LLVMContext &C, ArrayRef> Attrs); + static AttributeList get(LLVMContext &C, + ArrayRef> Attrs); /// \brief Create an AttributeList from attribute sets for a function, its /// return value, and all of its arguments. @@ -314,13 +314,11 @@ AttributeSet RetAttrs, ArrayRef ArgAttrs); - static AttributeList - getImpl(LLVMContext &C, - ArrayRef> Attrs); - private: explicit AttributeList(AttributeListImpl *LI) : pImpl(LI) {} + static AttributeList getImpl(LLVMContext &C, ArrayRef AttrSets); + public: AttributeList() = default; @@ -479,10 +477,13 @@ /// \brief Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; - typedef ArrayRef::iterator iterator; + typedef const AttributeSet *iterator; + iterator begin() const; + iterator end() const; + bool empty() const { return pImpl == nullptr; } + bool size() const; - iterator begin(unsigned Slot) const; - iterator end(unsigned Slot) const; + unsigned getNumAttrSets() const; /// operator==/!= - Provide equality predicates. bool operator==(const AttributeList &RHS) const { return pImpl == RHS.pImpl; } @@ -498,20 +499,7 @@ } /// \brief Return true if there are no attributes. - bool isEmpty() const { - return getNumSlots() == 0; - } - - /// \brief Return the number of slots used in this attribute list. This is - /// the number of arguments that have an attribute set on them (including the - /// function itself). - unsigned getNumSlots() const; - - /// \brief Return the index for the given slot. - unsigned getSlotIndex(unsigned Slot) const; - - /// \brief Return the attributes at the given slot. - AttributeSet getSlotAttributes(unsigned Slot) const; + bool isEmpty() const { return pImpl == nullptr; } void dump() const; }; Index: llvm/include/llvm/IR/Instructions.h =================================================================== --- llvm/include/llvm/IR/Instructions.h +++ llvm/include/llvm/IR/Instructions.h @@ -1714,7 +1714,7 @@ /// /// The index \p i is interpreted as /// - /// \p i == Attribute::ReturnIndex -> the return value + /// \p i == 0 -> the return value /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1233,8 +1233,10 @@ for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; + // Map from old to new AttributeList indices. + unsigned ParamIdx = Record[i] + 1; decodeLLVMAttributesForBitcode(B, Record[i+1]); - Attrs.push_back(AttributeList::get(Context, Record[i], B)); + Attrs.push_back(AttributeList::get(Context, ParamIdx, B)); } MAttributes.push_back(AttributeList::get(Context, Attrs)); @@ -1419,6 +1421,7 @@ uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. + ++Idx; // Map from old to new AttributeList indices. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -618,7 +618,9 @@ SmallVector Record; for (ValueEnumerator::IndexAndAttrSet Pair : AttrGrps) { - unsigned AttrListIndex = Pair.first; + // Translate from current AttributeList indices to old indices to preserve + // bitcode compatibility. + unsigned AttrListIndex = Pair.first - 1; AttributeSet AS = Pair.second; Record.push_back(VE.getAttributeGroupID(Pair)); Record.push_back(AttrListIndex); @@ -660,10 +662,12 @@ SmallVector Record; for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { - const AttributeList &A = Attrs[i]; - for (unsigned i = 0, e = A.getNumSlots(); i != e; ++i) - Record.push_back( - VE.getAttributeGroupID({A.getSlotIndex(i), A.getSlotAttributes(i)})); + AttributeList AL = Attrs[i]; + for (unsigned i = 0, e = AL.getNumAttrSets(); i != e; ++i) { + AttributeSet AS = AL.getAttributes(i); + if (AS.hasAttributes()) + Record.push_back(VE.getAttributeGroupID({i, AS})); + } Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record); Record.clear(); Index: llvm/lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- llvm/lib/Bitcode/Writer/ValueEnumerator.cpp +++ llvm/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -899,8 +899,11 @@ } // Do lookups for all attribute groups. - for (unsigned i = 0, e = PAL.getNumSlots(); i != e; ++i) { - IndexAndAttrSet Pair = {PAL.getSlotIndex(i), PAL.getSlotAttributes(i)}; + for (unsigned i = 0, e = PAL.getNumAttrSets(); i != e; ++i) { + AttributeSet AS = PAL.getAttributes(i); + if (!AS.hasAttributes()) + continue; + IndexAndAttrSet Pair = {i, AS}; unsigned &Entry = AttributeGroupMap[Pair]; if (Entry == 0) { AttributeGroups.push_back(Pair); Index: llvm/lib/IR/AttributeImpl.h =================================================================== --- llvm/lib/IR/AttributeImpl.h +++ llvm/lib/IR/AttributeImpl.h @@ -209,27 +209,21 @@ /// return type, and parameters. class AttributeListImpl final : public FoldingSetNode, - private TrailingObjects { + private TrailingObjects { friend class AttributeList; friend TrailingObjects; private: - LLVMContext &Context; - unsigned NumSlots; ///< Number of entries in this set. /// Bitset with a bit for each available attribute Attribute::AttrKind. uint64_t AvailableFunctionAttrs; + LLVMContext &Context; + unsigned NumAttrSets; ///< Number of entries in this set. // Helper fn for TrailingObjects class. - size_t numTrailingObjects(OverloadToken) { return NumSlots; } - - /// \brief Return a pointer to the IndexAttrPair for the specified slot. - const IndexAttrPair *getSlotPair(unsigned Slot) const { - return getTrailingObjects() + Slot; - } + size_t numTrailingObjects(OverloadToken) { return NumAttrSets; } public: - AttributeListImpl(LLVMContext &C, - ArrayRef> Slots); + AttributeListImpl(LLVMContext &C, ArrayRef Sets); // AttributesSetImpt is uniqued, these should not be available. AttributeListImpl(const AttributeListImpl &) = delete; @@ -240,40 +234,18 @@ /// \brief Get the context that created this AttributeListImpl. LLVMContext &getContext() { return Context; } - /// \brief Return the number of slots used in this attribute list. This is - /// the number of arguments that have an attribute set on them (including the - /// function itself). - unsigned getNumSlots() const { return NumSlots; } - - /// \brief Get the index of the given "slot" in the AttrNodes list. This index - /// is the index of the return, parameter, or function object that the - /// attributes are applied to, not the index into the AttrNodes list where the - /// attributes reside. - unsigned getSlotIndex(unsigned Slot) const { - return getSlotPair(Slot)->first; - } - - /// \brief Retrieve the attribute set node for the given "slot" in the - /// AttrNode list. - AttributeSet getSlotAttributes(unsigned Slot) const { - return getSlotPair(Slot)->second; - } - /// \brief Return true if the AttributeSet or the FunctionIndex has an /// enum attribute of the given kind. bool hasFnAttribute(Attribute::AttrKind Kind) const { return AvailableFunctionAttrs & ((uint64_t)1) << Kind; } - typedef AttributeSet::iterator iterator; - iterator begin(unsigned Slot) const { - return getSlotAttributes(Slot).begin(); - } - iterator end(unsigned Slot) const { return getSlotAttributes(Slot).end(); } + typedef const AttributeSet* iterator; + iterator begin() const { return getTrailingObjects(); } + iterator end() const { return begin() + NumAttrSets; } void Profile(FoldingSetNodeID &ID) const; - static void Profile(FoldingSetNodeID &ID, - ArrayRef> Nodes); + static void Profile(FoldingSetNodeID &ID, ArrayRef Nodes); void dump() const; }; Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -720,48 +720,35 @@ // AttributeListImpl Definition //===----------------------------------------------------------------------===// -AttributeListImpl::AttributeListImpl( - LLVMContext &C, ArrayRef> Slots) - : Context(C), NumSlots(Slots.size()), AvailableFunctionAttrs(0) { -#ifndef NDEBUG - assert(!Slots.empty() && "pointless AttributeListImpl"); - if (Slots.size() >= 2) { - auto &PrevPair = Slots.front(); - for (auto &CurPair : Slots.drop_front()) { - assert(PrevPair.first <= CurPair.first && "Attribute set not ordered!"); - } - } -#endif +AttributeListImpl::AttributeListImpl(LLVMContext &C, + ArrayRef Sets) + : AvailableFunctionAttrs(0), Context(C), NumAttrSets(Sets.size()) { + assert(!Sets.empty() && "pointless AttributeListImpl"); // There's memory after the node where we can store the entries in. - std::copy(Slots.begin(), Slots.end(), getTrailingObjects()); + std::copy(Sets.begin(), Sets.end(), getTrailingObjects()); // Initialize AvailableFunctionAttrs summary bitset. static_assert(Attribute::EndAttrKinds <= sizeof(AvailableFunctionAttrs) * CHAR_BIT, "Too many attributes"); - static_assert(AttributeList::FunctionIndex == ~0u, - "FunctionIndex should be biggest possible index"); - const auto &Last = Slots.back(); - if (Last.first == AttributeList::FunctionIndex) { - AttributeSet Node = Last.second; - for (Attribute I : Node) { - if (!I.isStringAttribute()) - AvailableFunctionAttrs |= ((uint64_t)1) << I.getKindAsEnum(); - } + static_assert(AttributeList::FunctionIndex == 0U, + "FunctionIndex should be lowest possible index"); + const auto &FnAttrs = Sets.front(); + for (Attribute I : FnAttrs) { + if (!I.isStringAttribute()) + AvailableFunctionAttrs |= ((uint64_t)1) << I.getKindAsEnum(); } } void AttributeListImpl::Profile(FoldingSetNodeID &ID) const { - Profile(ID, makeArrayRef(getSlotPair(0), getNumSlots())); + Profile(ID, makeArrayRef(begin(), end())); } -void AttributeListImpl::Profile( - FoldingSetNodeID &ID, ArrayRef> Nodes) { - for (const auto &Node : Nodes) { - ID.AddInteger(Node.first); - ID.AddPointer(Node.second.SetNode); - } +void AttributeListImpl::Profile(FoldingSetNodeID &ID, + ArrayRef Sets) { + for (const auto &Set : Sets) + ID.AddPointer(Set.SetNode); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -774,24 +761,11 @@ // AttributeList Construction and Mutation Methods //===----------------------------------------------------------------------===// -AttributeList AttributeList::getImpl( - LLVMContext &C, ArrayRef> Attrs) { - assert(!Attrs.empty() && "creating pointless AttributeList"); -#ifndef NDEBUG - unsigned LastIndex = 0; - bool IsFirst = true; - for (auto &&AttrPair : Attrs) { - assert((IsFirst || LastIndex < AttrPair.first) && - "unsorted or duplicate AttributeList indices"); - assert(AttrPair.second.hasAttributes() && "pointless AttributeList slot"); - LastIndex = AttrPair.first; - IsFirst = false; - } -#endif - +AttributeList AttributeList::getImpl(LLVMContext &C, + ArrayRef AttrSets) { LLVMContextImpl *pImpl = C.pImpl; FoldingSetNodeID ID; - AttributeListImpl::Profile(ID, Attrs); + AttributeListImpl::Profile(ID, AttrSets); void *InsertPoint; AttributeListImpl *PA = @@ -802,8 +776,8 @@ if (!PA) { // Coallocate entries after the AttributeListImpl itself. void *Mem = ::operator new( - AttributeListImpl::totalSizeToAlloc(Attrs.size())); - PA = new (Mem) AttributeListImpl(C, Attrs); + AttributeListImpl::totalSizeToAlloc(AttrSets.size())); + PA = new (Mem) AttributeListImpl(C, AttrSets); pImpl->AttrsLists.InsertNode(PA, InsertPoint); } @@ -844,7 +818,7 @@ AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec)); } - return getImpl(C, AttrPairVec); + return get(C, AttrPairVec); } AttributeList @@ -854,35 +828,73 @@ if (Attrs.empty()) return AttributeList(); - return getImpl(C, Attrs); + assert(std::is_sorted(Attrs.begin(), Attrs.end(), + [](const std::pair &LHS, + const std::pair &RHS) { + return LHS.first < RHS.first; + }) && + "Misordered Attributes list!"); + assert(none_of(Attrs, + [](const std::pair &Pair) { + return !Pair.second.hasAttributes(); + }) && + "Pointless attribute!"); + + unsigned MaxIndex = 0; + for (auto Pair : Attrs) + MaxIndex = std::max(MaxIndex, Pair.first); + + SmallVector AttrVec(MaxIndex + 1); + for (auto Pair : Attrs) + AttrVec[Pair.first] = Pair.second; + + return getImpl(C, AttrVec); } AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, AttributeSet RetAttrs, ArrayRef ArgAttrs) { - SmallVector, 8> AttrPairs; + // Find the last position with attributes. Most arguments don't have + // attributes, so it's nice if we can have fewer unique AttributeListImpls by + // dropping empty attribute sets at the end of the list. + unsigned LastAttrPos = ~0U; + if (FnAttrs.hasAttributes()) + LastAttrPos = 0; if (RetAttrs.hasAttributes()) - AttrPairs.emplace_back(ReturnIndex, RetAttrs); - size_t Index = 1; + LastAttrPos = 1; + unsigned Pos = 2; for (AttributeSet AS : ArgAttrs) { if (AS.hasAttributes()) - AttrPairs.emplace_back(Index, AS); - ++Index; + LastAttrPos = Pos; + ++Pos; } - if (FnAttrs.hasAttributes()) - AttrPairs.emplace_back(FunctionIndex, FnAttrs); - if (AttrPairs.empty()) + + // If we don't have any attributes, we're done. + if (LastAttrPos == ~0U) return AttributeList(); - return getImpl(C, AttrPairs); + + SmallVector AttrSets; + AttrSets.reserve(LastAttrPos + 1); + // If we have any attributes, we always have function attributes. + AttrSets.push_back(FnAttrs); + if (LastAttrPos >= 1) + AttrSets.push_back(RetAttrs); + if (LastAttrPos >= 2) { + // Drop the empty argument attribute sets at the end. + ArgAttrs = ArgAttrs.take_front(LastAttrPos - 1); + AttrSets.insert(AttrSets.end(), ArgAttrs.begin(), ArgAttrs.end()); + } + + return getImpl(C, AttrSets); } AttributeList AttributeList::get(LLVMContext &C, unsigned Index, const AttrBuilder &B) { if (!B.hasAttributes()) return AttributeList(); - AttributeSet AS = AttributeSet::get(C, B); - std::pair Arr[1] = {{Index, AS}}; - return getImpl(C, Arr); + SmallVector AttrSets(Index+1); + AttrSets[Index] = AttributeSet::get(C, B); + return getImpl(C, AttrSets); } AttributeList AttributeList::get(LLVMContext &C, unsigned Index, @@ -905,32 +917,22 @@ ArrayRef Attrs) { if (Attrs.empty()) return AttributeList(); - if (Attrs.size() == 1) return Attrs[0]; - - SmallVector, 8> AttrNodeVec; - AttributeListImpl *A0 = Attrs[0].pImpl; - if (A0) - AttrNodeVec.append(A0->getSlotPair(0), A0->getSlotPair(A0->getNumSlots())); - // Copy all attributes from Attrs into AttrNodeVec while keeping AttrNodeVec - // ordered by index. Because we know that each list in Attrs is ordered by - // index we only need to merge each successive list in rather than doing a - // full sort. - for (unsigned I = 1, E = Attrs.size(); I != E; ++I) { - AttributeListImpl *ALI = Attrs[I].pImpl; - if (!ALI) continue; - SmallVector, 8>::iterator - ANVI = AttrNodeVec.begin(), ANVE; - for (const IndexAttrPair *AI = ALI->getSlotPair(0), - *AE = ALI->getSlotPair(ALI->getNumSlots()); - AI != AE; ++AI) { - ANVE = AttrNodeVec.end(); - while (ANVI != ANVE && ANVI->first <= AI->first) - ++ANVI; - ANVI = AttrNodeVec.insert(ANVI, *AI) + 1; - } + if (Attrs.size() == 1) + return Attrs[0]; + + unsigned MaxSize = 0; + for (auto &List : Attrs) + MaxSize = std::max(MaxSize, List.getNumAttrSets()); + + SmallVector NewAttrSets(MaxSize); + for (unsigned I = 0; I < MaxSize; ++I) { + AttrBuilder CurBuilder; + for (AttributeList List : Attrs) + CurBuilder.merge(List.getAttributes(I)); + NewAttrSets[I] = AttributeSet::get(C, CurBuilder); } - return getImpl(C, AttrNodeVec); + return getImpl(C, NewAttrSets); } AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index, @@ -954,29 +956,20 @@ Attribute A) const { assert(std::is_sorted(Indices.begin(), Indices.end())); - unsigned I = 0, E = pImpl ? pImpl->getNumSlots() : 0; - SmallVector AttrVec; + SmallVector AttrSets(this->begin(), this->end()); + unsigned MaxIndex = 0; + for (unsigned Index : Indices) + MaxIndex = std::max(MaxIndex, Index); + if (MaxIndex >= AttrSets.size()) + AttrSets.resize(MaxIndex + 1); + for (unsigned Index : Indices) { - // Add all attribute slots before the current index. - for (; I < E && getSlotIndex(I) < Index; ++I) - AttrVec.emplace_back(getSlotIndex(I), pImpl->getSlotAttributes(I)); - - // Add the attribute at this index. If we already have attributes at this - // index, merge them into a new set. - AttrBuilder B; - if (I < E && getSlotIndex(I) == Index) { - B.merge(AttrBuilder(pImpl->getSlotAttributes(I))); - ++I; - } + AttrBuilder B(AttrSets[Index]); B.addAttribute(A); - AttrVec.emplace_back(Index, AttributeSet::get(C, B)); + AttrSets[Index] = AttributeSet::get(C, B); } - // Add remaining attributes. - for (; I < E; ++I) - AttrVec.emplace_back(getSlotIndex(I), pImpl->getSlotAttributes(I)); - - return get(C, AttrVec); + return getImpl(C, AttrSets); } AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index, @@ -996,33 +989,15 @@ "Attempt to change alignment!"); #endif - SmallVector AttrVec; - uint64_t NumAttrs = pImpl->getNumSlots(); - unsigned I; + SmallVector AttrSets(this->begin(), this->end()); + if (Index >= AttrSets.size()) + AttrSets.resize(Index + 1); - // Add all the attribute slots before the one we need to merge. - for (I = 0; I < NumAttrs; ++I) { - if (getSlotIndex(I) >= Index) - break; - AttrVec.emplace_back(getSlotIndex(I), pImpl->getSlotAttributes(I)); - } + AttrBuilder Merged(AttrSets[Index]); + Merged.merge(B); + AttrSets[Index] = AttributeSet::get(C, Merged); - AttrBuilder NewAttrs; - if (I < NumAttrs && getSlotIndex(I) == Index) { - // We need to merge the attribute sets. - NewAttrs.merge(pImpl->getSlotAttributes(I)); - ++I; - } - NewAttrs.merge(B); - - // Add the new or merged attribute set at this index. - AttrVec.emplace_back(Index, AttributeSet::get(C, NewAttrs)); - - // Add the remaining entries. - for (; I < NumAttrs; ++I) - AttrVec.emplace_back(getSlotIndex(I), pImpl->getSlotAttributes(I)); - - return get(C, AttrVec); + return getImpl(C, AttrSets); } AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index, @@ -1041,54 +1016,36 @@ return removeAttributes(C, Index, B); } -AttributeList AttributeList::removeAttributes(LLVMContext &C, unsigned Index, - const AttrBuilder &Attrs) const { +AttributeList +AttributeList::removeAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &AttrsToRemove) const { if (!pImpl) return AttributeList(); // FIXME it is not obvious how this should work for alignment. // For now, say we can't pass in alignment, which no current use does. - assert(!Attrs.hasAlignmentAttr() && "Attempt to change alignment!"); - - // Add the attribute slots before the one we're trying to add. - SmallVector AttrSets; - uint64_t NumAttrs = pImpl->getNumSlots(); - AttrBuilder B; - uint64_t LastIndex = 0; - for (unsigned I = 0, E = NumAttrs; I != E; ++I) { - if (getSlotIndex(I) >= Index) { - if (getSlotIndex(I) == Index) - B = AttrBuilder(getSlotAttributes(LastIndex++)); - break; - } - LastIndex = I + 1; - AttrSets.push_back({getSlotIndex(I), getSlotAttributes(I)}); - } + assert(!AttrsToRemove.hasAlignmentAttr() && "Attempt to change alignment!"); - // Remove the attributes from the existing set and add them. - B.remove(Attrs); - if (B.hasAttributes()) - AttrSets.push_back({Index, AttributeSet::get(C, B)}); + SmallVector AttrSets(this->begin(), this->end()); + if (Index >= AttrSets.size()) + AttrSets.resize(Index + 1); - // Add the remaining attribute slots. - for (unsigned I = LastIndex, E = NumAttrs; I < E; ++I) - AttrSets.push_back({getSlotIndex(I), getSlotAttributes(I)}); + AttrBuilder B(AttrSets[Index]); + B.remove(AttrsToRemove); + AttrSets[Index] = AttributeSet::get(C, B); - return get(C, AttrSets); + return getImpl(C, AttrSets); } AttributeList AttributeList::removeAttributes(LLVMContext &C, unsigned WithoutIndex) const { if (!pImpl) return AttributeList(); - - SmallVector, 4> AttrSet; - for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) { - unsigned Index = getSlotIndex(I); - if (Index != WithoutIndex) - AttrSet.push_back({Index, pImpl->getSlotAttributes(I)}); - } - return get(C, AttrSet); + if (WithoutIndex >= getNumAttrSets()) + return *this; + SmallVector AttrSets(this->begin(), this->end()); + AttrSets[WithoutIndex] = AttributeSet(); + return getImpl(C, AttrSets); } AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C, @@ -1157,20 +1114,22 @@ bool AttributeList::hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const { - return hasAttribute(ArgNo + 1, Kind); + return hasAttribute(ArgNo + FirstArgIndex, Kind); } bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr, unsigned *Index) const { if (!pImpl) return false; - for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) - for (AttributeListImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I); - II != IE; ++II) - if (II->hasAttribute(Attr)) { - if (Index) *Index = pImpl->getSlotIndex(I); - return true; - } + unsigned I = 0; + for (AttributeSet Set : *this) { + if (Set.hasAttribute(Attr)) { + if (Index) + *Index = I; + return true; + } + ++I; + } return false; } @@ -1214,60 +1173,34 @@ } AttributeSet AttributeList::getAttributes(unsigned Index) const { - if (!pImpl) return AttributeSet(); - - // Loop through to find the attribute node we want. - for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) - if (pImpl->getSlotIndex(I) == Index) - return pImpl->getSlotAttributes(I); - - return AttributeSet(); + if (!pImpl || Index >= getNumAttrSets()) + return AttributeSet(); + return pImpl->begin()[Index]; } -AttributeList::iterator AttributeList::begin(unsigned Slot) const { - if (!pImpl) - return ArrayRef().begin(); - return pImpl->begin(Slot); +AttributeList::iterator AttributeList::begin() const { + return pImpl ? pImpl->begin() : nullptr; } -AttributeList::iterator AttributeList::end(unsigned Slot) const { - if (!pImpl) - return ArrayRef().end(); - return pImpl->end(Slot); +AttributeList::iterator AttributeList::end() const { + return pImpl ? pImpl->end() : nullptr; } //===----------------------------------------------------------------------===// // AttributeList Introspection Methods //===----------------------------------------------------------------------===// -unsigned AttributeList::getNumSlots() const { - return pImpl ? pImpl->getNumSlots() : 0; -} - -unsigned AttributeList::getSlotIndex(unsigned Slot) const { - assert(pImpl && Slot < pImpl->getNumSlots() && - "Slot # out of range!"); - return pImpl->getSlotIndex(Slot); -} - -AttributeSet AttributeList::getSlotAttributes(unsigned Slot) const { - assert(pImpl && Slot < pImpl->getNumSlots() && - "Slot # out of range!"); - return pImpl->getSlotAttributes(Slot); +unsigned AttributeList::getNumAttrSets() const { + return pImpl ? pImpl->NumAttrSets : 0; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void AttributeList::dump() const { dbgs() << "PAL[\n"; - for (unsigned i = 0, e = getNumSlots(); i < e; ++i) { - uint64_t Index = getSlotIndex(i); - dbgs() << " { "; - if (Index == ~0U) - dbgs() << "~0U"; - else - dbgs() << Index; - dbgs() << " => " << getAsString(Index) << " }\n"; + for (unsigned i = 0, e = getNumAttrSets(); i < e; ++i) { + if (getAttributes(i).hasAttributes()) + dbgs() << " { " << i << " => " << getAsString(i) << " }\n"; } dbgs() << "]\n"; @@ -1278,26 +1211,16 @@ // AttrBuilder Method Implementations //===----------------------------------------------------------------------===// +// FIXME: Remove this ctor, use AttributeSet. AttrBuilder::AttrBuilder(AttributeList AL, unsigned Index) { - AttributeListImpl *pImpl = AL.pImpl; - if (!pImpl) return; - - for (unsigned I = 0, E = pImpl->getNumSlots(); I != E; ++I) { - if (pImpl->getSlotIndex(I) != Index) continue; - - for (AttributeListImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I); - II != IE; ++II) - addAttribute(*II); - - break; - } + AttributeSet AS = AL.getAttributes(Index); + for (const Attribute &A : AS) + addAttribute(A); } AttrBuilder::AttrBuilder(AttributeSet AS) { - if (AS.hasAttributes()) { - for (const Attribute &A : AS) - addAttribute(A); - } + for (const Attribute &A : AS) + addAttribute(A); } void AttrBuilder::clear() { Index: llvm/lib/IR/Core.cpp =================================================================== --- llvm/lib/IR/Core.cpp +++ llvm/lib/IR/Core.cpp @@ -1853,18 +1853,32 @@ F->clearGC(); } +/// Adjust an LLVMAttributeIndex from the C API indices to the internal C++ +/// indices used by the AttributeList interface. +static void adjustAttrListIndex(LLVMAttributeIndex &Idx) { + // Adding one works: + // type | C API | C++ API + // func | -1 | 0 + // ret | 0 | 1 + // arg | 1... | 2... + ++Idx; +} + void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, LLVMAttributeRef A) { + adjustAttrListIndex(Idx); unwrap(F)->addAttribute(Idx, unwrap(A)); } unsigned LLVMGetAttributeCountAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx) { + adjustAttrListIndex(Idx); auto AS = unwrap(F)->getAttributes().getAttributes(Idx); return AS.getNumAttributes(); } void LLVMGetAttributesAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, LLVMAttributeRef *Attrs) { + adjustAttrListIndex(Idx); auto AS = unwrap(F)->getAttributes().getAttributes(Idx); for (auto A : AS) *Attrs++ = wrap(A); @@ -1873,6 +1887,7 @@ LLVMAttributeRef LLVMGetEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, unsigned KindID) { + adjustAttrListIndex(Idx); return wrap(unwrap(F)->getAttribute(Idx, (Attribute::AttrKind)KindID)); } @@ -1880,16 +1895,19 @@ LLVMAttributeRef LLVMGetStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, const char *K, unsigned KLen) { + adjustAttrListIndex(Idx); return wrap(unwrap(F)->getAttribute(Idx, StringRef(K, KLen))); } void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, unsigned KindID) { + adjustAttrListIndex(Idx); unwrap(F)->removeAttribute(Idx, (Attribute::AttrKind)KindID); } void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, const char *K, unsigned KLen) { + adjustAttrListIndex(Idx); unwrap(F)->removeAttribute(Idx, StringRef(K, KLen)); } @@ -2170,11 +2188,13 @@ void LLVMAddCallSiteAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, LLVMAttributeRef A) { + adjustAttrListIndex(Idx); CallSite(unwrap(C)).addAttribute(Idx, unwrap(A)); } unsigned LLVMGetCallSiteAttributeCount(LLVMValueRef C, LLVMAttributeIndex Idx) { + adjustAttrListIndex(Idx); auto CS = CallSite(unwrap(C)); auto AS = CS.getAttributes().getAttributes(Idx); return AS.getNumAttributes(); @@ -2182,6 +2202,7 @@ void LLVMGetCallSiteAttributes(LLVMValueRef C, LLVMAttributeIndex Idx, LLVMAttributeRef *Attrs) { + adjustAttrListIndex(Idx); auto CS = CallSite(unwrap(C)); auto AS = CS.getAttributes().getAttributes(Idx); for (auto A : AS) @@ -2191,6 +2212,7 @@ LLVMAttributeRef LLVMGetCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, unsigned KindID) { + adjustAttrListIndex(Idx); return wrap(CallSite(unwrap(C)) .getAttribute(Idx, (Attribute::AttrKind)KindID)); } @@ -2198,18 +2220,21 @@ LLVMAttributeRef LLVMGetCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, const char *K, unsigned KLen) { + adjustAttrListIndex(Idx); return wrap(CallSite(unwrap(C)) .getAttribute(Idx, StringRef(K, KLen))); } void LLVMRemoveCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, unsigned KindID) { + adjustAttrListIndex(Idx); CallSite(unwrap(C)) .removeAttribute(Idx, (Attribute::AttrKind)KindID); } void LLVMRemoveCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, const char *K, unsigned KLen) { + adjustAttrListIndex(Idx); CallSite(unwrap(C)).removeAttribute(Idx, StringRef(K, KLen)); } Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -418,6 +418,9 @@ // question is a call argument; or be indirectly implied by the kind of its // containing operand bundle, if the operand is a bundle operand. + if (i == 0) + return hasRetAttr(Kind); + // FIXME: Avoid these i - 1 calculations and update the API to use zero-based // indices. if (i < (getNumArgOperands() + 1)) Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -1720,17 +1720,9 @@ } bool Verifier::verifyAttributeCount(AttributeList Attrs, unsigned Params) { - if (Attrs.getNumSlots() == 0) - return true; - - unsigned LastSlot = Attrs.getNumSlots() - 1; - unsigned LastIndex = Attrs.getSlotIndex(LastSlot); - if (LastIndex <= Params || - (LastIndex == AttributeList::FunctionIndex && - (LastSlot == 0 || Attrs.getSlotIndex(LastSlot - 1) <= Params))) - return true; - - return false; + // There shouldn't be more attribute sets than there are parameters plus the + // function and return value. + return Attrs.getNumAttrSets() <= Params + 2; } /// Verify that statepoint intrinsic is well formed. Index: llvm/lib/Transforms/Utils/FunctionComparator.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -76,12 +76,14 @@ int FunctionComparator::cmpAttrs(const AttributeList L, const AttributeList R) const { - if (int Res = cmpNumbers(L.getNumSlots(), R.getNumSlots())) + if (int Res = cmpNumbers(L.getNumAttrSets(), R.getNumAttrSets())) return Res; - for (unsigned i = 0, e = L.getNumSlots(); i != e; ++i) { - AttributeList::iterator LI = L.begin(i), LE = L.end(i), RI = R.begin(i), - RE = R.end(i); + for (unsigned i = 0, e = L.getNumAttrSets(); i != e; ++i) { + AttributeSet LAS = L.getAttributes(i); + AttributeSet RAS = R.getAttributes(i); + AttributeSet::iterator LI = LAS.begin(), LE = LAS.end(); + AttributeSet::iterator RI = RAS.begin(), RE = RAS.end(); for (; LI != LE && RI != RE; ++LI, ++RI) { Attribute LA = *LI; Attribute RA = *RI; Index: llvm/utils/TableGen/IntrinsicEmitter.cpp =================================================================== --- llvm/utils/TableGen/IntrinsicEmitter.cpp +++ llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -563,7 +563,7 @@ if (ae) { while (ai != ae) { unsigned argNo = intrinsic.ArgumentAttributes[ai].first; - unsigned attrIdx = argNo + 1; // Must match AttributeList::FirstArgIndex + unsigned attrIdx = argNo + 2; // Must match AttributeList::FirstArgIndex OS << " const Attribute::AttrKind AttrParam" << attrIdx << "[]= {"; bool addComma = false;