218 changes: 218 additions & 0 deletions llvm/test/DebugInfo/assignment-tracking/X86/sdag-dangling-dbgassign.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
; RUN: llc %s -stop-before finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: -experimental-debug-variable-locations=false \
; RUN: | FileCheck %s --check-prefixes=CHECK,DBGVALUE
; RUN: llc %s -stop-before finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: -experimental-debug-variable-locations=true \
; RUN: | FileCheck %s --check-prefixes=CHECK,INSTRREF

;--------------------------------------------------------------------
; Adapted from sdag-dangling-dbgvalue.ll to test dbg.assign intrinsics. This
; ensures that dbg.assigns with no linked store are treated as dbg.values. For
; ease of writing, all the dbg.assign intrinsics refer to the same DIAssignID
; !54. There is no linked store in any case.
;
; This test case is basically generated from the following C code.
; Compiled with "--target=x86_64-apple-darwin -S -g -O3" to get debug
; info for optimized code.
;
; struct SS {
; int a;
; int b;
; } S = { .a = 23, .b = -17 };
;
; int test1() {
; struct SS* foo1 = &S;
; return (int)foo1;
; }
;
; int test2() {
; struct SS* foo2 = &S;
; struct SS* bar2 = &S;
; return (int)foo2 + (int)bar2;
; }
;
; int test3() {
; struct SS* bar3 = &S;
; struct SS* foo3 = &S;
; return (int)foo3 + (int)bar3;
; }
;
; int test4() {
; struct SS* foo4 = &S;
; struct SS* bar4 = &S;
; foo = 0;
; return (int)foo4 + (int)bar4;
; }
;
; int test5() {
; struct SS* bar5 = &S;
; struct SS* foo5 = &S;
; foo5 = 0;
; return (int)foo5 + (int)bar5;
; }
;--------------------------------------------------------------------

