Skip to content

Commit 58c108c

Browse files
committed
[NFC][AsmPrinter] Refactor DbgVariable as a std::variant
Only a subset of the fields of DbgVariable are meaningful at any time, and some fields are re-used for multiple purposes (for example FrameIndexExprs is used with a throw-away frame-index of 0 to hold a single DIExpression without needing to add another member). The exact invariants must be reverse-engineered by inspecting the actual use of the class, its imprecise/outdated doc-comment, and some asserts. Refactor DbgVariable into a sum type by inheriting from std::variant. This makes the active fields for any given state explicit and removes the need to re-use fields in disparate contexts. As a bonus, it seems to reduce the size on my x86_64 linux box from 144 bytes to 96 bytes. There is some potential cost to `std::get` as it must check the active alternative even when context or an assert obviates it. To try to help ensure the compiler can optimize out the checks the patch also adds a helper `get` method which uses the noexcept `std::get_if`. Some of the extra cost would also be avoided more cleanly with a refactor that exposes the alternative types in the public interface, which will come in another patch. Differential Revision: https://reviews.llvm.org/D158675
1 parent 093aa37 commit 58c108c

File tree

3 files changed

+152
-117
lines changed

3 files changed

+152
-117
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -882,12 +882,11 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
882882
return VariableDie;
883883
}
884884

