Add a pass to collect dropped var statistics for MIR (#126686)

This patch attempts to reland
https://github.com/llvm/llvm-project/pull/120780 while addressing the
issues that caused the patch to be reverted.

Namely:

1. The patch had included code from the llvm/Passes directory in the
llvm/CodeGen directory.

2. The patch increased the backend compile time by 2% due to adding a
very expensive include in MachineFunctionPass.h

The patch has been re-structured so that there is no dependency between
the llvm/Passes and llvm/CodeGen directory, by moving the base class,
`class DroppedVariableStats` to the llvm/IR directory.

The expensive include in MachineFunctionPass.h has been changed to
contain forward declarations instead of other header includes which was
pulling a ton of code into MachineFunctionPass.h and should resolve any
issues when it comes to compile time increase.
This commit is contained in:
Shubham Sandeep Rastogi 2025-02-12 14:08:18 -08:00 committed by GitHub
parent 65ed4fa57e
commit 92f916faba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1486 additions and 152 deletions

View File

@ -0,0 +1,59 @@
///===- DroppedVariableStatsMIR.h - Opt Diagnostics -*- 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
///
///===---------------------------------------------------------------------===//
/// \file
/// Dropped Variable Statistics for Debug Information. Reports any number
/// of DBG_VALUEs that get dropped due to an optimization pass.
///
///===---------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATSMIR_H
#define LLVM_CODEGEN_DROPPEDVARIABLESTATSMIR_H
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/DroppedVariableStats.h"
namespace llvm {
/// A class to collect and print dropped debug information due to MIR
/// optimization passes. After every MIR pass is run, it will print how many
/// #DBG_VALUEs were dropped due to that pass.
class DroppedVariableStatsMIR : public DroppedVariableStats {
public:
DroppedVariableStatsMIR() : DroppedVariableStats(false) {}
void runBeforePass(StringRef PassID, MachineFunction *MF);
void runAfterPass(StringRef PassID, MachineFunction *MF);
private:
const MachineFunction *MFunc;
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
/// after a pass has run to facilitate dropped variable calculation for an
/// llvm::MachineFunction.
void runOnMachineFunction(const MachineFunction *MF, bool Before);
/// Iterate over all Instructions in a MachineFunction and report any dropped
/// debug information.
void calculateDroppedVarStatsOnMachineFunction(const MachineFunction *MF,
StringRef PassID,
StringRef FuncOrModName);
/// Override base class method to run on an llvm::MachineFunction
/// specifically.
virtual void
visitEveryInstruction(unsigned &DroppedCount,
DenseMap<VarID, DILocation *> &InlinedAtsMap,
VarID Var) override;
/// Override base class method to run on DBG_VALUEs specifically.
virtual void visitEveryDebugRecord(
DenseSet<VarID> &VarIDSet,
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
StringRef FuncName, bool Before) override;
};
} // namespace llvm
#endif

View File

@ -14,13 +14,19 @@
#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H #ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
#define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H #define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/ADT/DenseSet.h"
#include "llvm/IR/DiagnosticInfo.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Function.h" #include <tuple>
#include "llvm/IR/PassInstrumentation.h"
namespace llvm { namespace llvm {
class DIScope;
class DILocalVariable;
class Function;
class DILocation;
class DebugLoc;
class StringRef;
/// A unique key that represents a debug variable. /// A unique key that represents a debug variable.
/// First const DIScope *: Represents the scope of the debug variable. /// First const DIScope *: Represents the scope of the debug variable.
/// Second const DIScope *: Represents the InlinedAt scope of the debug /// Second const DIScope *: Represents the InlinedAt scope of the debug
@ -33,13 +39,7 @@ using VarID =
/// statistics. /// statistics.
class DroppedVariableStats { class DroppedVariableStats {
public: public:
DroppedVariableStats(bool DroppedVarStatsEnabled) DroppedVariableStats(bool DroppedVarStatsEnabled);
: DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
if (DroppedVarStatsEnabled)
llvm::outs()
<< "Pass Level, Pass Name, Num of Dropped Variables, Func or "
"Module Name\n";
};
virtual ~DroppedVariableStats() {} virtual ~DroppedVariableStats() {}
@ -50,20 +50,9 @@ public:
bool getPassDroppedVariables() { return PassDroppedVariables; } bool getPassDroppedVariables() { return PassDroppedVariables; }
protected: protected:
void setup() { void setup();
DebugVariablesStack.push_back(
{DenseMap<const Function *, DebugVariables>()});
InlinedAts.push_back(
{DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
}
void cleanup() { void cleanup();
assert(!DebugVariablesStack.empty() &&
"DebugVariablesStack shouldn't be empty!");
assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
DebugVariablesStack.pop_back();
InlinedAts.pop_back();
}
bool DroppedVariableStatsEnabled = false; bool DroppedVariableStatsEnabled = false;
struct DebugVariables { struct DebugVariables {
@ -73,7 +62,6 @@ protected:
DenseSet<VarID> DebugVariablesAfter; DenseSet<VarID> DebugVariablesAfter;
}; };
protected:
/// A stack of a DenseMap, that maps DebugVariables for every pass to an /// A stack of a DenseMap, that maps DebugVariables for every pass to an
/// llvm::Function. A stack is used because an optimization pass can call /// llvm::Function. A stack is used because an optimization pass can call
/// other passes. /// other passes.
@ -90,78 +78,27 @@ protected:
void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables, void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables,
StringRef FuncName, StringRef PassID, StringRef FuncName, StringRef PassID,
StringRef FuncOrModName, StringRef FuncOrModName,
StringRef PassLevel, StringRef PassLevel, const Function *Func);
const Function *Func) {
unsigned DroppedCount = 0;
DenseSet<VarID> &DebugVariablesBeforeSet =
DbgVariables.DebugVariablesBefore;
DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
auto It = InlinedAts.back().find(FuncName);
if (It == InlinedAts.back().end())
return;
DenseMap<VarID, DILocation *> &InlinedAtsMap = It->second;
// Find an Instruction that shares the same scope as the dropped #dbg_value
// or has a scope that is the child of the scope of the #dbg_value, and has
// an inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt
// chain contains the inlinedAt of the #dbg_value, if such an Instruction is
// found, debug information is dropped.
for (VarID Var : DebugVariablesBeforeSet) {
if (DebugVariablesAfterSet.contains(Var))
continue;
visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
removeVarFromAllSets(Var, Func);
}
if (DroppedCount > 0) {
llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount
<< ", " << FuncOrModName << "\n";
PassDroppedVariables = true;
} else
PassDroppedVariables = false;
}
/// Check if a \p Var has been dropped or is a false positive. Also update the /// Check if a \p Var has been dropped or is a false positive. Also update the
/// \p DroppedCount if a debug variable is dropped. /// \p DroppedCount if a debug variable is dropped.
bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope, bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope,
const DIScope *DbgValScope, const DIScope *DbgValScope,
DenseMap<VarID, DILocation *> &InlinedAtsMap, DenseMap<VarID, DILocation *> &InlinedAtsMap,
VarID Var, unsigned &DroppedCount) { VarID Var, unsigned &DroppedCount);
// If the Scope is a child of, or equal to the DbgValScope and is inlined at
// the Var's InlinedAt location, return true to signify that the Var has
// been dropped.
if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
InlinedAtsMap[Var])) {
// Found another instruction in the variable's scope, so there exists a
// break point at which the variable could be observed. Count it as
// dropped.
DroppedCount++;
return true;
}
return false;
}
/// Run code to populate relevant data structures over an llvm::Function or /// Run code to populate relevant data structures over an llvm::Function or
/// llvm::MachineFunction. /// llvm::MachineFunction.
void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before) { void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before);
auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
: DbgVariables.DebugVariablesAfter);
auto &InlinedAtsMap = InlinedAts.back();
if (Before)
InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
VarIDSet = DenseSet<VarID>();
visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
}
/// Populate the VarIDSet and InlinedAtMap with the relevant information /// Populate the VarIDSet and InlinedAtMap with the relevant information
/// needed for before and after pass analysis to determine dropped variable /// needed for before and after pass analysis to determine dropped variable
/// status. /// status.
void populateVarIDSetAndInlinedMap( void populateVarIDSetAndInlinedMap(
const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet, const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap, DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
StringRef FuncName, bool Before) { StringRef FuncName, bool Before);
VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
VarIDSet.insert(Key);
if (Before)
InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
}
/// Visit every llvm::Instruction or llvm::MachineInstruction and check if the /// Visit every llvm::Instruction or llvm::MachineInstruction and check if the
/// debug variable denoted by its ID \p Var may have been dropped by an /// debug variable denoted by its ID \p Var may have been dropped by an
/// optimization pass. /// optimization pass.
@ -179,47 +116,18 @@ protected:
private: private:
/// Remove a dropped debug variable's VarID from all Sets in the /// Remove a dropped debug variable's VarID from all Sets in the
/// DroppedVariablesBefore stack. /// DroppedVariablesBefore stack.
void removeVarFromAllSets(VarID Var, const Function *F) { void removeVarFromAllSets(VarID Var, const Function *F);
// Do not remove Var from the last element, it will be popped from the
// stack.
for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
}
/// Return true if \p Scope is the same as \p DbgValScope or a child scope of /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
/// \p DbgValScope, return false otherwise. /// \p DbgValScope, return false otherwise.
bool isScopeChildOfOrEqualTo(const DIScope *Scope, bool isScopeChildOfOrEqualTo(const DIScope *Scope,
const DIScope *DbgValScope) { const DIScope *DbgValScope);
while (Scope != nullptr) {
if (VisitedScope.find(Scope) == VisitedScope.end()) {
VisitedScope.insert(Scope);
if (Scope == DbgValScope) {
VisitedScope.clear();
return true;
}
Scope = Scope->getScope();
} else {
VisitedScope.clear();
return false;
}
}
return false;
}
/// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
/// the InlinedAt chain, return false otherwise. /// the InlinedAt chain, return false otherwise.
bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt, bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
const DILocation *DbgValInlinedAt) { const DILocation *DbgValInlinedAt);
if (DbgValInlinedAt == InlinedAt)
return true;
if (!DbgValInlinedAt)
return false;
auto *IA = InlinedAt;
while (IA) {
if (IA == DbgValInlinedAt)
return true;
IA = IA->getInlinedAt();
}
return false;
}
bool PassDroppedVariables = false; bool PassDroppedVariables = false;
}; };