; CHECK: ![[FOO1:.*]] = !DILocalVariable(name: "foo1"
; CHECK: ![[BAR1:.*]] = !DILocalVariable(name: "bar1"
; CHECK: ![[FOO2:.*]] = !DILocalVariable(name: "foo2"
; CHECK: ![[BAR2:.*]] = !DILocalVariable(name: "bar2"
; CHECK: ![[FOO3:.*]] = !DILocalVariable(name: "bar3"
; CHECK: ![[BAR3:.*]] = !DILocalVariable(name: "foo3"
; CHECK: ![[FOO4:.*]] = !DILocalVariable(name: "foo4"
; CHECK: ![[BAR4:.*]] = !DILocalVariable(name: "bar4"
; CHECK: ![[BAR5:.*]] = !DILocalVariable(name: "bar5"
; CHECK: ![[FOO5:.*]] = !DILocalVariable(name: "foo5"

source_filename = "sdag-dangling-dbgvalue.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.4.0"

%struct.SS = type { i32, i32 }

@S = global %struct.SS { i32 23, i32 -17 }, align 4, !dbg !0

; Verify that the def comes before the for foo1.
define i32 @test1() local_unnamed_addr #0 !dbg !17 {
; CHECK-LABEL: bb.0.entry1
; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[BAR1]], !DIExpression()
; CHECK-NEXT: [[REG1:%[0-9]+]]:gr64 = LEA64r
; INSTRREF-SAME: debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[FOO1]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG1]], $noreg, ![[FOO1]], !DIExpression()
entry1:
call void @llvm.dbg.assign(metadata ptr @S, metadata !20, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !23
call void @llvm.dbg.assign(metadata ptr null, metadata !22, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !24
ret i32 ptrtoint (ptr @S to i32), !dbg !25
}

; Verify that the def comes before the for foo2 and bar2.
define i32 @test2() local_unnamed_addr #0 !dbg !26 {
; CHECK-LABEL: bb.0.entry2
; CHECK-NEXT: [[REG2:%[0-9]+]]:gr64 = LEA64r
; INSTRREF-SAME: debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[FOO2]], !DIExpression()
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[BAR2]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG2]], $noreg, ![[FOO2]], !DIExpression
; DBGVALUE-NEXT: DBG_VALUE [[REG2]], $noreg, ![[BAR2]], !DIExpression
entry2:
call void @llvm.dbg.assign(metadata ptr @S, metadata !28, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !30
call void @llvm.dbg.assign(metadata ptr @S, metadata !29, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !31
ret i32 add (i32 ptrtoint (ptr @S to i32), i32 ptrtoint (ptr @S to i32)), !dbg !32
}

; Verify that the def comes before the for foo3 and bar3.
define i32 @test3() local_unnamed_addr #0 !dbg !33 {
; CHECK-LABEL: bb.0.entry3
; CHECK-NEXT: [[REG3:%[0-9]+]]:gr64 = LEA64r
; INSTRREF-SAME: debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[BAR3]], !DIExpression()
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[FOO3]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG3]], $noreg, ![[BAR3]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG3]], $noreg, ![[FOO3]], !DIExpression()
entry3:
call void @llvm.dbg.assign(metadata ptr @S, metadata !36, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !38
call void @llvm.dbg.assign(metadata ptr @S, metadata !35, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !37
ret i32 add (i32 ptrtoint (ptr @S to i32), i32 ptrtoint (ptr @S to i32)), !dbg !39
}

; Verify that the def comes before the for bar4.
define i32 @test4() local_unnamed_addr #0 !dbg !40 {
; CHECK-LABEL: bb.0.entry4
;; NOTE: The check for `DBG_VALUE $noreg, $noreg, ![[FOO4]], !DIExpression()`
;; has been removed because AT lowering removes redundant debug intrinsics.
; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[FOO4]], !DIExpression()
; CHECK-NEXT: [[REG4:%[0-9]+]]:gr64 = LEA64r
; INSTRREF-SAME: debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[BAR4]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG4]], $noreg, ![[BAR4]], !DIExpression()
entry4:
call void @llvm.dbg.assign(metadata ptr @S, metadata !42, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !44
call void @llvm.dbg.assign(metadata ptr @S, metadata !43, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !45
call void @llvm.dbg.assign(metadata ptr null, metadata !42, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !44
ret i32 ptrtoint (ptr @S to i32), !dbg !46
}

; Verify that we do not get a DBG_VALUE that maps foo5 to @S here.
define i32 @test5() local_unnamed_addr #0 !dbg !47 {
; CHECK-LABEL: bb.0.entry5:
; cHECK-NEXT: DBG_VALUE $noreg, $noreg, ![[FOO5]], !DIExpression()
; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[FOO5]], !DIExpression()
; CHECK-NEXT: [[REG5:%[0-9]+]]:gr64 = LEA64r
; INSTRREF-SAME: debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0, ![[BAR5]], !DIExpression()
; DBGVALUE-NEXT: DBG_VALUE [[REG5]], $noreg, ![[BAR5]], !DIExpression()
; CHECK-NOT: DBG_{{.*}} ![[FOO5]], !DIExpression()
; CHECK: RET
entry5:
call void @llvm.dbg.assign(metadata ptr @S, metadata !49, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !51
call void @llvm.dbg.assign(metadata ptr @S, metadata !50, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !52
call void @llvm.dbg.assign(metadata ptr null, metadata !50, metadata !DIExpression(), metadata !54, metadata ptr undef, metadata !DIExpression()), !dbg !52
ret i32 ptrtoint (ptr @S to i32), !dbg !53
}

declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1

attributes #0 = { nounwind readnone uwtable }
attributes #1 = { nounwind readnone speculatable }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!12, !13, !14, !15}
!llvm.ident = !{!16}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "S", scope: !2, file: !3, line: 4, type: !8, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 327229) (llvm/trunk 327239)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7)
!3 = !DIFile(filename: "sdag-dangling-dbgvalue.c", directory: "/repo/uabbpet/llvm-master")
!4 = !{}
!5 = !{!6}
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!7 = !{!0}
!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "SS", file: !3, line: 1, size: 64, elements: !9)
!9 = !{!10, !11}
!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 2, baseType: !6, size: 32)
!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 3, baseType: !6, size: 32, offset: 32)
!12 = !{i32 2, !"Dwarf Version", i32 2}
!13 = !{i32 2, !"Debug Info Version", i32 3}
!14 = !{i32 1, !"wchar_size", i32 4}
!15 = !{i32 7, !"PIC Level", i32 2}
!16 = !{!"clang version 7.0.0 (trunk 327229) (llvm/trunk 327239)"}
!17 = distinct !DISubprogram(name: "test1", scope: !3, file: !3, line: 6, type: !18, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !2, retainedNodes: !19)
!18 = !DISubroutineType(types: !5)
!19 = !{!20, !22}
!20 = !DILocalVariable(name: "foo1", scope: !17, file: !3, line: 7, type: !21)
!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64)
!22 = !DILocalVariable(name: "bar1", scope: !17, file: !3, line: 8, type: !21)
!23 = !DILocation(line: 7, column: 14, scope: !17)
!24 = !DILocation(line: 8, column: 14, scope: !17)
!25 = !DILocation(line: 9, column: 3, scope: !17)
!26 = distinct !DISubprogram(name: "test2", scope: !3, file: !3, line: 12, type: !18, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !2, retainedNodes: !27)
!27 = !{!28, !29}
!28 = !DILocalVariable(name: "foo2", scope: !26, file: !3, line: 13, type: !21)
!29 = !DILocalVariable(name: "bar2", scope: !26, file: !3, line: 14, type: !21)
!30 = !DILocation(line: 13, column: 14, scope: !26)
!31 = !DILocation(line: 14, column: 14, scope: !26)
!32 = !DILocation(line: 15, column: 3, scope: !26)
!33 = distinct !DISubprogram(name: "test3", scope: !3, file: !3, line: 18, type: !18, isLocal: false, isDefinition: true, scopeLine: 18, isOptimized: true, unit: !2, retainedNodes: !34)
!34 = !{!35, !36}
!35 = !DILocalVariable(name: "bar3", scope: !33, file: !3, line: 19, type: !21)
!36 = !DILocalVariable(name: "foo3", scope: !33, file: !3, line: 20, type: !21)
!37 = !DILocation(line: 19, column: 14, scope: !33)
!38 = !DILocation(line: 20, column: 14, scope: !33)
!39 = !DILocation(line: 21, column: 3, scope: !33)
!40 = distinct !DISubprogram(name: "test4", scope: !3, file: !3, line: 24, type: !18, isLocal: false, isDefinition: true, scopeLine: 24, isOptimized: true, unit: !2, retainedNodes: !41)
!41 = !{!42, !43}
!42 = !DILocalVariable(name: "foo4", scope: !40, file: !3, line: 25, type: !21)
!43 = !DILocalVariable(name: "bar4", scope: !40, file: !3, line: 26, type: !21)
!44 = !DILocation(line: 25, column: 14, scope: !40)
!45 = !DILocation(line: 26, column: 14, scope: !40)
!46 = !DILocation(line: 28, column: 3, scope: !40)
!47 = distinct !DISubprogram(name: "test5", scope: !3, file: !3, line: 31, type: !18, isLocal: false, isDefinition: true, scopeLine: 31, isOptimized: true, unit: !2, retainedNodes: !48)
!48 = !{!49, !50}
!49 = !DILocalVariable(name: "bar5", scope: !47, file: !3, line: 32, type: !21)
!50 = !DILocalVariable(name: "foo5", scope: !47, file: !3, line: 33, type: !21)
!51 = !DILocation(line: 32, column: 14, scope: !47)
!52 = !DILocation(line: 33, column: 14, scope: !47)
!53 = !DILocation(line: 35, column: 3, scope: !47)
!54 = distinct !DIAssignID()
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
; RUN: llc -mtriple=x86_64-unknown-unknown -start-after=codegenprepare \
; RUN: -experimental-assignment-tracking \
; RUN: -stop-before finalize-isel %s -o - \
; RUN: -experimental-debug-variable-locations=false \
; RUN: | FileCheck %s --check-prefixes=CHECK,DBGVALUE
; RUN: llc -mtriple=x86_64-unknown-unknown -start-after=codegenprepare \
; RUN: -experimental-assignment-tracking \
; RUN: -stop-before finalize-isel %s -o - \
; RUN: -experimental-debug-variable-locations=true \
; RUN: | FileCheck %s --check-prefixes=CHECK,INSTRREF

