Skip to content

Commit 4b3faa9

Browse files
[InstrRef] Skip clobbered EntryValue register recovery
This changes the final stage of InstrRef, i.e. the TransferTracker (which combines the values locations with the variable values), so that it treats a DEBUG_VALUE of an EntryValue just like a DEBUG_VALUE of a constant: a location that is never clobbered and can be propagated to subsequent BBs as long as no other DEBUG_VALUE intrinsics updated the variable. We add two tests here: 1. `entry_value_clobbered_stack_copy` that saves a register on the stack, uses this register as an entry value DBG_VALUE location, and then clobbers it. Prior to this patch, this test would crash because we would try to describe a new location for the variable in terms of what was saved on the stack, and use an invalid expression to do so. This is not needed as an EntryValue can never be clobbered. 2. `entry_value_gets_propagated`, that tests that an EntryValue DBG_VALUE is propagated in a diamond-shaped CFG. This patch is trying to reland #77938 but also fixes the bug with InstrRef based LiveDebugValues, where entry values were not being propagated in a diamond-shaped CFG.
1 parent 3894bdc commit 4b3faa9

File tree

3 files changed

+152
-1
lines changed

3 files changed

+152
-1
lines changed

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,16 @@ class TransferTracker {
668668

669669
auto &[Var, DILoc] = DVMap.lookupDVID(VarID);
670670

671+
// If the expression is a DW_OP_entry_value, emit the variable location
672+
// as-is.
673+
if (DIExpr->isEntryValue()) {
674+
Register Reg = MTracker->LocIdxToLocID[Num.getLoc()];
675+
MachineOperand MO = MachineOperand::CreateReg(Reg, false);
676+
PendingDbgValues.push_back(std::make_pair(
677+
VarID, &*emitMOLoc(MO, Var, {DIExpr, Prop.Indirect, false})));
678+
return true;
679+
}
680+
671681
// Is the variable appropriate for entry values (i.e., is a parameter).
672682
if (!isEntryValueVariable(Var, DIExpr))
673683
return false;
@@ -694,7 +704,7 @@ class TransferTracker {
694704
DebugVariableID VarID = DVMap.getDVID(Var);
695705

696706
// Ignore non-register locations, we don't transfer those.
697-
if (MI.isUndefDebugValue() ||
707+
if (MI.isUndefDebugValue() || MI.getDebugExpression()->isEntryValue() ||
698708
all_of(MI.debug_operands(),
699709
[](const MachineOperand &MO) { return !MO.isReg(); })) {
700710
auto It = ActiveVLocs.find(VarID);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# RUN: llc --run-pass=livedebugvalues -o - %s | FileCheck %s
2+
# REQUIRES: x86-registered-target
3+
4+
--- |
5+
target triple = "x86_64-"
6+
define void @foo(ptr swiftasync %0) !dbg !4 {
7+
call void @llvm.dbg.value(metadata ptr %0, metadata !9, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !17
8+
ret void
9+
}
10+
declare void @llvm.dbg.value(metadata, metadata, metadata)
11+
12+
!llvm.module.flags = !{!0}
13+
!llvm.dbg.cu = !{!1}
14+
15+
!0 = !{i32 2, !"Debug Info Version", i32 3}
16+
!1 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !2, producer: "blah", isOptimized: true, flags: "blah", runtimeVersion: 5, emissionKind: FullDebug)
17+
!2 = !DIFile(filename: "blah", directory: "blah")
18+
!3 = !{}
19+
!4 = distinct !DISubprogram(name: "blah", linkageName: "blah", scope: !2, file: !2, line: 284, type: !7, unit: !1)
20+
!7 = !DISubroutineType(types: !3)
21+
!9 = !DILocalVariable(name: "self", arg: 3, scope: !4, file: !2, line: 328, type: !12, flags: DIFlagArtificial)
22+
!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "blah", scope: !2, file: !2, size: 64, elements: !3)
23+
!17 = !DILocation(line: 328, column: 17, scope: !4)
24+
25+
...
26+
---
27+
name: foo
28+
alignment: 16
29+
debugInstrRef: true
30+
tracksDebugUserValues: true
31+
liveins:
32+
- { reg: '$r14', virtual-reg: '' }
33+
stack:
34+
- { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
35+
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
36+
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
37+
body: |
38+
bb.0:
39+
liveins: $r14
40+
; Put a copy of r14 on the stack.
41+
MOV64mr $rbp, 1, $noreg, -48, $noreg, $r14 :: (store (s64) into %stack.0)
42+
DBG_VALUE $r14, $noreg, !9, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !17
43+
MOV64mi32 $noreg, 1, $noreg, 0, $noreg, 0, debug-location !17 :: (store (s64) into `ptr null`)
44+
$r14 = MOV64rr killed $r13
45+
; Clobber $r14
46+
RETI64 24
47+
# CHECK: bb.0:
48+
# CHECK: MOV64mr $rbp, 1, $noreg, -48, $noreg, $r14
49+
# CHECK-NEXT: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)
50+
# CHECK-NOT: DBG_VALUE
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# RUN: llc --run-pass=livedebugvalues -o - %s | FileCheck %s
2+
# REQUIRES: x86-registered-target
3+
--- |
4+
target triple = "x86_64-"
5+
6+
define i32 @baz(i32 swiftasync %arg1, i32 noundef %arg2, i1 %cond) !dbg !9 {
7+
tail call void @llvm.dbg.value(metadata i32 %arg1, metadata !17, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19
8+
br i1 %cond, label %if.then, label %if.else, !dbg !22
9+
if.then:
10+
%call = call i32 @foo(i32 noundef %arg1), !dbg !23
11+
br label %if.end, !dbg !25
12+
if.else:
13+
%call1 = call i32 @foo(i32 noundef %arg2), !dbg !26
14+
br label %if.end
15+
if.end:
16+
%temp.0 = phi i32 [ %call, %if.then ], [ %call1, %if.else ], !dbg !28
17+
ret i32 %temp.0, !dbg !29
18+
}
19+
20+
declare i32 @foo(i32)
21+
declare void @llvm.dbg.value(metadata, metadata, metadata)
22+
23+
!llvm.dbg.cu = !{!0}
24+
!llvm.module.flags = !{!2, !3}
25+
26+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "ha", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
27+
!1 = !DIFile(filename: "test.c", directory: "hah")
28+
!2 = !{i32 7, !"Dwarf Version", i32 4}
29+
!3 = !{i32 2, !"Debug Info Version", i32 3}
30+
!9 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 3, type: !10, scopeLine: 3, unit: !0, retainedNodes: !13)
31+
!10 = !DISubroutineType(types: !11)
32+
!11 = !{!12, !12, !12, !12}
33+
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
34+
!13 = !{!14, !15, !16, !17}
35+
!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !9, file: !1, line: 3, type: !12)
36+
!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !9, file: !1, line: 3, type: !12)
37+
!16 = !DILocalVariable(name: "cond", arg: 3, scope: !9, file: !1, line: 3, type: !12)
38+
!17 = !DILocalVariable(name: "local", scope: !9, file: !1, line: 4, type: !12)
39+
!19 = !DILocation(line: 0, scope: !9)
40+
!20 = !DILocation(line: 7, column: 7, scope: !21)
41+
!21 = distinct !DILexicalBlock(scope: !9, file: !1, line: 7, column: 7)
42+
!22 = !DILocation(line: 7, column: 7, scope: !9)
43+
!23 = !DILocation(line: 8, column: 12, scope: !24)
44+
!24 = distinct !DILexicalBlock(scope: !21, file: !1, line: 7, column: 13)
45+
!25 = !DILocation(line: 9, column: 3, scope: !24)
46+
!26 = !DILocation(line: 10, column: 12, scope: !27)
47+
!27 = distinct !DILexicalBlock(scope: !21, file: !1, line: 9, column: 10)
48+
!28 = !DILocation(line: 0, scope: !21)
49+
!29 = !DILocation(line: 13, column: 3, scope: !9)
50+
51+
...
52+
---
53+
name: baz
54+
alignment: 16
55+
debugInstrRef: true
56+
tracksDebugUserValues: true
57+
liveins:
58+
- { reg: '$r14', virtual-reg: '' }
59+
- { reg: '$edi', virtual-reg: '' }
60+
- { reg: '$esi', virtual-reg: '' }
61+
- { reg: '$edx', virtual-reg: '' }
62+
body: |
63+
bb.0:
64+
successors: %bb.2(0x40000000), %bb.1(0x40000000)
65+
liveins: $r14, $edi, $edx, $esi
66+
DBG_VALUE $r14, $noreg, !14, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !19
67+
$r14 = MOV64ri 0, debug-location !20
68+
CMP32ri killed renamable $edx, 0, implicit-def $eflags, debug-location !20
69+
JCC_1 %bb.2, 4, implicit killed $eflags, debug-location !22
70+
bb.1.if.then:
71+
successors: %bb.3(0x80000000)
72+
liveins: $edi, $r13
73+
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $eax, debug-location !23
74+
JMP_1 %bb.3, debug-location !25
75+
bb.2.if.else:
76+
successors: %bb.3(0x80000000)
77+
liveins: $esi, $r13
78+
$edi = MOV32rr killed $esi, debug-location !26
79+
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $eax, debug-location !26
80+
bb.3.if.end:
81+
liveins: $eax
82+
$rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !29
83+
RET64 implicit $eax, debug-location !29
84+
# CHECK-LABEL: bb.0:
85+
# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)
86+
# CHECK-LABEL: bb.1.if.then:
87+
# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)
88+
# CHECK-LABEL: bb.2.if.else:
89+
# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)
90+
# CHECK-LABEL: bb.3.if.end:
91+
# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)

0 commit comments

Comments
 (0)