View File

@ -14,12 +14,17 @@
#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATSIR_H #ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATSIR_H
#define LLVM_CODEGEN_DROPPEDVARIABLESTATSIR_H #define LLVM_CODEGEN_DROPPEDVARIABLESTATSIR_H
#include "llvm/IR/InstIterator.h" #include "llvm/IR/DroppedVariableStats.h"
#include "llvm/IR/Module.h"
#include "llvm/Passes/DroppedVariableStats.h"
namespace llvm { namespace llvm {
class Any;
class StringRef;
class PassInstrumentationCallbacks;
class Function;
class Module;
class DILocation;
/// A class to collect and print dropped debug information due to LLVM IR /// A class to collect and print dropped debug information due to LLVM IR
/// optimization passes. After every LLVM IR pass is run, it will print how many /// optimization passes. After every LLVM IR pass is run, it will print how many
/// #dbg_values were dropped due to that pass. /// #dbg_values were dropped due to that pass.
@ -28,56 +33,42 @@ public:
DroppedVariableStatsIR(bool DroppedVarStatsEnabled) DroppedVariableStatsIR(bool DroppedVarStatsEnabled)
: llvm::DroppedVariableStats(DroppedVarStatsEnabled) {} : llvm::DroppedVariableStats(DroppedVarStatsEnabled) {}
void runBeforePass(StringRef P, Any IR) { void runBeforePass(StringRef P, Any IR);
setup();
if (const auto *M = unwrapIR<Module>(IR))
return this->runOnModule(P, M, true);
if (const auto *F = unwrapIR<Function>(IR))
return this->runOnFunction(P, F, true);
}
void runAfterPass(StringRef P, Any IR) { void runAfterPass(StringRef P, Any IR);
if (const auto *M = unwrapIR<Module>(IR))
runAfterPassModule(P, M);
else if (const auto *F = unwrapIR<Function>(IR))
runAfterPassFunction(P, F);
cleanup();
}
void registerCallbacks(PassInstrumentationCallbacks &PIC); void registerCallbacks(PassInstrumentationCallbacks &PIC);
private: private:
const Function *Func; const Function *Func;
void runAfterPassFunction(StringRef PassID, const Function *F) { void runAfterPassFunction(StringRef PassID, const Function *F);
runOnFunction(PassID, F, false);
calculateDroppedVarStatsOnFunction(F, PassID, F->getName().str(), void runAfterPassModule(StringRef PassID, const Module *M);
"Function");
}
void runAfterPassModule(StringRef PassID, const Module *M) {
runOnModule(PassID, M, false);
calculateDroppedVarStatsOnModule(M, PassID, M->getName().str(), "Module");
}
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
/// after a pass has run to facilitate dropped variable calculation for an /// after a pass has run to facilitate dropped variable calculation for an
/// llvm::Function. /// llvm::Function.
void runOnFunction(StringRef PassID, const Function *F, bool Before); void runOnFunction(StringRef PassID, const Function *F, bool Before);
/// Iterate over all Instructions in a Function and report any dropped debug /// Iterate over all Instructions in a Function and report any dropped debug
/// information. /// information.
void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID, void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
StringRef FuncOrModName, StringRef FuncOrModName,
StringRef PassLevel); StringRef PassLevel);
/// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
/// after a pass has run to facilitate dropped variable calculation for an /// after a pass has run to facilitate dropped variable calculation for an
/// llvm::Module. Calls runOnFunction on every Function in the Module. /// llvm::Module. Calls runOnFunction on every Function in the Module.
void runOnModule(StringRef PassID, const Module *M, bool Before); void runOnModule(StringRef PassID, const Module *M, bool Before);
/// Iterate over all Functions in a Module and report any dropped debug /// Iterate over all Functions in a Module and report any dropped debug
/// information. Will call calculateDroppedVarStatsOnFunction on every /// information. Will call calculateDroppedVarStatsOnFunction on every
/// Function. /// Function.
void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID, void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
StringRef FuncOrModName, StringRef FuncOrModName,
StringRef PassLevel); StringRef PassLevel);
/// Override base class method to run on an llvm::Function specifically. /// Override base class method to run on an llvm::Function specifically.
virtual void virtual void
visitEveryInstruction(unsigned &DroppedCount, visitEveryInstruction(unsigned &DroppedCount,
@ -90,10 +81,7 @@ private:
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap, DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
StringRef FuncName, bool Before) override; StringRef FuncName, bool Before) override;
template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) { template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR);
const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
return IRPtr ? *IRPtr : nullptr;
}
}; };
} // namespace llvm } // namespace llvm

