Skip to content

Commit 913b561

Browse files
committed
[Assignment Tracking][6/*] Add trackAssignments function
The Assignment Tracking debug-info feature is outlined in this RFC: https://discourse.llvm.org/t/ rfc-assignment-tracking-a-better-way-of-specifying-variable-locations-in-ir Add trackAssignments which adds assignment tracking metadata to a function for a specified set of variables. The intended callers are the inliner and the front end - those calls will be added in separate patches. I've added a pass called declare-to-assign (AssignmentTrackingPass) that converts dbg.declare intrinsics to dbg.assigns using trackAssignments so that the function can be easily tested (see llvm/test/DebugInfo/Generic/track-assignments.ll). The pass could also be used by front ends to easily test out enabling assignment tracking. Reviewed By: jmorse Differential Revision: https://reviews.llvm.org/D132225
1 parent 322cf74 commit 913b561

File tree

7 files changed

+865
-1
lines changed

7 files changed

+865
-1
lines changed

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace llvm {
3737
class LLVMContext;
3838
class Module;
3939
class Value;
40+
class DbgAssignIntrinsic;
4041

4142
class DIBuilder {
4243
Module &M;
@@ -47,6 +48,7 @@ namespace llvm {
4748
Function *ValueFn; ///< llvm.dbg.value
4849
Function *LabelFn; ///< llvm.dbg.label
4950
Function *AddrFn; ///< llvm.dbg.addr
51+
Function *AssignFn; ///< llvm.dbg.assign
5052

5153
SmallVector<TrackingMDNodeRef, 4> AllEnumTypes;
5254
/// Track the RetainTypes, since they can be updated later on.
@@ -917,6 +919,26 @@ namespace llvm {
917919
DIExpression *Expr, const DILocation *DL,
918920
BasicBlock *InsertAtEnd);
919921

922+
/// Insert a new llvm.dbg.assign intrinsic call.
923+
/// \param LinkedInstr Instruction with a DIAssignID to link with the new
924+
/// intrinsic. The intrinsic will be inserted after
925+
/// this instruction.
926+
/// \param Val The value component of this dbg.assign.
927+
/// \param SrcVar Variable's debug info descriptor.
928+
/// \param ValExpr A complex location expression to modify \p Val.
929+
/// \param Addr The address component (store destination).
930+
/// \param AddrExpr A complex location expression to modify \p Addr.
931+
/// NOTE: \p ValExpr carries the FragInfo for the
932+
/// variable.
933+
/// \param DL Debug info location, usually: (line: 0,
934+
/// column: 0, scope: var-decl-scope). See
935+
/// getDebugValueLoc.
936+
DbgAssignIntrinsic *insertDbgAssign(Instruction *LinkedInstr, Value *Val,
937+
DILocalVariable *SrcVar,
938+
DIExpression *ValExpr, Value *Addr,
939+
DIExpression *AddrExpr,
940+
const DILocation *DL);
941+
920942
/// Insert a new llvm.dbg.declare intrinsic call.
921943
/// \param Storage llvm::Value of the variable
922944
/// \param VarInfo Variable's debug info descriptor.

llvm/include/llvm/IR/DebugInfo.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818

1919
#include "llvm/ADT/STLExtras.h"
2020
#include "llvm/ADT/SmallPtrSet.h"
21+
#include "llvm/ADT/SmallSet.h"
2122
#include "llvm/ADT/SmallVector.h"
2223
#include "llvm/ADT/TinyPtrVector.h"
2324
#include "llvm/ADT/iterator_range.h"
25+
#include "llvm/IR/DataLayout.h"
2426
#include "llvm/IR/IntrinsicInst.h"
27+
#include "llvm/IR/PassManager.h"
2528

2629
namespace llvm {
2730

@@ -225,8 +228,75 @@ void RAUW(DIAssignID *Old, DIAssignID *New);
225228
/// Remove all Assignment Tracking related intrinsics and metadata from \p F.
226229
void deleteAll(Function *F);
227230

231+
/// Helper struct for trackAssignments, below. We don't use the similar
232+
/// DebugVariable class because trackAssignments doesn't (yet?) understand
233+
/// partial variables (fragment info) as input and want to make that clear and
234+
/// explicit using types. In addition, eventually we will want to understand
235+
/// expressions that modify the base address too, which a DebugVariable doesn't
236+
/// capture.
237+
struct VarRecord {
238+
DILocalVariable *Var;
239+
DILocation *DL;
240+
241+
VarRecord(DbgVariableIntrinsic *DVI)
242+
: Var(DVI->getVariable()), DL(getDebugValueLoc(DVI)) {}
243+
VarRecord(DILocalVariable *Var, DILocation *DL) : Var(Var), DL(DL) {}
244+
friend bool operator<(const VarRecord &LHS, const VarRecord &RHS) {
245+
return std::tie(LHS.Var, LHS.DL) < std::tie(RHS.Var, RHS.DL);
246+
}
247+
friend bool operator==(const VarRecord &LHS, const VarRecord &RHS) {
248+
return std::tie(LHS.Var, LHS.DL) == std::tie(RHS.Var, RHS.DL);
249+
}
250+
};
251+
252+
/// Map of backing storage to a set of variables that are stored to it.
253+
/// TODO: Backing storage shouldn't be limited to allocas only. Some local
254+
/// variables have their storage allocated by the calling function (addresses
255+
/// passed in with sret & byval parameters).
256+
using StorageToVarsMap = DenseMap<const AllocaInst *, SmallSet<VarRecord, 2>>;
257+
258+
/// Track assignments to \p Vars between \p Start and \p End.
259+
260+
void trackAssignments(Function::iterator Start, Function::iterator End,
261+
const StorageToVarsMap &Vars, const DataLayout &DL,
262+
bool DebugPrints = false);
263+
264+
/// Describes properties of a store that has a static size and offset into a
265+
/// some base storage. Used by the getAssignmentInfo functions.
266+
struct AssignmentInfo {
267+
AllocaInst const *Base; ///< Base storage.
268+
uint64_t OffsetInBits; ///< Offset into Base.
269+
uint64_t SizeInBits; ///< Number of bits stored.
270+
bool StoreToWholeAlloca; ///< SizeInBits equals the size of the base storage.
271+
272+
AssignmentInfo(const DataLayout &DL, AllocaInst const *Base,
273+
uint64_t OffsetInBits, uint64_t SizeInBits)
274+
: Base(Base), OffsetInBits(OffsetInBits), SizeInBits(SizeInBits),
275+
StoreToWholeAlloca(
276+
OffsetInBits == 0 &&
277+
SizeInBits == DL.getTypeSizeInBits(Base->getAllocatedType())) {}
278+
};
279+
280+
Optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
281+
const MemIntrinsic *I);
282+
Optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
283+
const StoreInst *SI);
284+
Optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL,
285+
const AllocaInst *AI);
286+
228287
} // end namespace at
229288

289+
/// Convert @llvm.dbg.declare intrinsics into sets of @llvm.dbg.assign
290+
/// intrinsics by treating stores to the dbg.declare'd address as assignments
291+
/// to the variable. Not all kinds of variables are supported yet; those will
292+
/// be left with their dbg.declare intrinsics.
293+
class AssignmentTrackingPass : public PassInfoMixin<AssignmentTrackingPass> {
294+
public:
295+
void runOnFunction(Function &F);
296+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
297+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
298+
};
299+
230300
/// Return true if assignment tracking is enabled.
231301
bool getEnableAssignmentTracking();
232302
} // end namespace llvm

llvm/lib/IR/DIBuilder.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static cl::opt<bool>
3030

3131
DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU)
3232
: M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr),
33-
ValueFn(nullptr), LabelFn(nullptr), AddrFn(nullptr),
33+
ValueFn(nullptr), LabelFn(nullptr), AddrFn(nullptr), AssignFn(nullptr),
3434
AllowUnresolvedNodes(AllowUnresolvedNodes) {
3535
if (CUNode) {
3636
if (const auto &ETs = CUNode->getEnumTypes())
@@ -960,6 +960,36 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
960960
return insertDeclare(Storage, VarInfo, Expr, DL, InsertAtEnd, InsertBefore);
961961
}
962962

963+
DbgAssignIntrinsic *
964+
DIBuilder::insertDbgAssign(Instruction *LinkedInstr, Value *Val,
965+
DILocalVariable *SrcVar, DIExpression *ValExpr,
966+
Value *Addr, DIExpression *AddrExpr,
967+
const DILocation *DL) {
968+
LLVMContext &Ctx = LinkedInstr->getContext();
969+
Module *M = LinkedInstr->getModule();
970+
if (!AssignFn)
971+
AssignFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_assign);
972+
973+
auto *Link = LinkedInstr->getMetadata(LLVMContext::MD_DIAssignID);
974+
assert(Link && "Linked instruction must have DIAssign metadata attached");
975+
976+
std::array<Value *, 6> Args = {
977+
MetadataAsValue::get(Ctx, ValueAsMetadata::get(Val)),
978+
MetadataAsValue::get(Ctx, SrcVar),
979+
MetadataAsValue::get(Ctx, ValExpr),
980+
MetadataAsValue::get(Ctx, Link),
981+
MetadataAsValue::get(Ctx, ValueAsMetadata::get(Addr)),
982+
MetadataAsValue::get(Ctx, AddrExpr),
983+
};
984+
985+
IRBuilder<> B(Ctx);
986+
B.SetCurrentDebugLocation(DL);
987+
988+
auto *DVI = cast<DbgAssignIntrinsic>(B.CreateCall(AssignFn, Args));
989+
DVI->insertAfter(LinkedInstr);
990+
return DVI;
991+
}
992+
963993
Instruction *DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL,
964994
Instruction *InsertBefore) {
965995
return insertLabel(LabelInfo, DL,

0 commit comments

Comments
 (0)