Skip to content

Commit e086990

Browse files
SLTozerfelipepiovezan
authored andcommitted
[DebugInfo] Process single-location debug values in variadic form when producing DWARF
Revision c383f4d enabled using variadic-form debug values to represent single-location, non-stack-value debug values, and a further patch made all DBG_INSTR_REFs use variadic form. Not all code paths were updated correctly to handle the new syntax however, with entry values in still expecting an expression that begins exactly DW_OP_LLVM_entry_value, 1. A function already exists to select non-variadic-like expressions; this patch adds an extra function to cheaply simplify such cases to non-variadic form, which we use prior to any entry-value processing to put DBG_INSTR_REFs and DBG_VALUEs down the same code path. We also use it for a few DIExpression functions that check for whether the first element(s) of a DIExpression match a particular pattern, so that they will return the same result for DIExpression(DW_OP_LLVM_arg, 0, <ops>) as for DIExpression(<ops>). Differential Revision: https://reviews.llvm.org/D158185 (cherry picked from commit 9811ffe)
1 parent 74082e7 commit e086990

File tree

5 files changed

+168
-37
lines changed

5 files changed

+168
-37
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2900,6 +2900,13 @@ class DIExpression : public MDNode {
29002900
/// DW_OP_LLVM_arg op as its first operand, or if it contains none.
29012901
bool isSingleLocationExpression() const;
29022902

2903+
/// Returns a reference to the elements contained in this expression, skipping
2904+
/// past the leading `DW_OP_LLVM_arg, 0` if one is present.
2905+
/// Similar to `convertToNonVariadicExpression`, but faster and cheaper - it
2906+
/// does not check whether the expression is a single-location expression, and
2907+
/// it returns elements rather than creating a new DIExpression.
2908+
std::optional<ArrayRef<uint64_t>> getSingleLocationExpressionElements() const;
2909+
29032910
/// Removes all elements from \p Expr that do not apply to an undef debug
29042911
/// value, which includes every operator that computes the value/location on
29052912
/// the DWARF stack, including any DW_OP_LLVM_arg elements (making the result
@@ -2918,6 +2925,9 @@ class DIExpression : public MDNode {
29182925
/// single debug operand at the start of the expression, then return that
29192926
/// expression in a non-variadic form by removing DW_OP_LLVM_arg from the
29202927
/// expression if it is present; otherwise returns std::nullopt.
2928+
/// See also `getSingleLocationExpressionElements` above, which skips
2929+
/// checking `isSingleLocationExpression` and returns a list of elements
2930+
/// rather than a DIExpression.
29212931
static std::optional<const DIExpression *>
29222932
convertToNonVariadicExpression(const DIExpression *Expr);
29232933

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,15 @@ const DIType *DbgVariable::getType() const {
240240
/// Get .debug_loc entry for the instruction range starting at MI.
241241
static DbgValueLoc getDebugLocValue(const MachineInstr *MI) {
242242
const DIExpression *Expr = MI->getDebugExpression();
243-
const bool IsVariadic = MI->isDebugValueList();
243+
auto SingleLocExprOpt = DIExpression::convertToNonVariadicExpression(Expr);
244+
const bool IsVariadic = !SingleLocExprOpt;
245+
// If we have a variadic debug value instruction that is equivalent to a
246+
// non-variadic instruction, then convert it to non-variadic form here.
247+
if (!IsVariadic && !MI->isNonListDebugValue()) {
248+
assert(MI->getNumDebugOperands() == 1 &&
249+
"Mismatched DIExpression and debug operands for debug instruction.");
250+
Expr = *SingleLocExprOpt;
251+
}
244252
assert(MI->getNumOperands() >= 3);
245253
SmallVector<DbgValueLocEntry, 4> DbgValueLocEntries;
246254
for (const MachineOperand &Op : MI->debug_operands()) {

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,13 +1343,23 @@ DIExpression *DIExpression::getImpl(LLVMContext &Context,
13431343
DEFINE_GETIMPL_STORE_NO_OPS(DIExpression, (Elements));
13441344
}
13451345
bool DIExpression::isEntryValue() const {
1346-
return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_LLVM_entry_value;
1346+
if (auto singleLocElts = getSingleLocationExpressionElements()) {
1347+
return singleLocElts->size() > 0 &&
1348+
(*singleLocElts)[0] == dwarf::DW_OP_LLVM_entry_value;
1349+
}
1350+
return false;
13471351
}
13481352
bool DIExpression::startsWithDeref() const {
1349-
return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref;
1353+
if (auto singleLocElts = getSingleLocationExpressionElements())
1354+
return singleLocElts->size() > 0 &&
1355+
(*singleLocElts)[0] == dwarf::DW_OP_deref;
1356+
return false;
13501357
}
13511358
bool DIExpression::isDeref() const {
1352-
return getNumElements() == 1 && startsWithDeref();
1359+
if (auto singleLocElts = getSingleLocationExpressionElements())
1360+
return singleLocElts->size() == 1 &&
1361+
(*singleLocElts)[0] == dwarf::DW_OP_deref;
1362+
return false;
13531363
}
13541364

13551365
DIAssignID *DIAssignID::getImpl(LLVMContext &Context, StorageType Storage,
@@ -1526,14 +1536,34 @@ bool DIExpression::isSingleLocationExpression() const {
15261536

15271537
auto ExprOpBegin = expr_ops().begin();
15281538
auto ExprOpEnd = expr_ops().end();
1529-
if (ExprOpBegin->getOp() == dwarf::DW_OP_LLVM_arg)
1539+
if (ExprOpBegin->getOp() == dwarf::DW_OP_LLVM_arg) {
1540+
if (ExprOpBegin->getArg(0) != 0)
1541+
return false;
15301542
++ExprOpBegin;
1543+
}
15311544

15321545
return !std::any_of(ExprOpBegin, ExprOpEnd, [](auto Op) {
15331546
return Op.getOp() == dwarf::DW_OP_LLVM_arg;
15341547
});
15351548
}
15361549

1550+
std::optional<ArrayRef<uint64_t>>
1551+
DIExpression::getSingleLocationExpressionElements() const {
1552+
// Check for `isValid` covered by `isSingleLocationExpression`.
1553+
if (!isSingleLocationExpression())
1554+
return std::nullopt;
1555+
1556+
// An empty expression is already non-variadic.
1557+
if (!getNumElements())
1558+
return ArrayRef<uint64_t>();
1559+
1560+
// If Expr does not have a leading DW_OP_LLVM_arg then we don't need to do
1561+
// anything.
1562+
if (getElements()[0] == dwarf::DW_OP_LLVM_arg)
1563+
return getElements().drop_front(2);
1564+
return getElements();
1565+
}
1566+
15371567
const DIExpression *
15381568
DIExpression::convertToUndefExpression(const DIExpression *Expr) {
15391569
SmallVector<uint64_t, 3> UndefOps;
@@ -1559,23 +1589,13 @@ DIExpression::convertToVariadicExpression(const DIExpression *Expr) {
15591589

15601590
std::optional<const DIExpression *>
15611591
DIExpression::convertToNonVariadicExpression(const DIExpression *Expr) {
1562-
// Check for `isValid` covered by `isSingleLocationExpression`.
1563-
if (!Expr->isSingleLocationExpression())
1592+
if (!Expr)
15641593
return std::nullopt;
15651594

1566-
// An empty expression is already non-variadic.
1567-
if (!Expr->getNumElements())
1568-
return Expr;
1595+
if (auto Elts = Expr->getSingleLocationExpressionElements())
1596+
return DIExpression::get(Expr->getContext(), *Elts);
15691597

1570-
auto ElementsBegin = Expr->elements_begin();
1571-
// If Expr does not have a leading DW_OP_LLVM_arg then we don't need to do
1572-
// anything.
1573-
if (*ElementsBegin != dwarf::DW_OP_LLVM_arg)
1574-
return Expr;
1575-
1576-
SmallVector<uint64_t> NonVariadicOps(
1577-
make_range(ElementsBegin + 2, Expr->elements_end()));
1578-
return DIExpression::get(Expr->getContext(), NonVariadicOps);
1598+
return std::nullopt;
15791599
}
15801600

15811601
void DIExpression::canonicalizeExpressionOps(SmallVectorImpl<uint64_t> &Ops,
@@ -1646,23 +1666,29 @@ void DIExpression::appendOffset(SmallVectorImpl<uint64_t> &Ops,
16461666
}
16471667

16481668
bool DIExpression::extractIfOffset(int64_t &Offset) const {
1649-
if (getNumElements() == 0) {
1669+
auto SingleLocEltsOpt = getSingleLocationExpressionElements();
1670+
if (!SingleLocEltsOpt)
1671+
return false;
1672+
auto SingleLocElts = *SingleLocEltsOpt;
1673+
1674+
if (SingleLocElts.size() == 0) {
16501675
Offset = 0;
16511676
return true;
16521677
}
16531678

1654-
if (getNumElements() == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
1655-
Offset = Elements[1];
1679+
if (SingleLocElts.size() == 2 &&
1680+
SingleLocElts[0] == dwarf::DW_OP_plus_uconst) {
1681+
Offset = SingleLocElts[1];
16561682
return true;
16571683
}
16581684

1659-
if (getNumElements() == 3 && Elements[0] == dwarf::DW_OP_constu) {
1660-
if (Elements[2] == dwarf::DW_OP_plus) {
1661-
Offset = Elements[1];
1685+
if (SingleLocElts.size() == 3 && SingleLocElts[0] == dwarf::DW_OP_constu) {
1686+
if (SingleLocElts[2] == dwarf::DW_OP_plus) {
1687+
Offset = SingleLocElts[1];
16621688
return true;
16631689
}
1664-
if (Elements[2] == dwarf::DW_OP_minus) {
1665-
Offset = -Elements[1];
1690+
if (SingleLocElts[2] == dwarf::DW_OP_minus) {
1691+
Offset = -SingleLocElts[1];
16661692
return true;
16671693
}
16681694
}
@@ -1685,18 +1711,23 @@ const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
16851711
unsigned &AddrClass) {
16861712
// FIXME: This seems fragile. Nothing that verifies that these elements
16871713
// actually map to ops and not operands.
1714+
auto SingleLocEltsOpt = Expr->getSingleLocationExpressionElements();
1715+
if (!SingleLocEltsOpt)
1716+
return nullptr;
1717+
auto SingleLocElts = *SingleLocEltsOpt;
1718+
16881719
const unsigned PatternSize = 4;
1689-
if (Expr->Elements.size() >= PatternSize &&
1690-
Expr->Elements[PatternSize - 4] == dwarf::DW_OP_constu &&
1691-
Expr->Elements[PatternSize - 2] == dwarf::DW_OP_swap &&
1692-
Expr->Elements[PatternSize - 1] == dwarf::DW_OP_xderef) {
1693-
AddrClass = Expr->Elements[PatternSize - 3];
1720+
if (SingleLocElts.size() >= PatternSize &&
1721+
SingleLocElts[PatternSize - 4] == dwarf::DW_OP_constu &&
1722+
SingleLocElts[PatternSize - 2] == dwarf::DW_OP_swap &&
1723+
SingleLocElts[PatternSize - 1] == dwarf::DW_OP_xderef) {
1724+
AddrClass = SingleLocElts[PatternSize - 3];
16941725

1695-
if (Expr->Elements.size() == PatternSize)
1726+
if (SingleLocElts.size() == PatternSize)
16961727
return nullptr;
1697-
return DIExpression::get(Expr->getContext(),
1698-
ArrayRef(&*Expr->Elements.begin(),
1699-
Expr->Elements.size() - PatternSize));
1728+
return DIExpression::get(
1729+
Expr->getContext(),
1730+
ArrayRef(&*SingleLocElts.begin(), SingleLocElts.size() - PatternSize));
17001731
}
17011732
return Expr;
17021733
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# RUN: llc %s --start-after=livedebugvalues --filetype=obj -o - \
2+
# RUN: | llvm-dwarfdump - --name=test-var -o - | FileCheck %s
3+
4+
# Test that when an entry value expression appears in a DBG_VALUE_LIST, we are
5+
# able to produce a valid entry value location in DWARF.
6+
7+
# CHECK: DW_OP_entry_value(DW_OP_reg14 R14), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x10, DW_OP_deref
8+
9+
--- |
10+
source_filename = "test.ll"
11+
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
12+
target triple = "x86_64-apple-macosx12.1.0"
13+
14+
declare void @llvm.dbg.value(metadata, metadata, metadata)
15+
16+
define swifttailcc void @blah(ptr swiftasync %0) !dbg !15 {
17+
%use = getelementptr i8, ptr %0, i64 9
18+
call void @llvm.dbg.value(metadata ptr %0, metadata !18, metadata !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 16, DW_OP_deref, DW_OP_deref)), !dbg !22
19+
%use1 = load i32, ptr null, align 4, !dbg !27
20+
%use2 = sext i32 %use1 to i64
21+
%use3 = getelementptr i8, ptr null, i64 %use2
22+
store ptr %use3, ptr %0, align 8
23+
ret void
24+
}
25+
26+
!llvm.module.flags = !{!0}
27+
!llvm.dbg.cu = !{!1}
28+
29+
!0 = !{i32 2, !"Debug Info Version", i32 3}
30+
!1 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !2, producer: "blah", isOptimized: true, flags: "blah", runtimeVersion: 5, emissionKind: FullDebug, globals: !3, imports: !9, sysroot: "blah", sdk: "blah")
31+
!2 = !DIFile(filename: "blah", directory: "blah")
32+
!3 = !{!4, !10}
33+
!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
34+
!5 = distinct !DIGlobalVariable(name: "blah", linkageName: "blah", scope: !6, file: !2, line: 49, type: !7, isLocal: true, isDefinition: true)
35+
!6 = !DIModule(scope: null, name: "blah", includePath: "blah")
36+
!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8)
37+
!8 = !DICompositeType(tag: DW_TAG_structure_type, name: "blah", scope: !6, file: !2, size: 64, elements: !9, runtimeLang: DW_LANG_Swift, identifier: "blah")
38+
!9 = !{}
39+
!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
40+
!11 = distinct !DIGlobalVariable(name: "blah", linkageName: "blah", scope: !6, file: !2, line: 44, type: !12, isLocal: false, isDefinition: true)
41+
!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
42+
!13 = !DICompositeType(tag: DW_TAG_structure_type, name: "blah", scope: !14, file: !2, size: 64, elements: !9, runtimeLang: DW_LANG_Swift, identifier: "blah")
43+
!14 = !DIModule(scope: null, name: "blah", configMacros: "blah", includePath: "blah")
44+
!15 = distinct !DISubprogram(name: "blah", linkageName: "blah", scope: !16, file: !2, line: 115, type: !17, scopeLine: 117, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !9, thrownTypes: !9)
45+
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "blah", scope: !6, file: !2, elements: !9, runtimeLang: DW_LANG_Swift, identifier: "blah")
46+
!17 = !DISubroutineType(types: !9)
47+
!18 = !DILocalVariable(name: "test-var", arg: 1, scope: !19, file: !2, line: 95, type: !21, flags: DIFlagArtificial)
48+
!19 = distinct !DISubprogram(name: "blah", linkageName: "blah", scope: !16, file: !2, line: 95, type: !20, scopeLine: 95, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !9)
49+
!20 = distinct !DISubroutineType(types: !9)
50+
!21 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16)
51+
!22 = !DILocation(line: 95, column: 9, scope: !19, inlinedAt: !23)
52+
!23 = distinct !DILocation(line: 0, scope: !24, inlinedAt: !25)
53+
!24 = distinct !DISubprogram(name: "blah", linkageName: "blah", scope: !16, file: !2, type: !20, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1)
54+
!25 = distinct !DILocation(line: 121, column: 36, scope: !26)
55+
!26 = distinct !DILexicalBlock(scope: !15, file: !2, line: 116, column: 7)
56+
!27 = !DILocation(line: 0, scope: !28, inlinedAt: !23)
57+
!28 = !DILexicalBlockFile(scope: !19, file: !2, discriminator: 0)
58+
59+
...
60+
---
61+
name: blah
62+
alignment: 16
63+
tracksRegLiveness: true
64+
debugInstrRef: true
65+
tracksDebugUserValues: true
66+
registers: []
67+
liveins:
68+
- { reg: '$r14', virtual-reg: '' }
69+
frameInfo:
70+
maxAlignment: 1
71+
body: |
72+
bb.0 (%ir-block.1):
73+
liveins: $r14
74+
75+
DBG_PHI $r14, 1
76+
DBG_INSTR_REF !18, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 16, DW_OP_deref, DW_OP_deref), dbg-instr-ref(1, 0), debug-location !22
77+
DBG_VALUE_LIST !18, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 16, DW_OP_deref, DW_OP_deref), $r14, debug-location !DILocation(line: 0, scope: !19, inlinedAt: !23)
78+
renamable $rax = MOVSX64rm32 $noreg, 1, $noreg, 0, $noreg, debug-location !27 :: (load (s32) from `ptr null`)
79+
MOV64mr killed renamable $r14, 1, $noreg, 0, $noreg, killed renamable $rax :: (store (s64) into %ir.0)
80+
RETI64 8
81+
82+
...

llvm/test/DebugInfo/X86/pr52584.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
; CHECK: DW_TAG
1010
define dso_local void @test() !dbg !4 {
1111
entry:
12-
call void @llvm.dbg.value(metadata !DIArgList(i128 0), metadata !7, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 127)), !dbg !12
12+
call void @llvm.dbg.value(metadata !DIArgList(i128 0), metadata !7, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 0, DW_OP_plus, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 127)), !dbg !12
1313
ret void, !dbg !12
1414
}
1515

0 commit comments

Comments
 (0)