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
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- DebugInfo.h - Debug Information Helpers ------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines a bunch of datatypes that are useful for creating and
// walking debug info in LLVM IR form. They essentially provide wrappers around
// the information in the global variables that's needed when constructing the
// DWARF information.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_DEBUGINFO_H
#define LLVM_IR_DEBUGINFO_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PassManager.h"
#include <optional>
namespace llvm {
class DbgDeclareInst;
class DbgValueInst;
class DbgVariableIntrinsic;
class Instruction;
class Module;
/// Finds all intrinsics declaring local variables as living in the memory that
/// 'V' points to. This may include a mix of dbg.declare and
/// dbg.addr intrinsics.
TinyPtrVector<DbgVariableIntrinsic *> FindDbgAddrUses(Value *V);
/// Like \c FindDbgAddrUses, but only returns dbg.declare intrinsics, not
/// dbg.addr.
TinyPtrVector<DbgDeclareInst *> FindDbgDeclareUses(Value *V);
/// Finds the llvm.dbg.value intrinsics describing a value.
void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V);
/// Finds the debug info intrinsics describing a value.
void findDbgUsers(SmallVectorImpl<DbgVariableIntrinsic *> &DbgInsts, Value *V);
/// Find subprogram that is enclosing this scope.
DISubprogram *getDISubprogram(const MDNode *Scope);
/// Produce a DebugLoc to use for each dbg.declare that is promoted to a
/// dbg.value.
DebugLoc getDebugValueLoc(DbgVariableIntrinsic *DII);
/// Strip debug info in the module if it exists.
///
/// To do this, we remove all calls to the debugger intrinsics and any named
/// metadata for debugging. We also remove debug locations for instructions.
/// Return true if module is modified.
bool StripDebugInfo(Module &M);
bool stripDebugInfo(Function &F);
/// Downgrade the debug info in a module to contain only line table information.
///
/// In order to convert debug info to what -gline-tables-only would have
/// created, this does the following:
/// 1) Delete all debug intrinsics.
/// 2) Delete all non-CU named metadata debug info nodes.
/// 3) Create new DebugLocs for each instruction.
/// 4) Create a new CU debug info, and similarly for every metadata node
/// that's reachable from the CU debug info.
/// All debug type metadata nodes are unreachable and garbage collected.
bool stripNonLineTableDebugInfo(Module &M);
/// Update the debug locations contained within the MD_loop metadata attached
/// to the instruction \p I, if one exists. \p Updater is applied to Metadata
/// operand in the MD_loop metadata: the returned value is included in the
/// updated loop metadata node if it is non-null.
void updateLoopMetadataDebugLocations(
Instruction &I, function_ref<Metadata *(Metadata *)> Updater);
/// Return Debug Info Metadata Version by checking module flags.
unsigned getDebugMetadataVersionFromModule(const Module &M);
/// Utility to find all debug info in a module.
///
/// DebugInfoFinder tries to list all debug info MDNodes used in a module. To
/// list debug info MDNodes used by an instruction, DebugInfoFinder uses
/// processDeclare, processValue and processLocation to handle DbgDeclareInst,
/// DbgValueInst and DbgLoc attached to instructions. processModule will go
/// through all DICompileUnits in llvm.dbg.cu and list debug info MDNodes
/// used by the CUs.
class DebugInfoFinder {
public:
/// Process entire module and collect debug info anchors.
void processModule(const Module &M);
/// Process a single instruction and collect debug info anchors.
void processInstruction(const Module &M, const Instruction &I);
/// Process DbgVariableIntrinsic.
void processVariable(const Module &M, const DbgVariableIntrinsic &DVI);
/// Process debug info location.
void processLocation(const Module &M, const DILocation *Loc);
/// Process subprogram.
void processSubprogram(DISubprogram *SP);
/// Clear all lists.
void reset();
private:
void processCompileUnit(DICompileUnit *CU);
void processScope(DIScope *Scope);
void processType(DIType *DT);
bool addCompileUnit(DICompileUnit *CU);
bool addGlobalVariable(DIGlobalVariableExpression *DIG);
bool addScope(DIScope *Scope);
bool addSubprogram(DISubprogram *SP);
bool addType(DIType *DT);
public:
using compile_unit_iterator =
SmallVectorImpl<DICompileUnit *>::const_iterator;
using subprogram_iterator = SmallVectorImpl<DISubprogram *>::const_iterator;
using global_variable_expression_iterator =
SmallVectorImpl<DIGlobalVariableExpression *>::const_iterator;
using type_iterator = SmallVectorImpl<DIType *>::const_iterator;
using scope_iterator = SmallVectorImpl<DIScope *>::const_iterator;
iterator_range<compile_unit_iterator> compile_units() const {
return make_range(CUs.begin(), CUs.end());
}
iterator_range<subprogram_iterator> subprograms() const {
return make_range(SPs.begin(), SPs.end());
}
iterator_range<global_variable_expression_iterator> global_variables() const {
return make_range(GVs.begin(), GVs.end());
}
iterator_range<type_iterator> types() const {
return make_range(TYs.begin(), TYs.end());
}
iterator_range<scope_iterator> scopes() const {
return make_range(Scopes.begin(), Scopes.end());
}
unsigned compile_unit_count() const { return CUs.size(); }
unsigned global_variable_count() const { return GVs.size(); }
unsigned subprogram_count() const { return SPs.size(); }
unsigned type_count() const { return TYs.size(); }
unsigned scope_count() const { return Scopes.size(); }
private:
SmallVector<DICompileUnit *, 8> CUs;
SmallVector<DISubprogram *, 8> SPs;
SmallVector<DIGlobalVariableExpression *, 8> GVs;
SmallVector<DIType *, 8> TYs;
SmallVector<DIScope *, 8> Scopes;
SmallPtrSet<const MDNode *, 32> NodesSeen;
};
/// Assignment Tracking (at).
namespace at {
//
// Utilities for enumerating storing instructions from an assignment ID.
//
/// A range of instructions.
using AssignmentInstRange =
iterator_range<SmallVectorImpl<Instruction *>::iterator>;
/// Return a range of instructions (typically just one) that have \p ID
/// as an attachment.
/// Iterators invalidated by adding or removing DIAssignID metadata to/from any
/// instruction (including by deleting or cloning instructions).
AssignmentInstRange getAssignmentInsts(DIAssignID *ID);
/// Return a range of instructions (typically just one) that perform the
/// assignment that \p DAI encodes.
/// Iterators invalidated by adding or removing DIAssignID metadata to/from any
/// instruction (including by deleting or cloning instructions).
inline AssignmentInstRange getAssignmentInsts(const DbgAssignIntrinsic *DAI) {
return getAssignmentInsts(DAI->getAssignID());
}
//
// Utilities for enumerating llvm.dbg.assign intrinsic from an assignment ID.
//
/// High level: this is an iterator for llvm.dbg.assign intrinsics.
/// Implementation details: this is a wrapper around Value's User iterator that
/// dereferences to a DbgAssignIntrinsic ptr rather than a User ptr.
class DbgAssignIt
: public iterator_adaptor_base<DbgAssignIt, Value::user_iterator,
typename std::iterator_traits<
Value::user_iterator>::iterator_category,
DbgAssignIntrinsic *, std::ptrdiff_t,
DbgAssignIntrinsic **,
DbgAssignIntrinsic *&> {
public:
DbgAssignIt(Value::user_iterator It) : iterator_adaptor_base(It) {}
DbgAssignIntrinsic *operator*() const { return cast<DbgAssignIntrinsic>(*I); }
};
/// A range of llvm.dbg.assign intrinsics.
using AssignmentMarkerRange = iterator_range<DbgAssignIt>;
/// Return a range of dbg.assign intrinsics which use \ID as an operand.
/// Iterators invalidated by deleting an intrinsic contained in this range.
AssignmentMarkerRange getAssignmentMarkers(DIAssignID *ID);
/// Return a range of dbg.assign intrinsics for which \p Inst performs the
/// assignment they encode.
/// Iterators invalidated by deleting an intrinsic contained in this range.
inline AssignmentMarkerRange getAssignmentMarkers(const Instruction *Inst) {
if (auto *ID = Inst->getMetadata(LLVMContext::MD_DIAssignID))
return getAssignmentMarkers(cast<DIAssignID>(ID));
else
return make_range(Value::user_iterator(), Value::user_iterator());
}
/// Delete the llvm.dbg.assign intrinsics linked to \p Inst.
void deleteAssignmentMarkers(const Instruction *Inst);
/// Replace all uses (and attachments) of \p Old with \p New.
void RAUW(DIAssignID *Old, DIAssignID *New);
/// Remove all Assignment Tracking related intrinsics and metadata from \p F.
void deleteAll(Function *F);
/// Helper struct for trackAssignments, below. We don't use the similar
/// DebugVariable class because trackAssignments doesn't (yet?) understand
/// partial variables (fragment info) as input and want to make that clear and
/// explicit using types. In addition, eventually we will want to understand
/// expressions that modify the base address too, which a DebugVariable doesn't
/// capture.
struct VarRecord {
DILocalVariable *Var;
DILocation *DL;
VarRecord(DbgVariableIntrinsic *DVI)
: Var(DVI->getVariable()), DL(getDebugValueLoc(DVI)) {}
VarRecord(DILocalVariable *Var, DILocation *DL) : Var(Var), DL(DL) {}
friend bool operator<(const VarRecord &LHS, const VarRecord &RHS) {
return std::tie(LHS.Var, LHS.DL) < std::tie(RHS.Var, RHS.DL);
}
friend bool operator==(const VarRecord &LHS, const VarRecord &RHS) {
return std::tie(LHS.Var, LHS.DL) == std::tie(RHS.Var, RHS.DL);
}
};
/// Map of backing storage to a set of variables that are stored to it.
/// TODO: Backing storage shouldn't be limited to allocas only. Some local
/// variables have their storage allocated by the calling function (addresses
/// passed in with sret & byval parameters).
using StorageToVarsMap = DenseMap<const AllocaInst *, SmallSet<VarRecord, 2>>;
/// Track assignments to \p Vars between \p Start and \p End.
void trackAssignments(Function::iterator Start, Function::iterator End,
const StorageToVarsMap &Vars, const DataLayout &DL,
bool DebugPrints = false);
/// Describes properties of a store that has a static size and offset into a
/// some base storage. Used by the getAssignmentInfo functions.
struct AssignmentInfo {
AllocaInst const *Base; ///< Base storage.
uint64_t OffsetInBits; ///< Offset into Base.
uint64_t SizeInBits; ///< Number of bits stored.
bool StoreToWholeAlloca; ///< SizeInBits equals the size of the base storage.
AssignmentInfo(const DataLayout &DL, AllocaInst const *Base,
uint64_t OffsetInBits, uint64_t SizeInBits)
: Base(Base), OffsetInBits(OffsetInBits), SizeInBits(SizeInBits),
StoreToWholeAlloca(
OffsetInBits == 0 &&
SizeInBits == DL.getTypeSizeInBits(Base->getAllocatedType())) {}
};
std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
const MemIntrinsic *I);
std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
const StoreInst *SI);
std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
const AllocaInst *AI);
} // end namespace at
/// Convert @llvm.dbg.declare intrinsics into sets of @llvm.dbg.assign
/// intrinsics by treating stores to the dbg.declare'd address as assignments
/// to the variable. Not all kinds of variables are supported yet; those will
/// be left with their dbg.declare intrinsics.
/// The pass sets the debug-info-assignment-tracking module flag to true to
/// indicate assignment tracking has been enabled.
class AssignmentTrackingPass : public PassInfoMixin<AssignmentTrackingPass> {
/// Note: this method does not set the debug-info-assignment-tracking module
/// flag.
void runOnFunction(Function &F);
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
/// Return true if assignment tracking is enabled for module \p M.
bool isAssignmentTrackingEnabled(const Module &M);
} // end namespace llvm
#endif // LLVM_IR_DEBUGINFO_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|