Skip to content

Commit

Permalink
[Assignment Tracking][Analysis] Add analysis pass
Browse files Browse the repository at this point in the history
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
    rust-lang#2 https://reviews.llvm.org/D136321
    rust-lang#3 https://reviews.llvm.org/D136325
    rust-lang#4 https://reviews.llvm.org/D136331
    rust-lang#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 rust-lang#4 plumbs the analysis
into SelectionDAG, and patch rust-lang#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 rust-lang#3 for the purpose of landing the
patches seperately. However, most them would require an update for each
patch. In addition, patch rust-lang#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
  • Loading branch information
OCHyams committed Dec 9, 2022
1 parent 93099c7 commit 1d1de74
Show file tree
Hide file tree
Showing 39 changed files with 6,342 additions and 76 deletions.
117 changes: 117 additions & 0 deletions llvm/include/llvm/CodeGen/AssignmentTrackingAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#ifndef LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H
#define LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H

#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/Pass.h"

namespace llvm {
class Function;
class Instruction;
class Value;
class raw_ostream;
} // namespace llvm
class FunctionVarLocsBuilder;

namespace llvm {
/// Type wrapper for integer ID for Variables. 0 is reserved.
enum class VariableID : unsigned { Reserved = 0 };
/// Variable location definition used by FunctionVarLocs.
struct VarLocInfo {
llvm::VariableID VariableID;
DIExpression *Expr = nullptr;
DebugLoc DL;
Value *V = nullptr; // TODO: Needs to be value_s_ for variadic expressions.
};

/// Data structure describing the variable locations in a function. Used as the
/// result of the AssignmentTrackingAnalysis pass. Essentially read-only
/// outside of AssignmentTrackingAnalysis where it is built.
class FunctionVarLocs {
/// Maps VarLocInfo.VariableID to a DebugVariable for VarLocRecords.
SmallVector<DebugVariable> Variables;
/// List of variable location changes grouped by the instruction the
/// change occurs before (see VarLocsBeforeInst). The elements from
/// zero to SingleVarLocEnd represent variables with a single location.
SmallVector<VarLocInfo> VarLocRecords;
/// End of range of VarLocRecords that represent variables with a single
/// location that is valid for the entire scope. Range starts at 0.
unsigned SingleVarLocEnd = 0;
/// Maps an instruction to a range of VarLocs that start just before it.
DenseMap<const Instruction *, std::pair<unsigned, unsigned>>
VarLocsBeforeInst;

public:
/// Return the DILocalVariable for the location definition represented by \p
/// ID.
DILocalVariable *getDILocalVariable(const VarLocInfo *Loc) const {
VariableID VarID = Loc->VariableID;
return getDILocalVariable(VarID);
}
/// Return the DILocalVariable of the variable represented by \p ID.
DILocalVariable *getDILocalVariable(VariableID ID) const {
return const_cast<DILocalVariable *>(getVariable(ID).getVariable());
}
/// Return the DebugVariable represented by \p ID.
const DebugVariable &getVariable(VariableID ID) const {
return Variables[static_cast<unsigned>(ID)];
}

///@name iterators
///@{
/// First single-location variable location definition.
const VarLocInfo *single_locs_begin() const { return VarLocRecords.begin(); }
/// One past the last single-location variable location definition.
const VarLocInfo *single_locs_end() const {
const auto *It = VarLocRecords.begin();
std::advance(It, SingleVarLocEnd);
return It;
}
/// First variable location definition that comes before \p Before.
const VarLocInfo *locs_begin(const Instruction *Before) const {
auto Span = VarLocsBeforeInst.lookup(Before);
const auto *It = VarLocRecords.begin();
std::advance(It, Span.first);
return It;
}
/// One past the last variable location definition that comes before \p
/// Before.
const VarLocInfo *locs_end(const Instruction *Before) const {
auto Span = VarLocsBeforeInst.lookup(Before);
const auto *It = VarLocRecords.begin();
std::advance(It, Span.second);
return It;
}
///@}

void print(raw_ostream &OS, const Function &Fn) const;

///@{
/// Non-const methods used by AssignmentTrackingAnalysis (which invalidate
/// analysis results if called incorrectly).
void init(FunctionVarLocsBuilder &Builder);
void clear();
///@}
};

class AssignmentTrackingAnalysis : public FunctionPass {
std::unique_ptr<FunctionVarLocs> Results;

public:
static char ID;

AssignmentTrackingAnalysis();

bool runOnFunction(Function &F) override;

static bool isRequired() { return true; }

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}

const FunctionVarLocs *getResults() { return Results.get(); }
};

} // end namespace llvm
#endif // LLVM_CODEGEN_ASSIGNMENTTRACKINGANALYSIS_H
9 changes: 7 additions & 2 deletions llvm/include/llvm/CodeGen/SelectionDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class ConstantInt;
class DataLayout;
struct fltSemantics;
class FunctionLoweringInfo;
class FunctionVarLocs;
class GlobalValue;
struct KnownBits;
class LegacyDivergenceAnalysis;
Expand Down Expand Up @@ -222,6 +223,7 @@ class SelectionDAG {
const SelectionDAGTargetInfo *TSI = nullptr;
const TargetLowering *TLI = nullptr;
const TargetLibraryInfo *LibInfo = nullptr;
const FunctionVarLocs *FnVarLocs = nullptr;
MachineFunction *MF;
Pass *SDAGISelPass = nullptr;
LLVMContext *Context;
Expand Down Expand Up @@ -452,8 +454,8 @@ class SelectionDAG {
/// Prepare this SelectionDAG to process code in the given MachineFunction.
void init(MachineFunction &NewMF, OptimizationRemarkEmitter &NewORE,
Pass *PassPtr, const TargetLibraryInfo *LibraryInfo,
LegacyDivergenceAnalysis * Divergence,
ProfileSummaryInfo *PSIin, BlockFrequencyInfo *BFIin);
LegacyDivergenceAnalysis *Divergence, ProfileSummaryInfo *PSIin,
BlockFrequencyInfo *BFIin, FunctionVarLocs const *FnVarLocs);

void setFunctionLoweringInfo(FunctionLoweringInfo * FuncInfo) {
FLI = FuncInfo;
Expand All @@ -476,6 +478,9 @@ class SelectionDAG {
const TargetLibraryInfo &getLibInfo() const { return *LibInfo; }
const SelectionDAGTargetInfo &getSelectionDAGInfo() const { return *TSI; }
const LegacyDivergenceAnalysis *getDivergenceAnalysis() const { return DA; }
/// Returns the result of the AssignmentTrackingAnalysis pass if it's
/// available, otherwise return nullptr.
const FunctionVarLocs *getFunctionVarLocs() const { return FnVarLocs; }
LLVMContext *getContext() const { return Context; }
OptimizationRemarkEmitter &getORE() const { return *ORE; }
ProfileSummaryInfo *getPSI() const { return PSI; }
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void initializeADCELegacyPassPass(PassRegistry&);
void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&);
void initializeAlignmentFromAssumptionsPass(PassRegistry&);
void initializeAlwaysInlinerLegacyPassPass(PassRegistry&);
void initializeAssignmentTrackingAnalysisPass(PassRegistry &);
void initializeAssumeSimplifyPassLegacyPassPass(PassRegistry &);
void initializeAssumeBuilderPassLegacyPassPass(PassRegistry &);
void initializeAnnotation2MetadataLegacyPass(PassRegistry &);
Expand Down

0 comments on commit 1d1de74

Please sign in to comment.