; Adapted from sdag-ir-salvage.ll to test dbg.assign intrinsics. This ensures
; that dbg.assigns with no linked store are treated as dbg.values.

; Test that the dbg.value for %baz, which doesn't exist in the 'next' bb,
; can be salvaged back to the underlying argument vreg.

; CHECK: ![[AAAVAR:.*]] = !DILocalVariable(name: "aaa",
; CHECK-LABEL: bb.0.entry:
; INSTRREF: DBG_PHI $rdi, 1
; CHECK-LABEL: bb.1.next:
; INSTRREF: DBG_INSTR_REF 1, 0, ![[AAAVAR]]
; DBGVALUE: DBG_VALUE %{{[0-9]+}}, $noreg, ![[AAAVAR]]

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-linux-gnu"

define i8 @f(ptr %foo) local_unnamed_addr !dbg !6 {
entry:
%bar = getelementptr i32, ptr %foo, i32 4
%baz = bitcast ptr %bar to ptr
%quux = load i8, ptr %baz
br label %next

next: ; preds = %entry
tail call void @llvm.dbg.assign(metadata ptr %baz, metadata !15, metadata !DIExpression(), metadata !31, metadata ptr undef, metadata !DIExpression()), !dbg !30
%xyzzy = add i8 %quux, 123
br label %fin

fin: ; preds = %next
%trains = getelementptr i32, ptr %foo, i32 3
%planes = bitcast ptr %trains to ptr
%cars = load i8, ptr %planes
%ret = add i8 %xyzzy, %cars
ret i8 %ret
}

; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #0

attributes #0 = { nounwind readnone speculatable }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!25, !26, !27, !28}
!llvm.ident = !{!29}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "test.c", directory: ".")
!2 = !{}
!6 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 18, type: !7, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14)
!7 = !DISubroutineType(types: !8)
!8 = !{!13}
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_unsigned)
!14 = !{!15}
!15 = !DILocalVariable(name: "aaa", scope: !6, file: !1, line: 18, type: !13)
!25 = !{i32 2, !"Dwarf Version", i32 4}
!26 = !{i32 2, !"Debug Info Version", i32 3}
!27 = !{i32 1, !"wchar_size", i32 4}
!28 = !{i32 7, !"PIC Level", i32 2}
!29 = !{!"clang"}
!30 = !DILocation(line: 18, column: 14, scope: !6)
!31 = distinct !DIAssignID()
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
; RUN: llc %s -start-after=codegenprepare -stop-before finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: -experimental-debug-variable-locations=false \
; RUN: | FileCheck %s --check-prefixes=CHECK,DBGVALUE
; RUN: llc %s -start-after=codegenprepare -stop-before finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: -experimental-debug-variable-locations=true \
; RUN: | FileCheck %s --check-prefixes=CHECK,INSTRREF

