Skip to content

Commit cb714e7

Browse files
authored
[DebugInfo][InstrRef] Avoid producing broken DW_OP_deref_sizes (#123967)
We use variable locations such as DBG_VALUE $xmm0 as shorthand to refer to "the low lane of $xmm0", and this is reflected in how DWARF is interpreted too. However InstrRefBasedLDV tries to be smart and interprets such a DBG_VALUE as a 128-bit reference. We then issue a DW_OP_deref_size of 128 bits to the stack, which isn't permitted by DWARF (it's larger than a pointer). Solve this for now by not using DW_OP_deref_size if it would be illegal. Instead we'll use DW_OP_deref, and the consumer will load the variable type from the stack, which should be correct. There's still a risk of imprecision when LLVM decides to use smaller or larger value types than the source-variable type, which manifests as too-little or too-much memory being read from the stack. However we can't solve that without putting more type information in debug-info. fixes #64093
1 parent 2e6cc79 commit cb714e7

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,27 @@ MLocTracker::emitLoc(const SmallVectorImpl<ResolvedDbgOp> &DbgOps,
12901290
}
12911291
}
12921292

1293+
// https://github.com/llvm/llvm-project/issues/64093
1294+
// in particular #issuecomment-2531264124. We use variable locations
1295+
// such as DBG_VALUE $xmm0 as shorthand to refer to "the low lane of
1296+
// $xmm0", and this is reflected in how DWARF is interpreted too.
1297+
// However InstrRefBasedLDV tries to be smart and interprets such a
1298+
// DBG_VALUE as a 128-bit reference. We then issue a DW_OP_deref_size
1299+
// of 128 bits to the stack, which isn't permitted by DWARF (it's
1300+
// larger than a pointer).
1301+
//
1302+
// Solve this for now by not using DW_OP_deref_size if it would be
1303+
// illegal. Instead we'll use DW_OP_deref, and the consumer will load
1304+
// the variable type from the stack, which should be correct.
1305+
//
1306+
// There's still a risk of imprecision when LLVM decides to use
1307+
// smaller or larger value types than the source-variable type, which
1308+
// manifests as too-little or too-much memory being read from the stack.
1309+
// However we can't solve that without putting more type information in
1310+
// debug-info.
1311+
if (ValueSizeInBits > MF.getTarget().getPointerSizeInBits(0))
1312+
UseDerefSize = false;
1313+
12931314
SmallVector<uint64_t, 5> OffsetOps;
12941315
TRI.getOffsetOpcodes(Spill.SpillOffset, OffsetOps);
12951316
bool StackValue = false;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# RUN: llc %s -o - -experimental-debug-variable-locations=true \
2+
# RUN: -run-pass=livedebugvalues \
3+
# RUN: | FileCheck %s --implicit-check-not=DBG_VALUE
4+
# RUN: llc %s -o - -experimental-debug-variable-locations=true \
5+
# RUN: -start-before=livedebugvalues -filetype=obj \
6+
# RUN: | llvm-dwarfdump - | FileCheck %s --check-prefix=DWARF
7+
#
8+
# LLVM can produce DIExpressions that convert from one value of arbitrary size
9+
# to another. This is normally fine, however that means the value for a
10+
# variable tracked in instruction referencing might not be the same size as the
11+
# variable itself.
12+
#
13+
# We typically use vector registers as shorthand for "the lower lane of the
14+
# vector register", for example if we have a single float we might say
15+
#
16+
# DBG_VALUE $xmm0
17+
#
18+
# and that's reflected in DWARF too. However, instruction-referencing tries to
19+
# solve several size problems (see deref-spills-with-size.mir), and gets
20+
# confused by this shorthand. It manifests in the test sequence below: we
21+
# locate a variable in a vector register, spill it, then force a stack variable
22+
# location to be produced. InstrRefBasedLDV would like to produce a
23+
# DW_OP_deref_size indicating that 128 bits should be loaded for the 32 bit
24+
# register, but this would be wrong (and illegal DWARF as the max load size is
25+
# the pointer size).
26+
#
27+
# As a sticking-plaster fix: detect when we're about to emit these illegal
28+
# DWARF locations, and instead use DW_OP_deref_size. There's a small risk we
29+
# read too much or too little data, but it's better than emitting illegal DWARF.
30+
31+
# CHECK: ![[VAR:[0-9]+]] = !DILocalVariable(name: "flannel",
32+
33+
## Check that we're not producing DW_OP_deref_size, instead using the isIndirect
34+
## field of DBG_VALUEs.
35+
36+
# CHECK: DBG_VALUE $xmm0, $noreg,
37+
# CHECK: DBG_VALUE $rsp, 0, ![[VAR]], !DIExpression(DW_OP_plus_uconst, 8),
38+
39+
## Check that we produce a breg location with no further expression attached.
40+
41+
# DWARF: DW_TAG_variable
42+
# DWARF-NEXT: DW_AT_location
43+
# DWARF-NEXT: DW_OP_reg17 XMM0
44+
# DWARF-NEXT: DW_OP_breg7 RSP+8)
45+
# DWARF-NEXT: DW_AT_name ("flannel")
46+
47+
--- |
48+
; ModuleID = 'missingvar.ll'
49+
source_filename = "a"
50+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
51+
target triple = "x86_64-unknown-linux-gnu"
52+
53+
define linkonce_odr void @_ZNSt5dequeIPN4llvm4LoopESaIS2_EE13_M_insert_auxESt15_Deque_iteratorIS2_RS2_PS2_EmRKS2_() local_unnamed_addr align 2 !dbg !3 {
54+
entry:
55+
call void @llvm.dbg.value(metadata i32 0, metadata !8, metadata !DIExpression()), !dbg !7
56+
call void @llvm.dbg.value(metadata i32 0, metadata !10, metadata !DIExpression()), !dbg !7
57+
ret void
58+
}
59+
60+
declare void @llvm.dbg.value(metadata, metadata, metadata)
61+
62+
!llvm.module.flags = !{!0, !9}
63+
!llvm.dbg.cu = !{!1}
64+
65+
!0 = !{i32 2, !"Debug Info Version", i32 3}
66+
!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 4, emissionKind: FullDebug)
67+
!2 = !DIFile(filename: "bees.cpp", directory: "")
68+
!3 = distinct !DISubprogram(name: "nope", scope: !2, file: !2, line: 1, type: !4, spFlags: DISPFlagDefinition, unit: !1)
69+
!4 = !DISubroutineType(types: !5)
70+
!5 = !{!6}
71+
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
72+
!7 = !DILocation(line: 1, scope: !3)
73+
!8 = !DILocalVariable(name: "flannel", scope: !3, type: !6)
74+
!9 = !{i32 2, !"Dwarf Version", i32 5}
75+
!10 = !DILocalVariable(name: "shoes", scope: !3, type: !11)
76+
!11 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
77+
78+
79+
...
80+
---
81+
name: _ZNSt5dequeIPN4llvm4LoopESaIS2_EE13_M_insert_auxESt15_Deque_iteratorIS2_RS2_PS2_EmRKS2_
82+
alignment: 16
83+
tracksRegLiveness: true
84+
debugInstrRef: true
85+
liveins:
86+
- { reg: '$rdi' }
87+
- { reg: '$rsi' }
88+
- { reg: '$rdx' }
89+
frameInfo:
90+
stackSize: 16
91+
offsetAdjustment: -16
92+
maxAlignment: 16
93+
maxCallFrameSize: 0
94+
stack:
95+
- { id: 6, type: spill-slot, offset: -16, size: 16, alignment: 16 }
96+
machineFunctionInfo: {}
97+
body: |
98+
bb.0.entry:
99+
liveins: $rdi, $rdx, $rsi, $rbp, $xmm0
100+
101+
102+
$xmm0 = XORPSrr $xmm0, $xmm0, debug-location !7
103+
DBG_VALUE $xmm0, $noreg, !8, !DIExpression(), debug-location !7
104+
VMOVUPSmr $rsp, 1, $noreg, 36, $noreg, $xmm0 :: (store (s128) into %stack.6)
105+
$xmm0 = XORPSrr $xmm0, $xmm0, debug-location !7
106+
RET64 0, debug-location !7
107+
...

0 commit comments

Comments
 (0)