| ; REQUIRES: asserts,x86-registered-target |
| ; RUN: opt --bitcode-mdindex-threshold=0 -module-summary %s -o %t.bc |
| ; RUN: opt --bitcode-mdindex-threshold=0 -module-summary %p/Inputs/funcimport-debug-retained-nodes.ll -o %t2.bc |
| |
| ; RUN: llvm-lto2 run %t2.bc %t.bc --save-temps -o %t3 \ |
| ; RUN: -r=%t.bc,main,px -r=%t.bc,func,px -r=%t2.bc,func,x -r=%t2.bc,foo,rx \ |
| ; RUN: --debug-only=bitcode-reader --thinlto-threads=1 2>&1 \ |
| ; RUN: | FileCheck --allow-empty --check-prefix=LTO %s \ |
| ; RUN: --implicit-check-not='ignoring invalid debug info' \ |
| ; RUN: --implicit-check-not='warning' |
| |
| ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s \ |
| ; RUN: --implicit-check-not='DISubprogram(name: "inlined_out_clone"' \ |
| ; RUN: --implicit-check-not='DICompositeType({{.*}}, identifier: "local_type"' |
| |
| ; Check that retained nodes of lazy-loaded DISubprograms are cleaned up |
| ; from incorrectly-scoped local types. |
| |
| ; When DebugTypeODRUniquing feature is enabled (e.g. with ThinLTO), |
| ; local DITypes with the same `identifier` values are uniqued in scope |
| ; of LLVM context during metadata loading. |
| ; DISubprograms may reference their local types via `retainedNodes` attribute. |
| ; Thus, during ThinLTO, the final module may end up having multiple |
| ; DISubprograms referencing the same uniqued local type. |
| ; MetadataLoader should clean up retainedNodes lists of DISubprograms from |
| ; such references after loading subprograms and their local types. |
| ; This test checks that such cleanup is done when metadata nodes are loaded |
| ; in lazy fashion without relying on cleanup performed during |
| ; eager function-level or module-level METADATA_BLOCK loading. |
| |
| ; In order to trigger lazy-loading of DISubprogram "inlined_out_clone" |
| ; from module-level METADATA_BLOCK in %p/Inputs/funcimport-debug-retained-nodes.ll: |
| ; 1. The emission of metadata index is forced by setting |
| ; --bitcode-md-index-threshold. If no MD index is emitted in BC file, |
| ; MetadataLoader loads all metadata from a module-level METADATA_BLOCK eagerly. |
| ; 2. The DISubprogram is referenced by locations inlined in two different |
| ; IR functions, thus, it is emitted in module-level METADATA_BLOCK. |
| ; 3. The DISubprogram is not referenced by any local variable of a function, |
| ; so that it is not loaded eagerly when reading function-level METADATA_BLOCK. |
| ; Otherwise, cleanup would be performed on it during function-level |
| ; METADATA_BLOCK loading. |
| ; 4. No other METADATA_BLOCK should be loaded after lazy-loading the target |
| ; DISubprogram, to avoid cleanup being performed later. We want to observe |
| ; the behavior of MetadataLoader when loading the target DISubprogram lazily |
| ; without interference from metadata blocks loaded later. Therefore, @foo from |
| ; %p/Inputs/funcimport-debug-retained-nodes.ll, that follows @func referencing |
| ; the target DISubprogram, is marked as dso_preemptable => unsafe for LTO |
| ; function import. |
| |
| ; This test should pass if, after ThinLTO function import, the final module |
| ; contains two DISubprograms "inlined_out_clone", and none of them reference |
| ; the local type that doesn't belong to them via `retainedNodes`. |
| ; It should fail if `retainedNodes` field of DISubprogram "inlined_out_clone" |
| ; loaded from %p/Inputs/funcimport-debug-retained-nodes.ll references |
| ; DICompositeType from the scope of DISubprogram "inlined_out_clone" from |
| ; %p/funcimport-debug-retained-nodes.ll (the type that is uniqued |
| ; due to DebugTypeODRUniquing on). |
| |
| ; Check that lazy loading codepath is triggered, the subprogram is cleaned up, |
| ; and MetadataLoaderImpl::resolveLoadedMetadata() is not called after that. |
| ; LTO: Lazy metadata loading: Resolved loaded metadata. Cleaned up 1 subprogram(s). |
| ; LTO-NOT: Resolved loaded metadata |
| |
| ; The module %p/funcimport-debug-retained-nodes.ll contains: |
| ; - DICompositeType "local_type", and |
| ; - DISubprogram "inlined_out_clone" with empty retainedNodes list. |
| ; The module %p/Inputs/funcimport-debug-retained-nodes.ll contains: |
| ; - DICompositeType "local_type", and |
| ; - DISubprogram "inlined_out_clone" with "local_type" in its retainedNodes. |
| ; After function import into module %p/funcimport-debug-retained-nodes.ll, |
| ; the output module contains: |
| ; - a single DICompositeType "local_type" that comes from %p/funcimport-debug-retained-nodes.ll |
| ; (due to ODR-uniquing, "local_type" from %p/Inputs/funcimport-debug-retained-nodes.ll |
| ; is not imported during function import), |
| ; - DISubprogram "inlined_out_clone" from %p/funcimport-debug-retained-nodes.ll |
| ; with empty retainedNodes list, and |
| ; - DISubprogram "inlined_out_clone" from %p/Inputs/funcimport-debug-retained-nodes.ll. |
| ; This test expects its retaiendNodes to be empty, cleaned up from reference |
| ; to "local_type" from %p/funcimport-debug-retained-nodes.ll (that, without proper |
| ; cleanup, would occur because of ODR-uniquing). The following check lines ensure that. |
| |
| ; CHECK: ![[ORIGINAL_FILE:[0-9]+]] = !DIFile(filename: "funcimport_debug.c", |
| ; CHECK: ![[EMPTY:[0-9]+]] = !{} |
| ; CHECK: ![[IMPORTED_FILE:[0-9]+]] = !DIFile(filename: "funcimport_debug2.c", |
| ; CHECK: ![[ORIGINAL_SP:[0-9]+]] = distinct !DISubprogram(name: "inlined_out_clone", {{.*}}, file: ![[ORIGINAL_FILE]], {{.*}}, retainedNodes: ![[EMPTY]] |
| ; CHECK: !DICompositeType(tag: DW_TAG_class_type, scope: ![[ORIGINAL_SP]], {{.*}}, identifier: "local_type" |
| ; CHECK: !DISubprogram(name: "inlined_out_clone", {{.*}}, file: ![[IMPORTED_FILE]], {{.*}}, retainedNodes: ![[EMPTY]] |
| |
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" |
| target triple = "x86_64-unknown-linux-gnu" |
| |
| define i32 @main() !dbg !5 { |
| entry: |
| %a = alloca i8, align 4 |
| #dbg_declare(ptr %a, !9, !DIExpression(), !12) |
| call void (...) @func() |
| ret i32 0 |
| } |
| |
| declare void @func(...) |
| |
| !llvm.dbg.cu = !{!0} |
| !llvm.module.flags = !{!3, !4} |
| |
| !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
| !1 = !DIFile(filename: "funcimport_debug.c", directory: ".") |
| !2 = !{} |
| !3 = !{i32 2, !"Dwarf Version", i32 4} |
| !4 = !{i32 2, !"Debug Info Version", i32 3} |
| !5 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 2, type: !6, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) |
| !6 = !DISubroutineType(types: !7) |
| !7 = !{!8} |
| !8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) |
| !9 = !DILocalVariable(name: "foo_ptr", scope: !10, file: !1, line: 4, type: !11) |
| !10 = distinct !DISubprogram(name: "inlined_out_clone", scope: !1, file: !1, line: 20, type: !6, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) |
| !11 = !DICompositeType(tag: DW_TAG_class_type, scope: !10, file: !1, line: 210, size: 8, flags: DIFlagTypePassByValue, elements: !2, identifier: "local_type") |
| !12 = !DILocation(line: 3, column: 1, scope: !10, inlinedAt: !13) |
| !13 = !DILocation(line: 3, column: 3, scope: !5) |