Index: llvm/include/llvm/IR/Module.h =================================================================== --- llvm/include/llvm/IR/Module.h +++ llvm/include/llvm/IR/Module.h @@ -17,6 +17,7 @@ #include "llvm-c/Types.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" @@ -195,6 +196,9 @@ ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) NamedMDSymTabType NamedMDSymTab; ///< NamedMDNode names. DataLayout DL; ///< DataLayout associated with the module + SmallPtrSet TemporaryMDNodes; ///< Holds the temporary MD nodes + ///< that are used as list nodes. + StringMap CurrentIntrinsicIds; ///< Keep track of the current unique id count for ///< the specified intrinsic basename. @@ -250,6 +254,9 @@ /// Get the data layout for the module's target platform. const DataLayout &getDataLayout() const; + /// Get the set of temporary MD nodes. + SmallPtrSet &getTempMDNodes() { return TemporaryMDNodes; } + /// Get the target triple which is a string describing the target host. /// @returns a string containing the target triple. const std::string &getTargetTriple() const { return TargetTriple; } @@ -943,6 +950,10 @@ /// /// An empty version is returned if no such metadata is attached. VersionTuple getDarwinTargetVariantSDKVersion() const; + + /// Turn temporary MD nodes that may have been created during linking into + /// permanent ones. + void makeTempMDNodesPermanent(); }; /// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the Index: llvm/lib/IR/Module.cpp =================================================================== --- llvm/lib/IR/Module.cpp +++ llvm/lib/IR/Module.cpp @@ -823,3 +823,10 @@ VersionTuple Module::getDarwinTargetVariantSDKVersion() const { return getSDKVersionMD(getModuleFlag("darwin.target_variant.SDK Version")); } + +void Module::makeTempMDNodesPermanent() { + for (auto *TNode : TemporaryMDNodes) { + MDNode::replaceWithPermanent(TempMDNode(TNode)); + } + TemporaryMDNodes.clear(); +} Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -1061,6 +1061,7 @@ if (Error Err = linkRegularLTO(std::move(M), /*LivenessFromIndex=*/true)) return Err; + RegularLTO.CombinedModule->makeTempMDNodesPermanent(); // Ensure we don't have inconsistently split LTO units with type tests. // FIXME: this checks both LTO and ThinLTO. It happens to work as we take Index: llvm/lib/Linker/IRMover.cpp =================================================================== --- llvm/lib/Linker/IRMover.cpp +++ llvm/lib/Linker/IRMover.cpp @@ -1341,6 +1341,20 @@ auto replaceDstValue = [&](MDNode *New) { Metadata *FlagOps[] = {DstOp->getOperand(0), ID, New}; MDNode *Flag = MDNode::get(DstM.getContext(), FlagOps); + // Find the list node we are about to replace. + MDNode *OldOp = + cast(DstModFlags->getOperand(DstIndex)->getOperand(2)); + auto &TempSet = DstM.getTempMDNodes(); + // If the existing list node is a temporary node, + // delete it and remove it from the module's set of temporary nodes. + if (TempSet.contains(OldOp)) { + TempSet.erase(OldOp); + MDNode::deleteTemporary(OldOp); + } + // If the new list node is a temporary MDnode, add it to the set of + // temporary nodes. + if (New->isTemporary()) + TempSet.insert(New); DstModFlags->setOperand(DstIndex, Flag); Flags[ID].first = Flag; }; @@ -1407,7 +1421,8 @@ MDs.append(DstValue->op_begin(), DstValue->op_end()); MDs.append(SrcValue->op_begin(), SrcValue->op_end()); - replaceDstValue(MDNode::get(DstM.getContext(), MDs)); + // Use a temporary MDnode because it can be deleted.. + replaceDstValue(MDNode::getTemporary(DstM.getContext(), MDs).release()); break; } case Module::AppendUnique: { @@ -1417,8 +1432,10 @@ Elts.insert(DstValue->op_begin(), DstValue->op_end()); Elts.insert(SrcValue->op_begin(), SrcValue->op_end()); - replaceDstValue(MDNode::get(DstM.getContext(), - makeArrayRef(Elts.begin(), Elts.end()))); + replaceDstValue( + MDNode::getTemporary(DstM.getContext(), + makeArrayRef(Elts.begin(), Elts.end())) + .release()); break; } } Index: llvm/tools/llvm-link/llvm-link.cpp =================================================================== --- llvm/tools/llvm-link/llvm-link.cpp +++ llvm/tools/llvm-link/llvm-link.cpp @@ -469,6 +469,8 @@ Flags | Linker::Flags::OverrideFromSrc)) return 1; + Composite->makeTempMDNodesPermanent(); + // Import any functions requested via -import if (!importFunctions(argv[0], *Composite)) return 1; Index: llvm/unittests/Linker/LinkModulesTest.cpp =================================================================== --- llvm/unittests/Linker/LinkModulesTest.cpp +++ llvm/unittests/Linker/LinkModulesTest.cpp @@ -359,4 +359,71 @@ ASSERT_EQ(F->getNumUses(), (unsigned)2); } +TEST_F(LinkModuleTest, UseTempMDNodesForMduleFlags) { + LLVMContext C; + SMDiagnostic Err; + + // Link 2 modules with metadata nodes that exhibit the behaviors "append" and + // "appendUnique". Make sure that the list MD nodes of the linked module are + // temporary MD nodes, so that they can be deleted in subsequent links, + // preventing memory being wasted on longer list nodes. + // FIXME: This test does not check that such a temp MD node is, in fact, + // deleted and truly deallocates its memory. Not sure how to write a test + // that would do this. + + const char *FooStr = R"IR( + declare void @foo(i32, i32) + declare i32 @bar(i32) + declare i32 @baz(i32, i32) + + !llvm.module.flags = !{!0, !1} + !0 = !{i32 5, !"CG Profile", !2} + !1 = !{i32 6, !"MyFlag", !3} + !2 = !{!4, !5} + !3 = !{!6, !7} + !4 = !{void (i32, i32)* @foo, i32 (i32)* @bar, i64 1} + !5 = !{void (i32, i32)* @foo, i32 (i32, i32)* @baz, i64 1} + !6 = !{i32 100, i32 200} + !7 = !{i32 300, i32 400} + )IR"; + + const char *BarStr = R"IR( + declare void @bar(i32, i32) + declare i32 @baz(i32) + declare i32 @fie(i32, i32) + + !llvm.module.flags = !{!0, !1} + !0 = !{i32 5, !"CG Profile", !2} + !1 = !{i32 6, !"MyFlag", !3} + !2 = !{!4, !5} + !3 = !{!6, !7} + !4 = !{void (i32, i32)* @bar, i32 (i32)* @baz, i64 1} + !5 = !{void (i32, i32)* @bar, i32 (i32, i32)* @fie, i64 1} + !6 = !{i32 100, i32 200} + !7 = !{i32 300, i32 400} + )IR"; + + std::unique_ptr Foo = parseAssemblyString(FooStr, Err, C); + assert(Foo); + std::unique_ptr Bar = parseAssemblyString(BarStr, Err, C); + assert(Bar); + bool Failed = Linker::linkModules(*Foo, std::move(Bar)); + ASSERT_FALSE(Failed); + + const NamedMDNode *ModFlags = Foo->getModuleFlagsMetadata(); + const MDNode *CGProfileFlag = ModFlags->getOperand(0); + ASSERT_TRUE(CGProfileFlag->getNumOperands() == 3); + const MDOperand &ListNode = CGProfileFlag->getOperand(2); + const MDNode *ListMDNode = cast(ListNode.get()); + ASSERT_TRUE(ListMDNode->isTemporary()); + ASSERT_TRUE(ListMDNode->getNumOperands() == 4); + + const MDNode *MyFlag = ModFlags->getOperand(1); + ASSERT_TRUE(MyFlag->getNumOperands() == 3); + const MDOperand &ListNode2 = MyFlag->getOperand(2); + const MDNode *ListMDNode2 = cast(ListNode2.get()); + ASSERT_TRUE(ListMDNode2->isTemporary()); + ASSERT_TRUE(ListMDNode2->getNumOperands() == 2); +} + } // end anonymous namespace