From 1a173576c93ee288b8b7c23139abd831ead050d9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 11 Apr 2017 13:32:11 +0000 Subject: [PATCH] [StripDeadDebug/DIFinder] Track inlined SPs Summary: In rL299692 I improved strip-dead-debug-info's ability to drop CUs that are not referenced from the current module. However, in doing so I neglected to realize that some SPs could be referenced entirely from inlined functions. It appears I was not the only one to make this mistake, because DebugInfoFinder, doesn't find those SPs either. Fix this in DebugInfoFinder and then use that to make sure not to drop those CUs in strip-dead-debug-info. Reviewers: aprantl Reviewed By: aprantl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31904 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299936 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/IR/DebugInfo.cpp | 12 ++++++- lib/Transforms/IPO/StripSymbols.cpp | 7 ++--- .../Generic/debuginfofinder-inlined-cu.ll | 31 +++++++++++++++++++ .../StripSymbols/strip-dead-debug-info.ll | 7 +++-- 4 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 test/DebugInfo/Generic/debuginfofinder-inlined-cu.ll diff --git a/lib/IR/DebugInfo.cpp b/lib/IR/DebugInfo.cpp index 4fe2553687c..c5d39c54430 100644 --- a/lib/IR/DebugInfo.cpp +++ b/lib/IR/DebugInfo.cpp @@ -79,9 +79,19 @@ void DebugInfoFinder::processModule(const Module &M) { processScope(M->getScope()); } } - for (auto &F : M.functions()) + for (auto &F : M.functions()) { if (auto *SP = cast_or_null(F.getSubprogram())) processSubprogram(SP); + // There could be subprograms from inlined functions referenced from + // instructions only. Walk the function to find them. + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + if (!I.getDebugLoc()) + continue; + processLocation(M, I.getDebugLoc().get()); + } + } + } } void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) { diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 4d52f5f3110..fb64367eef9 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -324,10 +324,9 @@ bool StripDeadDebugInfo::runOnModule(Module &M) { } std::set LiveCUs; - // Any CU referenced from a function is live. - for (Function &F : M.functions()) { - DISubprogram *SP = F.getSubprogram(); - if (SP && SP->getUnit()) + // Any CU referenced from a subprogram is live. + for (DISubprogram *SP : F.subprograms()) { + if (SP->getUnit()) LiveCUs.insert(SP->getUnit()); } diff --git a/test/DebugInfo/Generic/debuginfofinder-inlined-cu.ll b/test/DebugInfo/Generic/debuginfofinder-inlined-cu.ll new file mode 100644 index 00000000000..313e22d84f3 --- /dev/null +++ b/test/DebugInfo/Generic/debuginfofinder-inlined-cu.ll @@ -0,0 +1,31 @@ +; RUN: opt -analyze -module-debuginfo < %s | FileCheck %s + +; Verify that both compile units, even though one compile units's functions +; were entirely inlined into the other. +;CHECK: Compile unit: DW_LANG_C99 from /tmp/test1.c +;CHECK: Compile unit: DW_LANG_C99 from /tmp/test2.c +;CHECK: Subprogram: f from /tmp/test1.c:1 +;CHECK: Subprogram: g from /tmp/test2.c:1 + +define void @f() !dbg !4 { + ret void, !dbg !15 +} + +!llvm.dbg.cu = !{!0, !8} +!llvm.module.flags = !{!13, !16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.4 (192092)", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2) +!1 = !DIFile(filename: "test1.c", directory: "/tmp") +!2 = !{} +!4 = distinct !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2) +!5 = !DIFile(filename: "test1.c", directory: "/tmp") +!6 = !DISubroutineType(types: !7) +!7 = !{null} +!8 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.4 (192092)", isOptimized: false, emissionKind: FullDebug, file: !9, enums: !2, retainedTypes: !2, globals: !2, imports: !2) +!9 = !DIFile(filename: "test2.c", directory: "/tmp") +!11 = distinct !DISubprogram(name: "g", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !8, scopeLine: 1, file: !9, scope: !12, type: !6, variables: !2) +!12 = !DIFile(filename: "test2.c", directory: "/tmp") +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !DILocation(line: 1, scope: !4) +!15 = !DILocation(line: 1, scope: !11, inlinedAt: !14) +!16 = !{i32 1, !"Debug Info Version", i32 3} diff --git a/test/Transforms/StripSymbols/strip-dead-debug-info.ll b/test/Transforms/StripSymbols/strip-dead-debug-info.ll index eb8ff50137c..d18c07d54a9 100644 --- a/test/Transforms/StripSymbols/strip-dead-debug-info.ll +++ b/test/Transforms/StripSymbols/strip-dead-debug-info.ll @@ -24,7 +24,7 @@ entry: define i32 @foo(i32 %i) #2 !dbg !15 { entry: tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !18, metadata !19), !dbg !20 - %.0 = load i32, i32* @xyz, align 4 + %.0 = load i32, i32* @xyz, align 4, !dbg !30 ret i32 %.0, !dbg !21 } @@ -32,7 +32,7 @@ attributes #0 = { nounwind readnone } attributes #1 = { nounwind readnone ssp } attributes #2 = { nounwind readonly ssp } -!llvm.dbg.cu = !{!4, !23, !24} +!llvm.dbg.cu = !{!4, !23, !24, !28} !llvm.module.flags = !{!9} !0 = !DIGlobalVariableExpression(var: !1) @@ -63,3 +63,6 @@ attributes #2 = { nounwind readonly ssp } !25 = !{!26} !26 = !DIGlobalVariableExpression(var: !27, expr: !DIExpression(DW_OP_constu, 0, DW_OP_stack_value)) !27 = !DIGlobalVariable(name: "abcd2", scope: !2, file: !2, line: 2, type: !3, isLocal: true, isDefinition: true) +!28 = distinct !DICompileUnit(language: DW_LANG_C89, file: !2, producer: "InlineTest", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !5) +!29 = distinct !DISubprogram(name: "inlinefunc", linkageName: "inlinefunc", scope: null, file: !2, line: 7, type: !16, isLocal: false, isDefinition: true, isOptimized: true, unit: !28) +!30 = !DILocation(line: 100, scope: !29, inlinedAt: !21) -- 2.40.0