Skip to content

Commit 1d1de74

Browse files
committed
[Assignment Tracking][Analysis] Add analysis pass
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 initial revision of assignment tracking analysis pass --------------------------------------------------------- This patch squashes five individually reviewed patches into one: #1 https://reviews.llvm.org/D136320 #2 https://reviews.llvm.org/D136321 #3 https://reviews.llvm.org/D136325 #4 https://reviews.llvm.org/D136331 #5 https://reviews.llvm.org/D136335 Patch #1 introduces 2 new files: AssignmentTrackingAnalysis.h and .cpp. The two subsequent patches modify those files only. Patch #4 plumbs the analysis into SelectionDAG, and patch #5 is a collection of tests for the analysis as a whole. The analysis was broken up into smaller chunks for review purposes but for the most part the tests were written using the whole analysis. It would be possible to break up the tests for patches #1 through #3 for the purpose of landing the patches seperately. However, most them would require an update for each patch. In addition, patch #4 - which connects the analysis to SelectionDAG - is required by all of the tests. If there is build-bot trouble, we might try a different landing sequence. Analysis problem and goal ------------------------- Variables values can be stored in memory, or available as SSA values, or both. Using the Assignment Tracking metadata, it's not possible to determine a variable location just by looking at a debug intrinsic in isolation. Instructions without any metadata can change the location of a variable. The meaning of dbg.assign intrinsics changes depending on whether there are linked instructions, and where they are relative to those instructions. So we need to analyse the IR and convert the embedded information into a form that SelectionDAG can consume to produce debug variable locations in MIR. The solution is a dataflow analysis which, aiming to maximise the memory location coverage for variables, outputs a mapping of instruction positions to variable location definitions. API usage --------- The analysis is named `AssignmentTrackingAnalysis`. It is added as a required pass for SelectionDAGISel when assignment tracking is enabled. The results of the analysis are exposed via `getResults` using the returned `const FunctionVarLocs *`'s const methods: const VarLocInfo *single_locs_begin() const; const VarLocInfo *single_locs_end() const; const VarLocInfo *locs_begin(const Instruction *Before) const; const VarLocInfo *locs_end(const Instruction *Before) const; void print(raw_ostream &OS, const Function &Fn) const; Debug intrinsics can be ignored after running the analysis. Instead, variable location definitions that occur between an instruction `Inst` and its predecessor (or block start) can be found by looping over the range: locs_begin(Inst), locs_end(Inst) Similarly, variables with a memory location that is valid for their lifetime can be iterated over using the range: single_locs_begin(), single_locs_end() Further detail -------------- For an explanation of the dataflow implementation and the integration with SelectionDAG, please see the reviews linked at the top of this commit message. Reviewed By: jmorse
1 parent 93099c7 commit 1d1de74

39 files changed

