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 | |
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 | |
28 | void DroppedVariableStats::setup() { |
29 | DebugVariablesStack.push_back(Elt: {DenseMap<const Function *, DebugVariables>()}); |
30 | InlinedAts.push_back(Elt: {DenseMap<StringRef, DenseMap<VarID, DILocation *>>()}); |
31 | } |
32 | |
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 | |
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(Val: 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(V: Var)) |
58 | continue; |
59 | visitEveryInstruction(DroppedCount, InlinedAtsMap, Var); |
60 | removeVarFromAllSets(Var, F: 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 | |
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(InlinedAt: DbgLoc->getInlinedAt(), |
79 | DbgValInlinedAt: 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 | |
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(Key: FuncName, Args: DenseMap<VarID, DILocation *>()); |
96 | VarIDSet = DenseSet<VarID>(); |
97 | visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before); |
98 | } |
99 | |
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(V: Key); |
106 | if (Before) |
107 | InlinedAtsMap[FuncName].try_emplace(Key, Args: DbgLoc.getInlinedAt()); |
108 | } |
109 | |
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(RangeOrContainer&: DebugVariablesStack)) |
114 | DebugVariablesMap[F].DebugVariablesBefore.erase(V: Var); |
115 | } |
116 | |
117 | bool DroppedVariableStats::isScopeChildOfOrEqualTo(const DIScope *Scope, |
118 | const DIScope *DbgValScope) { |
119 | while (Scope != nullptr) { |
120 | if (VisitedScope.insert(V: 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 | |
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 | |