From a52cfbb4e3dcf861d053e7b99d6effe00bb351cc Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Mon, 25 Jan 2016 22:04:56 +0000 Subject: [PATCH] [ThinLTO] Find all needed metadata when linking metadata as postpass For metadata postpass linking, after importing all functions, we need to recursively walk through any nodes reached via imported functions to locate needed subprogram metadata. Some might only be reached indirectly via the variable list for an inlined function. llvm-svn: 258728 --- lib/Linker/IRMover.cpp | 33 ++++++++++++++++++++----- test/Linker/thinlto_funcimport_debug.ll | 16 +++++++++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/Linker/IRMover.cpp b/lib/Linker/IRMover.cpp index f30b623b523..6dbc183f782 100644 --- a/lib/Linker/IRMover.cpp +++ b/lib/Linker/IRMover.cpp @@ -501,6 +501,11 @@ class IRLinker { /// in an imported function. void findNeededSubprograms(); + /// Recursive helper for findNeededSubprograms to locate any DISubprogram + /// reached from the given Node, marking any found as needed. + void findReachedSubprograms(const MDNode *Node, + SmallPtrSet &Visited); + /// The value mapper leaves nulls in the list of subprograms for any /// in the UnneededSubprograms map. Strip those out after metadata linking. void stripNullSubprograms(); @@ -1194,6 +1199,21 @@ bool IRLinker::linkGlobalValueBody(GlobalValue &Dst, GlobalValue &Src) { return false; } +void IRLinker::findReachedSubprograms( + const MDNode *Node, SmallPtrSet &Visited) { + if (!Visited.insert(Node).second) + return; + DISubprogram *SP = getDISubprogram(Node); + if (SP) + UnneededSubprograms.erase(SP); + for (auto &Op : Node->operands()) { + const MDNode *OpN = dyn_cast_or_null(Op.get()); + if (!OpN) + continue; + findReachedSubprograms(OpN, Visited); + } +} + void IRLinker::findNeededSubprograms() { // Track unneeded nodes to make it simpler to handle the case // where we are checking if an already-mapped SP is needed. @@ -1231,17 +1251,18 @@ void IRLinker::findNeededSubprograms() { if (!IsMetadataLinkingPostpass) return; // In the case of metadata linking as a postpass (e.g. for function - // importing), see which DISubprogram MD from the source has an associated - // temporary metadata node, which means the SP was needed by an imported - // function. + // importing), see which MD from the source has an associated + // temporary metadata node, which means that any DISubprogram + // reached from that MD was needed by an imported function. + SmallPtrSet Visited; for (auto MDI : MetadataToIDs) { const MDNode *Node = dyn_cast(MDI.first); if (!Node) continue; - DISubprogram *SP = getDISubprogram(Node); - if (!SP || !ValIDToTempMDMap->count(MDI.second)) + if (!ValIDToTempMDMap->count(MDI.second)) continue; - UnneededSubprograms.erase(SP); + // Find any SP needed recursively from this needed Node. + findReachedSubprograms(Node, Visited); } } diff --git a/test/Linker/thinlto_funcimport_debug.ll b/test/Linker/thinlto_funcimport_debug.ll index 02f43b24c17..0e26a33375a 100644 --- a/test/Linker/thinlto_funcimport_debug.ll +++ b/test/Linker/thinlto_funcimport_debug.ll @@ -18,6 +18,8 @@ ; CHECK: distinct !DISubprogram(name: "func1" ; CHECK-NOT: distinct !DISubprogram(name: "func2" +; CHECK: distinct !DISubprogram(name: "func3" +; CHECK: distinct !DISubprogram(name: "func4" ; ModuleID = 'dbg.o' @@ -55,7 +57,7 @@ attributes #1 = { nounwind readnone } !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 251407) (llvm/trunk 251401)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) !1 = !DIFile(filename: "dbg.c", directory: ".") !2 = !{} -!3 = !{!4, !11} +!3 = !{!4, !11, !27, !30} !4 = distinct !DISubprogram(name: "func1", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, variables: !8) !5 = !DISubroutineType(types: !6) !6 = !{!7, !7} @@ -72,9 +74,17 @@ attributes #1 = { nounwind readnone } !17 = !DIExpression() !18 = !DILocation(line: 1, column: 15, scope: !4) !19 = !DILocation(line: 2, column: 7, scope: !4) -!20 = !DILocation(line: 3, column: 9, scope: !21) -!21 = distinct !DILexicalBlock(scope: !4, file: !1, line: 3, column: 7) +!20 = !DILocation(line: 3, column: 9, scope: !21, inlinedAt: !26) +!21 = distinct !DILexicalBlock(scope: !27, file: !1, line: 3, column: 7) !22 = !DILocation(line: 3, column: 7, scope: !4) !23 = !DILocation(line: 5, column: 3, scope: !4) !24 = !DILocation(line: 8, column: 15, scope: !11) !25 = !DILocation(line: 9, column: 3, scope: !11) +!26 = !DILocation(line: 9, column: 3, scope: !4) +!27 = distinct !DISubprogram(name: "func3", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !28) +!28 = !{!29} +!29 = !DILocalVariable(name: "n", arg: 1, scope: !30, file: !1, line: 8, type: !7) +!30 = distinct !DISubprogram(name: "func4", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !31) +!31 = !{!32} +!32 = !DILocalVariable(name: "n", arg: 1, scope: !30, file: !1, line: 8, type: !7) +