; Adapted from sdag-transfer-dbgvalue.ll to test dbg.assign intrinsics. This
; ensures that dbg.assigns with no linked store are treated as dbg.values.

; This tests that transferDbgValues() changes order of SDDbgValue transferred
; to another node and debug info for 'ADD32ri' appears *after* the instruction.
;
; This test case was generated from the following program
; using: clang -g -O3 -S -emit-llvm test.c
;
; int foo(int a, int *b) {
; int c = a + 512;
; if (c != 0)
; *b = a;
; return c;
; }

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; CHECK-LABEL: bb.0.entry:
; DBGVALUE: %[[REG:[0-9]+]]:gr32 = ADD32ri %1, 512
; DBGVALUE-NEXT: DBG_VALUE %[[REG]]
; INSTRREF: ADD32ri %1, 512, {{.*}}debug-instr-number 1
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0

; Function Attrs: nofree norecurse nounwind uwtable writeonly
define dso_local i32 @foo(i32 %a, ptr nocapture %b) local_unnamed_addr !dbg !7 {
entry:
%add = add nsw i32 %a, 512, !dbg !18
call void @llvm.dbg.assign(metadata i32 %add, metadata !16, metadata !DIExpression(), metadata !19, metadata ptr undef, metadata !DIExpression()), !dbg !17
%cmp = icmp eq i32 %add, 0, !dbg !18
br i1 %cmp, label %if.end, label %if.then, !dbg !18

if.then: ; preds = %entry
store i32 %a, ptr %b, align 4, !dbg !18
br label %if.end, !dbg !18

if.end: ; preds = %entry, %if.then
ret i32 %add, !dbg !18
}

; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
!1 = !DIFile(filename: "test.c", directory: "/")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 10.0.0"}
!7 = distinct !DISubprogram(name: "foo", scope: !8, file: !8, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
!8 = !DIFile(filename: "test.c", directory: "/")
!9 = !DISubroutineType(types: !10)
!10 = !{!11, !11, !12}
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
!13 = !{!14, !15, !16}
!14 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !8, line: 1, type: !11)
!15 = !DILocalVariable(name: "b", arg: 2, scope: !7, file: !8, line: 1, type: !12)
!16 = !DILocalVariable(name: "c", scope: !7, file: !8, line: 2, type: !11)
!17 = !DILocation(line: 0, scope: !7)
!18 = !DILocation(line: 2, column: 13, scope: !7)
!19 = distinct !DIAssignID()
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
; RUN: llc -stop-after=finalize-isel %s -o - \
; RUN: -experimental-assignment-tracking \
; RUN: | FileCheck %s

;; Check that a dbg.assign for a fully stack-homed variable causes the variable
;; location to appear in the Machine Function side table. Similar to
;; single-memory-location.ll except this has slightly more complicated input
;; (there's a loop and an assignment).
;;
;; $ cat test.cpp
;; int get();
;; void esc(int*);
;; void doSomething(int);
;; void fun() {
;; int local;
;; esc(&local);
;; while (local) {
;; local = get();
;; doSomething(local);
;; esc(&local);
;; }
;; }
;; $ clang++ -O2 -g -emit-llvm -S -c -Xclang -fexperimental-assignment-tracking

; CHECK: ![[VAR:[0-9]+]] = !DILocalVariable(name: "local",
; CHECK: stack:
; CHECK-NEXT: - { id: 0, name: local, type: default, offset: 0, size: 4, alignment: 4,
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK-NEXT: debug-info-variable: '![[VAR]]', debug-info-expression: '!DIExpression()',
; CHECK-NEXT: debug-info-location: '!{{.+}}' }

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: uwtable mustprogress
define dso_local void @_Z3funv() local_unnamed_addr #0 !dbg !7 {
entry:
%local = alloca i32, align 4, !DIAssignID !13
call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(), metadata !13, metadata ptr %local, metadata !DIExpression()), !dbg !14
%0 = bitcast ptr %local to ptr, !dbg !15
call void @llvm.lifetime.start.p0i8(i64 4, ptr nonnull %0) #4, !dbg !15
call void @_Z3escPi(ptr nonnull %local), !dbg !16
%1 = load i32, ptr %local, align 4, !dbg !17
%tobool.not1 = icmp eq i32 %1, 0, !dbg !17
br i1 %tobool.not1, label %while.end, label %while.body, !dbg !22

while.body: ; preds = %entry, %while.body
%call = call i32 @_Z3getv(), !dbg !23
store i32 %call, ptr %local, align 4, !dbg !25, !DIAssignID !26
call void @llvm.dbg.assign(metadata i32 %call, metadata !11, metadata !DIExpression(), metadata !26, metadata ptr %local, metadata !DIExpression()), !dbg !14
call void @_Z11doSomethingi(i32 %call), !dbg !27
call void @_Z3escPi(ptr nonnull %local), !dbg !28
%2 = load i32, ptr %local, align 4, !dbg !17
%tobool.not = icmp eq i32 %2, 0, !dbg !17
br i1 %tobool.not, label %while.end, label %while.body, !dbg !22, !llvm.loop !29

while.end: ; preds = %while.body, %entry
call void @llvm.lifetime.end.p0i8(i64 4, ptr nonnull %0) #4, !dbg !32
ret void, !dbg !32
}

declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture)
declare !dbg !33 dso_local void @_Z3escPi(ptr) local_unnamed_addr
declare !dbg !37 dso_local i32 @_Z3getv() local_unnamed_addr
declare !dbg !40 dso_local void @_Z11doSomethingi(i32) local_unnamed_addr
declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture)
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0"}
!7 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!8 = !DISubroutineType(types: !9)
!9 = !{null}
!10 = !{!11}
!11 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 5, type: !12)
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!13 = distinct !DIAssignID()
!14 = !DILocation(line: 0, scope: !7)
!15 = !DILocation(line: 5, column: 3, scope: !7)
!16 = !DILocation(line: 6, column: 3, scope: !7)
!17 = !DILocation(line: 7, column: 10, scope: !7)
!22 = !DILocation(line: 7, column: 3, scope: !7)
!23 = !DILocation(line: 8, column: 13, scope: !24)
!24 = distinct !DILexicalBlock(scope: !7, file: !1, line: 7, column: 17)
!25 = !DILocation(line: 8, column: 11, scope: !24)
!26 = distinct !DIAssignID()
!27 = !DILocation(line: 9, column: 5, scope: !24)
!28 = !DILocation(line: 10, column: 5, scope: !24)
!29 = distinct !{!29, !22, !30, !31}
!30 = !DILocation(line: 11, column: 3, scope: !7)
!31 = !{!"llvm.loop.mustprogress"}
!32 = !DILocation(line: 12, column: 1, scope: !7)
!33 = !DISubprogram(name: "esc", linkageName: "_Z3escPi", scope: !1, file: !1, line: 2, type: !34, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!34 = !DISubroutineType(types: !35)
!35 = !{null, !36}
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
!37 = !DISubprogram(name: "get", linkageName: "_Z3getv", scope: !1, file: !1, line: 1, type: !38, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!38 = !DISubroutineType(types: !39)
!39 = !{!12}
!40 = !DISubprogram(name: "doSomething", linkageName: "_Z11doSomethingi", scope: !1, file: !1, line: 3, type: !41, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!41 = !DISubroutineType(types: !42)
!42 = !{null, !12}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
; RUN: llc -stop-after=finalize-isel %s -o - \
; RUN: -experimental-assignment-tracking \
; RUN: | FileCheck %s

;; Check that a dbg.assign for a fully stack-homed variable causes the variable
;; location to appear in the Machine Function side table.
;;
;; $ cat test.cpp
;; void maybe_writes(int*);
;; void ext(int, int, int, int, int, int, int, int, int, int);
;; int example() {
;; int local;
;; maybe_writes(&local);
;; ext(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
;; return local;
;; }
;; $ clang++ -O2 -g -emit-llvm -S -c -Xclang -fexperimental-assignment-tracking

; CHECK: ![[VAR:[0-9]+]] = !DILocalVariable(name: "local",
; CHECK: stack:
; CHECK-NEXT: - { id: 0, name: local, type: default, offset: 0, size: 4, alignment: 4,
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK-NEXT: debug-info-variable: '![[VAR]]', debug-info-expression: '!DIExpression()',
; CHECK-NEXT: debug-info-location: '!{{.+}}' }

source_filename = "test.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define dso_local i32 @_Z7examplev() local_unnamed_addr !dbg !7 {
entry:
%local = alloca i32, align 4, !DIAssignID !13
call void @llvm.dbg.assign(metadata i1 undef, metadata !12, metadata !DIExpression(), metadata !13, metadata ptr %local, metadata !DIExpression()), !dbg !14
%0 = bitcast ptr %local to ptr, !dbg !15
call void @llvm.lifetime.start.p0i8(i64 4, ptr nonnull %0), !dbg !15
call void @_Z12maybe_writesPi(ptr nonnull %local), !dbg !16
call void @_Z3extiiiiiiiiii(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9), !dbg !17
%1 = load i32, ptr %local, align 4, !dbg !18
call void @llvm.lifetime.end.p0i8(i64 4, ptr nonnull %0), !dbg !23
ret i32 %1, !dbg !24
}

declare !dbg !25 dso_local void @_Z12maybe_writesPi(ptr) local_unnamed_addr
declare !dbg !29 dso_local void @_Z3extiiiiiiiiii(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) local_unnamed_addr
declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture)
declare void @llvm.lifetime.end.p0i8(i64 immarg, ptr nocapture)
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0"}
!7 = distinct !DISubprogram(name: "example", linkageName: "_Z7examplev", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
!8 = !DISubroutineType(types: !9)
!9 = !{!10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!12}
!12 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 4, type: !10)
!13 = distinct !DIAssignID()
!14 = !DILocation(line: 0, scope: !7)
!15 = !DILocation(line: 4, column: 4, scope: !7)
!16 = !DILocation(line: 5, column: 4, scope: !7)
!17 = !DILocation(line: 6, column: 4, scope: !7)
!18 = !DILocation(line: 7, column: 11, scope: !7)
!23 = !DILocation(line: 8, column: 1, scope: !7)
!24 = !DILocation(line: 7, column: 4, scope: !7)
!25 = !DISubprogram(name: "maybe_writes", linkageName: "_Z12maybe_writesPi", scope: !1, file: !1, line: 1, type: !26, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!26 = !DISubroutineType(types: !27)
!27 = !{null, !28}
!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
!29 = !DISubprogram(name: "ext", linkageName: "_Z3extiiiiiiiiii", scope: !1, file: !1, line: 2, type: !30, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!30 = !DISubroutineType(types: !31)
!31 = !{null, !10, !10, !10, !10, !10, !10, !10, !10, !10, !10}
58 changes: 58 additions & 0 deletions llvm/test/DebugInfo/assignment-tracking/X86/split-alloca.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; RUN: llc %s -o - -stop-after=finalize-isel \
; RUN: -experimental-assignment-tracking \
; RUN: | FileCheck %s --implicit-check-not=DBG

;; Hand written. Check that we fall back to emitting a list of defs for
;; variables with split allocas (i.e. we want to see DBG_VALUEs and no
;; debug-info-variable entry in the stack slot table).

; CHECK: stack:
; CHECK: - { id: 0, name: a, type: default, offset: 0, size: 4, alignment: 4,
; CHECK: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK: - { id: 1, name: c, type: default, offset: 0, size: 4, alignment: 4,
; CHECK: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK: DBG_VALUE %stack.0.a, $noreg, !{{.*}}, !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
; CHECK: DBG_VALUE %stack.1.c, $noreg, !{{.*}}, !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 64, 32)

target triple = "x86_64-unknown-linux-gnu"

define dso_local void @fun() !dbg !7 {
entry:
%a = alloca i32, align 4, !DIAssignID !16
call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !16, metadata ptr %a, metadata !DIExpression()), !dbg !17
%c = alloca i32, align 4, !DIAssignID !20
call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32), metadata !20, metadata ptr %c, metadata !DIExpression()), !dbg !17
store i32 5, ptr %a, !DIAssignID !21
ret void, !dbg !19
}

declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.c", directory: "/")
!2 = !{i32 7, !"Dwarf Version", i32 5}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{i32 1, !"wchar_size", i32 4}
!5 = !{i32 7, !"uwtable", i32 1}
!6 = !{!"clang version 14.0.0"}
!7 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!8 = !DISubroutineType(types: !9)
!9 = !{null}
!10 = !{!11}
!11 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 2, type: !12)
!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 96, elements: !14)
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!14 = !{!15}
!15 = !DISubrange(count: 3)
!16 = distinct !DIAssignID()
!17 = !DILocation(line: 0, scope: !7)
!18 = !DILocation(line: 2, column: 3, scope: !7)
!19 = !DILocation(line: 3, column: 1, scope: !7)
!20 = distinct !DIAssignID()
!21 = distinct !DIAssignID()
82 changes: 82 additions & 0 deletions llvm/test/DebugInfo/assignment-tracking/X86/untagged-store-frag.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
; RUN: llc %s -stop-after=finalize-isel -o - -experimental-assignment-tracking \
; RUN: | FileCheck %s --implicit-check-not=DBG_

;; Hand-written to test untagged store handling on a simple case. Here's what
;; we're looking at in the IR:

;; 1. mem(a): bits [0, 64) = !14
;; 2. dbg(a): bits [0, 64) = !14 ; Use memory loc
;; 3. dbg(a): bits [0, 32) = <unique ID> ; Use implicit loc, dbg.value has no ID
;; 4. dbg(a): bits [32, 64) = !16 ; These bits don't use mem loc.
;; ; Linked to a def that comes later ---+
;; ... ; |
;; 5. mem(a): bits [0, 32) = <unique ID> ; Untagged store ; |
;; .. ; |
;; 6. mem(a): bits [32, 64) = !16 ; <-----------------------------------+

;; Taking the '<number>.' above as the 'position', check we get defs that look
;; like this:
;; Position | bits [0, 32) | bits [32, 64)
;; ---------+--------------+---------------
;; 2. | Mem | Mem
;; 3. | Value | Mem
;; 4. | Value | Value
;; 5. | Mem | Value
;; 6. | Mem | Mem

; CHECK-DAG: ![[A:[0-9]+]] = !DILocalVariable(name: "a",

; CHECK: DBG_VALUE %stack.0.a.addr, $noreg, ![[A]], !DIExpression(DW_OP_deref)
; CHECK-NEXT: DBG_VALUE 5, $noreg, ![[A]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
; CHECK-NEXT: DBG_VALUE $noreg, $noreg, ![[A]], !DIExpression(DW_OP_LLVM_fragment, 32, 32)
; CHECK-NEXT: MOV32mi %stack.0.a.addr, 1, $noreg, 0, $noreg, 123
; CHECK-NEXT: DBG_VALUE %stack.0.a.addr, $noreg, ![[A]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
; CHECK-NEXT: MOV32mr %stack.0.a.addr, 1, $noreg, 4, $noreg, %1 :: (store (s32) into %ir.add.ptr, align 8)
; CHECK-NEXT: DBG_VALUE %stack.0.a.addr, $noreg, ![[A]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)

;; NOTE: The second and third DBG_VALUE combined make the first redundant. If
;; removeRedundantDbgInstrs gets smarter, add an instruction between the first
;; dbg.assign and the subsequent dbg.value.

target triple = "x86_64-unknown-linux-gnu"

define dso_local noundef i64 @_Z1fl(i64 noundef %a, i32 %b) #0 !dbg !8 {
entry:
%a.addr = alloca i64, align 8, !DIAssignID !13
call void @llvm.dbg.assign(metadata i1 undef, metadata !14, metadata !DIExpression(), metadata !13, metadata ptr %a.addr, metadata !DIExpression()), !dbg !15
call void @llvm.dbg.value(metadata i64 5, metadata !14, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !15
call void @llvm.dbg.assign(metadata i1 undef, metadata !14, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32), metadata !16, metadata ptr %a.addr, metadata !DIExpression()), !dbg !15
%frag.addr = bitcast ptr %a.addr to ptr
store i32 123, ptr %frag.addr, align 8
%0 = bitcast ptr %a.addr to ptr
%add.ptr = getelementptr inbounds i32, ptr %0, i64 1
store i32 %b, ptr %add.ptr, align 8, !DIAssignID !16
%1 = load i64, ptr %a.addr, align 8
ret i64 %1
}

declare void @llvm.dbg.value(metadata, metadata, metadata) #1
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5, !6}
!llvm.ident = !{!7}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/")
!2 = !{i32 7, !"Dwarf Version", i32 5}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{i32 1, !"wchar_size", i32 4}
!5 = !{i32 7, !"uwtable", i32 1}
!6 = !{i32 7, !"frame-pointer", i32 2}
!7 = !{!"clang version 14.0.0"}
!8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fl", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12)
!9 = !DISubroutineType(types: !10)
!10 = !{!11, !11}
!11 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
!12 = !{}
!13 = distinct !DIAssignID()
!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11)
!15 = !DILocation(line: 0, scope: !8)
!16 = distinct !DIAssignID()
!17 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 1, type: !11)
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
; RUN: llc %s -stop-after=finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: | FileCheck %s --implicit-check-not=DBG_VALUE

