2424#include " llvm/CodeGen/MachineVerifier.h"
2525#include " llvm/IR/Constants.h"
2626#include " llvm/IR/Function.h"
27+ #include " llvm/IR/InstIterator.h"
28+ #include " llvm/IR/IntrinsicInst.h"
2729#include " llvm/IR/Module.h"
2830#include " llvm/IR/PassInstrumentation.h"
2931#include " llvm/IR/PassManager.h"
@@ -138,6 +140,11 @@ static cl::opt<std::string> IRDumpDirectory(
138140 " files in this directory rather than written to stderr" ),
139141 cl::Hidden, cl::value_desc(" filename" ));
140142
143+ static cl::opt<bool >
144+ DroppedVarStats (" dropped-variable-stats" , cl::Hidden,
145+ cl::desc (" Dump dropped debug variables stats" ),
146+ cl::init(false ));
147+
141148template <typename IRUnitT> static const IRUnitT *unwrapIR (Any IR) {
142149 const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
143150 return IRPtr ? *IRPtr : nullptr ;
@@ -2445,16 +2452,16 @@ void DotCfgChangeReporter::registerCallbacks(
24452452StandardInstrumentations::StandardInstrumentations (
24462453 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
24472454 PrintPassOptions PrintPassOpts)
2448- : PrintPass(DebugLogging, PrintPassOpts),
2449- OptNone (DebugLogging),
2455+ : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
24502456 OptPassGate (Context),
24512457 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
24522458 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
24532459 PrintChanged == ChangePrinter::ColourDiffVerbose,
24542460 PrintChanged == ChangePrinter::ColourDiffVerbose ||
24552461 PrintChanged == ChangePrinter::ColourDiffQuiet),
24562462 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2457- Verify(DebugLogging), VerifyEach(VerifyEach) {}
2463+ Verify(DebugLogging), DroppedStats(DroppedVarStats),
2464+ VerifyEach(VerifyEach) {}
24582465
24592466PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
24602467 nullptr ;
@@ -2514,6 +2521,182 @@ void PrintCrashIRInstrumentation::registerCallbacks(
25142521 });
25152522}
25162523
2524+ void DroppedVariableStats::registerCallbacks (
2525+ PassInstrumentationCallbacks &PIC) {
2526+ if (!DroppedVarStats)
2527+ return ;
2528+
2529+ PIC.registerBeforeNonSkippedPassCallback (
2530+ [this ](StringRef P, Any IR) { return this ->runBeforePass (P, IR); });
2531+ PIC.registerAfterPassCallback (
2532+ [this ](StringRef P, Any IR, const PreservedAnalyses &PA) {
2533+ return this ->runAfterPass (P, IR, PA);
2534+ });
2535+ PIC.registerAfterPassInvalidatedCallback (
2536+ [this ](StringRef P, const PreservedAnalyses &PA) {
2537+ return this ->runAfterPassInvalidated (P, PA);
2538+ });
2539+ }
2540+
2541+ void DroppedVariableStats::runBeforePass (StringRef PassID, Any IR) {
2542+ DebugVariablesStack.push_back ({DenseMap<const Function *, DebugVariables>()});
2543+ InlinedAts.push_back ({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
2544+ if (auto *M = unwrapIR<Module>(IR))
2545+ return this ->runOnModule (M, true );
2546+ if (auto *F = unwrapIR<Function>(IR))
2547+ return this ->runOnFunction (F, true );
2548+ return ;
2549+ }
2550+
2551+ void DroppedVariableStats::runOnFunction (const Function *F, bool Before) {
2552+ auto &DebugVariables = DebugVariablesStack.back ()[F];
2553+ auto &VarIDSet = (Before ? DebugVariables.DebugVariablesBefore
2554+ : DebugVariables.DebugVariablesAfter );
2555+ auto &InlinedAtsMap = InlinedAts.back ();
2556+ auto FuncName = F->getName ();
2557+ if (Before)
2558+ InlinedAtsMap.try_emplace (FuncName, DenseMap<VarID, DILocation *>());
2559+ VarIDSet = DenseSet<VarID>();
2560+ for (const auto &I : instructions (F)) {
2561+ for (DbgRecord &DR : I.getDbgRecordRange ()) {
2562+ if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
2563+ auto *DbgVar = Dbg->getVariable ();
2564+ auto DbgLoc = DR.getDebugLoc ();
2565+ VarID Key{DbgVar->getScope (), DbgLoc->getInlinedAtScope (), DbgVar};
2566+ VarIDSet.insert (Key);
2567+ if (Before)
2568+ InlinedAtsMap[FuncName].try_emplace (Key, DbgLoc.getInlinedAt ());
2569+ }
2570+ }
2571+ }
2572+ }
2573+
2574+ void DroppedVariableStats::runOnModule (const Module *M, bool Before) {
2575+ for (auto &F : *M)
2576+ runOnFunction (&F, Before);
2577+ }
2578+
2579+ void DroppedVariableStats::removeVarFromAllSets (VarID Var, const Function *F) {
2580+ // Do not remove Var from the last element, it will be popped from the stack.
2581+ for (auto &DebugVariablesMap : llvm::drop_end (DebugVariablesStack))
2582+ DebugVariablesMap[F].DebugVariablesBefore .erase (Var);
2583+ }
2584+
2585+ void DroppedVariableStats::calculateDroppedVarStatsOnModule (
2586+ const Module *M, StringRef PassID, std::string FuncOrModName,
2587+ std::string PassLevel) {
2588+ for (auto &F : *M) {
2589+ calculateDroppedVarStatsOnFunction (&F, PassID, FuncOrModName, PassLevel);
2590+ }
2591+ }
2592+
2593+ void DroppedVariableStats::calculateDroppedVarStatsOnFunction (
2594+ const Function *F, StringRef PassID, std::string FuncOrModName,
2595+ std::string PassLevel) {
2596+ unsigned DroppedCount = 0 ;
2597+ StringRef FuncName = F->getName ();
2598+ DebugVariables &DbgVariables = DebugVariablesStack.back ()[F];
2599+ DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore ;
2600+ DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter ;
2601+ DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back ()[FuncName];
2602+ // Find an Instruction that shares the same scope as the dropped #dbg_value or
2603+ // has a scope that is the child of the scope of the #dbg_value, and has an
2604+ // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
2605+ // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
2606+ // debug information is dropped.
2607+ for (VarID Var : DebugVariablesBeforeSet) {
2608+ if (DebugVariablesAfterSet.contains (Var))
2609+ continue ;
2610+ const DIScope *DbgValScope = std::get<0 >(Var);
2611+ for (const auto &I : instructions (F)) {
2612+ auto *DbgLoc = I.getDebugLoc ().get ();
2613+ if (!DbgLoc)
2614+ continue ;
2615+
2616+ auto *Scope = DbgLoc->getScope ();
2617+ if (isScopeChildOfOrEqualTo (Scope, DbgValScope)) {
2618+ if (isInlinedAtChildOfOrEqualTo (DbgLoc->getInlinedAt (),
2619+ InlinedAtsMap[Var])) {
2620+ // Found another instruction in the variable's scope, so there exists
2621+ // a break point at which the variable could be observed. Count it as
2622+ // dropped.
2623+ DroppedCount++;
2624+ break ;
2625+ }
2626+ }
2627+ }
2628+ removeVarFromAllSets (Var, F);
2629+ }
2630+ if (DroppedCount > 0 ) {
2631+ llvm::outs () << PassLevel << " , " << PassID << " , " << DroppedCount << " , "
2632+ << FuncOrModName << " \n " ;
2633+ PassDroppedVariables = true ;
2634+ } else
2635+ PassDroppedVariables = false ;
2636+ }
2637+
2638+ void DroppedVariableStats::runAfterPassInvalidated (
2639+ StringRef PassID, const PreservedAnalyses &PA) {
2640+ DebugVariablesStack.pop_back ();
2641+ InlinedAts.pop_back ();
2642+ }
2643+
2644+ void DroppedVariableStats::runAfterPass (StringRef PassID, Any IR,
2645+ const PreservedAnalyses &PA) {
2646+ std::string PassLevel;
2647+ std::string FuncOrModName;
2648+ if (auto *M = unwrapIR<Module>(IR)) {
2649+ this ->runOnModule (M, false );
2650+ PassLevel = " Module" ;
2651+ FuncOrModName = M->getName ();
2652+ calculateDroppedVarStatsOnModule (M, PassID, FuncOrModName, PassLevel);
2653+ } else if (auto *F = unwrapIR<Function>(IR)) {
2654+ this ->runOnFunction (F, false );
2655+ PassLevel = " Function" ;
2656+ FuncOrModName = F->getName ();
2657+ calculateDroppedVarStatsOnFunction (F, PassID, FuncOrModName, PassLevel);
2658+ }
2659+
2660+ DebugVariablesStack.pop_back ();
2661+ InlinedAts.pop_back ();
2662+ return ;
2663+ }
2664+
2665+ bool DroppedVariableStats::isScopeChildOfOrEqualTo (DIScope *Scope,
2666+ const DIScope *DbgValScope) {
2667+ while (Scope != nullptr ) {
2668+ if (VisitedScope.find (Scope) == VisitedScope.end ()) {
2669+ VisitedScope.insert (Scope);
2670+ if (Scope == DbgValScope) {
2671+ VisitedScope.clear ();
2672+ return true ;
2673+ }
2674+ Scope = Scope->getScope ();
2675+ } else {
2676+ VisitedScope.clear ();
2677+ return false ;
2678+ }
2679+ }
2680+ return false ;
2681+ }
2682+
2683+ bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo (
2684+ const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
2685+ if (DbgValInlinedAt == InlinedAt)
2686+ return true ;
2687+ if (!DbgValInlinedAt)
2688+ return false ;
2689+ if (!InlinedAt)
2690+ return false ;
2691+ auto *IA = InlinedAt;
2692+ while (IA) {
2693+ if (IA == DbgValInlinedAt)
2694+ return true ;
2695+ IA = IA->getInlinedAt ();
2696+ }
2697+ return false ;
2698+ }
2699+
25172700void StandardInstrumentations::registerCallbacks (
25182701 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
25192702 PrintIR.registerCallbacks (PIC);
@@ -2529,6 +2712,7 @@ void StandardInstrumentations::registerCallbacks(
25292712 WebsiteChangeReporter.registerCallbacks (PIC);
25302713 ChangeTester.registerCallbacks (PIC);
25312714 PrintCrashIR.registerCallbacks (PIC);
2715+ DroppedStats.registerCallbacks (PIC);
25322716 if (MAM)
25332717 PreservedCFGChecker.registerCallbacks (PIC, *MAM);
25342718
0 commit comments