+6342
-76
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#ifndef LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H
2+
#define LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H
3+
4+
#include "llvm/IR/DebugInfoMetadata.h"
5+
#include "llvm/IR/DebugLoc.h"
6+
#include "llvm/Pass.h"
7+
8+
namespace llvm {
9+
class Function;
10+
class Instruction;
11+
class Value;
12+
class raw_ostream;
13+
} // namespace llvm
14+
class FunctionVarLocsBuilder;
15+
16+
namespace llvm {
17+
/// Type wrapper for integer ID for Variables. 0 is reserved.
18+
enum class VariableID : unsigned { Reserved = 0 };
19+
/// Variable location definition used by FunctionVarLocs.
20+
struct VarLocInfo {
21+
llvm::VariableID VariableID;
22+
DIExpression *Expr = nullptr;
23+
DebugLoc DL;
24+
Value *V = nullptr; // TODO: Needs to be value_s_ for variadic expressions.
25+
};
26+
27+
/// Data structure describing the variable locations in a function. Used as the
28+
/// result of the AssignmentTrackingAnalysis pass. Essentially read-only
29+
/// outside of AssignmentTrackingAnalysis where it is built.
30+
class FunctionVarLocs {
31+
/// Maps VarLocInfo.VariableID to a DebugVariable for VarLocRecords.
32+
SmallVector<DebugVariable> Variables;
33+
/// List of variable location changes grouped by the instruction the
34+
/// change occurs before (see VarLocsBeforeInst). The elements from
35+
/// zero to SingleVarLocEnd represent variables with a single location.
36+
SmallVector<VarLocInfo> VarLocRecords;
37+
/// End of range of VarLocRecords that represent variables with a single
38+
/// location that is valid for the entire scope. Range starts at 0.
39+
unsigned SingleVarLocEnd = 0;
40+
/// Maps an instruction to a range of VarLocs that start just before it.
41+
DenseMap<const Instruction *, std::pair<unsigned, unsigned>>
42+
VarLocsBeforeInst;
43+
44+
public:
45+
/// Return the DILocalVariable for the location definition represented by \p
46+
/// ID.
47+
DILocalVariable *getDILocalVariable(const VarLocInfo *Loc) const {
48+
VariableID VarID = Loc->VariableID;
49+
return getDILocalVariable(VarID);
50+
}
51+
/// Return the DILocalVariable of the variable represented by \p ID.
52+
DILocalVariable *getDILocalVariable(VariableID ID) const {
53+
return const_cast<DILocalVariable *>(getVariable(ID).getVariable());
54+
}
55+
/// Return the DebugVariable represented by \p ID.
56+
const DebugVariable &getVariable(VariableID ID) const {
57+
return Variables[static_cast<unsigned>(ID)];
58+
}
59+
60+
///@name iterators
61+
///@{
62+
/// First single-location variable location definition.
63+
const VarLocInfo *single_locs_begin() const { return VarLocRecords.begin(); }
64+
/// One past the last single-location variable location definition.
65+
const VarLocInfo *single_locs_end() const {
66+
const auto *It = VarLocRecords.begin();
67+
std::advance(It, SingleVarLocEnd);
68+
return It;
69+
}
70+
/// First variable location definition that comes before \p Before.
71+
const VarLocInfo *locs_begin(const Instruction *Before) const {
72+
auto Span = VarLocsBeforeInst.lookup(Before);
73+
const auto *It = VarLocRecords.begin();
74+
std::advance(It, Span.first);
75+
return It;
76+
}
77+
/// One past the last variable location definition that comes before \p
78+
/// Before.
79+
const VarLocInfo *locs_end(const Instruction *Before) const {
80+
auto Span = VarLocsBeforeInst.lookup(Before);
81+
const auto *It = VarLocRecords.begin();
82+
std::advance(It, Span.second);
83+
return It;
84+
}
85+
///@}
86+
87+
void print(raw_ostream &OS, const Function &Fn) const;
88+
89+
///@{
90+
/// Non-const methods used by AssignmentTrackingAnalysis (which invalidate
91+
/// analysis results if called incorrectly).
92+
void init(FunctionVarLocsBuilder &Builder);
93+
void clear();
94+
///@}
95+
};
96+
97+
class AssignmentTrackingAnalysis : public FunctionPass {
98+
std::unique_ptr<FunctionVarLocs> Results;
99+
100+
public:
101+
static char ID;
102+
103+
AssignmentTrackingAnalysis();
104+
105+
bool runOnFunction(Function &F) override;
106+
107+
static bool isRequired() { return true; }
108+
109+
void getAnalysisUsage(AnalysisUsage &AU) const override {
110+
AU.setPreservesAll();
111+
}
112+
113+
const FunctionVarLocs *getResults() { return Results.get(); }
114+
};
115+
116+
} // end namespace llvm
117+
#endif // LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class ConstantInt;
6868
class DataLayout;
6969
struct fltSemantics;
7070
class FunctionLoweringInfo;
71+
class FunctionVarLocs;
7172
class GlobalValue;
7273
struct KnownBits;
7374
class LegacyDivergenceAnalysis;
@@ -222,6 +223,7 @@ class SelectionDAG {
222223
const SelectionDAGTargetInfo *TSI = nullptr;
223224
const TargetLowering *TLI = nullptr;
224225
const TargetLibraryInfo *LibInfo = nullptr;
226+
const FunctionVarLocs *FnVarLocs = nullptr;
225227
MachineFunction *MF;
226228
Pass *SDAGISelPass = nullptr;
227229
LLVMContext *Context;
@@ -452,8 +454,8 @@ class SelectionDAG {
452454
/// Prepare this SelectionDAG to process code in the given MachineFunction.
453455
void init(MachineFunction &NewMF, OptimizationRemarkEmitter &NewORE,
454456
Pass *PassPtr, const TargetLibraryInfo *LibraryInfo,
455-
LegacyDivergenceAnalysis * Divergence,
456-
ProfileSummaryInfo *PSIin, BlockFrequencyInfo *BFIin);
457+
LegacyDivergenceAnalysis *Divergence, ProfileSummaryInfo *PSIin,
458+
BlockFrequencyInfo *BFIin, FunctionVarLocs const *FnVarLocs);
457459

458460
void setFunctionLoweringInfo(FunctionLoweringInfo * FuncInfo) {
459461
FLI = FuncInfo;
@@ -476,6 +478,9 @@ class SelectionDAG {
476478
const TargetLibraryInfo &getLibInfo() const { return *LibInfo; }
477479
const SelectionDAGTargetInfo &getSelectionDAGInfo() const { return *TSI; }
478480
const LegacyDivergenceAnalysis *getDivergenceAnalysis() const { return DA; }
481+
/// Returns the result of the AssignmentTrackingAnalysis pass if it's
482+
/// available, otherwise return nullptr.
483+
const FunctionVarLocs *getFunctionVarLocs() const { return FnVarLocs; }
479484
LLVMContext *getContext() const { return Context; }
480485
OptimizationRemarkEmitter &getORE() const { return *ORE; }
481486
ProfileSummaryInfo *getPSI() const { return PSI; }

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void initializeADCELegacyPassPass(PassRegistry&);
5454
void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&);
5555
void initializeAlignmentFromAssumptionsPass(PassRegistry&);
5656
void initializeAlwaysInlinerLegacyPassPass(PassRegistry&);
57+
void initializeAssignmentTrackingAnalysisPass(PassRegistry &);
5758
void initializeAssumeSimplifyPassLegacyPassPass(PassRegistry &);
5859
void initializeAssumeBuilderPassLegacyPassPass(PassRegistry &);
5960
void initializeAnnotation2MetadataLegacyPass(PassRegistry &);

0 commit comments

Comments
 (0)