196 changes: 0 additions & 196 deletions llvm/lib/CodeGen/DroppedVariableStats.cpp

This file was deleted.

178 changes: 176 additions & 2 deletions llvm/lib/Passes/StandardInstrumentations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2462,7 +2462,7 @@ StandardInstrumentations::StandardInstrumentations(
PrintChanged == ChangePrinter::ColourDiffVerbose ||
PrintChanged == ChangePrinter::ColourDiffQuiet),
WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
Verify(DebugLogging), DroppedStats(DroppedVarStats),
VerifyEach(VerifyEach) {}

PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
Expand Down Expand Up @@ -2523,6 +2523,180 @@ void PrintCrashIRInstrumentation::registerCallbacks(
});
}

void DroppedVariableStats::registerCallbacks(
PassInstrumentationCallbacks &PIC) {
if (!DroppedVarStats)
return;

PIC.registerBeforeNonSkippedPassCallback(
[this](StringRef P, Any IR) { return this->runBeforePass(P, IR); });
PIC.registerAfterPassCallback(
[this](StringRef P, Any IR, const PreservedAnalyses &PA) {
return this->runAfterPass(P, IR, PA);
});
PIC.registerAfterPassInvalidatedCallback(
[this](StringRef P, const PreservedAnalyses &PA) {
return this->runAfterPassInvalidated(P, PA);
});
}

void DroppedVariableStats::runBeforePass(StringRef PassID, Any IR) {
DebugVariablesStack.push_back({DenseMap<const Function *, DebugVariables>()});
InlinedAts.push_back({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
if (auto *M = unwrapIR<Module>(IR))
return this->runOnModule(M, true);
if (auto *F = unwrapIR<Function>(IR))
return this->runOnFunction(F, true);
}

void DroppedVariableStats::runOnFunction(const Function *F, bool Before) {
auto &DebugVariables = DebugVariablesStack.back()[F];
auto &VarIDSet = (Before ? DebugVariables.DebugVariablesBefore
: DebugVariables.DebugVariablesAfter);
auto &InlinedAtsMap = InlinedAts.back();
auto FuncName = F->getName();
if (Before)
InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
VarIDSet = DenseSet<VarID>();
for (const auto &I : instructions(F)) {
for (DbgRecord &DR : I.getDbgRecordRange()) {
if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
auto *DbgVar = Dbg->getVariable();
auto DbgLoc = DR.getDebugLoc();
VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
VarIDSet.insert(Key);
if (Before)
InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
}
}
}
}

void DroppedVariableStats::runOnModule(const Module *M, bool Before) {
for (auto &F : *M)
runOnFunction(&F, Before);
}

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);
}

void DroppedVariableStats::calculateDroppedVarStatsOnModule(
const Module *M, StringRef PassID, std::string FuncOrModName,
std::string PassLevel) {
for (auto &F : *M) {
calculateDroppedVarStatsOnFunction(&F, PassID, FuncOrModName, PassLevel);
}
}

void DroppedVariableStats::calculateDroppedVarStatsOnFunction(
const Function *F, StringRef PassID, std::string FuncOrModName,
std::string PassLevel) {
unsigned DroppedCount = 0;
StringRef FuncName = F->getName();
DebugVariables &DbgVariables = DebugVariablesStack.back()[F];
DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
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;
const DIScope *DbgValScope = std::get<0>(Var);
for (const auto &I : instructions(F)) {
auto *DbgLoc = I.getDebugLoc().get();
if (!DbgLoc)
continue;

auto *Scope = DbgLoc->getScope();
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++;
break;
}
}
}
removeVarFromAllSets(Var, F);
}
if (DroppedCount > 0) {
llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
<< FuncOrModName << "\n";
PassDroppedVariables = true;
} else
PassDroppedVariables = false;
}

void DroppedVariableStats::runAfterPassInvalidated(
StringRef PassID, const PreservedAnalyses &PA) {
DebugVariablesStack.pop_back();
InlinedAts.pop_back();
}

void DroppedVariableStats::runAfterPass(StringRef PassID, Any IR,
const PreservedAnalyses &PA) {
std::string PassLevel;
std::string FuncOrModName;
if (auto *M = unwrapIR<Module>(IR)) {
this->runOnModule(M, false);
PassLevel = "Module";
FuncOrModName = M->getName();
calculateDroppedVarStatsOnModule(M, PassID, FuncOrModName, PassLevel);
} else if (auto *F = unwrapIR<Function>(IR)) {
this->runOnFunction(F, false);
PassLevel = "Function";
FuncOrModName = F->getName();
calculateDroppedVarStatsOnFunction(F, PassID, FuncOrModName, PassLevel);
}

DebugVariablesStack.pop_back();
InlinedAts.pop_back();
}

bool DroppedVariableStats::isScopeChildOfOrEqualTo(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;
if (!InlinedAt)
return false;
auto *IA = InlinedAt;
while (IA) {
if (IA == DbgValInlinedAt)
return true;
IA = IA->getInlinedAt();
}
return false;
}

