Skip to content

Commit af6d43e

Browse files
[AsmPrinter][DebugInfo] Create EntryValue mode for DbgVariable
With D149881, we converted EntryValue MachineFunction table entries into `DbgVariables` initialized by a "DbgValue" intrinsic, which can only handle a single, non-fragment DIExpression. However, it is desirable to handle variables with multiple fragments and DIExpressions. To do this, we expand the `DbgVariable` class to handle the EntryValue case. This class can already operate under three different "modes" (stack slot, unchanging location described by a dbg value, changing location described by a loc list). A fourth case is added as a separate class entirely, but a subsequent patch should redesign `DbgVariable` with four subclasses in order to make the code more readable. This patch also exposed a bug in the `beginEntryValueExpression` function, which was not initializing the `LocationFlags` properly. Note how the `finalizeEntryValue` function resets that flag. We fix this bug here, as testing this changing in isolation would be tricky. Differential Revision: https://reviews.llvm.org/D158458
1 parent 8841709 commit af6d43e

File tree

5 files changed

+103
-12
lines changed

5 files changed

+103
-12
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,23 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
882882
return VariableDie;
883883
}
884884

885+
if (const std::optional<DbgVariableEntryValue> &EntryValueVar =
886+
DV.getEntryValue()) {
887+
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
888+
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
889+
// Emit each expression as: EntryValue(Register) <other ops> <Fragment>.
890+
for (auto [Register, Expr] : EntryValueVar->getEntryValuesInfo()) {
891+
DwarfExpr.addFragmentOffset(&Expr);
892+
DIExpressionCursor Cursor(Expr.getElements());
893+
DwarfExpr.beginEntryValueExpression(Cursor);
894+
DwarfExpr.addMachineRegExpression(
895+
*Asm->MF->getSubtarget().getRegisterInfo(), Cursor, Register);
896+
DwarfExpr.addExpression(std::move(Cursor));
897+
}
898+
addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
899+
return VariableDie;
900+
}
901+
885902
// .. else use frame index.
886903
if (!DV.hasFrameIndexExprs())
887904
return VariableDie;

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,21 +1564,16 @@ void DwarfDebug::collectVariableInfoFromMFTable(
15641564
cast<DILocalVariable>(Var.first), Var.second);
15651565
if (VI.inStackSlot())
15661566
RegVar->initializeMMI(VI.Expr, VI.getStackSlot());
1567-
else {
1568-
MachineLocation MLoc(VI.getEntryValueRegister(), /*IsIndirect*/ false);
1569-
auto LocEntry = DbgValueLocEntry(MLoc);
1570-
RegVar->initializeDbgValue(DbgValueLoc(VI.Expr, LocEntry));
1571-
}
1567+
else
1568+
RegVar->initializeEntryValue(VI.getEntryValueRegister(), *VI.Expr);
15721569
LLVM_DEBUG(dbgs() << "Created DbgVariable for " << VI.Var->getName()
15731570
<< "\n");
15741571

15751572
if (DbgVariable *DbgVar = MFVars.lookup(Var)) {
1576-
if (DbgVar->getValueLoc())
1577-
LLVM_DEBUG(dbgs() << "Dropping repeated entry value debug info for "
1578-
"variable "
1579-
<< VI.Var->getName() << "\n");
1580-
else
1573+
if (DbgVar->hasFrameIndexExprs())
15811574
DbgVar->addMMIEntry(*RegVar);
1575+
else
1576+
DbgVar->getEntryValue()->addExpr(VI.getEntryValueRegister(), *VI.Expr);
15821577
} else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) {
15831578
MFVars.insert({Var, RegVar.get()});
15841579
ConcreteEntities.push_back(std::move(RegVar));

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,64 @@ class DbgEntity {
100100
}
101101
};
102102

