# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK # RUN: llc %s -o - -start-before=livedebugvalues -filetype=obj -mtriple=x86_64-unknown-unknown | llvm-dwarfdump - | FileCheck %s --check-prefix=RANGES # Check that livedebugvalues does the right thing when register and constant # DBG_VALUEs interact, and that their ranges are correctly terminated by the # debug printing backend. --- | ; All these IR functions are duds, see the MIR below. source_filename = "<stdin>" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" define i32 @foo(i32* %bees, i32* %output) !dbg !4 { entry: br i1 undef, label %bb1, label %bb1 bb1: br label %bb3 bb2: br label %bb3 bb3: ret i32 0 } define i32 @bar(i32* %bees, i32* %output) !dbg !40 { entry: br i1 undef, label %bb1, label %bb1 bb1: br label %bb3 bb2: br label %bb3 bb3: ret i32 0 } define i32 @baz(i32* %bees, i32* %output) !dbg !80 { entry: br i1 undef, label %bb1, label %bb1 bb1: br label %bb3 bb2: br label %bb3 bb3: ret i32 0 } define i32 @qux(i32* %bees, i32* %output) !dbg !120 { entry: br i1 undef, label %bb1, label %bb1 bb1: br label %bb3 bb2: br label %bb3 bb3: ret i32 0 } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) ; Function Attrs: nounwind declare void @llvm.stackprotector(i8*, i8**) !llvm.module.flags = !{!0, !100} !llvm.dbg.cu = !{!1} !100 = !{i32 2, !"Dwarf Version", i32 4} !0 = !{i32 2, !"Debug Info Version", i32 3} !1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) !2 = !DIFile(filename: "bees.cpp", directory: ".") !3 = !DILocalVariable(name: "flannel", scope: !4, file: !2, line: 1, type: !16) !4 = distinct !DISubprogram(name: "nope", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) !5 = !DILocation(line: 0, scope: !4) !6 = !DILocation(line: 1, scope: !4) !7 = !DILocation(line: 2, scope: !4) !8 = !DILocation(line: 4, scope: !4) !9 = !DILocation(line: 5, scope: !4) !10 = !DILocation(line: 6, scope: !4) !11 = !DILocation(line: 7, scope: !4) !12 = !DILocation(line: 8, scope: !4) !13 = !{!3} !14 = !DISubroutineType(types: !15) !15 = !{!16} !16 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !40 = distinct !DISubprogram(name: "bar", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) !41 = !DILocalVariable(name: "towel", scope: !40, file: !2, line: 1, type: !16) !42 = !DILocation(line: 40, scope: !40) !80 = distinct !DISubprogram(name: "baz", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) !81 = !DILocalVariable(name: "socks", scope: !80, file: !2, line: 1, type: !16) !82 = !DILocation(line: 40, scope: !80) !120 = distinct !DISubprogram(name: "qux", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) !121 = !DILocalVariable(name: "shoes", scope: !120, file: !2, line: 1, type: !16) !122 = !DILocation(line: 40, scope: !120) ... --- name: foo alignment: 16 tracksRegLiveness: true registers: [] liveins: - { reg: '$rdi', virtual-reg: '' } body: | ; Two DBG_VALUEs for eax merge into bb3, check that livedebugvalues propagates ; the location. ; CHECK-LABEL: name: foo ; CHECK-LABEL: bb.1.bb1 ; CHECK: $eax = MOV32rr ; CHECK-NEXT: DBG_VALUE $eax ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.2.bb2 ; CHECK: $eax = ADD32ri8 ; CHECK-NEXT: DBG_VALUE $eax ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.3.bb3 ; CHECK: DBG_VALUE $eax ; Test for there being a location-list gap between bb1 and bb2, as the ; variable does not have a location over the ADD32ri. The range should also ; extend over the final bb. ; RANGES-LABEL: DW_TAG_subprogram ; RANGES: DW_AT_high_pc (0x[[NOPEHIGHPC:[0-9a-f]+]]) ; RANGES-LABEL: DW_AT_name ("nope") ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[NOPEADDR:[0-9a-f]+]]): DW_OP_reg0 RAX ; RANGES-NEXT: [ ; RANGES-NOT: 0x[[NOPEADDR]] ; RANGES-SAME: , 0x[[NOPEHIGHPC]]): DW_OP_reg0 RAX bb.0.entry: successors: %bb.1, %bb.2 liveins: $rdi $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags JCC_1 %bb.1, 2, implicit killed $eflags JMP_1 %bb.2 bb.1.bb1 (align 4): successors: %bb.3 liveins: $ecx, $rdi $eax = MOV32rr killed $ecx, implicit-def $rax DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8 JMP_1 %bb.3 bb.2.bb2: successors: %bb.3 liveins: $rax $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8 JMP_1 %bb.3 bb.3.bb3: liveins: $rax RET64 $eax, debug-location !9 ... --- name: bar alignment: 16 tracksRegLiveness: true registers: [] liveins: - { reg: '$rdi', virtual-reg: '' } body: | ; Two DBG_VALUEs, one for eax, the other for zero, merge into bb3. Check that ; livedebugvalues does not propagate anything. ; the location. ; CHECK-LABEL: name: bar ; CHECK-LABEL: bb.1.bb1 ; CHECK: $eax = MOV32rr ; CHECK-NEXT: DBG_VALUE 0 ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.2.bb2 ; CHECK: $eax = ADD32ri8 ; CHECK-NEXT: DBG_VALUE $eax ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.3.bb3 ; CHECK-NOT: DBG_VALUE ; Test for there being a location-list gap between bb1 and bb2, the variable ; should not have a location over the ADD32ri. The range of the last entry ; should not cover the last block. ; RANGES-LABEL: DW_TAG_subprogram ; RANGES: DW_AT_high_pc (0x[[BARHIGHPC:[0-9a-f]+]]) ; RANGES-LABEL: DW_AT_name ("bar") ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BARADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value ; RANGES-NEXT: [ ; RANGES-NOT: 0x[[BARADDR]] ; RANGES-NOT: 0x[[BARHIGHPC]] ; RANGES-SAME: ): DW_OP_reg0 RAX bb.0.entry: successors: %bb.1, %bb.2 liveins: $rdi $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags JCC_1 %bb.1, 2, implicit killed $eflags JMP_1 %bb.2 bb.1.bb1 (align 4): successors: %bb.3 liveins: $ecx, $rdi $eax = MOV32rr killed $ecx, implicit-def $rax DBG_VALUE 0, $noreg, !41, !DIExpression(), debug-location !42 JMP_1 %bb.3 bb.2.bb2: successors: %bb.3 liveins: $rax $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax DBG_VALUE $eax, $noreg, !41, !DIExpression(), debug-location !42 JMP_1 %bb.3 bb.3.bb3: liveins: $rax RET64 $eax, debug-location !42 ... --- name: baz alignment: 16 tracksRegLiveness: true registers: [] liveins: - { reg: '$rdi', virtual-reg: '' } body: | ; Two DBG_VALUEs, one for zero, the other for eax, merge into bb3. Check that ; livedebugvalues does not propagate anything. ; the location. ; CHECK-LABEL: name: baz ; CHECK-LABEL: bb.1.bb1 ; CHECK: $eax = MOV32rr ; CHECK-NEXT: DBG_VALUE $eax ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.2.bb2 ; CHECK: $eax = ADD32ri8 ; CHECK-NEXT: DBG_VALUE 0 ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.3.bb3 ; CHECK-NOT: DBG_VALUE ; Test for there being a location-list gap between bb1 and bb2, the variable ; should not have a location over the ADD32ri. The range of the last item ; should not cover the last block. ; RANGES-LABEL: DW_TAG_subprogram ; RANGES: DW_AT_high_pc (0x[[BAZHIGHPC:[0-9a-f]+]]) ; RANGES-LABEL: DW_AT_name ("baz") ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BAZADDR:[0-9a-f]+]]): DW_OP_reg0 RAX ; RANGES-NEXT: [ ; RANGES-NOT: 0x[[BAZADDR]] ; RANGES-NOT: 0x[[BAZHIGHPC]] ; RANGES-SAME: ): DW_OP_consts +0, DW_OP_stack_value bb.0.entry: successors: %bb.1, %bb.2 liveins: $rdi $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags JCC_1 %bb.1, 2, implicit killed $eflags JMP_1 %bb.2 bb.1.bb1 (align 4): successors: %bb.3 liveins: $ecx, $rdi $eax = MOV32rr killed $ecx, implicit-def $rax DBG_VALUE $eax, $noreg, !81, !DIExpression(), debug-location !82 JMP_1 %bb.3 bb.2.bb2: successors: %bb.3 liveins: $rax $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax DBG_VALUE 0, $noreg, !81, !DIExpression(), debug-location !82 JMP_1 %bb.3 bb.3.bb3: liveins: $rax RET64 $eax, debug-location !82 ... --- name: qux alignment: 16 tracksRegLiveness: true registers: [] liveins: - { reg: '$rdi', virtual-reg: '' } body: | ; Two DBG_VALUEs for zero merging into bb3, Check that livedebugvalues does ; propagate the zero into the merging block. ; CHECK-LABEL: name: qux ; CHECK-LABEL: bb.1.bb1 ; CHECK: $eax = MOV32rr ; CHECK-NEXT: DBG_VALUE 0 ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.2.bb2 ; CHECK: $eax = ADD32ri8 ; CHECK-NEXT: DBG_VALUE 0 ; CHECK-NEXT: JMP_1 %bb.3 ; CHECK-LABEL: bb.3.bb3 ; CHECK: DBG_VALUE 0 ; Test for there being a location-list gap between bb1 and bb2, the variable ; should not have a location over the ADD32ri. The final entry should cover ; the final block. ; RANGES-LABEL: DW_TAG_subprogram ; RANGES: DW_AT_high_pc (0x[[QUXHIGHPC:[0-9a-f]+]]) ; RANGES-LABEL: DW_AT_name ("qux") ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value ; RANGES-NOT: 0x[[QUXADDR]] ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXHIGHPC]]): DW_OP_consts +0, DW_OP_stack_value bb.0.entry: successors: %bb.1, %bb.2 liveins: $rdi $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags JCC_1 %bb.1, 2, implicit killed $eflags JMP_1 %bb.2 bb.1.bb1 (align 4): successors: %bb.3 liveins: $ecx, $rdi $eax = MOV32rr killed $ecx, implicit-def $rax DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122 JMP_1 %bb.3 bb.2.bb2: successors: %bb.3 liveins: $rax $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122 JMP_1 %bb.3 bb.3.bb3: liveins: $rax RET64 $eax, debug-location !122 ...