Index: llvm/lib/Transforms/IPO/StripSymbols.cpp =================================================================== --- llvm/lib/Transforms/IPO/StripSymbols.cpp +++ llvm/lib/Transforms/IPO/StripSymbols.cpp @@ -295,6 +295,41 @@ return stripDebugDeclareImpl(M); } +static void +collectCUsWithScope(const DIScope *Scope, std::set &LiveCUs, + SmallPtrSet &VisitedScopes) { + if (!Scope) + return; + + auto InS = VisitedScopes.insert(Scope); + if (!InS.second) + return; + + if (const auto *SP = dyn_cast(Scope)) { + if (SP->getUnit()) + LiveCUs.insert(SP->getUnit()); + return; + } + if (const auto *LB = dyn_cast(Scope)) { + const DISubprogram *SP = LB->getSubprogram(); + if (SP && SP->getUnit()) + LiveCUs.insert(SP->getUnit()); + return; + } + + collectCUsWithScope(Scope->getScope(), LiveCUs, VisitedScopes); +} + +static void +collectCUsForInlinedFuncs(const DILocation *Loc, + std::set &LiveCUs, + SmallPtrSet &VisitedScopes) { + if (!Loc) + return; + collectCUsWithScope(Loc->getScope(), LiveCUs, VisitedScopes); + collectCUsForInlinedFuncs(Loc->getInlinedAt(), LiveCUs, VisitedScopes); +} + static bool stripDeadDebugInfoImpl(Module &M) { bool Changed = false; @@ -322,10 +357,20 @@ } std::set LiveCUs; - // Any CU referenced from a subprogram is live. - for (DISubprogram *SP : F.subprograms()) { - if (SP->getUnit()) - LiveCUs.insert(SP->getUnit()); + SmallPtrSet VisitedScopes; + // Any CU is live if is referenced from a subprogram metadata that is attached + // to a function defined or inlined in the module. + for (const Function &Fn : M.functions()) { + collectCUsWithScope(Fn.getSubprogram(), LiveCUs, VisitedScopes); + for (const BasicBlock &BB : Fn) { + for (const Instruction &I : BB) { + if (!I.getDebugLoc()) + continue; + const DILocation *DILoc = I.getDebugLoc().get(); + if (DILoc && DILoc->getInlinedAt()) + collectCUsForInlinedFuncs(DILoc, LiveCUs, VisitedScopes); + } + } } bool HasDeadCUs = false; @@ -333,9 +378,6 @@ // Create our live global variable list. bool GlobalVariableChange = false; for (auto *DIG : DIC->getGlobalVariables()) { - if (DIG->getExpression() && DIG->getExpression()->isConstant()) - LiveGVs.insert(DIG); - // Make sure we only visit each global variable only once. if (!VisitedSet.insert(DIG).second) continue; Index: llvm/test/Transforms/StripSymbols/strip-cu-with-const-gve.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/StripSymbols/strip-cu-with-const-gve.ll @@ -0,0 +1,61 @@ +; This test checks that strip-dead-debug-info pass deletes debug compile units +; if global constants from those units are absent in split module. + +; RUN: opt -passes='strip-dead-debug-info,verify' %s -S | FileCheck %s + +; CHECK: !llvm.dbg.cu = !{!{{[0-9]+}}, !{{[0-9]+}}} +; CHECK-COUNT-2: !DICompileUnit + +;target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +;target triple = "spir64-unknown-unknown" + +; Function Attrs: convergent nounwind +define void @dev_func1() #0 !dbg !16 { + %1 = call i32 @dev_subfunc1(i32 0) #1, !dbg !19 + ret void, !dbg !20 +} + +; Function Attrs: convergent nounwind +define i32 @dev_subfunc1(i32 %0) #0 !dbg !21 { + ret i32 %0, !dbg !24 +} + +; Function Attrs: convergent nounwind +define void @dev_func2() #0 !dbg !25 { + ret void, !dbg !26 +} + +attributes #0 = { convergent nounwind } +attributes #1 = { convergent } + +!llvm.dbg.cu = !{!0, !8, !10} +!llvm.module.flags = !{!15} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, imports: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "dev_func1.cpp", directory: "/home/usr/test") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression(DW_OP_constu, 0, DW_OP_stack_value)) +!5 = distinct !DIGlobalVariable(name: "ZERO", scope: !1, file: !1, line: 32, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !9, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, imports: !2, splitDebugInlining: false, nameTableKind: None) +!9 = !DIFile(filename: "dev_func2.cpp", directory: "/home/usr/test") +!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !11, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !12, imports: !2, splitDebugInlining: false, nameTableKind: None) +!11 = !DIFile(filename: "file3.cpp", directory: "/home/usr/test") +!12 = !{!13} +!13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression(DW_OP_constu, 0, DW_OP_stack_value)) +!14 = distinct !DIGlobalVariable(name: "ZERO", scope: !11, file: !11, line: 145, type: !6, isLocal: true, isDefinition: true) +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = distinct !DISubprogram(name: "dev_func1", linkageName: "dev_func1", scope: !1, file: !1, line: 22, type: !17, scopeLine: 22, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!17 = !DISubroutineType(types: !18) +!18 = !{null} +!19 = !DILocation(line: 12, column: 1, scope: !16) +!20 = !DILocation(line: 29, column: 5, scope: !16) +!21 = distinct !DISubprogram(name: "dev_subfunc1", linkageName: "dev_subfunc1", scope: !1, file: !1, line: 42, type: !22, scopeLine: 42, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!22 = !DISubroutineType(types: !23) +!23 = !{!7, !7} +!24 = !DILocation(line: 5, column: 1, scope: !21) +!25 = distinct !DISubprogram(name: "dev_func2", linkageName: "dev_func2", scope: !9, file: !9, line: 22, type: !17, scopeLine: 22, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !2) +!26 = !DILocation(line: 29, column: 5, scope: !25) + Index: llvm/test/Transforms/StripSymbols/strip-cu-with-dangling-subprogram.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/StripSymbols/strip-cu-with-dangling-subprogram.ll @@ -0,0 +1,43 @@ +; This test checks that strip-dead-debug-info pass deletes debug compile units +; if functions from those units are absent in that module. + +; RUN: opt -passes='strip-dead-debug-info,verify' %s -S | FileCheck %s + +; CHECK: !llvm.dbg.cu = !{!{{[0-9]+}}, !{{[0-9]+}}} +; CHECK-COUNT-2: !DICompileUnit + +;target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +;target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define void @dev_func1() #0 !dbg !13 { + ret void, !dbg !14 +} + +; Function Attrs: nounwind +define void @dev_func2() #0 !dbg !15 { + ret void, !dbg !16 +} + +attributes #0 = { nounwind } + +!llvm.dbg.cu = !{!0, !3, !5} +!llvm.module.flags = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, imports: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "dev_func1.cpp", directory: "/home/user/test") +!2 = !{} +!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !4, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, imports: !2, splitDebugInlining: false, nameTableKind: None) +!4 = !DIFile(filename: "dev_func2.cpp", directory: "/home/user/test") +!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !6, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, imports: !7, splitDebugInlining: false, nameTableKind: None) +!6 = !DIFile(filename: "dev_func3.cpp", directory: "/home/user/test") +!7 = !{!8} +!8 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !6, entity: !9, file: !6, line: 129) +!9 = distinct !DISubprogram(name: "dev_func3", linkageName: "dev_func3", scope: !6, file: !6, line: 96, type: !10, scopeLine: 96, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !5, retainedNodes: !2) +!10 = !DISubroutineType(types: !11) +!11 = !{null} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = distinct !DISubprogram(name: "dev_func1", linkageName: "dev_func1", scope: !1, file: !1, line: 22, type: !10, scopeLine: 22, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!14 = !DILocation(line: 29, column: 5, scope: !13) +!15 = distinct !DISubprogram(name: "dev_func2", linkageName: "dev_func2", scope: !4, file: !4, line: 22, type: !10, scopeLine: 22, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !2) +!16 = !DILocation(line: 29, column: 5, scope: !15) Index: llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll =================================================================== --- llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll +++ llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll @@ -4,9 +4,10 @@ ; CHECK-NOT: "bar" ; CHECK-NOT: "abcd" ; CHECK-NOT: "GCC" -; CHECK: "Globals" -; CHECK: "abcd2" -; CHECK: "abcd3" +; CHECK-NOT: "Globals" +; CHECK-NOT: "abcd2" +; CHECK-NOT: "abcd3" +; CHECK: "InlineTest" source_filename = "test/Transforms/StripSymbols/strip-dead-debug-info.ll"