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({DenseMap<const Function *, DebugVariables>()}); 30 InlinedAts.push_back({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(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 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 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 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 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 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 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