103+
/// Helper class to model a DbgVariable whose location is derived from an
104+
/// EntryValue.
105+
/// TODO: split the current implementation of `DbgVariable` into a class per
106+
/// variant of location that it can represent, and make `DbgVariableEntryValue`
107+
/// a subclass.
108+
class DbgVariableEntryValue {
109+
struct EntryValueInfo {
110+
MCRegister Reg;
111+
const DIExpression &Expr;
112+
113+
/// Operator enabling sorting based on fragment offset.
114+
bool operator<(const EntryValueInfo &Other) const {
115+
return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits();
116+
}
117+
118+
private:
119+
uint64_t getFragmentOffsetInBits() const {
120+
std::optional<DIExpression::FragmentInfo> Fragment =
121+
Expr.getFragmentInfo();
122+
return Fragment ? Fragment->OffsetInBits : 0;
123+
}
124+
};
125+
126+
std::set<EntryValueInfo> EntryValues;
127+
128+
public:
129+
DbgVariableEntryValue(MCRegister Reg, const DIExpression &Expr) {
130+
addExpr(Reg, Expr);
131+
};
132+
133+
// Add the pair Reg, Expr to the list of entry values describing the variable.
134+
// If multiple expressions are added, it is the callers responsibility to
135+
// ensure they are all non-overlapping fragments.
136+
void addExpr(MCRegister Reg, const DIExpression &Expr) {
137+
std::optional<const DIExpression *> NonVariadicExpr =
138+
DIExpression::convertToNonVariadicExpression(&Expr);
139+
assert(NonVariadicExpr && *NonVariadicExpr);
140+
141+
EntryValues.insert({Reg, **NonVariadicExpr});
142+
}
143+
144+
/// Returns the set of EntryValueInfo.
145+
const std::set<EntryValueInfo> &getEntryValuesInfo() const {
146+
return EntryValues;
147+
}
148+
};
149+
103150
//===----------------------------------------------------------------------===//
104151
/// This class is used to track local variable information.
105152
///
106153
/// Variables can be created from allocas, in which case they're generated from
107154
/// the MMI table. Such variables can have multiple expressions and frame
108155
/// indices.
109156
///
157+
/// Variables can be created from the entry value of registers, in which case
158+
/// they're generated from the MMI table. Such variables can have either a
159+
/// single expression or multiple *fragment* expressions.
160+
///
110161
/// Variables can be created from \c DBG_VALUE instructions. Those whose
111162
/// location changes over time use \a DebugLocListIndex, while those with a
112163
/// single location use \a ValueLoc and (optionally) a single entry of \a Expr.
@@ -128,6 +179,8 @@ class DbgVariable : public DbgEntity {
128179
mutable SmallVector<FrameIndexExpr, 1>
129180
FrameIndexExprs; /// Frame index + expression.
130181

182+
std::optional<DbgVariableEntryValue> EntryValue;
183+
131184
public:
132185
/// Construct a DbgVariable.
133186
///
@@ -137,7 +190,7 @@ class DbgVariable : public DbgEntity {
137190
: DbgEntity(V, IA, DbgVariableKind) {}
138191

139192
bool isInitialized() const {
140-
return !FrameIndexExprs.empty() || ValueLoc;
193+
return !FrameIndexExprs.empty() || ValueLoc || EntryValue;
141194
}
142195

143196
/// Initialize from the MMI table.
@@ -161,6 +214,17 @@ class DbgVariable : public DbgEntity {
161214
FrameIndexExprs.push_back({0, E});
162215
}
163216

217+
void initializeEntryValue(MCRegister Reg, const DIExpression &Expr) {
218+
assert(!isInitialized() && "Already initialized?");
219+
EntryValue = DbgVariableEntryValue(Reg, Expr);
220+
}
221+
222+
const std::optional<DbgVariableEntryValue> &getEntryValue() const {
223+
return EntryValue;
224+
}
225+
226+
std::optional<DbgVariableEntryValue> &getEntryValue() { return EntryValue; }
227+
164228
/// Initialize from a DBG_VALUE instruction.
165229
void initializeDbgValue(const MachineInstr *DbgValue);
166230

llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ void DwarfExpression::beginEntryValueExpression(
414414

415415
SavedLocationKind = LocationKind;
416416
LocationKind = Register;
417+
LocationFlags |= EntryValue;
417418
IsEmittingEntryValue = true;
418419
enableTemporaryBuffer();
419420
}

llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,21 @@
33
# CHECK: DW_TAG_variable
44
# CHECK-NEXT: DW_AT_location (DW_OP_GNU_entry_value(DW_OP_reg22 W22))
55
# CHECK-NEXT: DW_AT_name ("a")
6+
# CHECK: DW_TAG_variable
7+
# CHECK-NEXT: DW_AT_location
8+
# CHECK-SAME: DW_OP_GNU_entry_value(DW_OP_reg22 W22), DW_OP_piece 0x8,
9+
# CHECK-SAME: DW_OP_GNU_entry_value(DW_OP_reg22 W22), DW_OP_plus_uconst 0x2a, DW_OP_piece 0x8)
10+
# CHECK-NEXT: DW_AT_name ("fragmented_var")
611

712

813
--- |
914
target triple = "aarch64--"
1015
define void @foo(ptr %unused_arg, ptr swiftasync %async_arg) !dbg !4 {
1116
call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !10, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !12
17+
; A two fragment variable.
18+
; Fragments intentionally out of order to ensure the code can handle this.
19+
call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !10, metadata !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 42, DW_OP_LLVM_fragment, 64, 64)), !dbg !12
20+
call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !11, metadata !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_LLVM_fragment, 0, 64)), !dbg !12
1221
ret void, !dbg !12
1322
}
1423
declare void @llvm.dbg.declare(metadata, metadata, metadata)
@@ -22,9 +31,10 @@
2231
!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
2332
!5 = !DISubroutineType(types: !6)
2433
!6 = !{null, !7, !7, !7}
25-
!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
34+
!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 128)
2635
!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
2736
!10 = !DILocalVariable(name: "a", scope: !4, file: !1, line: 1, type: !7)
37+
!11 = !DILocalVariable(name: "fragmented_var", scope: !4, file: !1, line: 1, type: !7)
2838
!12 = !DILocation(line: 1, column: 37, scope: !4)
2939
...
3040
---
@@ -38,6 +48,10 @@ stack:
3848
entry_values:
3949
- { entry-value-register: '$x22', debug-info-variable: '!10', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_deref)',
4050
debug-info-location: '!12' }
51+
- { entry-value-register: '$x22', debug-info-variable: '!11', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 42, DW_OP_deref, DW_OP_LLVM_fragment, 64, 64)',
52+
debug-info-location: '!12' }
53+
- { entry-value-register: '$x22', debug-info-variable: '!11', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_deref, DW_OP_LLVM_fragment, 0, 64)',
54+
debug-info-location: '!12' }
4155
body: |
4256
bb.0 (%ir-block.0):
4357
liveins: $x0, $x22, $lr

0 commit comments

Comments
 (0)