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