1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===-- llvm/DebugProgramInstruction.h - Stream of debug info -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Data structures for storing variable assignment information in LLVM. In the
// dbg.value design, a dbg.value intrinsic specifies the position in a block
// a source variable take on an LLVM Value:
//
// %foo = add i32 1, %0
// dbg.value(metadata i32 %foo, ...)
// %bar = void call @ext(%foo);
//
// and all information is stored in the Value / Metadata hierachy defined
// elsewhere in LLVM. In the "DPValue" design, each instruction /may/ have a
// connection with a DPMarker, which identifies a position immediately before the
// instruction, and each DPMarker /may/ then have connections to DPValues which
// record the variable assignment information. To illustrate:
//
// %foo = add i32 1, %0
// ; foo->DbgMarker == nullptr
// ;; There are no variable assignments / debug records "in front" of
// ;; the instruction for %foo, therefore it has no DbgMarker.
// %bar = void call @ext(%foo)
// ; bar->DbgMarker = {
// ; StoredDPValues = {
// ; DPValue(metadata i32 %foo, ...)
// ; }
// ; }
// ;; There is a debug-info record in front of the %bar instruction,
// ;; thus it points at a DPMarker object. That DPMarker contains a
// ;; DPValue in it's ilist, storing the equivalent information to the
// ;; dbg.value above: the Value, DILocalVariable, etc.
//
// This structure separates the two concerns of the position of the debug-info
// in the function, and the Value that it refers to. It also creates a new
// "place" in-between the Value / Metadata hierachy where we can customise
// storage and allocation techniques to better suite debug-info workloads.
// NB: as of the initial prototype, none of that has actually been attempted
// yet.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
#define LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/iterator.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/SymbolTableListTraits.h"
namespace llvm {
class Instruction;
class BasicBlock;
class MDNode;
class Module;
class DbgVariableIntrinsic;
class DIAssignID;
class DPMarker;
class DPValue;
class raw_ostream;
/// Record of a variable value-assignment, aka a non instruction representation
/// of the dbg.value intrinsic. Features various methods copied across from the
/// Instruction class to aid ease-of-use. DPValue objects should always be
/// linked into a DPMarker's StoredDPValues list. The marker connects a DPValue
/// back to it's position in the BasicBlock.
///
/// This class inherits from DebugValueUser to allow LLVM's metadata facilities
/// to update our references to metadata beneath our feet.
class DPValue : public ilist_node<DPValue>, private DebugValueUser {
friend class DebugValueUser;
// NB: there is no explicit "Value" field in this class, it's effectively the
// DebugValueUser superclass instead. The referred to Value can either be a
// ValueAsMetadata or a DIArgList.
DILocalVariable *Variable;
DIExpression *Expression;
DebugLoc DbgLoc;
DIExpression *AddressExpression;
public:
void deleteInstr();
const BasicBlock *getParent() const;
BasicBlock *getParent();
void dump() const;
void removeFromParent();
void eraseFromParent();
DPValue *getNextNode() { return &*std::next(getIterator()); }
DPValue *getPrevNode() { return &*std::prev(getIterator()); }
using self_iterator = simple_ilist<DPValue>::iterator;
using const_self_iterator = simple_ilist<DPValue>::const_iterator;
enum class LocationType {
Declare,
Value,
Assign,
End, ///< Marks the end of the concrete types.
Any, ///< To indicate all LocationTypes in searches.
};
/// Classification of the debug-info record that this DPValue represents.
/// Essentially, "is this a dbg.value or dbg.declare?". dbg.declares are not
/// currently supported, but it would be trivial to do so.
LocationType Type;
/// Marker that this DPValue is linked into.
DPMarker *Marker = nullptr;
/// Create a new DPValue representing the intrinsic \p DVI, for example the
/// assignment represented by a dbg.value.
DPValue(const DbgVariableIntrinsic *DVI);
DPValue(const DPValue &DPV);
/// Directly construct a new DPValue representing a dbg.value intrinsic
/// assigning \p Location to the DV / Expr / DI variable.
DPValue(Metadata *Location, DILocalVariable *DV, DIExpression *Expr,
const DILocation *DI, LocationType Type = LocationType::Value);
DPValue(Metadata *Value, DILocalVariable *Variable, DIExpression *Expression,
DIAssignID *AssignID, Metadata *Address,
DIExpression *AddressExpression, const DILocation *DI);
static DPValue *createDPVAssign(Value *Val, DILocalVariable *Variable,
DIExpression *Expression,
DIAssignID *AssignID, Value *Address,
DIExpression *AddressExpression,
const DILocation *DI);
static DPValue *createLinkedDPVAssign(Instruction *LinkedInstr, Value *Val,
DILocalVariable *Variable,
DIExpression *Expression,
Value *Address,
DIExpression *AddressExpression,
const DILocation *DI);
static DPValue *createDPValue(Value *Location, DILocalVariable *DV,
DIExpression *Expr, const DILocation *DI);
static DPValue *createDPValue(Value *Location, DILocalVariable *DV,
DIExpression *Expr, const DILocation *DI,
DPValue &InsertBefore);
static DPValue *createDPVDeclare(Value *Address, DILocalVariable *DV,
DIExpression *Expr, const DILocation *DI);
static DPValue *createDPVDeclare(Value *Address, DILocalVariable *DV,
DIExpression *Expr, const DILocation *DI,
DPValue &InsertBefore);
/// Iterator for ValueAsMetadata that internally uses direct pointer iteration
/// over either a ValueAsMetadata* or a ValueAsMetadata**, dereferencing to the
/// ValueAsMetadata .
class location_op_iterator
: public iterator_facade_base<location_op_iterator,
std::bidirectional_iterator_tag, Value *> {
PointerUnion<ValueAsMetadata *, ValueAsMetadata **> I;
public:
location_op_iterator(ValueAsMetadata *SingleIter) : I(SingleIter) {}
location_op_iterator(ValueAsMetadata **MultiIter) : I(MultiIter) {}
location_op_iterator(const location_op_iterator &R) : I(R.I) {}
location_op_iterator &operator=(const location_op_iterator &R) {
I = R.I;
return *this;
}
bool operator==(const location_op_iterator &RHS) const {
return I == RHS.I;
}
const Value *operator*() const {
ValueAsMetadata *VAM = I.is<ValueAsMetadata *>()
? I.get<ValueAsMetadata *>()
: *I.get<ValueAsMetadata **>();
return VAM->getValue();
};
Value *operator*() {
ValueAsMetadata *VAM = I.is<ValueAsMetadata *>()
? I.get<ValueAsMetadata *>()
: *I.get<ValueAsMetadata **>();
return VAM->getValue();
}
location_op_iterator &operator++() {
if (I.is<ValueAsMetadata *>())
I = I.get<ValueAsMetadata *>() + 1;
else
I = I.get<ValueAsMetadata **>() + 1;
return *this;
}
location_op_iterator &operator--() {
if (I.is<ValueAsMetadata *>())
I = I.get<ValueAsMetadata *>() - 1;
else
I = I.get<ValueAsMetadata **>() - 1;
return *this;
}
};
bool isDbgDeclare() { return Type == LocationType::Declare; }
bool isDbgValue() { return Type == LocationType::Value; }
/// Get the locations corresponding to the variable referenced by the debug
/// info intrinsic. Depending on the intrinsic, this could be the
/// variable's value or its address.
iterator_range<location_op_iterator> location_ops() const;
Value *getVariableLocationOp(unsigned OpIdx) const;
void replaceVariableLocationOp(Value *OldValue, Value *NewValue,
bool AllowEmpty = false);
void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
/// Adding a new location operand will always result in this intrinsic using
/// an ArgList, and must always be accompanied by a new expression that uses
/// the new operand.
void addVariableLocationOps(ArrayRef<Value *> NewValues,
DIExpression *NewExpr);
void setVariable(DILocalVariable *NewVar) { Variable = NewVar; }
void setExpression(DIExpression *NewExpr) { Expression = NewExpr; }
unsigned getNumVariableLocationOps() const;
bool hasArgList() const { return isa<DIArgList>(getRawLocation()); }
/// Returns true if this DPValue has no empty MDNodes in its location list.
bool hasValidLocation() const { return getVariableLocationOp(0) != nullptr; }
/// Does this describe the address of a local variable. True for dbg.addr
/// and dbg.declare, but not dbg.value, which describes its value.
bool isAddressOfVariable() const { return Type == LocationType::Declare; }
LocationType getType() const { return Type; }
DebugLoc getDebugLoc() const { return DbgLoc; }
void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); }
void setKillLocation();
bool isKillLocation() const;
DILocalVariable *getVariable() const { return Variable; }
DIExpression *getExpression() const { return Expression; }
/// Returns the metadata operand for the first location description. i.e.,
/// dbg intrinsic dbg.value,declare operand and dbg.assign 1st location
/// operand (the "value componenet"). Note the operand (singular) may be
/// a DIArgList which is a list of values.
Metadata *getRawLocation() const { return DebugValues[0]; }
Value *getValue(unsigned OpIdx = 0) const {
return getVariableLocationOp(OpIdx);
}
/// Use of this should generally be avoided; instead,
/// replaceVariableLocationOp and addVariableLocationOps should be used where
/// possible to avoid creating invalid state.
void setRawLocation(Metadata *NewLocation) {
assert(
(isa<ValueAsMetadata>(NewLocation) || isa<DIArgList>(NewLocation) ||
isa<MDNode>(NewLocation)) &&
"Location for a DPValue must be either ValueAsMetadata or DIArgList");
resetDebugValue(0, NewLocation);
}
/// Get the size (in bits) of the variable, or fragment of the variable that
/// is described.
std::optional<uint64_t> getFragmentSizeInBits() const;
bool isEquivalentTo(const DPValue &Other) {
return std::tie(Type, DebugValues, Variable, Expression, DbgLoc) ==
std::tie(Other.Type, Other.DebugValues, Other.Variable,
Other.Expression, Other.DbgLoc);
}
// Matches the definition of the Instruction version, equivalent to above but
// without checking DbgLoc.
bool isIdenticalToWhenDefined(const DPValue &Other) {
return std::tie(Type, DebugValues, Variable, Expression) ==
std::tie(Other.Type, Other.DebugValues, Other.Variable,
Other.Expression);
}
/// @name DbgAssign Methods
/// @{
bool isDbgAssign() const { return getType() == LocationType::Assign; }
Value *getAddress() const;
Metadata *getRawAddress() const {
return isDbgAssign() ? DebugValues[1] : DebugValues[0];
}
Metadata *getRawAssignID() const { return DebugValues[2]; }
DIAssignID *getAssignID() const;
DIExpression *getAddressExpression() const { return AddressExpression; }
void setAddressExpression(DIExpression *NewExpr) {
AddressExpression = NewExpr;
}
void setAssignId(DIAssignID *New);
void setAddress(Value *V) { resetDebugValue(1, ValueAsMetadata::get(V)); }
/// Kill the address component.
void setKillAddress();
/// Check whether this kills the address component. This doesn't take into
/// account the position of the intrinsic, therefore a returned value of false
/// does not guarentee the address is a valid location for the variable at the
/// intrinsic's position in IR.
bool isKillAddress() const;
/// @}
DPValue *clone() const;
/// Convert this DPValue back into a dbg.value intrinsic.
/// \p InsertBefore Optional position to insert this intrinsic.
/// \returns A new dbg.value intrinsic representiung this DPValue.
DbgVariableIntrinsic *createDebugIntrinsic(Module *M,
Instruction *InsertBefore) const;
void setMarker(DPMarker *M) { Marker = M; }
DPMarker *getMarker() { return Marker; }
const DPMarker *getMarker() const { return Marker; }
BasicBlock *getBlock();
const BasicBlock *getBlock() const;
Function *getFunction();
const Function *getFunction() const;
Module *getModule();
const Module *getModule() const;
LLVMContext &getContext();
const LLVMContext &getContext() const;
/// Insert this DPValue prior to \p InsertBefore. Must not be called if this
/// is already contained in a DPMarker.
void insertBefore(DPValue *InsertBefore);
void insertAfter(DPValue *InsertAfter);
void moveBefore(DPValue *MoveBefore);
void moveAfter(DPValue *MoveAfter);
void print(raw_ostream &O, bool IsForDebug = false) const;
void print(raw_ostream &ROS, ModuleSlotTracker &MST, bool IsForDebug) const;
};
/// Per-instruction record of debug-info. If an Instruction is the position of
/// some debugging information, it points at a DPMarker storing that info. Each
/// marker points back at the instruction that owns it. Various utilities are
/// provided for manipulating the DPValues contained within this marker.
///
/// This class has a rough surface area, because it's needed to preserve the one
/// arefact that we can't yet eliminate from the intrinsic / dbg.value
/// debug-info design: the order of DPValues/records is significant, and
/// duplicates can exist. Thus, if one has a run of debug-info records such as:
/// dbg.value(...
/// %foo = barinst
/// dbg.value(...
/// and remove barinst, then the dbg.values must be preserved in the correct
/// order. Hence, the use of iterators to select positions to insert things
/// into, or the occasional InsertAtHead parameter indicating that new records
/// should go at the start of the list.
///
/// There are only five or six places in LLVM that truly rely on this ordering,
/// which we can improve in the future. Additionally, many improvements in the
/// way that debug-info is stored can be achieved in this class, at a future
/// date.
class DPMarker {
public:
DPMarker() {}
/// Link back to the Instruction that owns this marker. Can be null during
/// operations that move a marker from one instruction to another.
Instruction *MarkedInstr = nullptr;
/// List of DPValues, each recording a single variable assignment, the
/// equivalent of a dbg.value intrinsic. There is a one-to-one relationship
/// between each dbg.value in a block and each DPValue once the
/// representation has been converted, and the ordering of DPValues is
/// meaningful in the same was a dbg.values.
simple_ilist<DPValue> StoredDPValues;
bool empty() const { return StoredDPValues.empty(); }
const BasicBlock *getParent() const;
BasicBlock *getParent();
/// Handle the removal of a marker: the position of debug-info has gone away,
/// but the stored debug records should not. Drop them onto the next
/// instruction, or otherwise work out what to do with them.
void removeMarker();
void dump() const;
void removeFromParent();
void eraseFromParent();
/// Implement operator<< on DPMarker.
void print(raw_ostream &O, bool IsForDebug = false) const;
void print(raw_ostream &ROS, ModuleSlotTracker &MST, bool IsForDebug) const;
/// Produce a range over all the DPValues in this Marker.
iterator_range<simple_ilist<DPValue>::iterator> getDbgValueRange();
iterator_range<simple_ilist<DPValue>::const_iterator>
getDbgValueRange() const;
/// Transfer any DPValues from \p Src into this DPMarker. If \p InsertAtHead
/// is true, place them before existing DPValues, otherwise afterwards.
void absorbDebugValues(DPMarker &Src, bool InsertAtHead);
/// Transfer the DPValues in \p Range from \p Src into this DPMarker. If
/// \p InsertAtHead is true, place them before existing DPValues, otherwise
// afterwards.
void absorbDebugValues(iterator_range<DPValue::self_iterator> Range,
DPMarker &Src, bool InsertAtHead);
/// Insert a DPValue into this DPMarker, at the end of the list. If
/// \p InsertAtHead is true, at the start.
void insertDPValue(DPValue *New, bool InsertAtHead);
/// Insert a DPValue prior to a DPValue contained within this marker.
void insertDPValue(DPValue *New, DPValue *InsertBefore);
/// Insert a DPValue after a DPValue contained within this marker.
void insertDPValueAfter(DPValue *New, DPValue *InsertAfter);
/// Clone all DPMarkers from \p From into this marker. There are numerous
/// options to customise the source/destination, due to gnarliness, see class
/// comment.
/// \p FromHere If non-null, copy from FromHere to the end of From's DPValues
/// \p InsertAtHead Place the cloned DPValues at the start of StoredDPValues
/// \returns Range over all the newly cloned DPValues
iterator_range<simple_ilist<DPValue>::iterator>
cloneDebugInfoFrom(DPMarker *From,
std::optional<simple_ilist<DPValue>::iterator> FromHere,
bool InsertAtHead = false);
/// Erase all DPValues in this DPMarker.
void dropDPValues();
/// Erase a single DPValue from this marker. In an ideal future, we would
/// never erase an assignment in this way, but it's the equivalent to
/// erasing a dbg.value from a block.
void dropOneDPValue(DPValue *DPV);
/// We generally act like all llvm Instructions have a range of DPValues
/// attached to them, but in reality sometimes we don't allocate the DPMarker
/// to save time and memory, but still have to return ranges of DPValues. When
/// we need to describe such an unallocated DPValue range, use this static
/// markers range instead. This will bite us if someone tries to insert a
/// DPValue in that range, but they should be using the Official (TM) API for
/// that.
static DPMarker EmptyDPMarker;
static iterator_range<simple_ilist<DPValue>::iterator> getEmptyDPValueRange(){
return make_range(EmptyDPMarker.StoredDPValues.end(), EmptyDPMarker.StoredDPValues.end());
}
};
inline raw_ostream &operator<<(raw_ostream &OS, const DPMarker &Marker) {
Marker.print(OS);
return OS;
}
inline raw_ostream &operator<<(raw_ostream &OS, const DPValue &Value) {
Value.print(OS);
return OS;
}
} // namespace llvm
#endif // LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|