Index: include/llvm/IR/GlobalObject.h =================================================================== --- include/llvm/IR/GlobalObject.h +++ include/llvm/IR/GlobalObject.h @@ -74,14 +74,23 @@ /// Check if this has any metadata. bool hasMetadata() const { return hasMetadataHashEntry(); } - /// Get the current metadata attachment, if any. + /// Get the current metadata attachments for the given kind, if any. /// - /// Returns \c nullptr if such an attachment is missing. + /// These functions require that the function have at most a single attachment + /// of the given kind, and return \c nullptr if such an attachment is missing. /// @{ MDNode *getMetadata(unsigned KindID) const; MDNode *getMetadata(StringRef Kind) const; /// @} + /// Appends all attachments with the given ID to \c MDs in insertion order. + /// If the global has no attachments with the given ID, or if ID is invalid, + /// leaves MDs unchanged. + /// @{ + void getMetadata(unsigned KindID, SmallVectorImpl &MDs) const; + void getMetadata(StringRef Kind, SmallVectorImpl &MDs) const; + /// @} + /// Set a particular kind of metadata attachment. /// /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or @@ -91,14 +100,19 @@ void setMetadata(StringRef Kind, MDNode *MD); /// @} - /// Get all current metadata attachments. + /// Add a metadata attachment. + /// @{ + void addMetadata(unsigned KindID, MDNode &MD); + void addMetadata(StringRef Kind, MDNode &MD); + /// @} + + /// Appends all attachments for the global to \c MDs, sorting by attachment + /// ID. Attachments with the same ID appear in insertion order. void getAllMetadata(SmallVectorImpl> &MDs) const; - /// Drop metadata not in the given list. - /// - /// Drop all metadata from \c this not included in \c KnownIDs. - void dropUnknownMetadata(ArrayRef KnownIDs); + /// Erase all metadata attachments with the given kind. + void eraseMetadata(unsigned KindID); void copyAttributesFrom(const GlobalValue *Src) override; @@ -108,7 +122,6 @@ V->getValueID() == Value::GlobalVariableVal; } -protected: void clearMetadata(); private: Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1719,7 +1719,7 @@ if (ParseMetadataAttachment(MDK, N)) return true; - GO.setMetadata(MDK, N); + GO.addMetadata(MDK, *N); return false; } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -4167,7 +4167,7 @@ MDNode *MD = MetadataList.getMDNodeFwdRefOrNull(Record[I + 1]); if (!MD) return error("Invalid metadata attachment"); - GO.setMetadata(K->second, MD); + GO.addMetadata(K->second, *MD); } return std::error_code(); } Index: lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.cpp +++ lib/Bitcode/Writer/ValueEnumerator.cpp @@ -345,6 +345,7 @@ SmallVector, 8> MDs; for (const GlobalVariable &GV : M.globals()) { + MDs.clear(); GV.getAllMetadata(MDs); for (const auto &I : MDs) EnumerateMetadata(&GV, I.second); @@ -356,6 +357,7 @@ EnumerateType(A.getType()); // Enumerate metadata attached to this function. + MDs.clear(); F.getAllMetadata(MDs); for (const auto &I : MDs) EnumerateMetadata(&F, I.second); Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -997,6 +997,33 @@ } }; +/// Multimap-like storage for metadata attachments for globals. This differs +/// from MDAttachmentMap in that it allows multiple attachments per metadata +/// kind. +class MDGlobalAttachmentMap { + struct Attachment { + unsigned MDKind; + TrackingMDNodeRef Node; + }; + SmallVector Attachments; + +public: + bool empty() const { return Attachments.empty(); } + + /// Appends all attachments with the given ID to \c Result in insertion order. + /// If the global has no attachments with the given ID, or if ID is invalid, + /// leaves Result unchanged. + void get(unsigned ID, SmallVectorImpl &Result); + + void insert(unsigned ID, MDNode &MD); + void erase(unsigned ID); + + /// Appends all attachments for the global to \c Result, sorting by attachment + /// ID. Attachments with the same ID appear in insertion order. This function + /// does \em not clear \c Result. + void getAll(SmallVectorImpl> &Result) const; +}; + class LLVMContextImpl { public: /// OwnedModules - The set of modules instantiated in this context, and which @@ -1108,7 +1135,7 @@ DenseMap InstructionMetadata; /// Collection of per-GlobalObject metadata used in this context. - DenseMap GlobalObjectMetadata; + DenseMap GlobalObjectMetadata; /// DiscriminatorTable - This table maps file:line locations to an /// integer representing the next DWARF path discriminator to assign to Index: lib/IR/Metadata.cpp =================================================================== --- lib/IR/Metadata.cpp +++ lib/IR/Metadata.cpp @@ -1125,6 +1125,43 @@ array_pod_sort(Result.begin(), Result.end()); } +void MDGlobalAttachmentMap::insert(unsigned ID, MDNode &MD) { + Attachments.push_back({ID, TrackingMDNodeRef(&MD)}); +} + +void MDGlobalAttachmentMap::get(unsigned ID, + SmallVectorImpl &Result) { + for (auto A : Attachments) + if (A.MDKind == ID) + Result.push_back(A.Node); +} + +void MDGlobalAttachmentMap::erase(unsigned ID) { + auto Follower = Attachments.begin(); + for (auto Leader = Attachments.begin(), E = Attachments.end(); Leader != E; + ++Leader) { + if (Leader->MDKind != ID) { + if (Follower != Leader) + *Follower = std::move(*Leader); + ++Follower; + } + } + Attachments.resize(Follower - Attachments.begin()); +} + +void MDGlobalAttachmentMap::getAll( + SmallVectorImpl> &Result) const { + for (auto &A : Attachments) + Result.emplace_back(A.MDKind, A.Node); + + // Sort the resulting array so it is stable with respect to metadata IDs. We + // need to preserve the original insertion order though. + std::stable_sort( + Result.begin(), Result.end(), + [](const std::pair &A, + const std::pair &B) { return A.first < B.first; }); +} + void Instruction::setMetadata(StringRef Kind, MDNode *Node) { if (!Node && !hasMetadata()) return; @@ -1281,27 +1318,30 @@ setHasMetadataHashEntry(false); } -MDNode *GlobalObject::getMetadata(unsigned KindID) const { - if (!hasMetadata()) - return nullptr; - return getContext().pImpl->GlobalObjectMetadata[this].lookup(KindID); +void GlobalObject::getMetadata(unsigned KindID, + SmallVectorImpl &MDs) const { + if (hasMetadata()) + getContext().pImpl->GlobalObjectMetadata[this].get(KindID, MDs); } -MDNode *GlobalObject::getMetadata(StringRef Kind) const { - if (!hasMetadata()) - return nullptr; - return getMetadata(getContext().getMDKindID(Kind)); +void GlobalObject::getMetadata(StringRef Kind, + SmallVectorImpl &MDs) const { + if (hasMetadata()) + getMetadata(getContext().getMDKindID(Kind), MDs); } -void GlobalObject::setMetadata(unsigned KindID, MDNode *MD) { - if (MD) { - if (!hasMetadata()) - setHasMetadataHashEntry(true); +void GlobalObject::addMetadata(unsigned KindID, MDNode &MD) { + if (!hasMetadata()) + setHasMetadataHashEntry(true); - getContext().pImpl->GlobalObjectMetadata[this].set(KindID, *MD); - return; - } + getContext().pImpl->GlobalObjectMetadata[this].insert(KindID, MD); +} +void GlobalObject::addMetadata(StringRef Kind, MDNode &MD) { + addMetadata(getContext().getMDKindID(Kind), MD); +} + +void GlobalObject::eraseMetadata(unsigned KindID) { // Nothing to unset. if (!hasMetadata()) return; @@ -1312,12 +1352,6 @@ clearMetadata(); } -void GlobalObject::setMetadata(StringRef Kind, MDNode *MD) { - if (!MD && !hasMetadata()) - return; - setMetadata(getContext().getMDKindID(Kind), MD); -} - void GlobalObject::getAllMetadata( SmallVectorImpl> &MDs) const { MDs.clear(); @@ -1328,33 +1362,35 @@ getContext().pImpl->GlobalObjectMetadata[this].getAll(MDs); } -void GlobalObject::dropUnknownMetadata(ArrayRef KnownIDs) { +void GlobalObject::clearMetadata() { if (!hasMetadata()) return; - if (KnownIDs.empty()) { - clearMetadata(); - return; - } + getContext().pImpl->GlobalObjectMetadata.erase(this); + setHasMetadataHashEntry(false); +} - SmallSet KnownSet; - KnownSet.insert(KnownIDs.begin(), KnownIDs.end()); - auto &Store = getContext().pImpl->GlobalObjectMetadata[this]; - assert(!Store.empty()); +void GlobalObject::setMetadata(unsigned KindID, MDNode *N) { + eraseMetadata(KindID); + if (N) + addMetadata(KindID, *N); +} - Store.remove_if([&KnownSet](const std::pair &I) { - return !KnownSet.count(I.first); - }); +void GlobalObject::setMetadata(StringRef Kind, MDNode *N) { + setMetadata(getContext().getMDKindID(Kind), N); +} - if (Store.empty()) - clearMetadata(); +MDNode *GlobalObject::getMetadata(unsigned KindID) const { + SmallVector MDs; + getMetadata(KindID, MDs); + assert(MDs.size() <= 1 && "Expected at most one metadata attachment"); + if (MDs.empty()) + return nullptr; + return MDs[0]; } -void GlobalObject::clearMetadata() { - if (!hasMetadata()) - return; - getContext().pImpl->GlobalObjectMetadata.erase(this); - setHasMetadataHashEntry(false); +MDNode *GlobalObject::getMetadata(StringRef Kind) const { + return getMetadata(getContext().getMDKindID(Kind)); } void Function::setSubprogram(DISubprogram *SP) { Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1991,6 +1991,7 @@ "blockaddress may not be used with the entry block!", Entry); } + unsigned NumDebugAttachments = 0; // Visit metadata attachments. for (const auto &I : MDs) { // Verify that the attachment is legal. @@ -1998,6 +1999,9 @@ default: break; case LLVMContext::MD_dbg: + ++NumDebugAttachments; + AssertDI(NumDebugAttachments == 1, + "function must have a single !dbg attachment", &F, I.second); AssertDI(isa(I.second), "function !dbg attachment must be a subprogram", &F, I.second); break; Index: lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- lib/Transforms/Utils/CloneFunction.cpp +++ lib/Transforms/Utils/CloneFunction.cpp @@ -122,11 +122,11 @@ SmallVector, 1> MDs; OldFunc->getAllMetadata(MDs); for (auto MD : MDs) - NewFunc->setMetadata( + NewFunc->addMetadata( MD.first, - MapMetadata(MD.second, VMap, - ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, - TypeMapper, Materializer)); + *MapMetadata(MD.second, VMap, + ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, + TypeMapper, Materializer)); // Loop over all of the basic blocks in the function, cloning them as // appropriate. Note that we save BE this way in order to handle cloning of Index: lib/Transforms/Utils/ValueMapper.cpp =================================================================== --- lib/Transforms/Utils/ValueMapper.cpp +++ lib/Transforms/Utils/ValueMapper.cpp @@ -950,8 +950,9 @@ // Remap the metadata attachments. SmallVector, 8> MDs; F.getAllMetadata(MDs); + F.clearMetadata(); for (const auto &I : MDs) - F.setMetadata(I.first, cast_or_null(mapMetadata(I.second))); + F.addMetadata(I.first, *cast(mapMetadata(I.second))); // Remap the argument types. if (TypeMapper) Index: test/Assembler/metadata.ll =================================================================== --- test/Assembler/metadata.ll +++ test/Assembler/metadata.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: @global = global i32 0, !foo [[M2:![0-9]+]], !baz [[M3:![0-9]+]] -@global = global i32 0, !foo !2, !baz !3 +; CHECK: @global = global i32 0, !foo [[M2:![0-9]+]], !foo [[M3:![0-9]+]], !baz [[M3]] +@global = global i32 0, !foo !2, !foo !3, !baz !3 ; CHECK-LABEL: @test ; CHECK: ret void, !foo [[M0:![0-9]+]], !bar [[M1:![0-9]+]] Index: test/Verifier/metadata-function-dbg.ll =================================================================== --- test/Verifier/metadata-function-dbg.ll +++ test/Verifier/metadata-function-dbg.ll @@ -1,6 +1,11 @@ ; RUN: not llvm-as %s -disable-output 2>&1 | FileCheck %s -define void @foo() !dbg !4 !dbg !4 { +define void @foo() !dbg !4 { + unreachable +} + +; CHECK: function must have a single !dbg attachment +define void @foo2() !dbg !4 !dbg !4 { unreachable } Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -2242,32 +2242,6 @@ EXPECT_EQ(T2, MDs[3].second); } -TEST_F(FunctionAttachmentTest, dropUnknownMetadata) { - Function *F = getFunction("foo"); - - MDTuple *T1 = getTuple(); - MDTuple *T2 = getTuple(); - MDTuple *P = getTuple(); - DISubprogram *SP = getSubprogram(); - - F->setMetadata("other1", T1); - F->setMetadata(LLVMContext::MD_dbg, SP); - F->setMetadata("other2", T2); - F->setMetadata(LLVMContext::MD_prof, P); - - unsigned Known[] = {Context.getMDKindID("other2"), LLVMContext::MD_prof}; - F->dropUnknownMetadata(Known); - - EXPECT_EQ(T2, F->getMetadata("other2")); - EXPECT_EQ(P, F->getMetadata(LLVMContext::MD_prof)); - EXPECT_EQ(nullptr, F->getMetadata("other1")); - EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); - - F->setMetadata("other2", nullptr); - F->setMetadata(LLVMContext::MD_prof, nullptr); - EXPECT_FALSE(F->hasMetadata()); -} - TEST_F(FunctionAttachmentTest, Verifier) { Function *F = getFunction("foo"); F->setMetadata("attach", getTuple());