Skip to content

Commit cecf619

Browse files
Reland [NFC] Move DroppedVariableStats to its own file and redesign it to be extensible.
Moved the IR unit test to the CodeGen folder to resolve linker errors: error: undefined reference to 'vtable for llvm::DroppedVariableStatsIR'
1 parent 7c07863 commit cecf619

File tree

8 files changed

+456
-299
lines changed

8 files changed

+456
-299
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
///===- DroppedVariableStats.h - Opt Diagnostics -*- C++ -*----------------===//
2+
///
3+
/// Part of the LLVM Project, under the Apache License v2.0 with LLVM
4+
/// Exceptions. See https://llvm.org/LICENSE.txt for license information.
5+
/// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
///
7+
///===---------------------------------------------------------------------===//
8+
/// \file
9+
/// Dropped Variable Statistics for Debug Information. Reports any number
10+
/// of #dbg_value that get dropped due to an optimization pass.
11+
///
12+
///===---------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
15+
#define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
16+
17+
#include "llvm/CodeGen/MachinePassManager.h"
18+
#include "llvm/IR/DebugInfoMetadata.h"
19+
#include "llvm/IR/DiagnosticInfo.h"
20+
#include "llvm/IR/Function.h"
21+
#include "llvm/IR/Module.h"
22+
#include "llvm/IR/PassInstrumentation.h"
23+
24+
namespace llvm {
25+
26+
/// A unique key that represents a debug variable.
27+
/// First const DIScope *: Represents the scope of the debug variable.
28+
/// Second const DIScope *: Represents the InlinedAt scope of the debug
29+
/// variable. const DILocalVariable *: It is a pointer to the debug variable
30+
/// itself.
31+
using VarID =
32+
std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
33+
34+
/// A base class to collect and print dropped debug information variable
35+
/// statistics.
36+
class DroppedVariableStats {
37+
public:
38+
DroppedVariableStats(bool DroppedVarStatsEnabled)
39+
: DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
40+
if (DroppedVarStatsEnabled)
41+
llvm::outs()
42+
<< "Pass Level, Pass Name, Num of Dropped Variables, Func or "
43+
"Module Name\n";
44+
};
45+
46+
virtual ~DroppedVariableStats() = default;
47+
48+
// We intend this to be unique per-compilation, thus no copies.
49+
DroppedVariableStats(const DroppedVariableStats &) = delete;
50+
void operator=(const DroppedVariableStats &) = delete;
51+
52+
bool getPassDroppedVariables() { return PassDroppedVariables; }
53+
54+
protected:
55+
void setup() {
56+
DebugVariablesStack.push_back(
57+
{DenseMap<const Function *, DebugVariables>()});
58+
InlinedAts.push_back(
59+
{DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
60+
}
61+
62+
void cleanup() {
63+
assert(!DebugVariablesStack.empty() &&
64+
"DebugVariablesStack shouldn't be empty!");
65+
assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
66+
DebugVariablesStack.pop_back();
67+
InlinedAts.pop_back();
68+
}
69+
70+
bool DroppedVariableStatsEnabled = false;
71+
struct DebugVariables {
72+
/// DenseSet of VarIDs before an optimization pass has run.
73+
DenseSet<VarID> DebugVariablesBefore;
74+
/// DenseSet of VarIDs after an optimization pass has run.
75+
DenseSet<VarID> DebugVariablesAfter;
76+
};
77+
78+
protected:
79+
/// A stack of a DenseMap, that maps DebugVariables for every pass to an
80+
/// llvm::Function. A stack is used because an optimization pass can call
81+
/// other passes.
82+
SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
83+
84+
/// A DenseSet tracking whether a scope was visited before.
85+
DenseSet<const DIScope *> VisitedScope;
86+
/// A stack of DenseMaps, which map the name of an llvm::Function to a
87+
/// DenseMap of VarIDs and their inlinedAt locations before an optimization
88+
/// pass has run.
89+
SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
90+
/// Calculate the number of dropped variables in an llvm::Function or
91+
/// llvm::MachineFunction and print the relevant information to stdout.
92+
void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables,
93+
StringRef FuncName, StringRef PassID,
94+
StringRef FuncOrModName,
95+
StringRef PassLevel, const Function *Func);
96+
97+
/// Check if a \p Var has been dropped or is a false positive. Also update the
98+
/// \p DroppedCount if a debug variable is dropped.
99+
bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope,
100+
const DIScope *DbgValScope,
101+
DenseMap<VarID, DILocation *> &InlinedAtsMap,
102+
VarID Var, unsigned &DroppedCount);
103+
/// Run code to populate relevant data structures over an llvm::Function or
104+
/// llvm::MachineFunction.
105+
void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before);
106+
/// Populate the VarIDSet and InlinedAtMap with the relevant information
107+
/// needed for before and after pass analysis to determine dropped variable
108+
/// status.
109+
void populateVarIDSetAndInlinedMap(
110+
const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
111+
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
112+
StringRef FuncName, bool Before);
113+
/// Visit every llvm::Instruction or llvm::MachineInstruction and check if the
114+
/// debug variable denoted by its ID \p Var may have been dropped by an
115+
/// optimization pass.
116+
virtual void
117+
visitEveryInstruction(unsigned &DroppedCount,
118+
DenseMap<VarID, DILocation *> &InlinedAtsMap,
119+
VarID Var) = 0;
120+
/// Visit every debug record in an llvm::Function or llvm::MachineFunction
121+
/// and call populateVarIDSetAndInlinedMap on it.
122+
virtual void visitEveryDebugRecord(
123+
DenseSet<VarID> &VarIDSet,
124+
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
125+
StringRef FuncName, bool Before) = 0;
126+
127+
private:
128+
/// Remove a dropped debug variable's VarID from all Sets in the
129+
/// DroppedVariablesBefore stack.
130+
void removeVarFromAllSets(VarID Var, const Function *F) {
131+
// Do not remove Var from the last element, it will be popped from the
132+
// stack.
133+
for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
134+
DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
135+
}
136+
/// Return true if \p Scope is the same as \p DbgValScope or a child scope of
137+
/// \p DbgValScope, return false otherwise.
138+
bool isScopeChildOfOrEqualTo(const DIScope *Scope,
139+
const DIScope *DbgValScope);
140+
/// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
141+
/// the InlinedAt chain, return false otherwise.
142+
bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
143+
const DILocation *DbgValInlinedAt);
144+
bool PassDroppedVariables = false;
145+
};
146+
147+
/// A class to collect and print dropped debug information due to LLVM IR
148+
/// optimization passes. After every LLVM IR pass is run, it will print how many
149+
/// #dbg_values were dropped due to that pass.
150+
class DroppedVariableStatsIR : public DroppedVariableStats {
151+
public:
152+
DroppedVariableStatsIR(bool DroppedVarStatsEnabled)
153+
: llvm::DroppedVariableStats(DroppedVarStatsEnabled) {}
154+
155+
virtual ~DroppedVariableStatsIR() = default;
156+
157+
void runBeforePass(Any IR) {
158+
setup();
159+
if (const auto *M = unwrapIR<Module>(IR))
160+
return this->runOnModule(M, true);
161+
if (const auto *F = unwrapIR<Function>(IR))
162+
return this->runOnFunction(F, true);
163+
}
164+
165+
void runAfterPass(StringRef P, Any IR) {
166+
if (const auto *M = unwrapIR<Module>(IR))
167+
runAfterPassModule(P, M);
168+
else if (const auto *F = unwrapIR<Function>(IR))
169+
runAfterPassFunction(P, F);
170+
cleanup();
171+
}
172+
173+
void registerCallbacks(PassInstrumentationCallbacks &PIC);
174+
175+
private:
176+
const Function *Func;
177+
178+
void runAfterPassFunction(StringRef PassID, const Function *F) {
179+
runOnFunction(F, false);
180+
calculateDroppedVarStatsOnFunction(F, PassID, F->getName().str(),
181+
"Function");
182+
}
183+
184+
void runAfterPassModule(StringRef PassID, const Module *M) {
185+
runOnModule(M, false);
186+
calculateDroppedVarStatsOnModule(M, PassID, M->getName().str(), "Module");
187+
}
188+
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
189+
/// after a pass has run to facilitate dropped variable calculation for an
190+
/// llvm::Function.
191+
void runOnFunction(const Function *F, bool Before);
192+
/// Iterate over all Instructions in a Function and report any dropped debug
193+
/// information.
194+
void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
195+
StringRef FuncOrModName,
196+
StringRef PassLevel);
197+
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
198+
/// after a pass has run to facilitate dropped variable calculation for an
199+
/// llvm::Module. Calls runOnFunction on every Function in the Module.
200+
void runOnModule(const Module *M, bool Before);
201+
/// Iterate over all Functions in a Module and report any dropped debug
202+
/// information. Will call calculateDroppedVarStatsOnFunction on every
203+
/// Function.
204+
void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
205+
StringRef FuncOrModName,
206+
StringRef PassLevel);
207+
/// Override base class method to run on an llvm::Function specifically.
208+
virtual void
209+
visitEveryInstruction(unsigned &DroppedCount,
210+
DenseMap<VarID, DILocation *> &InlinedAtsMap,
211+
VarID Var) override;
212+
/// Override base class method to run on #dbg_values specifically.
213+
virtual void visitEveryDebugRecord(
214+
DenseSet<VarID> &VarIDSet,
215+
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
216+
StringRef FuncName, bool Before) override;
217+
218+
template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
219+
const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
220+
return IRPtr ? *IRPtr : nullptr;
221+
}
222+
};
223+
224+
} // namespace llvm
225+
226+
#endif

