Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:22

0001 ///===- DroppedVariableStats.h - Opt Diagnostics -*- C++ -*----------------===//
0002 ///
0003 /// Part of the LLVM Project, under the Apache License v2.0 with LLVM
0004 /// Exceptions. See https://llvm.org/LICENSE.txt for license information.
0005 /// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 ///
0007 ///===---------------------------------------------------------------------===//
0008 /// \file
0009 /// Dropped Variable Statistics for Debug Information. Reports any number
0010 /// of #dbg_value that get dropped due to an optimization pass.
0011 ///
0012 ///===---------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
0015 #define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
0016 
0017 #include "llvm/IR/DebugInfoMetadata.h"
0018 #include "llvm/IR/DiagnosticInfo.h"
0019 #include "llvm/IR/Function.h"
0020 #include "llvm/IR/PassInstrumentation.h"
0021 
0022 namespace llvm {
0023 
0024 /// A unique key that represents a debug variable.
0025 /// First const DIScope *: Represents the scope of the debug variable.
0026 /// Second const DIScope *: Represents the InlinedAt scope of the debug
0027 /// variable. const DILocalVariable *: It is a pointer to the debug variable
0028 /// itself.
0029 using VarID =
0030     std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
0031 
0032 /// A base class to collect and print dropped debug information variable
0033 /// statistics.
0034 class DroppedVariableStats {
0035 public:
0036   DroppedVariableStats(bool DroppedVarStatsEnabled)
0037       : DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
0038     if (DroppedVarStatsEnabled)
0039       llvm::outs()
0040           << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
0041              "Module Name\n";
0042   };
0043 
0044   virtual ~DroppedVariableStats() {}
0045 
0046   // We intend this to be unique per-compilation, thus no copies.
0047   DroppedVariableStats(const DroppedVariableStats &) = delete;
0048   void operator=(const DroppedVariableStats &) = delete;
0049 
0050   bool getPassDroppedVariables() { return PassDroppedVariables; }
0051 
0052 protected:
0053   void setup() {
0054     DebugVariablesStack.push_back(
0055         {DenseMap<const Function *, DebugVariables>()});
0056     InlinedAts.push_back(
0057         {DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
0058   }
0059 
0060   void cleanup() {
0061     assert(!DebugVariablesStack.empty() &&
0062            "DebugVariablesStack shouldn't be empty!");
0063     assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
0064     DebugVariablesStack.pop_back();
0065     InlinedAts.pop_back();
0066   }
0067 
0068   bool DroppedVariableStatsEnabled = false;
0069   struct DebugVariables {
0070     /// DenseSet of VarIDs before an optimization pass has run.
0071     DenseSet<VarID> DebugVariablesBefore;
0072     /// DenseSet of VarIDs after an optimization pass has run.
0073     DenseSet<VarID> DebugVariablesAfter;
0074   };
0075 
0076 protected:
0077   /// A stack of a DenseMap, that maps DebugVariables for every pass to an
0078   /// llvm::Function. A stack is used because an optimization pass can call
0079   /// other passes.
0080   SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
0081 
0082   /// A DenseSet tracking whether a scope was visited before.
0083   DenseSet<const DIScope *> VisitedScope;
0084   /// A stack of DenseMaps, which map the name of an llvm::Function to a
0085   /// DenseMap of VarIDs and their inlinedAt locations before an optimization
0086   /// pass has run.
0087   SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
0088   /// Calculate the number of dropped variables in an llvm::Function or
0089   /// llvm::MachineFunction and print the relevant information to stdout.
0090   void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables,
0091                                      StringRef FuncName, StringRef PassID,
0092                                      StringRef FuncOrModName,
0093                                      StringRef PassLevel,
0094                                      const Function *Func) {
0095     unsigned DroppedCount = 0;
0096     DenseSet<VarID> &DebugVariablesBeforeSet =
0097         DbgVariables.DebugVariablesBefore;
0098     DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
0099     DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
0100     // Find an Instruction that shares the same scope as the dropped #dbg_value
0101     // or has a scope that is the child of the scope of the #dbg_value, and has
0102     // an inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt
0103     // chain contains the inlinedAt of the #dbg_value, if such an Instruction is
0104     // found, debug information is dropped.
0105     for (VarID Var : DebugVariablesBeforeSet) {
0106       if (DebugVariablesAfterSet.contains(Var))
0107         continue;
0108       visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
0109       removeVarFromAllSets(Var, Func);
0110     }
0111     if (DroppedCount > 0) {
0112       llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount
0113                    << ", " << FuncOrModName << "\n";
0114       PassDroppedVariables = true;
0115     } else
0116       PassDroppedVariables = false;
0117   }
0118 
0119   /// Check if a \p Var has been dropped or is a false positive. Also update the
0120   /// \p DroppedCount if a debug variable is dropped.
0121   bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope,
0122                           const DIScope *DbgValScope,
0123                           DenseMap<VarID, DILocation *> &InlinedAtsMap,
0124                           VarID Var, unsigned &DroppedCount) {
0125     // If the Scope is a child of, or equal to the DbgValScope and is inlined at
0126     // the Var's InlinedAt location, return true to signify that the Var has
0127     // been dropped.
0128     if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
0129       if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
0130                                       InlinedAtsMap[Var])) {
0131         // Found another instruction in the variable's scope, so there exists a
0132         // break point at which the variable could be observed. Count it as
0133         // dropped.
0134         DroppedCount++;
0135         return true;
0136       }
0137     return false;
0138   }
0139   /// Run code to populate relevant data structures over an llvm::Function or
0140   /// llvm::MachineFunction.
0141   void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before) {
0142     auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
0143                              : DbgVariables.DebugVariablesAfter);
0144     auto &InlinedAtsMap = InlinedAts.back();
0145     if (Before)
0146       InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
0147     VarIDSet = DenseSet<VarID>();
0148     visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
0149   }
0150   /// Populate the VarIDSet and InlinedAtMap with the relevant information
0151   /// needed for before and after pass analysis to determine dropped variable
0152   /// status.
0153   void populateVarIDSetAndInlinedMap(
0154       const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
0155       DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
0156       StringRef FuncName, bool Before) {
0157     VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
0158     VarIDSet.insert(Key);
0159     if (Before)
0160       InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
0161   }
0162   /// Visit every llvm::Instruction or llvm::MachineInstruction and check if the
0163   /// debug variable denoted by its ID \p Var may have been dropped by an
0164   /// optimization pass.
0165   virtual void
0166   visitEveryInstruction(unsigned &DroppedCount,
0167                         DenseMap<VarID, DILocation *> &InlinedAtsMap,
0168                         VarID Var) = 0;
0169   /// Visit every debug record in an llvm::Function or llvm::MachineFunction
0170   /// and call populateVarIDSetAndInlinedMap on it.
0171   virtual void visitEveryDebugRecord(
0172       DenseSet<VarID> &VarIDSet,
0173       DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
0174       StringRef FuncName, bool Before) = 0;
0175 
0176 private:
0177   /// Remove a dropped debug variable's VarID from all Sets in the
0178   /// DroppedVariablesBefore stack.
0179   void removeVarFromAllSets(VarID Var, const Function *F) {
0180     // Do not remove Var from the last element, it will be popped from the
0181     // stack.
0182     for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
0183       DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
0184   }
0185   /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
0186   /// \p DbgValScope, return false otherwise.
0187   bool isScopeChildOfOrEqualTo(const DIScope *Scope,
0188                                const DIScope *DbgValScope) {
0189     while (Scope != nullptr) {
0190       if (VisitedScope.find(Scope) == VisitedScope.end()) {
0191         VisitedScope.insert(Scope);
0192         if (Scope == DbgValScope) {
0193           VisitedScope.clear();
0194           return true;
0195         }
0196         Scope = Scope->getScope();
0197       } else {
0198         VisitedScope.clear();
0199         return false;
0200       }
0201     }
0202     return false;
0203   }
0204   /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
0205   /// the InlinedAt chain, return false otherwise.
0206   bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
0207                                    const DILocation *DbgValInlinedAt) {
0208     if (DbgValInlinedAt == InlinedAt)
0209       return true;
0210     if (!DbgValInlinedAt)
0211       return false;
0212     auto *IA = InlinedAt;
0213     while (IA) {
0214       if (IA == DbgValInlinedAt)
0215         return true;
0216       IA = IA->getInlinedAt();
0217     }
0218     return false;
0219   }
0220   bool PassDroppedVariables = false;
0221 };
0222 
0223 } // namespace llvm
0224 
0225 #endif