xref: /freebsd/contrib/llvm-project/llvm/lib/IR/DroppedVariableStats.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 ///===- DroppedVariableStats.cpp ----------------------------------------===//
2 ///
3 /// Part of the LLVM Project, under the Apache License v2.0 with LLVM
4 /// Exceptions. See https://llvm.org/LICENSE.txt for license information.
5 /// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 ///
7 ///===---------------------------------------------------------------------===//
8 /// \file
9 /// Dropped Variable Statistics for Debug Information. Reports any number
10 /// of #dbg_value that get dropped due to an optimization pass.
11 ///
12 ///===---------------------------------------------------------------------===//
13 
14 #include "llvm/IR/DroppedVariableStats.h"
15 #include "llvm/IR/DebugInfoMetadata.h"
16 #include "llvm/IR/DiagnosticInfo.h"
17 #include "llvm/IR/Function.h"
18 
19 using namespace llvm;
20 
DroppedVariableStats(bool DroppedVarStatsEnabled)21 DroppedVariableStats::DroppedVariableStats(bool DroppedVarStatsEnabled)
22     : DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
23   if (DroppedVarStatsEnabled)
24     llvm::outs() << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
25                     "Module Name\n";
26 }
27 
setup()28 void DroppedVariableStats::setup() {
29   DebugVariablesStack.push_back({DenseMap<const Function *, DebugVariables>()});
30   InlinedAts.push_back({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
31 }
32 
cleanup()33 void DroppedVariableStats::cleanup() {
34   assert(!DebugVariablesStack.empty() &&
35          "DebugVariablesStack shouldn't be empty!");
36   assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
37   DebugVariablesStack.pop_back();
38   InlinedAts.pop_back();
39 }
40 
calculateDroppedStatsAndPrint(DebugVariables & DbgVariables,StringRef FuncName,StringRef PassID,StringRef FuncOrModName,StringRef PassLevel,const Function * Func)41 void DroppedVariableStats::calculateDroppedStatsAndPrint(
42     DebugVariables &DbgVariables, StringRef FuncName, StringRef PassID,
43     StringRef FuncOrModName, StringRef PassLevel, const Function *Func) {
44   unsigned DroppedCount = 0;
45   DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
46   DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
47   auto It = InlinedAts.back().find(FuncName);
48   if (It == InlinedAts.back().end())
49     return;
50   DenseMap<VarID, DILocation *> &InlinedAtsMap = It->second;
51   // Find an Instruction that shares the same scope as the dropped #dbg_value
52   // or has a scope that is the child of the scope of the #dbg_value, and has
53   // an inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt
54   // chain contains the inlinedAt of the #dbg_value, if such an Instruction is
55   // found, debug information is dropped.
56   for (VarID Var : DebugVariablesBeforeSet) {
57     if (DebugVariablesAfterSet.contains(Var))
58       continue;
59     visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
60     removeVarFromAllSets(Var, Func);
61   }
62   if (DroppedCount > 0) {
63     llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
64                  << FuncOrModName << "\n";
65     PassDroppedVariables = true;
66   } else
67     PassDroppedVariables = false;
68 }
69 
updateDroppedCount(DILocation * DbgLoc,const DIScope * Scope,const DIScope * DbgValScope,DenseMap<VarID,DILocation * > & InlinedAtsMap,VarID Var,unsigned & DroppedCount)70 bool DroppedVariableStats::updateDroppedCount(
71     DILocation *DbgLoc, const DIScope *Scope, const DIScope *DbgValScope,
72     DenseMap<VarID, DILocation *> &InlinedAtsMap, VarID Var,
73     unsigned &DroppedCount) {
74   // If the Scope is a child of, or equal to the DbgValScope and is inlined at
75   // the Var's InlinedAt location, return true to signify that the Var has
76   // been dropped.
77   if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
78     if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
79                                     InlinedAtsMap[Var])) {
80       // Found another instruction in the variable's scope, so there exists a
81       // break point at which the variable could be observed. Count it as
82       // dropped.
83       DroppedCount++;
84       return true;
85     }
86   return false;
87 }
88 
run(DebugVariables & DbgVariables,StringRef FuncName,bool Before)89 void DroppedVariableStats::run(DebugVariables &DbgVariables, StringRef FuncName,
90                                bool Before) {
91   auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
92                            : DbgVariables.DebugVariablesAfter);
93   auto &InlinedAtsMap = InlinedAts.back();
94   if (Before)
95     InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
96   VarIDSet = DenseSet<VarID>();
97   visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
98 }
99 
populateVarIDSetAndInlinedMap(const DILocalVariable * DbgVar,DebugLoc DbgLoc,DenseSet<VarID> & VarIDSet,DenseMap<StringRef,DenseMap<VarID,DILocation * >> & InlinedAtsMap,StringRef FuncName,bool Before)100 void DroppedVariableStats::populateVarIDSetAndInlinedMap(
101     const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
102     DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
103     StringRef FuncName, bool Before) {
104   VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
105   VarIDSet.insert(Key);
106   if (Before)
107     InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
108 }
109 
removeVarFromAllSets(VarID Var,const Function * F)110 void DroppedVariableStats::removeVarFromAllSets(VarID Var, const Function *F) {
111   // Do not remove Var from the last element, it will be popped from the
112   // stack.
113   for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
114     DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
115 }
116 
isScopeChildOfOrEqualTo(const DIScope * Scope,const DIScope * DbgValScope)117 bool DroppedVariableStats::isScopeChildOfOrEqualTo(const DIScope *Scope,
118                                                    const DIScope *DbgValScope) {
119   while (Scope != nullptr) {
120     if (VisitedScope.insert(Scope).second) {
121       if (Scope == DbgValScope) {
122         VisitedScope.clear();
123         return true;
124       }
125       Scope = Scope->getScope();
126     } else {
127       VisitedScope.clear();
128       return false;
129     }
130   }
131   return false;
132 }
133 
isInlinedAtChildOfOrEqualTo(const DILocation * InlinedAt,const DILocation * DbgValInlinedAt)134 bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
135     const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
136   if (DbgValInlinedAt == InlinedAt)
137     return true;
138   if (!DbgValInlinedAt)
139     return false;
140   auto *IA = InlinedAt;
141   while (IA) {
142     if (IA == DbgValInlinedAt)
143       return true;
144     IA = IA->getInlinedAt();
145   }
146   return false;
147 }
148