diff --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h --- a/llvm/include/llvm/IR/DebugInfo.h +++ b/llvm/include/llvm/IR/DebugInfo.h @@ -112,6 +112,7 @@ void processCompileUnit(DICompileUnit *CU); void processScope(DIScope *Scope); void processType(DIType *DT); + void processLocalVariable(DILocalVariable *DV); bool addCompileUnit(DICompileUnit *CU); bool addGlobalVariable(DIGlobalVariableExpression *DIG); bool addScope(DIScope *Scope); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -267,6 +267,14 @@ processType(TVal->getType()); } } + + for (auto *N : SP->getRetainedNodes()) { + if (auto *Var = dyn_cast(N)) { + processLocalVariable(Var); + } else if (auto *T = dyn_cast(N)) { + processType(T); + } + } } void DebugInfoFinder::processVariable(const Module &M, @@ -275,7 +283,10 @@ if (!N) return; - auto *DV = dyn_cast(N); + processLocalVariable(dyn_cast(N)); +} + +void DebugInfoFinder::processLocalVariable(DILocalVariable *DV) { if (!DV) return; 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 @@ -244,7 +244,12 @@ mapToSelfIfNew(CU); for (DIType *Type : DIFinder->types()) - mapToSelfIfNew(Type); + // Don't skip subprogram's local types. + if (!isa_and_present(Type->getScope()) || + SPClonedWithinModule == nullptr || + dyn_cast(Type->getScope())->getSubprogram() != + SPClonedWithinModule) + mapToSelfIfNew(Type); } else { assert(!SPClonedWithinModule && "Subprogram should be in DIFinder->subprogram_count()..."); @@ -271,6 +276,32 @@ for (Instruction &II : *BB) RemapInstruction(&II, VMap, RemapFlag, TypeMapper, Materializer); + if (SPClonedWithinModule != nullptr) { + if (DICompileUnit *CU = SPClonedWithinModule->getUnit()) { + // If we cloned the type, referenced by DICompileUnit, we must add a + // reference on it. + SmallVector TypesToAdd; + for (DIScope *S : CU->getRetainedTypes()) { + if (DIType *Type = dyn_cast(S)) { + auto It = VMap.MD().find(Type); + + if (It != VMap.MD().end() && It->first != It->second) + TypesToAdd.push_back(It->second.get()); + else if (It == VMap.MD().end()) { + Metadata *Cloned = MDNode::replaceWithDistinct(Type->clone()); + TypesToAdd.push_back(Cloned); + VMap.MD()[Type].reset(Cloned); + } + } + } + + SmallVector NewTypes(CU->getRetainedTypes().begin(), + CU->getRetainedTypes().end()); + NewTypes.append(TypesToAdd); + CU->replaceRetainedTypes(MDNode::get(CU->getContext(), NewTypes)); + } + } + // Only update !llvm.dbg.cu for DifferentModule (not CloneModule). In the // same module, the compile unit will already be listed (or not). When // cloning a module, CloneModule() will handle creating the named metadata. 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 @@ -799,6 +799,118 @@ EXPECT_FALSE(verifyModule(*ImplModule, &errs())); } +TEST(CloneFunction, CloneFunctionWithRetainedNodes) { + StringRef ImplAssembly = R"( + declare void @llvm.dbg.declare(metadata, metadata, metadata) + + define void @test() !dbg !3 { + call void @llvm.dbg.declare(metadata i8* undef, metadata !5, metadata !DIExpression()), !dbg !7 + call void @llvm.dbg.declare(metadata i8* undef, metadata !19, metadata !DIExpression()), !dbg !8 + ret void + } + + declare void @cloned() + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, enums: !{}, retainedTypes: !{!21, !14}) + !1 = !DIFile(filename: "test.cpp", directory: "") + !2 = !{i32 1, !"Debug Info Version", i32 3} + !3 = distinct !DISubprogram(name: "test", scope: !1, unit: !0, retainedNodes: !9) + !4 = distinct !DISubprogram(name: "inlined", scope: !1, unit: !0, retainedNodes: !{!5}) + !5 = !DILocalVariable(name: "awaitables", scope: !4, type: !23) + !6 = distinct !DILexicalBlock(scope: !4, file: !1, line: 1) + !7 = !DILocation(line: 1, scope: !6, inlinedAt: !8) + !8 = !DILocation(line: 10, scope: !3) + !9 = !{!12, !15, !17, !18, !20} + !12 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "retained_composite", scope: !3, file: !1, line: 13, size: 192, elements: !{}) + !14 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, scope: !0, file: !1, line: 13, size: 200, elements: !{}) + !15 = !DILocalVariable(name: "a", scope: !3) + !16 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, scope: !3, file: !1, line: 13, size: 208, elements: !{}) + !17 = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "imported_l", file: !1, line: 14, scope: !3, entity: !16) + !18 = !DILabel(scope: !3, name: "l", file: !1, line: 22) + !19 = !DILocalVariable(name: "b", type: !12, scope: !3) + !20 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "other_sp", scope: !4, file: !1, line: 13, size: 216, elements: !{}) + !21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 32, align: 32, elements: !{}, dataLocation: !16, rank: 7, name: "cu_local", scope: !3) + !22 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) + !23 = !DIDerivedType(name: "local_float", tag: DW_TAG_const_type, baseType: !22, scope: !3) + !float_type = !{!23} + )"; + + LLVMContext Context; + SMDiagnostic Error; + + auto ImplModule = parseAssemblyString(ImplAssembly, Error, Context); + EXPECT_TRUE(ImplModule != nullptr); + auto *Func = ImplModule->getFunction("test"); + EXPECT_TRUE(Func != nullptr); + auto *ClonedFunc = ImplModule->getFunction("cloned"); + EXPECT_TRUE(ClonedFunc != nullptr); + + EXPECT_FALSE(verifyModule(*ImplModule, &errs())); + + ValueToValueMapTy VMap; + SmallVector Returns; + ClonedCodeInfo CCI; + CloneFunctionInto(ClonedFunc, Func, VMap, + CloneFunctionChangeType::GlobalChanges, Returns, "", &CCI); + + EXPECT_FALSE(verifyModule(*ImplModule, &errs())); + + // Check that retained and local types are copied. + DISubprogram *FuncSP = Func->getSubprogram(); + DISubprogram *ClonedSP = ClonedFunc->getSubprogram(); + DICompileUnit *CU = FuncSP->getUnit(); + EXPECT_NE(FuncSP, nullptr); + EXPECT_NE(ClonedSP, nullptr); + EXPECT_EQ(FuncSP->getRetainedNodes().size(), 5u); + EXPECT_EQ(FuncSP->getRetainedNodes().size(), + ClonedSP->getRetainedNodes().size()); + for (unsigned I = 0; I < FuncSP->getRetainedNodes().size(); ++I) { + auto *Node = FuncSP->getRetainedNodes()[I]; + auto *Copy = ClonedSP->getRetainedNodes()[I]; + + // Check that the order of retainedNodes is preserved by + // checking that the corresponding node has the same name. + if (auto *Var = dyn_cast(Node)) { + auto *VarCopy = dyn_cast(Copy); + EXPECT_NE(VarCopy, nullptr); + EXPECT_EQ(Var->getName(), VarCopy->getName()); + } else if (auto *Label = dyn_cast(Node)) { + auto *LabelCopy = dyn_cast(Copy); + EXPECT_NE(LabelCopy, nullptr); + EXPECT_EQ(Label->getName(), LabelCopy->getName()); + } else if (auto *IE = dyn_cast(Node)) { + auto *IECopy = dyn_cast(Copy); + EXPECT_NE(IECopy, nullptr); + EXPECT_EQ(IE->getName(), IECopy->getName()); + } else if (auto *T = dyn_cast(Node)) { + auto *TCopy = dyn_cast(Copy); + EXPECT_NE(TCopy, nullptr); + EXPECT_EQ(T->getName(), TCopy->getName()); + // Check that node belonging to another subprogram wasn't copied. + if (T->getName() == "other_sp") { + EXPECT_EQ(Node, Copy); + continue; + } + } + + // Check that node was copied + EXPECT_NE(Node, Copy); + } + + // Check that list of types of CU is updated when variable is cloned. + EXPECT_EQ(CU->getRetainedTypes().size(), 3u); + EXPECT_EQ((*(CU->getRetainedTypes().begin()))->getName(), + (*(++ ++CU->getRetainedTypes().begin()))->getName()); + + auto *FloatType = dyn_cast( + ImplModule->getNamedMetadata("float_type")->getOperand(0)); + EXPECT_EQ(FloatType->getName(), "local_float"); + EXPECT_TRUE(VMap.MD().contains(FloatType)); + EXPECT_NE(FloatType, VMap.MD()[FloatType]); +} + TEST(CloneFunction, CloneFunctionWithInlinedSubprograms) { StringRef ImplAssembly = R"( declare void @llvm.dbg.declare(metadata, metadata, metadata)