;; Check that sandwiching instructions between a linked store and dbg.assign
;; results in a dbg.value(prev_value) being inserted at the store, and a
;; dbg.value(deref) at the dbg.assign.
;; Same as use-known-value-at-early-mem-def.ll except the "early mem def" is
;; for a fragment of the variable rather than the whole.

; CHECK: bb.0.entry:
; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var:[0-9]+]], !DIExpression(DW_OP_deref), debug-location
; CHECK: MOV64mi32 %stack.0.c, 1, $noreg, 0, $noreg, 5
;; No DBG_VALUE required because the stack location is still valid.

; CHECK: MOV32mi %stack.0.c, 1, $noreg, 0, $noreg, 1
; CHECK-NEXT: DBG_VALUE $noreg, $noreg, ![[var]], !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location
;; This DBG_VALUE is added by the frag-agg pass because bits [32, 64) are still
;; live in memory.
; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)

; CHECK: CALL64pcrel32 @d
; CHECK-NEXT: ADJCALLSTACKUP64
; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32), debug-location

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind uwtable
define dso_local void @b() local_unnamed_addr #0 !dbg !7 {
entry:
%c = alloca i64, align 1, !DIAssignID !13
call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(), metadata !13, metadata i64* %c, metadata !DIExpression()), !dbg !14
call void @llvm.lifetime.start.p0i64(i64 1, i64* nonnull %c) #4, !dbg !15
store i64 5, i64* %c, align 1, !dbg !16, !DIAssignID !20
call void @llvm.dbg.assign(metadata i64 5, metadata !11, metadata !DIExpression(), metadata !20, metadata i64* %c, metadata !DIExpression()), !dbg !14
tail call void (...) @d() #4, !dbg !21