885-
if (const std::optional<DbgVariableEntryValue> &EntryValueVar =
886-
DV.getEntryValue()) {
885+
if (const std::set<EntryValueInfo> *EntryValues = DV.getEntryValues()) {
887886
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
888887
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
889888
// Emit each expression as: EntryValue(Register) <other ops> <Fragment>.
890-
for (auto [Register, Expr] : EntryValueVar->getEntryValuesInfo()) {
889+
for (auto [Register, Expr] : *EntryValues) {
891890
DwarfExpr.addFragmentOffset(&Expr);
892891
DIExpressionCursor Cursor(Expr.getElements());
893892
DwarfExpr.beginEntryValueExpression(Cursor);

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -257,21 +257,37 @@ static DbgValueLoc getDebugLocValue(const MachineInstr *MI) {
257257
return DbgValueLoc(Expr, DbgValueLocEntries, IsVariadic);
258258
}
259259

260-
void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) {
261-
assert(FrameIndexExprs.empty() && "Already initialized?");
262-
assert(!ValueLoc.get() && "Already initialized?");
260+
/// Initialize from the MMI table.
261+
void DbgVariable::initializeMMI(const DIExpression *E, int FI) {
262+
assert(holds<std::monostate>() && "Already initialized");
263+
assert((!E || E->isValid()) && "Expected valid expression");
264+
assert(FI != std::numeric_limits<int>::max() && "Expected valid index");
265+
emplace<MMILoc>().FrameIndexExprs.push_back({FI, E});
266+
}
267+
268+
void DbgVariable::initializeDbgValue(DbgValueLoc Value) {
269+
assert(holds<std::monostate>() && "Already initialized");
270+
assert(!Value.getExpression()->isFragment() && "Fragments not supported");
271+
emplace<SingleLoc>(Value);
272+
}
263273

274+
void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) {
275+
assert(holds<std::monostate>() && "Already initialized");
264276
assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable");
265277
assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() &&
266278
"Wrong inlined-at");
279+
emplace<SingleLoc>(getDebugLocValue(DbgValue));
280+
}
267281

268-
ValueLoc = std::make_unique<DbgValueLoc>(getDebugLocValue(DbgValue));
269-
if (auto *E = DbgValue->getDebugExpression())
270-
if (E->getNumElements())
271-
FrameIndexExprs.push_back({0, E});
282+
void DbgVariable::initializeEntryValue(MCRegister Reg,
283+
const DIExpression &Expr) {
284+
assert(holds<std::monostate>() && "Already initialized?");
285+
emplace<EntryValueLoc>(Reg, Expr);
272286
}
273287

274-
ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const {
288+
ArrayRef<FrameIndexExpr> DbgVariable::getFrameIndexExprs() const {
289+
auto &FrameIndexExprs = get<MMILoc>().FrameIndexExprs;
290+
275291
if (FrameIndexExprs.size() == 1)
276292
return FrameIndexExprs;
277293

@@ -290,13 +306,11 @@ ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const {
290306
}
291307

292308
void DbgVariable::addMMIEntry(const DbgVariable &V) {
293-
assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry");
294-
assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry");
295309
assert(V.getVariable() == getVariable() && "conflicting variable");
296310
assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location");
297311

298-
assert(!FrameIndexExprs.empty() && "Expected an MMI entry");
299-
assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry");
312+
auto &FrameIndexExprs = get<MMILoc>().FrameIndexExprs;
313+
auto &VFrameIndexExprs = V.get<MMILoc>().FrameIndexExprs;
300314

301315
// FIXME: This logic should not be necessary anymore, as we now have proper
302316
// deduplication. However, without it, we currently run into the assertion
@@ -308,7 +322,7 @@ void DbgVariable::addMMIEntry(const DbgVariable &V) {
308322
return;
309323
}
310324

311-
for (const auto &FIE : V.FrameIndexExprs)
325+
for (const auto &FIE : VFrameIndexExprs)
312326
// Ignore duplicate entries.
313327
if (llvm::none_of(FrameIndexExprs, [&](const FrameIndexExpr &Other) {
314328
return FIE.FI == Other.FI && FIE.Expr == Other.Expr;
@@ -1573,7 +1587,7 @@ void DwarfDebug::collectVariableInfoFromMFTable(
15731587
if (DbgVar->hasFrameIndexExprs())
15741588
DbgVar->addMMIEntry(*RegVar);
15751589
else
1576-
DbgVar->getEntryValue()->addExpr(VI.getEntryValueRegister(), *VI.Expr);
1590+
DbgVar->addEntryValueExpr(VI.getEntryValueRegister(), *VI.Expr);
15771591
} else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) {
15781592
MFVars.insert({Var, RegVar.get()});
15791593
ConcreteEntities.push_back(std::move(RegVar));

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 122 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <limits>
4242
#include <memory>
4343
#include <utility>
44+
#include <variant>
4445
#include <vector>
4546

4647
namespace llvm {
@@ -100,36 +101,59 @@ class DbgEntity {
100101
}
101102
};
102103

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-
}
104+
/// Proxy for one MMI entry.
105+
struct FrameIndexExpr {
106+
int FI;
107+
const DIExpression *Expr;
108+
};
117109

118-
private:
119-
uint64_t getFragmentOffsetInBits() const {
120-
std::optional<DIExpression::FragmentInfo> Fragment =
121-
Expr.getFragmentInfo();
122-
return Fragment ? Fragment->OffsetInBits : 0;
123-
}
124-
};
110+
/// Represents an entry-value location, or a fragment of one.
111+
struct EntryValueInfo {
112+
MCRegister Reg;
113+
const DIExpression &Expr;
125114

126-
std::set<EntryValueInfo> EntryValues;
115+
/// Operator enabling sorting based on fragment offset.
116+
bool operator<(const EntryValueInfo &Other) const {
117+
return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits();
118+
}
127119

128-
public:
129-
DbgVariableEntryValue(MCRegister Reg, const DIExpression &Expr) {
120+
private:
121+
uint64_t getFragmentOffsetInBits() const {
122+
std::optional<DIExpression::FragmentInfo> Fragment = Expr.getFragmentInfo();
123+
return Fragment ? Fragment->OffsetInBits : 0;
124+
}
125+
};
126+
127+
// Namespace for private alternatives of a DbgVariable.
128+
namespace {
129+
/// Single value location description.
130+
struct SingleLoc {
131+
std::unique_ptr<DbgValueLoc> ValueLoc;
132+
const DIExpression *Expr;
133+
SingleLoc(DbgValueLoc ValueLoc)
134+
: ValueLoc(std::make_unique<DbgValueLoc>(ValueLoc)),
135+
Expr(ValueLoc.getExpression()) {
136+
if (!Expr->getNumElements())
137+
Expr = nullptr;
138+
}
139+
};
140+
/// Multi-value location description.
141+
struct MultiLoc {
142+
/// Index of the entry list in DebugLocs.
143+
unsigned DebugLocListIndex = ~0u;
144+
/// DW_OP_LLVM_tag_offset value from DebugLocs.
145+
std::optional<uint8_t> DebugLocListTagOffset;
146+
};
147+
/// Single location defined by (potentially multiple) MMI entries.
148+
struct MMILoc {
149+
mutable SmallVector<FrameIndexExpr, 1> FrameIndexExprs;
150+
};
151+
/// Single location defined by (potentially multiple) EntryValueInfo.
152+
struct EntryValueLoc {
153+
std::set<EntryValueInfo> EntryValues;
154+
EntryValueLoc(MCRegister Reg, const DIExpression &Expr) {
130155
addExpr(Reg, Expr);
131156
};
132-
133157
// Add the pair Reg, Expr to the list of entry values describing the variable.
134158
// If multiple expressions are added, it is the callers responsibility to
135159
// ensure they are all non-overlapping fragments.
@@ -140,46 +164,48 @@ class DbgVariableEntryValue {
140164

141165
EntryValues.insert({Reg, **NonVariadicExpr});
142166
}
143-
144-
/// Returns the set of EntryValueInfo.
145-
const std::set<EntryValueInfo> &getEntryValuesInfo() const {
146-
return EntryValues;
147-
}
148167
};
168+
} // namespace
149169

150170
//===----------------------------------------------------------------------===//
151171
/// This class is used to track local variable information.
152172
///
173+
/// Variables that have been optimized out hold the \c monostate alternative.
174+
/// This is not distinguished from the case of a constructed \c DbgVariable
175+
/// which has not be initialized yet.
176+
///
153177
/// Variables can be created from allocas, in which case they're generated from
154-
/// the MMI table. Such variables can have multiple expressions and frame
155-
/// indices.
178+
/// the MMI table. Such variables hold the \c MMILoc alternative which can have
179+
/// multiple expressions and frame indices.
156180
///
157181
/// 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.
182+
/// they're generated from the MMI table. Such variables hold the \c
183+
/// EntryValueLoc alternative which can either have a single expression or
184+
/// multiple *fragment* expressions.
160185
///
161-
/// Variables can be created from \c DBG_VALUE instructions. Those whose
162-
/// location changes over time use \a DebugLocListIndex, while those with a
163-
/// single location use \a ValueLoc and (optionally) a single entry of \a Expr.
164-
///
165-
/// Variables that have been optimized out use none of these fields.
166-
class DbgVariable : public DbgEntity {
167-
/// Index of the entry list in DebugLocs.
168-
unsigned DebugLocListIndex = ~0u;
169-
/// DW_OP_LLVM_tag_offset value from DebugLocs.
170-
std::optional<uint8_t> DebugLocListTagOffset;
171-
172-
/// Single value location description.
173-
std::unique_ptr<DbgValueLoc> ValueLoc = nullptr;
174-
175-
struct FrameIndexExpr {
176-
int FI;
177-
const DIExpression *Expr;
178-
};
179-
mutable SmallVector<FrameIndexExpr, 1>
180-
FrameIndexExprs; /// Frame index + expression.
181-
182-
std::optional<DbgVariableEntryValue> EntryValue;
186+
/// Variables can be created from \c DBG_VALUE instructions. Those whose
187+
/// location changes over time hold a \c MultiLoc alternative which uses \c
188+
/// DebugLocListIndex and (optionally) \c DebugLocListTagOffset, while those
189+
/// with a single location hold a \c SingleLoc alternative which use \c ValueLoc
190+
/// and (optionally) a single \c Expr.
191+
class DbgVariable : public DbgEntity,
192+
private std::variant<std::monostate, SingleLoc, MultiLoc,
193+
MMILoc, EntryValueLoc> {
194+
195+
/// Member shorthand for std::holds_alternative
196+
template <typename T> bool holds() const {
197+
return std::holds_alternative<T>(*this);
198+
}
199+
/// Asserting, noexcept member alternative to std::get
200+
template <typename T> auto &get() noexcept {
201+
assert(holds<T>());
202+
return *std::get_if<T>(this);
203+
}
204+
/// Asserting, noexcept member alternative to std::get
205+
template <typename T> const auto &get() const noexcept {
206+
assert(holds<T>());
207+
return *std::get_if<T>(this);
208+
}
183209

184210
public:
185211
/// Construct a DbgVariable.
@@ -189,41 +215,27 @@ class DbgVariable : public DbgEntity {
189215
DbgVariable(const DILocalVariable *V, const DILocation *IA)
190216
: DbgEntity(V, IA, DbgVariableKind) {}
191217

192-
bool isInitialized() const {
193-
return !FrameIndexExprs.empty() || ValueLoc || EntryValue;
194-
}
195-
196218
/// Initialize from the MMI table.
197-
void initializeMMI(const DIExpression *E, int FI) {
198-
assert(!isInitialized() && "Already initialized?");
199-
200-
assert((!E || E->isValid()) && "Expected valid expression");
201-
assert(FI != std::numeric_limits<int>::max() && "Expected valid index");
202-
203-
FrameIndexExprs.push_back({FI, E});
204-
}
219+
void initializeMMI(const DIExpression *E, int FI);
205220

206221
// Initialize variable's location.
207-
void initializeDbgValue(DbgValueLoc Value) {
208-
assert(!isInitialized() && "Already initialized?");
209-
assert(!Value.getExpression()->isFragment() && "Fragments not supported.");
222+
void initializeDbgValue(DbgValueLoc Value);
210223

211-
ValueLoc = std::make_unique<DbgValueLoc>(Value);
212-
if (auto *E = ValueLoc->getExpression())
213-
if (E->getNumElements())
214-
FrameIndexExprs.push_back({0, E});
215-
}
224+
void initializeEntryValue(MCRegister Reg, const DIExpression &Expr);
216225

217-
void initializeEntryValue(MCRegister Reg, const DIExpression &Expr) {
218-
assert(!isInitialized() && "Already initialized?");
219-
EntryValue = DbgVariableEntryValue(Reg, Expr);
226+
const std::set<EntryValueInfo> *getEntryValues() const {
227+
if (const auto *EV = std::get_if<EntryValueLoc>(this))
228+
return &EV->EntryValues;
229+
return nullptr;
220230
}
221-
222-
const std::optional<DbgVariableEntryValue> &getEntryValue() const {
223-
return EntryValue;
231+
std::set<EntryValueInfo> *getEntryValues() {
232+
if (auto *EV = std::get_if<EntryValueLoc>(this))
233+
return &EV->EntryValues;
234+
return nullptr;
235+
}
236+
void addEntryValueExpr(MCRegister Reg, const DIExpression &Expr) {
237+
get<EntryValueLoc>().addExpr(Reg, Expr);
224238
}
225-
226-
std::optional<DbgVariableEntryValue> &getEntryValue() { return EntryValue; }
227239

228240
/// Initialize from a DBG_VALUE instruction.
229241
void initializeDbgValue(const MachineInstr *DbgValue);
@@ -234,21 +246,38 @@ class DbgVariable : public DbgEntity {
234246
}
235247

236248
const DIExpression *getSingleExpression() const {
237-
assert(ValueLoc.get() && FrameIndexExprs.size() <= 1);
238-
return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr;
249+
return get<SingleLoc>().Expr;
239250
}
240251

241-
void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; }
242-
unsigned getDebugLocListIndex() const { return DebugLocListIndex; }
243-
void setDebugLocListTagOffset(uint8_t O) { DebugLocListTagOffset = O; }
252+
void setDebugLocListIndex(uint8_t O) {
253+
if (auto *M = std::get_if<MultiLoc>(this))
254+
M->DebugLocListIndex = O;
255+
else
256+
emplace<MultiLoc>().DebugLocListIndex = O;
257+
}
258+
unsigned getDebugLocListIndex() const {
259+
if (auto *M = std::get_if<MultiLoc>(this))
260+
return M->DebugLocListIndex;
261+
return ~0U;
262+
}
263+
void setDebugLocListTagOffset(uint8_t O) {
264+
if (auto *M = std::get_if<MultiLoc>(this))
265+
M->DebugLocListTagOffset = O;
266+
else
267+
emplace<MultiLoc>().DebugLocListTagOffset = O;
268+
}
244269
std::optional<uint8_t> getDebugLocListTagOffset() const {
245-
return DebugLocListTagOffset;
270+
return get<MultiLoc>().DebugLocListTagOffset;
246271
}
247272
StringRef getName() const { return getVariable()->getName(); }
248-
const DbgValueLoc *getValueLoc() const { return ValueLoc.get(); }
273+
const DbgValueLoc *getValueLoc() const {
274+
if (auto *M = std::get_if<SingleLoc>(this))
275+
return M->ValueLoc.get();
276+
return nullptr;
277+
}
249278
/// Get the FI entries, sorted by fragment offset.
250279
ArrayRef<FrameIndexExpr> getFrameIndexExprs() const;
251-
bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); }
280+
bool hasFrameIndexExprs() const { return holds<MMILoc>(); }
252281
void addMMIEntry(const DbgVariable &V);
253282

254283
// Translate tag to proper Dwarf tag.
@@ -277,14 +306,7 @@ class DbgVariable : public DbgEntity {
277306
return false;
278307
}
279308

280-
bool hasComplexAddress() const {
281-
assert(ValueLoc.get() && "Expected DBG_VALUE, not MMI variable");
282-
assert((FrameIndexExprs.empty() ||
283-
(FrameIndexExprs.size() == 1 &&
284-
FrameIndexExprs[0].Expr->getNumElements())) &&
285-
"Invalid Expr for DBG_VALUE");
286-
return !FrameIndexExprs.empty();
287-
}
309+
bool hasComplexAddress() const { return get<SingleLoc>().Expr; }
288310

289311
const DIType *getType() const;
290312

0 commit comments

Comments
 (0)