void StandardInstrumentations::registerCallbacks(
PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
PrintIR.registerCallbacks(PIC);
Expand All @@ -2538,7 +2712,7 @@ void StandardInstrumentations::registerCallbacks(
WebsiteChangeReporter.registerCallbacks(PIC);
ChangeTester.registerCallbacks(PIC);
PrintCrashIR.registerCallbacks(PIC);
DroppedStatsIR.registerCallbacks(PIC);
DroppedStats.registerCallbacks(PIC);
if (MAM)
PreservedCFGChecker.registerCallbacks(PIC, *MAM);

Expand Down
1 change: 0 additions & 1 deletion llvm/unittests/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ add_llvm_unittest(CodeGenTests
CCStateTest.cpp
DIEHashTest.cpp
DIETest.cpp
DroppedVariableStatsIRTest.cpp
DwarfStringPoolEntryRefTest.cpp
InstrRefLDVTest.cpp
LowLevelTypeTest.cpp
Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_llvm_unittest(IRTests
ShuffleVectorInstTest.cpp
StructuralHashTest.cpp
TimePassesTest.cpp
DroppedVariableStatsTest.cpp
TypesTest.cpp
UseTest.cpp
UserTest.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//===- unittests/IR/DroppedVariableStatsIRTest.cpp ------------------------===//
//===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
//----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand All @@ -7,7 +8,6 @@
//===----------------------------------------------------------------------===//

#include "llvm/AsmParser/Parser.h"
#include "llvm/CodeGen/DroppedVariableStats.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LegacyPassManager.h"
Expand Down Expand Up @@ -44,7 +44,7 @@ namespace {
// This test ensures that if a #dbg_value and an instruction that exists in the
// same scope as that #dbg_value are both deleted as a result of an optimization
// pass, debug information is considered not dropped.
TEST(DroppedVariableStatsIR, BothDeleted) {
TEST(DroppedVariableStats, BothDeleted) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -79,8 +79,9 @@ TEST(DroppedVariableStatsIR, BothDeleted) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -91,15 +92,16 @@ TEST(DroppedVariableStatsIR, BothDeleted) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), false);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that shares the same scope as the #dbg_value still exists,
// debug information is conisdered dropped.
TEST(DroppedVariableStatsIR, DbgValLost) {
TEST(DroppedVariableStats, DbgValLost) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -134,8 +136,9 @@ TEST(DroppedVariableStatsIR, DbgValLost) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -145,15 +148,16 @@ TEST(DroppedVariableStatsIR, DbgValLost) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that has an unrelated scope as the #dbg_value still
// exists, debug information is conisdered not dropped.
TEST(DroppedVariableStatsIR, UnrelatedScopes) {
TEST(DroppedVariableStats, UnrelatedScopes) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -189,8 +193,9 @@ TEST(DroppedVariableStatsIR, UnrelatedScopes) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -200,15 +205,16 @@ TEST(DroppedVariableStatsIR, UnrelatedScopes) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), false);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that has a scope which is a child of the #dbg_value scope
// still exists, debug information is conisdered dropped.
TEST(DroppedVariableStatsIR, ChildScopes) {
TEST(DroppedVariableStats, ChildScopes) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -244,8 +250,9 @@ TEST(DroppedVariableStatsIR, ChildScopes) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -255,16 +262,17 @@ TEST(DroppedVariableStatsIR, ChildScopes) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that has a scope which is a child of the #dbg_value scope
// still exists, and the #dbg_value is inlined at another location, debug
// information is conisdered not dropped.
TEST(DroppedVariableStatsIR, InlinedAt) {
TEST(DroppedVariableStats, InlinedAt) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -300,8 +308,9 @@ TEST(DroppedVariableStatsIR, InlinedAt) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -311,16 +320,17 @@ TEST(DroppedVariableStatsIR, InlinedAt) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), false);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that has a scope which is a child of the #dbg_value scope
// still exists, and the #dbg_value and the instruction are inlined at another
// location, debug information is conisdered dropped.
TEST(DroppedVariableStatsIR, InlinedAtShared) {
TEST(DroppedVariableStats, InlinedAtShared) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -356,8 +366,9 @@ TEST(DroppedVariableStatsIR, InlinedAtShared) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -367,16 +378,17 @@ TEST(DroppedVariableStatsIR, InlinedAtShared) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}

// This test ensures that if a #dbg_value is dropped after an optimization pass,
// but an instruction that has a scope which is a child of the #dbg_value scope
// still exists, and the instruction is inlined at a location that is the
// #dbg_value's inlined at location, debug information is conisdered dropped.
TEST(DroppedVariableStatsIR, InlinedAtChild) {
TEST(DroppedVariableStats, InlinedAtChild) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);

Expand Down Expand Up @@ -413,8 +425,9 @@ TEST(DroppedVariableStatsIR, InlinedAtChild) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);

DroppedVariableStatsIR Stats(true);
Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
DroppedVariableStats Stats(true);
Stats.runBeforePass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));

// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
Expand All @@ -424,8 +437,9 @@ TEST(DroppedVariableStatsIR, InlinedAtChild) {
}
break;
}
PreservedAnalyses PA;
Stats.runAfterPass("Test",
llvm::Any(const_cast<const llvm::Module *>(M.get())));
llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}

Expand Down