; --- VV Hand written VV --- ;
%bc = bitcast i64* %c to i32*
store i32 1, i32* %bc, align 1, !dbg !16, !DIAssignID !31
;; Check that a dbg.value(undef, frag(0, 32)) is inserted here. The value of
;; the fragment is "unknown". TODO: In this case the value of the fragment is
;; still obviously 5; a future improvement could be to be smarter and work
;; this out. But that's a lot of work for an uncommon case.
tail call void (...) @d() #4, !dbg !21
call void @llvm.dbg.assign(metadata i32 1, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !31, metadata i32* %bc, metadata !DIExpression()), !dbg !14
; --- AA Hand written AA --- ;

call void @a(i64* nonnull %c) #4, !dbg !22
call void @llvm.lifetime.end.p0i64(i64 1, i64* nonnull %c) #4, !dbg !23
ret void, !dbg !23
}

declare void @llvm.lifetime.start.p0i64(i64 immarg, i64* nocapture) #1
declare !dbg !24 dso_local void @d(...) local_unnamed_addr #2
declare !dbg !27 dso_local void @a(i64*) local_unnamed_addr #2
declare void @llvm.lifetime.end.p0i64(i64 immarg, i64* nocapture) #1
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #3

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "reduce.c", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0"}
!7 = distinct !DISubprogram(name: "b", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!8 = !DISubroutineType(types: !9)
!9 = !{null}
!10 = !{!11}
!11 = !DILocalVariable(name: "c", scope: !7, file: !1, line: 4, type: !12)
!12 = !DIBasicType(name: "char", size: 64, encoding: DW_ATE_unsigned)
!13 = distinct !DIAssignID()
!14 = !DILocation(line: 0, scope: !7)
!15 = !DILocation(line: 4, column: 3, scope: !7)
!16 = !DILocation(line: 4, column: 8, scope: !7)
!20 = distinct !DIAssignID()
!21 = !DILocation(line: 5, column: 3, scope: !7)
!22 = !DILocation(line: 6, column: 3, scope: !7)
!23 = !DILocation(line: 7, column: 1, scope: !7)
!24 = !DISubprogram(name: "d", scope: !1, file: !1, line: 2, type: !25, spFlags: DISPFlagOptimized, retainedNodes: !2)
!25 = !DISubroutineType(types: !26)
!26 = !{null, null}
!27 = !DISubprogram(name: "a", scope: !1, file: !1, line: 1, type: !28, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!28 = !DISubroutineType(types: !29)
!29 = !{null, !30}
!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
!31 = distinct !DIAssignID()
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
; RUN: llc %s -stop-after=finalize-isel -o - \
; RUN: -experimental-assignment-tracking \
; RUN: | FileCheck %s --implicit-check-not=DBG_VALUE

;; Check that sandwiching instructions between a linked store and dbg.assign
;; results in a dbg.value(prev_value) being inserted at the store, and a
;; dbg.value(deref) at the dbg.assign.

; CHECK: bb.0.entry:
; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var:[0-9]+]], !DIExpression(DW_OP_deref), debug-location
; CHECK: MOV8mi %stack.0.c, 1, $noreg, 0, $noreg, 0
;; No DBG_VALUE required because the stack location is still valid.

