blob: 3908c22d42ab70960f566317478c1a806a1e8edd [file] [log] [blame] [edit]
; 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)