llvm/include/llvm/Passes/StandardInstrumentations.h

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/SmallVector.h"
2020
#include "llvm/ADT/StringRef.h"
2121
#include "llvm/ADT/StringSet.h"
22+
#include "llvm/CodeGen/DroppedVariableStats.h"
2223
#include "llvm/CodeGen/MachineBasicBlock.h"
2324
#include "llvm/IR/BasicBlock.h"
2425
#include "llvm/IR/DebugInfoMetadata.h"
@@ -579,83 +580,6 @@ class PrintCrashIRInstrumentation {
579580
static void SignalHandler(void *);
580581
};
581582

582-
/// A class to collect and print dropped debug information variable statistics.
583-
/// After every LLVM IR pass is run, it will print how many #dbg_values were
584-
/// dropped due to that pass.
585-
class DroppedVariableStats {
586-
public:
587-
DroppedVariableStats(bool DroppedVarStatsEnabled) {
588-
if (DroppedVarStatsEnabled)
589-
llvm::outs()
590-
<< "Pass Level, Pass Name, Num of Dropped Variables, Func or "
591-
"Module Name\n";
592-
};
593-
// We intend this to be unique per-compilation, thus no copies.
594-
DroppedVariableStats(const DroppedVariableStats &) = delete;
595-
void operator=(const DroppedVariableStats &) = delete;
596-
597-
void registerCallbacks(PassInstrumentationCallbacks &PIC);
598-
void runBeforePass(StringRef PassID, Any IR);
599-
void runAfterPass(StringRef PassID, Any IR, const PreservedAnalyses &PA);
600-
void runAfterPassInvalidated(StringRef PassID, const PreservedAnalyses &PA);
601-
bool getPassDroppedVariables() { return PassDroppedVariables; }
602-
603-
private:
604-
bool PassDroppedVariables = false;
605-
/// A unique key that represents a #dbg_value.
606-
using VarID =
607-
std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
608-
609-
struct DebugVariables {
610-
/// DenseSet of VarIDs before an optimization pass has run.
611-
DenseSet<VarID> DebugVariablesBefore;
612-
/// DenseSet of VarIDs after an optimization pass has run.
613-
DenseSet<VarID> DebugVariablesAfter;
614-
};
615-
616-
/// A stack of a DenseMap, that maps DebugVariables for every pass to an
617-
/// llvm::Function. A stack is used because an optimization pass can call
618-
/// other passes.
619-
SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
620-
621-
/// A DenseSet tracking whether a scope was visited before.
622-
DenseSet<const DIScope *> VisitedScope;
623-
/// A stack of DenseMaps, which map the name of an llvm::Function to a
624-
/// DenseMap of VarIDs and their inlinedAt locations before an optimization
625-
/// pass has run.
626-
SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
627-
628-
/// Iterate over all Functions in a Module and report any dropped debug
629-
/// information. Will call calculateDroppedVarStatsOnFunction on every
630-
/// Function.
631-
void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
632-
std::string FuncOrModName,
633-
std::string PassLevel);
634-
/// Iterate over all Instructions in a Function and report any dropped debug
635-
/// information.
636-
void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
637-
std::string FuncOrModName,
638-
std::string PassLevel);
639-
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
640-
/// after a pass has run to facilitate dropped variable calculation for an
641-
/// llvm::Function.
642-
void runOnFunction(const Function *F, bool Before);
643-
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
644-
/// after a pass has run to facilitate dropped variable calculation for an
645-
/// llvm::Module. Calls runOnFunction on every Function in the Module.
646-
void runOnModule(const Module *M, bool Before);
647-
/// Remove a dropped #dbg_value VarID from all Sets in the
648-
/// DroppedVariablesBefore stack.
649-
void removeVarFromAllSets(VarID Var, const Function *F);
650-
/// Return true if \p Scope is the same as \p DbgValScope or a child scope of
651-
/// \p DbgValScope, return false otherwise.
652-
bool isScopeChildOfOrEqualTo(DIScope *Scope, const DIScope *DbgValScope);
653-
/// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
654-
/// the InlinedAt chain, return false otherwise.
655-
bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
656-
const DILocation *DbgValInlinedAt);
657-
};
658-
659583
/// This class provides an interface to register all the standard pass
660584
/// instrumentations and manages their state (if any).
661585
class StandardInstrumentations {
@@ -673,7 +597,7 @@ class StandardInstrumentations {
673597
PrintCrashIRInstrumentation PrintCrashIR;
674598
IRChangedTester ChangeTester;
675599
VerifyInstrumentation Verify;
676-
DroppedVariableStats DroppedStats;
600+
DroppedVariableStatsIR DroppedStatsIR;
677601

678602
bool VerifyEach;
679603

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ add_llvm_component_library(LLVMCodeGen
5050
DeadMachineInstructionElim.cpp
5151
DetectDeadLanes.cpp
5252
DFAPacketizer.cpp
53+
DroppedVariableStats.cpp
5354
DwarfEHPrepare.cpp
5455
EarlyIfConversion.cpp
5556
EdgeBundles.cpp

0 commit comments

Comments
 (0)