diff --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp --- a/llvm/lib/Transforms/Utils/CloneFunction.cpp +++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp @@ -137,16 +137,6 @@ MD[SP].reset(SP); } - SmallVector, 1> MDs; - OldFunc->getAllMetadata(MDs); - for (auto MD : MDs) { - NewFunc->addMetadata( - MD.first, - *MapMetadata(MD.second, VMap, - ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, - TypeMapper, Materializer)); - } - // Everything else beyond this point deals with function instructions, // so if we are dealing with a function declaration, we're done. if (OldFunc->isDeclaration()) @@ -162,7 +152,6 @@ // 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 // recursive functions into themselves. - // for (Function::const_iterator BI = OldFunc->begin(), BE = OldFunc->end(); BI != BE; ++BI) { const BasicBlock &BB = *BI; @@ -201,6 +190,19 @@ for (DIType *Type : DIFinder.types()) VMap.MD()[Type].reset(Type); + // Duplicate the metadata that is attached to the cloned function. + // Subprograms/CUs/types that were already mapped to themselves won't be + // duplicated. + SmallVector, 1> MDs; + OldFunc->getAllMetadata(MDs); + for (auto MD : MDs) { + NewFunc->addMetadata( + MD.first, + *MapMetadata(MD.second, VMap, + ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, + TypeMapper, Materializer)); + } + // Loop over all of the instructions in the function, fixing up operand // references as we go. This uses VMap to do all the hard work. for (Function::iterator BB = diff --git a/llvm/unittests/Transforms/Utils/CloningTest.cpp b/llvm/unittests/Transforms/Utils/CloningTest.cpp --- a/llvm/unittests/Transforms/Utils/CloningTest.cpp +++ b/llvm/unittests/Transforms/Utils/CloningTest.cpp @@ -681,7 +681,7 @@ ValueToValueMapTy VMap; SmallVector Returns; ClonedCodeInfo CCI; - CloneFunctionInto(DeclFunction, ImplFunction, VMap, true, Returns, "", &CCI); + CloneFunctionInto(ImplFunction, DeclFunction, VMap, true, Returns, "", &CCI); EXPECT_FALSE(verifyModule(*ImplModule, &errs())); EXPECT_FALSE(CCI.ContainsCalls); @@ -719,6 +719,55 @@ EXPECT_TRUE(CCI.ContainsDynamicAllocas); } +TEST(CloneFunction, CloneFunctionWithSubprograms) { + // Tests that the debug info is duplicated correctly when a DISubprogram + // happens to be one of the operands of the DISubprogram that is being cloned. + // In general, operands of "test" that are distinct should be duplicated, + // but in this case "my_operator" should not be duplicated. If it is + // duplicated, the metadata in the llvm.dbg.declare could end up with + // different duplicates. + StringRef ImplAssembly = R"( + declare void @llvm.dbg.declare(metadata, metadata, metadata) + + define void @test() !dbg !5 { + call void @llvm.dbg.declare(metadata i8* undef, metadata !4, metadata !DIExpression()), !dbg !6 + ret void + } + + declare void @cloned() + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1) + !1 = !DIFile(filename: "test.cpp", directory: "") + !2 = !{i32 1, !"Debug Info Version", i32 3} + !3 = distinct !DISubprogram(name: "my_operator", scope: !1, unit: !0, retainedNodes: !{!4}) + !4 = !DILocalVariable(name: "awaitables", scope: !3) + !5 = distinct !DISubprogram(name: "test", scope: !3, unit: !0) + !6 = !DILocation(line: 55, column: 15, scope: !3, inlinedAt: !7) + !7 = distinct !DILocation(line: 73, column: 14, scope: !5) + )"; + + LLVMContext Context; + SMDiagnostic Error; + + auto ImplModule = parseAssemblyString(ImplAssembly, Error, Context); + EXPECT_TRUE(ImplModule != nullptr); + auto *OldFunc = ImplModule->getFunction("test"); + EXPECT_TRUE(OldFunc != nullptr); + auto *NewFunc = ImplModule->getFunction("cloned"); + EXPECT_TRUE(NewFunc != nullptr); + + ValueToValueMapTy VMap; + SmallVector Returns; + ClonedCodeInfo CCI; + CloneFunctionInto(NewFunc, OldFunc, VMap, true, Returns, "", &CCI); + + // This fails if the scopes in the llvm.dbg.declare variable and location + // aren't the same. + EXPECT_FALSE(verifyModule(*ImplModule, &errs())); +} + TEST(CloneFunction, CloneFunctionToDifferentModule) { StringRef ImplAssembly = R"( define void @foo() {