View File

@ -22,10 +22,10 @@
#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DroppedVariableStatsIR.h"
#include "llvm/IR/OptBisect.h" #include "llvm/IR/OptBisect.h"
#include "llvm/IR/PassTimingInfo.h" #include "llvm/IR/PassTimingInfo.h"
#include "llvm/IR/ValueHandle.h" #include "llvm/IR/ValueHandle.h"
#include "llvm/Passes/DroppedVariableStatsIR.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/TimeProfiler.h"
#include "llvm/Transforms/IPO/SampleProfileProbe.h" #include "llvm/Transforms/IPO/SampleProfileProbe.h"

View File

@ -50,6 +50,7 @@ add_llvm_component_library(LLVMCodeGen
DeadMachineInstructionElim.cpp DeadMachineInstructionElim.cpp
DetectDeadLanes.cpp DetectDeadLanes.cpp
DFAPacketizer.cpp DFAPacketizer.cpp
DroppedVariableStatsMIR.cpp
DwarfEHPrepare.cpp DwarfEHPrepare.cpp
EarlyIfConversion.cpp EarlyIfConversion.cpp
EdgeBundles.cpp EdgeBundles.cpp

View File

@ -0,0 +1,95 @@
///===- DroppedVariableStatsMIR.cpp ---------------------------------------===//
///
/// 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
///
///===---------------------------------------------------------------------===//
/// \file
/// Dropped Variable Statistics for Debug Information. Reports any number
/// of DBG_VALUEs that get dropped due to an optimization pass.
///
///===---------------------------------------------------------------------===//
#include "llvm/CodeGen/DroppedVariableStatsMIR.h"
#include "llvm/IR/DebugInfoMetadata.h"
using namespace llvm;
void DroppedVariableStatsMIR::runBeforePass(StringRef PassID,
MachineFunction *MF) {
if (PassID == "Debug Variable Analysis")
return;
setup();
return runOnMachineFunction(MF, true);
}
void DroppedVariableStatsMIR::runAfterPass(StringRef PassID,
MachineFunction *MF) {
if (PassID == "Debug Variable Analysis")
return;
runOnMachineFunction(MF, false);
calculateDroppedVarStatsOnMachineFunction(MF, PassID, MF->getName().str());
cleanup();
}
void DroppedVariableStatsMIR::runOnMachineFunction(const MachineFunction *MF,
bool Before) {
auto &DebugVariables = DebugVariablesStack.back()[&MF->getFunction()];
auto FuncName = MF->getName();
MFunc = MF;
run(DebugVariables, FuncName, Before);
}
void DroppedVariableStatsMIR::calculateDroppedVarStatsOnMachineFunction(
const MachineFunction *MF, StringRef PassID, StringRef FuncOrModName) {
MFunc = MF;
StringRef FuncName = MF->getName();
const Function *Func = &MF->getFunction();
DebugVariables &DbgVariables = DebugVariablesStack.back()[Func];
calculateDroppedStatsAndPrint(DbgVariables, FuncName, PassID, FuncOrModName,
"MachineFunction", Func);
}
void DroppedVariableStatsMIR::visitEveryInstruction(
unsigned &DroppedCount, DenseMap<VarID, DILocation *> &InlinedAtsMap,
VarID Var) {
unsigned PrevDroppedCount = DroppedCount;
const DIScope *DbgValScope = std::get<0>(Var);
for (const auto &MBB : *MFunc) {
for (const auto &MI : MBB) {
if (!MI.isDebugInstr()) {
auto *DbgLoc = MI.getDebugLoc().get();
if (!DbgLoc)
continue;
auto *Scope = DbgLoc->getScope();
if (updateDroppedCount(DbgLoc, Scope, DbgValScope, InlinedAtsMap, Var,
DroppedCount))
break;
}
}
if (PrevDroppedCount != DroppedCount) {
PrevDroppedCount = DroppedCount;
break;
}
}
}
void DroppedVariableStatsMIR::visitEveryDebugRecord(
DenseSet<VarID> &VarIDSet,
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
StringRef FuncName, bool Before) {
for (const auto &MBB : *MFunc) {
for (const auto &MI : MBB) {
if (MI.isDebugValueLike()) {
auto *DbgVar = MI.getDebugVariable();
if (!DbgVar)
continue;
auto DbgLoc = MI.getDebugLoc();
populateVarIDSetAndInlinedMap(DbgVar, DbgLoc, VarIDSet, InlinedAtsMap,
FuncName, Before);
}
}
}
}

View File

@ -20,6 +20,7 @@
#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/CodeGen/DroppedVariableStatsMIR.h"
#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
@ -32,6 +33,11 @@
using namespace llvm; using namespace llvm;
using namespace ore; using namespace ore;
static cl::opt<bool> DroppedVarStatsMIR(
"dropped-variable-stats-mir", cl::Hidden,
cl::desc("Dump dropped debug variables stats for MIR passes"),
cl::init(false));
Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O, Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O,
const std::string &Banner) const { const std::string &Banner) const {
return createMachineFunctionPrinterPass(O, Banner); return createMachineFunctionPrinterPass(O, Banner);
@ -91,7 +97,16 @@ bool MachineFunctionPass::runOnFunction(Function &F) {
MFProps.reset(ClearedProperties); MFProps.reset(ClearedProperties);
bool RV = runOnMachineFunction(MF); bool RV;
if (DroppedVarStatsMIR) {
DroppedVariableStatsMIR DroppedVarStatsMF;
auto PassName = getPassName();
DroppedVarStatsMF.runBeforePass(PassName, &MF);
RV = runOnMachineFunction(MF);
DroppedVarStatsMF.runAfterPass(PassName, &MF);
} else {
RV = runOnMachineFunction(MF);
}
if (ShouldEmitSizeRemarks) { if (ShouldEmitSizeRemarks) {
// We wanted size remarks. Check if there was a change to the number of // We wanted size remarks. Check if there was a change to the number of

View File

@ -26,6 +26,8 @@ add_llvm_component_library(LLVMCore
DiagnosticInfo.cpp DiagnosticInfo.cpp
DiagnosticPrinter.cpp DiagnosticPrinter.cpp
Dominators.cpp Dominators.cpp
DroppedVariableStats.cpp
DroppedVariableStatsIR.cpp
EHPersonalities.cpp EHPersonalities.cpp
FPEnv.cpp FPEnv.cpp
Function.cpp Function.cpp

View File

@ -0,0 +1,147 @@
///===- DroppedVariableStats.cpp ----------------------------------------===//
///
/// 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
///
///===---------------------------------------------------------------------===//
/// \file
/// Dropped Variable Statistics for Debug Information. Reports any number
/// of #dbg_value that get dropped due to an optimization pass.
///
///===---------------------------------------------------------------------===//
#include "llvm/IR/DroppedVariableStats.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
using namespace llvm;
DroppedVariableStats::DroppedVariableStats(bool DroppedVarStatsEnabled)
: DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
if (DroppedVarStatsEnabled)
llvm::outs() << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
"Module Name\n";
}
void DroppedVariableStats::setup() {
DebugVariablesStack.push_back({DenseMap<const Function *, DebugVariables>()});
InlinedAts.push_back({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
}
void DroppedVariableStats::cleanup() {
assert(!DebugVariablesStack.empty() &&
"DebugVariablesStack shouldn't be empty!");
assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
DebugVariablesStack.pop_back();
InlinedAts.pop_back();
}
void DroppedVariableStats::calculateDroppedStatsAndPrint(
DebugVariables &DbgVariables, StringRef FuncName, StringRef PassID,
StringRef FuncOrModName, StringRef PassLevel, const Function *Func) {
unsigned DroppedCount = 0;
DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
if (InlinedAts.back().find(FuncName) == InlinedAts.back().end())
return;
DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
// Find an Instruction that shares the same scope as the dropped #dbg_value
// or has a scope that is the child of the scope of the #dbg_value, and has
// an inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt
// chain contains the inlinedAt of the #dbg_value, if such an Instruction is
// found, debug information is dropped.
for (VarID Var : DebugVariablesBeforeSet) {
if (DebugVariablesAfterSet.contains(Var))
continue;
visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
removeVarFromAllSets(Var, Func);
}
if (DroppedCount > 0) {
llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
<< FuncOrModName << "\n";
PassDroppedVariables = true;
} else
PassDroppedVariables = false;
}
bool DroppedVariableStats::updateDroppedCount(
DILocation *DbgLoc, const DIScope *Scope, const DIScope *DbgValScope,
DenseMap<VarID, DILocation *> &InlinedAtsMap, VarID Var,
unsigned &DroppedCount) {
// If the Scope is a child of, or equal to the DbgValScope and is inlined at
// the Var's InlinedAt location, return true to signify that the Var has
// been dropped.
if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
InlinedAtsMap[Var])) {
// Found another instruction in the variable's scope, so there exists a
// break point at which the variable could be observed. Count it as
// dropped.
DroppedCount++;
return true;
}
return false;
}
void DroppedVariableStats::run(DebugVariables &DbgVariables, StringRef FuncName,
bool Before) {
auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
: DbgVariables.DebugVariablesAfter);
auto &InlinedAtsMap = InlinedAts.back();
if (Before)
InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
VarIDSet = DenseSet<VarID>();
visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
}
void DroppedVariableStats::populateVarIDSetAndInlinedMap(
const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
StringRef FuncName, bool Before) {
VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
VarIDSet.insert(Key);
if (Before)
InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
}
void DroppedVariableStats::removeVarFromAllSets(VarID Var, const Function *F) {
// Do not remove Var from the last element, it will be popped from the
// stack.
for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
}
bool DroppedVariableStats::isScopeChildOfOrEqualTo(const DIScope *Scope,
const DIScope *DbgValScope) {
while (Scope != nullptr) {
if (VisitedScope.find(Scope) == VisitedScope.end()) {
VisitedScope.insert(Scope);
if (Scope == DbgValScope) {
VisitedScope.clear();
return true;
}
Scope = Scope->getScope();
} else {
VisitedScope.clear();
return false;
}
}
return false;
}
bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
if (DbgValInlinedAt == InlinedAt)
return true;
if (!DbgValInlinedAt)
return false;
auto *IA = InlinedAt;
while (IA) {
if (IA == DbgValInlinedAt)
return true;
IA = IA->getInlinedAt();
}
return false;
}

View File

@ -11,10 +11,48 @@
/// ///
///===---------------------------------------------------------------------===// ///===---------------------------------------------------------------------===//
#include "llvm/Passes/DroppedVariableStatsIR.h" #include "llvm/IR/DroppedVariableStatsIR.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassInstrumentation.h"
using namespace llvm; using namespace llvm;
template <typename IRUnitT>
const IRUnitT *DroppedVariableStatsIR::unwrapIR(Any IR) {
const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
return IRPtr ? *IRPtr : nullptr;
}
void DroppedVariableStatsIR::runBeforePass(StringRef P, Any IR) {
setup();
if (const auto *M = unwrapIR<Module>(IR))
return this->runOnModule(P, M, true);
if (const auto *F = unwrapIR<Function>(IR))
return this->runOnFunction(P, F, true);
}
void DroppedVariableStatsIR::runAfterPass(StringRef P, Any IR) {
if (const auto *M = unwrapIR<Module>(IR))
runAfterPassModule(P, M);
else if (const auto *F = unwrapIR<Function>(IR))
runAfterPassFunction(P, F);
cleanup();
}
void DroppedVariableStatsIR::runAfterPassFunction(StringRef PassID,
const Function *F) {
runOnFunction(PassID, F, false);
calculateDroppedVarStatsOnFunction(F, PassID, F->getName().str(), "Function");
}
void DroppedVariableStatsIR::runAfterPassModule(StringRef PassID,
const Module *M) {
runOnModule(PassID, M, false);
calculateDroppedVarStatsOnModule(M, PassID, M->getName().str(), "Module");
}
void DroppedVariableStatsIR::runOnFunction(StringRef PassID, const Function *F, void DroppedVariableStatsIR::runOnFunction(StringRef PassID, const Function *F,
bool Before) { bool Before) {
auto &DebugVariables = DebugVariablesStack.back()[F]; auto &DebugVariables = DebugVariablesStack.back()[F];

View File

@ -1,6 +1,5 @@
add_llvm_component_library(LLVMPasses add_llvm_component_library(LLVMPasses
CodeGenPassBuilder.cpp CodeGenPassBuilder.cpp
DroppedVariableStatsIR.cpp
OptimizationLevel.cpp OptimizationLevel.cpp
PassBuilder.cpp PassBuilder.cpp
PassBuilderBindings.cpp PassBuilderBindings.cpp

View File

@ -27,6 +27,7 @@ add_llvm_unittest(CodeGenTests
CCStateTest.cpp CCStateTest.cpp
DIEHashTest.cpp DIEHashTest.cpp
DIETest.cpp DIETest.cpp
DroppedVariableStatsMIRTest.cpp
DwarfStringPoolEntryRefTest.cpp DwarfStringPoolEntryRefTest.cpp
InstrRefLDVTest.cpp InstrRefLDVTest.cpp
LowLevelTypeTest.cpp LowLevelTypeTest.cpp

File diff suppressed because it is too large Load Diff