; CHECK: MOV8mi %stack.0.c, 1, $noreg, 0, $noreg, 1
; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[var]], !DIExpression(), debug-location
; CHECK: CALL64pcrel32 @d
; CHECK-NEXT: ADJCALLSTACKUP64
; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_deref), debug-location

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind uwtable
define dso_local void @b() local_unnamed_addr #0 !dbg !7 {
entry:
%c = alloca i8, align 1, !DIAssignID !13
call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(), metadata !13, metadata i8* %c, metadata !DIExpression()), !dbg !14
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %c) #4, !dbg !15
store i8 0, i8* %c, align 1, !dbg !16, !DIAssignID !20
call void @llvm.dbg.assign(metadata i8 0, metadata !11, metadata !DIExpression(), metadata !20, metadata i8* %c, metadata !DIExpression()), !dbg !14
tail call void (...) @d() #4, !dbg !21

; --- VV Hand written VV --- ;
store i8 1, i8* %c, align 1, !dbg !16, !DIAssignID !31
; Check that a dbg.value(0) is inserted here.
tail call void (...) @d() #4, !dbg !21
call void @llvm.dbg.assign(metadata i8 1, metadata !11, metadata !DIExpression(), metadata !31, metadata i8* %c, metadata !DIExpression()), !dbg !14
; --- AA Hand written AA --- ;

call void @a(i8* nonnull %c) #4, !dbg !22
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %c) #4, !dbg !23
ret void, !dbg !23
}

declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
declare !dbg !24 dso_local void @d(...) local_unnamed_addr #2
declare !dbg !27 dso_local void @a(i8*) local_unnamed_addr #2
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #3

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "reduce.c", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0"}
!7 = distinct !DISubprogram(name: "b", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!8 = !DISubroutineType(types: !9)
!9 = !{null}
!10 = !{!11}
!11 = !DILocalVariable(name: "c", scope: !7, file: !1, line: 4, type: !12)
!12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
!13 = distinct !DIAssignID()
!14 = !DILocation(line: 0, scope: !7)
!15 = !DILocation(line: 4, column: 3, scope: !7)
!16 = !DILocation(line: 4, column: 8, scope: !7)
!20 = distinct !DIAssignID()
!21 = !DILocation(line: 5, column: 3, scope: !7)
!22 = !DILocation(line: 6, column: 3, scope: !7)
!23 = !DILocation(line: 7, column: 1, scope: !7)
!24 = !DISubprogram(name: "d", scope: !1, file: !1, line: 2, type: !25, spFlags: DISPFlagOptimized, retainedNodes: !2)
!25 = !DISubroutineType(types: !26)
!26 = !{null, null}
!27 = !DISubprogram(name: "a", scope: !1, file: !1, line: 1, type: !28, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!28 = !DISubroutineType(types: !29)
!29 = !{null, !30}
!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
!31 = distinct !DIAssignID()