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 ;
@@ -2443,16 +2450,16 @@ void DotCfgChangeReporter::registerCallbacks(
24432450StandardInstrumentations::StandardInstrumentations (
24442451 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
24452452 PrintPassOptions PrintPassOpts)
2446- : PrintPass(DebugLogging, PrintPassOpts),
2447- OptNone (DebugLogging),
2453+ : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
24482454 OptPassGate (Context),
24492455 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
24502456 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
24512457 PrintChanged == ChangePrinter::ColourDiffVerbose,
24522458 PrintChanged == ChangePrinter::ColourDiffVerbose ||
24532459 PrintChanged == ChangePrinter::ColourDiffQuiet),
24542460 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2455- Verify(DebugLogging), VerifyEach(VerifyEach) {}
2461+ Verify(DebugLogging), DroppedStats(DroppedVarStats),
2462+ VerifyEach(VerifyEach) {}
24562463
24572464PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
24582465 nullptr ;
@@ -2512,6 +2519,182 @@ void PrintCrashIRInstrumentation::registerCallbacks(
25122519 });
25132520}
25142521
2522+ void DroppedVariableStats::registerCallbacks (
2523+ PassInstrumentationCallbacks &PIC) {
2524+ if (!DroppedVarStats)
2525+ return ;
2526+
2527+ PIC.registerBeforeNonSkippedPassCallback (
2528+ [this ](StringRef P, Any IR) { return this ->runBeforePass (P, IR); });
2529+ PIC.registerAfterPassCallback (
2530+ [this ](StringRef P, Any IR, const PreservedAnalyses &PA) {
2531+ return this ->runAfterPass (P, IR, PA);
2532+ });
2533+ PIC.registerAfterPassInvalidatedCallback (
2534+ [this ](StringRef P, const PreservedAnalyses &PA) {
2535+ return this ->runAfterPassInvalidated (P, PA);
2536+ });
2537+ }
2538+
2539+ void DroppedVariableStats::runBeforePass (StringRef PassID, Any IR) {
2540+ DebugVariablesStack.push_back ({DenseMap<const Function *, DebugVariables>()});
2541+ InlinedAts.push_back ({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
2542+ if (auto *M = unwrapIR<Module>(IR))
2543+ return this ->runOnModule (M, true );
2544+ if (auto *F = unwrapIR<Function>(IR))
2545+ return this ->runOnFunction (F, true );
2546+ return ;
2547+ }
2548+
2549+ void DroppedVariableStats::runOnFunction (const Function *F, bool Before) {
2550+ auto &DebugVariables = DebugVariablesStack.back ()[F];
2551+ auto &VarIDSet = (Before ? DebugVariables.DebugVariablesBefore
2552+ : DebugVariables.DebugVariablesAfter );
2553+ auto &InlinedAtsMap = InlinedAts.back ();
2554+ auto FuncName = F->getName ();
2555+ if (Before)
2556+ InlinedAtsMap.try_emplace (FuncName, DenseMap<VarID, DILocation *>());
2557+ VarIDSet = DenseSet<VarID>();
2558+ for (const auto &I : instructions (F)) {
2559+ for (DbgRecord &DR : I.getDbgRecordRange ()) {
2560+ if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
2561+ auto *DbgVar = Dbg->getVariable ();
2562+ auto DbgLoc = DR.getDebugLoc ();
2563+ VarID Key{DbgVar->getScope (), DbgLoc->getInlinedAtScope (), DbgVar};
2564+ VarIDSet.insert (Key);
2565+ if (Before)
2566+ InlinedAtsMap[FuncName].try_emplace (Key, DbgLoc.getInlinedAt ());
2567+ }
2568+ }
2569+ }
2570+ }
2571+
2572+ void DroppedVariableStats::runOnModule (const Module *M, bool Before) {
2573+ for (auto &F : *M)
2574+ runOnFunction (&F, Before);
2575+ }
2576+
2577+ void DroppedVariableStats::removeVarFromAllSets (VarID Var, const Function *F) {
2578+ // Do not remove Var from the last element, it will be popped from the stack.
2579+ for (auto &DebugVariablesMap : llvm::drop_end (DebugVariablesStack))
2580+ DebugVariablesMap[F].DebugVariablesBefore .erase (Var);
2581+ }
2582+
2583+ void DroppedVariableStats::calculateDroppedVarStatsOnModule (
2584+ const Module *M, StringRef PassID, std::string FuncOrModName,
2585+ std::string PassLevel) {
2586+ for (auto &F : *M) {
2587+ calculateDroppedVarStatsOnFunction (&F, PassID, FuncOrModName, PassLevel);
2588+ }
2589+ }
2590+
2591+ void DroppedVariableStats::calculateDroppedVarStatsOnFunction (
2592+ const Function *F, StringRef PassID, std::string FuncOrModName,
2593+ std::string PassLevel) {
2594+ unsigned DroppedCount = 0 ;
2595+ StringRef FuncName = F->getName ();
2596+ DebugVariables &DbgVariables = DebugVariablesStack.back ()[F];
2597+ DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore ;
2598+ DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter ;
2599+ DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back ()[FuncName];
2600+ // Find an Instruction that shares the same scope as the dropped #dbg_value or
2601+ // has a scope that is the child of the scope of the #dbg_value, and has an
2602+ // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
2603+ // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
2604+ // debug information is dropped.
2605+ for (VarID Var : DebugVariablesBeforeSet) {
2606+ if (DebugVariablesAfterSet.contains (Var))
2607+ continue ;
2608+ const DIScope *DbgValScope = std::get<0 >(Var);
2609+ for (const auto &I : instructions (F)) {
2610+ auto *DbgLoc = I.getDebugLoc ().get ();
2611+ if (!DbgLoc)
2612+ continue ;
2613+
2614+ auto *Scope = DbgLoc->getScope ();
2615+ if (isScopeChildOfOrEqualTo (Scope, DbgValScope)) {
2616+ if (isInlinedAtChildOfOrEqualTo (DbgLoc->getInlinedAt (),
2617+ InlinedAtsMap[Var])) {
2618+ // Found another instruction in the variable's scope, so there exists
2619+ // a break point at which the variable could be observed. Count it as
2620+ // dropped.
2621+ DroppedCount++;
2622+ break ;
2623+ }
2624+ }
2625+ }
2626+ removeVarFromAllSets (Var, F);
2627+ }
2628+ if (DroppedCount > 0 ) {
2629+ llvm::outs () << PassLevel << " , " << PassID << " , " << DroppedCount << " , "
2630+ << FuncOrModName << " \n " ;
2631+ PassDroppedVariables = true ;
2632+ } else
2633+ PassDroppedVariables = false ;
2634+ }
2635+
2636+ void DroppedVariableStats::runAfterPassInvalidated (
2637+ StringRef PassID, const PreservedAnalyses &PA) {
2638+ DebugVariablesStack.pop_back ();
2639+ InlinedAts.pop_back ();
2640+ }
2641+
2642+ void DroppedVariableStats::runAfterPass (StringRef PassID, Any IR,
2643+ const PreservedAnalyses &PA) {
2644+ std::string PassLevel;
2645+ std::string FuncOrModName;
2646+ if (auto *M = unwrapIR<Module>(IR)) {
2647+ this ->runOnModule (M, false );
2648+ PassLevel = " Module" ;
2649+ FuncOrModName = M->getName ();
2650+ calculateDroppedVarStatsOnModule (M, PassID, FuncOrModName, PassLevel);
2651+ } else if (auto *F = unwrapIR<Function>(IR)) {
2652+ this ->runOnFunction (F, false );
2653+ PassLevel = " Function" ;
2654+ FuncOrModName = F->getName ();
2655+ calculateDroppedVarStatsOnFunction (F, PassID, FuncOrModName, PassLevel);
2656+ }
2657+
2658+ DebugVariablesStack.pop_back ();
2659+ InlinedAts.pop_back ();
2660+ return ;
2661+ }
2662+
2663+ bool DroppedVariableStats::isScopeChildOfOrEqualTo (DIScope *Scope,
2664+ const DIScope *DbgValScope) {
2665+ while (Scope != nullptr ) {
2666+ if (VisitedScope.find (Scope) == VisitedScope.end ()) {
2667+ VisitedScope.insert (Scope);
2668+ if (Scope == DbgValScope) {
2669+ VisitedScope.clear ();
2670+ return true ;
2671+ }
2672+ Scope = Scope->getScope ();
2673+ } else {
2674+ VisitedScope.clear ();
2675+ return false ;
2676+ }
2677+ }
2678+ return false ;
2679+ }
2680+
2681+ bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo (
2682+ const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
2683+ if (DbgValInlinedAt == InlinedAt)
2684+ return true ;
2685+ if (!DbgValInlinedAt)
2686+ return false ;
2687+ if (!InlinedAt)
2688+ return false ;
2689+ auto *IA = InlinedAt;
2690+ while (IA) {
2691+ if (IA == DbgValInlinedAt)
2692+ return true ;
2693+ IA = IA->getInlinedAt ();
2694+ }
2695+ return false ;
2696+ }
2697+
25152698void StandardInstrumentations::registerCallbacks (
25162699 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
25172700 PrintIR.registerCallbacks (PIC);
@@ -2527,6 +2710,7 @@ void StandardInstrumentations::registerCallbacks(
25272710 WebsiteChangeReporter.registerCallbacks (PIC);
25282711 ChangeTester.registerCallbacks (PIC);
25292712 PrintCrashIR.registerCallbacks (PIC);
2713+ DroppedStats.registerCallbacks (PIC);
25302714 if (MAM)
25312715 PreservedCFGChecker.registerCallbacks (PIC, *MAM);
25322716
0 commit comments