Index: lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- lib/Transforms/Utils/CloneFunction.cpp +++ lib/Transforms/Utils/CloneFunction.cpp @@ -210,6 +210,21 @@ RemapInstruction(&II, VMap, ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, TypeMapper, Materializer); + + // Register all DICompileUnits of the old parent module in the new parent module + auto* OldModule = OldFunc->getParent(); + auto* NewModule = NewFunc->getParent(); + if (OldModule && NewModule && OldModule != NewModule && DIFinder.compile_unit_count()) { + auto* NMD = NewModule->getOrInsertNamedMetadata("llvm.dbg.cu"); + // Avoid multiple insertions of the same DICompileUnit to NMD. + SmallPtrSet Visited; + for (auto* Operand : NMD->operands()) + Visited.insert(Operand); + for (auto* Unit : DIFinder.compile_units()) + // VMap.MD()[Unit] == Unit + if (Visited.insert(Unit).second) + NMD->addOperand(Unit); + } } /// Return a copy of the specified function and add it to that function's Index: lib/Transforms/Utils/CloneModule.cpp =================================================================== --- lib/Transforms/Utils/CloneModule.cpp +++ lib/Transforms/Utils/CloneModule.cpp @@ -181,13 +181,25 @@ } // And named metadata.... + const auto* LLVM_DBG_CU = M.getNamedMetadata("llvm.dbg.cu"); for (Module::const_named_metadata_iterator I = M.named_metadata_begin(), E = M.named_metadata_end(); I != E; ++I) { const NamedMDNode &NMD = *I; NamedMDNode *NewNMD = New->getOrInsertNamedMetadata(NMD.getName()); - for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) - NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap)); + if (&NMD == LLVM_DBG_CU) { + // Do not insert duplicate operands. + SmallPtrSet Visited; + for (const auto* Operand : NewNMD->operands()) + Visited.insert(Operand); + for (const auto* Operand : NMD.operands()) { + auto* MappedOperand = MapMetadata(Operand, VMap); + if (Visited.insert(MappedOperand).second) + NewNMD->addOperand(MappedOperand); + } + } else + for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) + NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap)); } return New; Index: unittests/Transforms/Utils/CloningTest.cpp =================================================================== --- unittests/Transforms/Utils/CloningTest.cpp +++ unittests/Transforms/Utils/CloningTest.cpp @@ -652,6 +652,62 @@ } } +static int GetDICompileUnitCount(const Module& M) { + if (const auto* LLVM_DBG_CU = M.getNamedMetadata("llvm.dbg.cu")) { + return LLVM_DBG_CU->getNumOperands(); + } + return 0; +} + +TEST(CloneFunction, CloneFunctionToDifferentModule) { + StringRef ImplAssembly = R"( + define void @foo() { + ret void, !dbg !5 + } + + !llvm.module.flags = !{!0} + !llvm.dbg.cu = !{!2, !6} + !0 = !{i32 1, !"Debug Info Version", i32 3} + !1 = distinct !DISubprogram(unit: !2) + !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) + !3 = !DIFile(filename: "foo.c", directory: "/tmp") + !4 = distinct !DISubprogram(unit: !2) + !5 = !DILocation(line: 4, scope: !1) + !6 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) + )"; + StringRef DeclAssembly = R"( + declare void @foo() + )"; + + LLVMContext Context; + SMDiagnostic Error; + + auto ImplModule = parseAssemblyString(ImplAssembly, Error, Context); + EXPECT_TRUE(ImplModule != nullptr); + // DICompileUnits: !2, !6. Only !2 is reachable from @foo(). + EXPECT_TRUE(GetDICompileUnitCount(*ImplModule) == 2); + auto* ImplFunction = ImplModule->getFunction("foo"); + EXPECT_TRUE(ImplFunction != nullptr); + + auto DeclModule = parseAssemblyString(DeclAssembly, Error, Context); + EXPECT_TRUE(DeclModule != nullptr); + // No DICompileUnits defined here. + EXPECT_TRUE(GetDICompileUnitCount(*DeclModule) == 0); + auto* DeclFunction = DeclModule->getFunction("foo"); + EXPECT_TRUE(DeclFunction != nullptr); + + ValueToValueMapTy VMap; + VMap[ImplFunction] = DeclFunction; + // No args to map + SmallVector Returns; + CloneFunctionInto(DeclFunction, ImplFunction, VMap, true, Returns); + + EXPECT_FALSE(verifyModule(*ImplModule, &errs())); + EXPECT_FALSE(verifyModule(*DeclModule, &errs())); + // DICompileUnit !2 shall be inserted into DeclModule. + EXPECT_TRUE(GetDICompileUnitCount(*DeclModule) == 1); +} + class CloneModule : public ::testing::Test { protected: void SetUp() override {