xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
15ffd83dbSDimitry Andric //===-- Statistics.cpp - Debug Info quality metrics -----------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "llvm-dwarfdump.h"
100b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
110b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
120b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
140b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
158bcb0991SDimitry Andric #include "llvm/Support/JSON.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #define DEBUG_TYPE "dwarfdump"
180b57cec5SDimitry Andric using namespace llvm;
195ffd83dbSDimitry Andric using namespace llvm::dwarfdump;
205ffd83dbSDimitry Andric using namespace llvm::object;
210b57cec5SDimitry Andric 
22fe6060f1SDimitry Andric namespace {
238bcb0991SDimitry Andric /// This represents the number of categories of debug location coverage being
248bcb0991SDimitry Andric /// calculated. The first category is the number of variables with 0% location
258bcb0991SDimitry Andric /// coverage, but the last category is the number of variables with 100%
268bcb0991SDimitry Andric /// location coverage.
278bcb0991SDimitry Andric constexpr int NumOfCoverageCategories = 12;
288bcb0991SDimitry Andric 
29fe6060f1SDimitry Andric /// This is used for zero location coverage bucket.
30fe6060f1SDimitry Andric constexpr unsigned ZeroCoverageBucket = 0;
31fe6060f1SDimitry Andric 
32*349cc55cSDimitry Andric /// The UINT64_MAX is used as an indication of the overflow.
33*349cc55cSDimitry Andric constexpr uint64_t OverflowValue = std::numeric_limits<uint64_t>::max();
34*349cc55cSDimitry Andric 
35fe6060f1SDimitry Andric /// This represents variables DIE offsets.
36fe6060f1SDimitry Andric using AbstractOriginVarsTy = llvm::SmallVector<uint64_t>;
37fe6060f1SDimitry Andric /// This maps function DIE offset to its variables.
38fe6060f1SDimitry Andric using AbstractOriginVarsTyMap = llvm::DenseMap<uint64_t, AbstractOriginVarsTy>;
39fe6060f1SDimitry Andric /// This represents function DIE offsets containing an abstract_origin.
40fe6060f1SDimitry Andric using FunctionsWithAbstractOriginTy = llvm::SmallVector<uint64_t>;
41fe6060f1SDimitry Andric 
42*349cc55cSDimitry Andric /// This represents a data type for the stats and it helps us to
43*349cc55cSDimitry Andric /// detect an overflow.
44*349cc55cSDimitry Andric /// NOTE: This can be implemented as a template if there is an another type
45*349cc55cSDimitry Andric /// needing this.
46*349cc55cSDimitry Andric struct SaturatingUINT64 {
47*349cc55cSDimitry Andric   /// Number that represents the stats.
48*349cc55cSDimitry Andric   uint64_t Value;
49*349cc55cSDimitry Andric 
50*349cc55cSDimitry Andric   SaturatingUINT64(uint64_t Value_) : Value(Value_) {}
51*349cc55cSDimitry Andric 
52*349cc55cSDimitry Andric   void operator++(int) { return *this += 1; }
53*349cc55cSDimitry Andric   void operator+=(uint64_t Value_) {
54*349cc55cSDimitry Andric     if (Value != OverflowValue) {
55*349cc55cSDimitry Andric       if (Value < OverflowValue - Value_)
56*349cc55cSDimitry Andric         Value += Value_;
57*349cc55cSDimitry Andric       else
58*349cc55cSDimitry Andric         Value = OverflowValue;
59*349cc55cSDimitry Andric     }
60*349cc55cSDimitry Andric   }
61*349cc55cSDimitry Andric };
62*349cc55cSDimitry Andric 
630b57cec5SDimitry Andric /// Holds statistics for one function (or other entity that has a PC range and
640b57cec5SDimitry Andric /// contains variables, such as a compile unit).
650b57cec5SDimitry Andric struct PerFunctionStats {
660b57cec5SDimitry Andric   /// Number of inlined instances of this function.
67*349cc55cSDimitry Andric   uint64_t NumFnInlined = 0;
685ffd83dbSDimitry Andric   /// Number of out-of-line instances of this function.
69*349cc55cSDimitry Andric   uint64_t NumFnOutOfLine = 0;
700b57cec5SDimitry Andric   /// Number of inlined instances that have abstract origins.
71*349cc55cSDimitry Andric   uint64_t NumAbstractOrigins = 0;
720b57cec5SDimitry Andric   /// Number of variables and parameters with location across all inlined
730b57cec5SDimitry Andric   /// instances.
74*349cc55cSDimitry Andric   uint64_t TotalVarWithLoc = 0;
750b57cec5SDimitry Andric   /// Number of constants with location across all inlined instances.
76*349cc55cSDimitry Andric   uint64_t ConstantMembers = 0;
775ffd83dbSDimitry Andric   /// Number of arificial variables, parameters or members across all instances.
78*349cc55cSDimitry Andric   uint64_t NumArtificial = 0;
790b57cec5SDimitry Andric   /// List of all Variables and parameters in this function.
800b57cec5SDimitry Andric   StringSet<> VarsInFunction;
810b57cec5SDimitry Andric   /// Compile units also cover a PC range, but have this flag set to false.
820b57cec5SDimitry Andric   bool IsFunction = false;
830b57cec5SDimitry Andric   /// Function has source location information.
840b57cec5SDimitry Andric   bool HasSourceLocation = false;
850b57cec5SDimitry Andric   /// Number of function parameters.
86*349cc55cSDimitry Andric   uint64_t NumParams = 0;
870b57cec5SDimitry Andric   /// Number of function parameters with source location.
88*349cc55cSDimitry Andric   uint64_t NumParamSourceLocations = 0;
890b57cec5SDimitry Andric   /// Number of function parameters with type.
90*349cc55cSDimitry Andric   uint64_t NumParamTypes = 0;
910b57cec5SDimitry Andric   /// Number of function parameters with a DW_AT_location.
92*349cc55cSDimitry Andric   uint64_t NumParamLocations = 0;
935ffd83dbSDimitry Andric   /// Number of local variables.
94*349cc55cSDimitry Andric   uint64_t NumLocalVars = 0;
955ffd83dbSDimitry Andric   /// Number of local variables with source location.
96*349cc55cSDimitry Andric   uint64_t NumLocalVarSourceLocations = 0;
975ffd83dbSDimitry Andric   /// Number of local variables with type.
98*349cc55cSDimitry Andric   uint64_t NumLocalVarTypes = 0;
995ffd83dbSDimitry Andric   /// Number of local variables with DW_AT_location.
100*349cc55cSDimitry Andric   uint64_t NumLocalVarLocations = 0;
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric /// Holds accumulated global statistics about DIEs.
1040b57cec5SDimitry Andric struct GlobalStats {
1050b57cec5SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations.
106*349cc55cSDimitry Andric   SaturatingUINT64 TotalBytesCovered = 0;
107e8d8bef9SDimitry Andric   /// Total number of parent DIE PC range bytes covered by DW_AT_Locations.
108*349cc55cSDimitry Andric   SaturatingUINT64 ScopeBytesCovered = 0;
109480093f4SDimitry Andric   /// Total number of PC range bytes in each variable's enclosing scope.
110*349cc55cSDimitry Andric   SaturatingUINT64 ScopeBytes = 0;
1118bcb0991SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations with
1128bcb0991SDimitry Andric   /// the debug entry values (DW_OP_entry_value).
113*349cc55cSDimitry Andric   SaturatingUINT64 ScopeEntryValueBytesCovered = 0;
1148bcb0991SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations of
1158bcb0991SDimitry Andric   /// formal parameters.
116*349cc55cSDimitry Andric   SaturatingUINT64 ParamScopeBytesCovered = 0;
1175ffd83dbSDimitry Andric   /// Total number of PC range bytes in each parameter's enclosing scope.
118*349cc55cSDimitry Andric   SaturatingUINT64 ParamScopeBytes = 0;
1198bcb0991SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations with
1208bcb0991SDimitry Andric   /// the debug entry values (DW_OP_entry_value) (only for parameters).
121*349cc55cSDimitry Andric   SaturatingUINT64 ParamScopeEntryValueBytesCovered = 0;
1228bcb0991SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations (only for local
1238bcb0991SDimitry Andric   /// variables).
124*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarScopeBytesCovered = 0;
1255ffd83dbSDimitry Andric   /// Total number of PC range bytes in each local variable's enclosing scope.
126*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarScopeBytes = 0;
1278bcb0991SDimitry Andric   /// Total number of PC range bytes covered by DW_AT_locations with
1288bcb0991SDimitry Andric   /// the debug entry values (DW_OP_entry_value) (only for local variables).
129*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarScopeEntryValueBytesCovered = 0;
1308bcb0991SDimitry Andric   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
131*349cc55cSDimitry Andric   SaturatingUINT64 CallSiteEntries = 0;
1328bcb0991SDimitry Andric   /// Total number of call site DIEs (DW_TAG_call_site).
133*349cc55cSDimitry Andric   SaturatingUINT64 CallSiteDIEs = 0;
1348bcb0991SDimitry Andric   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
135*349cc55cSDimitry Andric   SaturatingUINT64 CallSiteParamDIEs = 0;
1360b57cec5SDimitry Andric   /// Total byte size of concrete functions. This byte size includes
1370b57cec5SDimitry Andric   /// inline functions contained in the concrete functions.
138*349cc55cSDimitry Andric   SaturatingUINT64 FunctionSize = 0;
1390b57cec5SDimitry Andric   /// Total byte size of inlined functions. This is the total number of bytes
1400b57cec5SDimitry Andric   /// for the top inline functions within concrete functions. This can help
1410b57cec5SDimitry Andric   /// tune the inline settings when compiling to match user expectations.
142*349cc55cSDimitry Andric   SaturatingUINT64 InlineFunctionSize = 0;
1438bcb0991SDimitry Andric };
1448bcb0991SDimitry Andric 
1458bcb0991SDimitry Andric /// Holds accumulated debug location statistics about local variables and
1468bcb0991SDimitry Andric /// formal parameters.
1478bcb0991SDimitry Andric struct LocationStats {
1488bcb0991SDimitry Andric   /// Map the scope coverage decile to the number of variables in the decile.
1498bcb0991SDimitry Andric   /// The first element of the array (at the index zero) represents the number
1508bcb0991SDimitry Andric   /// of variables with the no debug location at all, but the last element
1518bcb0991SDimitry Andric   /// in the vector represents the number of fully covered variables within
1528bcb0991SDimitry Andric   /// its scope.
153*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> VarParamLocStats{
154*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1558bcb0991SDimitry Andric   /// Map non debug entry values coverage.
156*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> VarParamNonEntryValLocStats{
157*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1588bcb0991SDimitry Andric   /// The debug location statistics for formal parameters.
159*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> ParamLocStats{
160*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1618bcb0991SDimitry Andric   /// Map non debug entry values coverage for formal parameters.
162*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> ParamNonEntryValLocStats{
163*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1648bcb0991SDimitry Andric   /// The debug location statistics for local variables.
165*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> LocalVarLocStats{
166*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1678bcb0991SDimitry Andric   /// Map non debug entry values coverage for local variables.
168*349cc55cSDimitry Andric   std::vector<SaturatingUINT64> LocalVarNonEntryValLocStats{
169*349cc55cSDimitry Andric       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
1708bcb0991SDimitry Andric   /// Total number of local variables and function parameters processed.
171*349cc55cSDimitry Andric   SaturatingUINT64 NumVarParam = 0;
1728bcb0991SDimitry Andric   /// Total number of formal parameters processed.
173*349cc55cSDimitry Andric   SaturatingUINT64 NumParam = 0;
1748bcb0991SDimitry Andric   /// Total number of local variables processed.
175*349cc55cSDimitry Andric   SaturatingUINT64 NumVar = 0;
1760b57cec5SDimitry Andric };
1775ffd83dbSDimitry Andric } // namespace
1780b57cec5SDimitry Andric 
1798bcb0991SDimitry Andric /// Collect debug location statistics for one DIE.
180e8d8bef9SDimitry Andric static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
181*349cc55cSDimitry Andric                             std::vector<SaturatingUINT64> &VarParamLocStats,
182*349cc55cSDimitry Andric                             std::vector<SaturatingUINT64> &ParamLocStats,
183*349cc55cSDimitry Andric                             std::vector<SaturatingUINT64> &LocalVarLocStats,
1845ffd83dbSDimitry Andric                             bool IsParam, bool IsLocalVar) {
185e8d8bef9SDimitry Andric   auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned {
1868bcb0991SDimitry Andric     // No debug location at all for the variable.
187e8d8bef9SDimitry Andric     if (ScopeBytesCovered == 0)
1888bcb0991SDimitry Andric       return 0;
1898bcb0991SDimitry Andric     // Fully covered variable within its scope.
190e8d8bef9SDimitry Andric     if (ScopeBytesCovered >= BytesInScope)
1918bcb0991SDimitry Andric       return NumOfCoverageCategories - 1;
1928bcb0991SDimitry Andric     // Get covered range (e.g. 20%-29%).
193e8d8bef9SDimitry Andric     unsigned LocBucket = 100 * (double)ScopeBytesCovered / BytesInScope;
1948bcb0991SDimitry Andric     LocBucket /= 10;
1958bcb0991SDimitry Andric     return LocBucket + 1;
1968bcb0991SDimitry Andric   };
1978bcb0991SDimitry Andric 
1988bcb0991SDimitry Andric   unsigned CoverageBucket = getCoverageBucket();
199fe6060f1SDimitry Andric 
200*349cc55cSDimitry Andric   VarParamLocStats[CoverageBucket].Value++;
2018bcb0991SDimitry Andric   if (IsParam)
202*349cc55cSDimitry Andric     ParamLocStats[CoverageBucket].Value++;
2038bcb0991SDimitry Andric   else if (IsLocalVar)
204*349cc55cSDimitry Andric     LocalVarLocStats[CoverageBucket].Value++;
2055ffd83dbSDimitry Andric }
206fe6060f1SDimitry Andric 
2075ffd83dbSDimitry Andric /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
2085ffd83dbSDimitry Andric /// and DeclLine. The identifier aims to be unique for any unique entities,
2095ffd83dbSDimitry Andric /// but keeping the same among different instances of the same entity.
2105ffd83dbSDimitry Andric static std::string constructDieID(DWARFDie Die,
2115ffd83dbSDimitry Andric                                   StringRef Prefix = StringRef()) {
2125ffd83dbSDimitry Andric   std::string IDStr;
2135ffd83dbSDimitry Andric   llvm::raw_string_ostream ID(IDStr);
2145ffd83dbSDimitry Andric   ID << Prefix
2155ffd83dbSDimitry Andric      << Die.getName(DINameKind::LinkageName);
2165ffd83dbSDimitry Andric 
2175ffd83dbSDimitry Andric   // Prefix + Name is enough for local variables and parameters.
2185ffd83dbSDimitry Andric   if (!Prefix.empty() && !Prefix.equals("g"))
2195ffd83dbSDimitry Andric     return ID.str();
2205ffd83dbSDimitry Andric 
2215ffd83dbSDimitry Andric   auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file);
2225ffd83dbSDimitry Andric   std::string File;
2235ffd83dbSDimitry Andric   if (DeclFile) {
2245ffd83dbSDimitry Andric     DWARFUnit *U = Die.getDwarfUnit();
2255ffd83dbSDimitry Andric     if (const auto *LT = U->getContext().getLineTableForUnit(U))
2265ffd83dbSDimitry Andric       if (LT->getFileNameByIndex(
2275ffd83dbSDimitry Andric               dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(),
2285ffd83dbSDimitry Andric               DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
2295ffd83dbSDimitry Andric         File = std::string(sys::path::filename(File));
2305ffd83dbSDimitry Andric   }
2315ffd83dbSDimitry Andric   ID << ":" << (File.empty() ? "/" : File);
2325ffd83dbSDimitry Andric   ID << ":"
2335ffd83dbSDimitry Andric      << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0);
2345ffd83dbSDimitry Andric   return ID.str();
2358bcb0991SDimitry Andric }
2368bcb0991SDimitry Andric 
237e8d8bef9SDimitry Andric /// Return the number of bytes in the overlap of ranges A and B.
238e8d8bef9SDimitry Andric static uint64_t calculateOverlap(DWARFAddressRange A, DWARFAddressRange B) {
239e8d8bef9SDimitry Andric   uint64_t Lower = std::max(A.LowPC, B.LowPC);
240e8d8bef9SDimitry Andric   uint64_t Upper = std::min(A.HighPC, B.HighPC);
241e8d8bef9SDimitry Andric   if (Lower >= Upper)
242e8d8bef9SDimitry Andric     return 0;
243e8d8bef9SDimitry Andric   return Upper - Lower;
244e8d8bef9SDimitry Andric }
245e8d8bef9SDimitry Andric 
2460b57cec5SDimitry Andric /// Collect debug info quality metrics for one DIE.
247fe6060f1SDimitry Andric static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
248fe6060f1SDimitry Andric                                const std::string &VarPrefix,
249fe6060f1SDimitry Andric                                uint64_t BytesInScope, uint32_t InlineDepth,
2500b57cec5SDimitry Andric                                StringMap<PerFunctionStats> &FnStatMap,
2518bcb0991SDimitry Andric                                GlobalStats &GlobalStats,
252fe6060f1SDimitry Andric                                LocationStats &LocStats,
253fe6060f1SDimitry Andric                                AbstractOriginVarsTy *AbstractOriginVariables) {
254fe6060f1SDimitry Andric   const dwarf::Tag Tag = Die.getTag();
255fe6060f1SDimitry Andric   // Skip CU node.
256fe6060f1SDimitry Andric   if (Tag == dwarf::DW_TAG_compile_unit)
257fe6060f1SDimitry Andric     return;
258fe6060f1SDimitry Andric 
2590b57cec5SDimitry Andric   bool HasLoc = false;
2600b57cec5SDimitry Andric   bool HasSrcLoc = false;
2610b57cec5SDimitry Andric   bool HasType = false;
262e8d8bef9SDimitry Andric   uint64_t TotalBytesCovered = 0;
263e8d8bef9SDimitry Andric   uint64_t ScopeBytesCovered = 0;
2648bcb0991SDimitry Andric   uint64_t BytesEntryValuesCovered = 0;
2658bcb0991SDimitry Andric   auto &FnStats = FnStatMap[FnPrefix];
266fe6060f1SDimitry Andric   bool IsParam = Tag == dwarf::DW_TAG_formal_parameter;
267fe6060f1SDimitry Andric   bool IsLocalVar = Tag == dwarf::DW_TAG_variable;
268fe6060f1SDimitry Andric   bool IsConstantMember = Tag == dwarf::DW_TAG_member &&
2695ffd83dbSDimitry Andric                           Die.find(dwarf::DW_AT_const_value);
2700b57cec5SDimitry Andric 
271fe6060f1SDimitry Andric   // For zero covered inlined variables the locstats will be
272fe6060f1SDimitry Andric   // calculated later.
273fe6060f1SDimitry Andric   bool DeferLocStats = false;
274fe6060f1SDimitry Andric 
275fe6060f1SDimitry Andric   if (Tag == dwarf::DW_TAG_call_site || Tag == dwarf::DW_TAG_GNU_call_site) {
2768bcb0991SDimitry Andric     GlobalStats.CallSiteDIEs++;
2770b57cec5SDimitry Andric     return;
2780b57cec5SDimitry Andric   }
2790b57cec5SDimitry Andric 
280fe6060f1SDimitry Andric   if (Tag == dwarf::DW_TAG_call_site_parameter ||
281fe6060f1SDimitry Andric       Tag == dwarf::DW_TAG_GNU_call_site_parameter) {
2828bcb0991SDimitry Andric     GlobalStats.CallSiteParamDIEs++;
2838bcb0991SDimitry Andric     return;
2848bcb0991SDimitry Andric   }
2858bcb0991SDimitry Andric 
2865ffd83dbSDimitry Andric   if (!IsParam && !IsLocalVar && !IsConstantMember) {
2870b57cec5SDimitry Andric     // Not a variable or constant member.
2880b57cec5SDimitry Andric     return;
2890b57cec5SDimitry Andric   }
2900b57cec5SDimitry Andric 
2915ffd83dbSDimitry Andric   // Ignore declarations of global variables.
2925ffd83dbSDimitry Andric   if (IsLocalVar && Die.find(dwarf::DW_AT_declaration))
2935ffd83dbSDimitry Andric     return;
2945ffd83dbSDimitry Andric 
2950b57cec5SDimitry Andric   if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
2960b57cec5SDimitry Andric       Die.findRecursively(dwarf::DW_AT_decl_line))
2970b57cec5SDimitry Andric     HasSrcLoc = true;
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   if (Die.findRecursively(dwarf::DW_AT_type))
3000b57cec5SDimitry Andric     HasType = true;
3010b57cec5SDimitry Andric 
302fe6060f1SDimitry Andric   if (Die.find(dwarf::DW_AT_abstract_origin)) {
303fe6060f1SDimitry Andric     if (Die.find(dwarf::DW_AT_location) || Die.find(dwarf::DW_AT_const_value)) {
304fe6060f1SDimitry Andric       if (AbstractOriginVariables) {
305fe6060f1SDimitry Andric         auto Offset = Die.find(dwarf::DW_AT_abstract_origin);
306fe6060f1SDimitry Andric         // Do not track this variable any more, since it has location
307fe6060f1SDimitry Andric         // coverage.
308fe6060f1SDimitry Andric         llvm::erase_value(*AbstractOriginVariables, (*Offset).getRawUValue());
309fe6060f1SDimitry Andric       }
310fe6060f1SDimitry Andric     } else {
311fe6060f1SDimitry Andric       // The locstats will be handled at the end of
312fe6060f1SDimitry Andric       // the collectStatsRecursive().
313fe6060f1SDimitry Andric       DeferLocStats = true;
314fe6060f1SDimitry Andric     }
315fe6060f1SDimitry Andric   }
316fe6060f1SDimitry Andric 
3178bcb0991SDimitry Andric   auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
3188bcb0991SDimitry Andric     DWARFUnit *U = Die.getDwarfUnit();
3198bcb0991SDimitry Andric     DataExtractor Data(toStringRef(D),
3208bcb0991SDimitry Andric                        Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
3215ffd83dbSDimitry Andric     DWARFExpression Expression(Data, U->getAddressByteSize(),
3225ffd83dbSDimitry Andric                                U->getFormParams().Format);
3238bcb0991SDimitry Andric     // Consider the expression containing the DW_OP_entry_value as
3248bcb0991SDimitry Andric     // an entry value.
325*349cc55cSDimitry Andric     return llvm::any_of(Expression, [](const DWARFExpression::Operation &Op) {
3268bcb0991SDimitry Andric       return Op.getCode() == dwarf::DW_OP_entry_value ||
3278bcb0991SDimitry Andric              Op.getCode() == dwarf::DW_OP_GNU_entry_value;
3288bcb0991SDimitry Andric     });
3298bcb0991SDimitry Andric   };
3308bcb0991SDimitry Andric 
3310b57cec5SDimitry Andric   if (Die.find(dwarf::DW_AT_const_value)) {
3320b57cec5SDimitry Andric     // This catches constant members *and* variables.
3330b57cec5SDimitry Andric     HasLoc = true;
334e8d8bef9SDimitry Andric     ScopeBytesCovered = BytesInScope;
335e8d8bef9SDimitry Andric     TotalBytesCovered = BytesInScope;
3360b57cec5SDimitry Andric   } else {
3370b57cec5SDimitry Andric     // Handle variables and function arguments.
338480093f4SDimitry Andric     Expected<std::vector<DWARFLocationExpression>> Loc =
339480093f4SDimitry Andric         Die.getLocations(dwarf::DW_AT_location);
340480093f4SDimitry Andric     if (!Loc) {
341480093f4SDimitry Andric       consumeError(Loc.takeError());
3420b57cec5SDimitry Andric     } else {
343480093f4SDimitry Andric       HasLoc = true;
344480093f4SDimitry Andric       // Get PC coverage.
345480093f4SDimitry Andric       auto Default = find_if(
346480093f4SDimitry Andric           *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
347480093f4SDimitry Andric       if (Default != Loc->end()) {
3480b57cec5SDimitry Andric         // Assume the entire range is covered by a single location.
349e8d8bef9SDimitry Andric         ScopeBytesCovered = BytesInScope;
350e8d8bef9SDimitry Andric         TotalBytesCovered = BytesInScope;
351480093f4SDimitry Andric       } else {
352e8d8bef9SDimitry Andric         // Caller checks this Expected result already, it cannot fail.
353e8d8bef9SDimitry Andric         auto ScopeRanges = cantFail(Die.getParent().getAddressRanges());
354480093f4SDimitry Andric         for (auto Entry : *Loc) {
355e8d8bef9SDimitry Andric           TotalBytesCovered += Entry.Range->HighPC - Entry.Range->LowPC;
356e8d8bef9SDimitry Andric           uint64_t ScopeBytesCoveredByEntry = 0;
357e8d8bef9SDimitry Andric           // Calculate how many bytes of the parent scope this entry covers.
358e8d8bef9SDimitry Andric           // FIXME: In section 2.6.2 of the DWARFv5 spec it says that "The
359e8d8bef9SDimitry Andric           // address ranges defined by the bounded location descriptions of a
360e8d8bef9SDimitry Andric           // location list may overlap". So in theory a variable can have
361e8d8bef9SDimitry Andric           // multiple simultaneous locations, which would make this calculation
362e8d8bef9SDimitry Andric           // misleading because we will count the overlapped areas
363e8d8bef9SDimitry Andric           // twice. However, clang does not currently emit DWARF like this.
364e8d8bef9SDimitry Andric           for (DWARFAddressRange R : ScopeRanges) {
365e8d8bef9SDimitry Andric             ScopeBytesCoveredByEntry += calculateOverlap(*Entry.Range, R);
366e8d8bef9SDimitry Andric           }
367e8d8bef9SDimitry Andric           ScopeBytesCovered += ScopeBytesCoveredByEntry;
368480093f4SDimitry Andric           if (IsEntryValue(Entry.Expr))
369e8d8bef9SDimitry Andric             BytesEntryValuesCovered += ScopeBytesCoveredByEntry;
370480093f4SDimitry Andric         }
3710b57cec5SDimitry Andric       }
3720b57cec5SDimitry Andric     }
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric 
3758bcb0991SDimitry Andric   // Calculate the debug location statistics.
376fe6060f1SDimitry Andric   if (BytesInScope && !DeferLocStats) {
377*349cc55cSDimitry Andric     LocStats.NumVarParam.Value++;
3788bcb0991SDimitry Andric     if (IsParam)
379*349cc55cSDimitry Andric       LocStats.NumParam.Value++;
3808bcb0991SDimitry Andric     else if (IsLocalVar)
381*349cc55cSDimitry Andric       LocStats.NumVar.Value++;
3828bcb0991SDimitry Andric 
383e8d8bef9SDimitry Andric     collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats,
3845ffd83dbSDimitry Andric                     LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam,
3858bcb0991SDimitry Andric                     IsLocalVar);
3868bcb0991SDimitry Andric     // Non debug entry values coverage statistics.
387e8d8bef9SDimitry Andric     collectLocStats(ScopeBytesCovered - BytesEntryValuesCovered, BytesInScope,
3888bcb0991SDimitry Andric                     LocStats.VarParamNonEntryValLocStats,
3898bcb0991SDimitry Andric                     LocStats.ParamNonEntryValLocStats,
3905ffd83dbSDimitry Andric                     LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar);
3918bcb0991SDimitry Andric   }
3928bcb0991SDimitry Andric 
3930b57cec5SDimitry Andric   // Collect PC range coverage data.
3940b57cec5SDimitry Andric   if (DWARFDie D =
3950b57cec5SDimitry Andric           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
3960b57cec5SDimitry Andric     Die = D;
3975ffd83dbSDimitry Andric 
3985ffd83dbSDimitry Andric   std::string VarID = constructDieID(Die, VarPrefix);
3995ffd83dbSDimitry Andric   FnStats.VarsInFunction.insert(VarID);
4005ffd83dbSDimitry Andric 
401e8d8bef9SDimitry Andric   GlobalStats.TotalBytesCovered += TotalBytesCovered;
4020b57cec5SDimitry Andric   if (BytesInScope) {
403e8d8bef9SDimitry Andric     GlobalStats.ScopeBytesCovered += ScopeBytesCovered;
404480093f4SDimitry Andric     GlobalStats.ScopeBytes += BytesInScope;
4058bcb0991SDimitry Andric     GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
4068bcb0991SDimitry Andric     if (IsParam) {
407e8d8bef9SDimitry Andric       GlobalStats.ParamScopeBytesCovered += ScopeBytesCovered;
408480093f4SDimitry Andric       GlobalStats.ParamScopeBytes += BytesInScope;
4098bcb0991SDimitry Andric       GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
4108bcb0991SDimitry Andric     } else if (IsLocalVar) {
411e8d8bef9SDimitry Andric       GlobalStats.LocalVarScopeBytesCovered += ScopeBytesCovered;
4125ffd83dbSDimitry Andric       GlobalStats.LocalVarScopeBytes += BytesInScope;
4135ffd83dbSDimitry Andric       GlobalStats.LocalVarScopeEntryValueBytesCovered +=
4145ffd83dbSDimitry Andric           BytesEntryValuesCovered;
4158bcb0991SDimitry Andric     }
416*349cc55cSDimitry Andric     assert(GlobalStats.ScopeBytesCovered.Value <= GlobalStats.ScopeBytes.Value);
4170b57cec5SDimitry Andric   }
4185ffd83dbSDimitry Andric 
4195ffd83dbSDimitry Andric   if (IsConstantMember) {
4205ffd83dbSDimitry Andric     FnStats.ConstantMembers++;
4215ffd83dbSDimitry Andric     return;
4225ffd83dbSDimitry Andric   }
4235ffd83dbSDimitry Andric 
4245ffd83dbSDimitry Andric   FnStats.TotalVarWithLoc += (unsigned)HasLoc;
4255ffd83dbSDimitry Andric 
4265ffd83dbSDimitry Andric   if (Die.find(dwarf::DW_AT_artificial)) {
4275ffd83dbSDimitry Andric     FnStats.NumArtificial++;
4285ffd83dbSDimitry Andric     return;
4295ffd83dbSDimitry Andric   }
4305ffd83dbSDimitry Andric 
4318bcb0991SDimitry Andric   if (IsParam) {
4320b57cec5SDimitry Andric     FnStats.NumParams++;
4330b57cec5SDimitry Andric     if (HasType)
4340b57cec5SDimitry Andric       FnStats.NumParamTypes++;
4350b57cec5SDimitry Andric     if (HasSrcLoc)
4360b57cec5SDimitry Andric       FnStats.NumParamSourceLocations++;
4370b57cec5SDimitry Andric     if (HasLoc)
4380b57cec5SDimitry Andric       FnStats.NumParamLocations++;
4398bcb0991SDimitry Andric   } else if (IsLocalVar) {
4405ffd83dbSDimitry Andric     FnStats.NumLocalVars++;
4410b57cec5SDimitry Andric     if (HasType)
4425ffd83dbSDimitry Andric       FnStats.NumLocalVarTypes++;
4430b57cec5SDimitry Andric     if (HasSrcLoc)
4445ffd83dbSDimitry Andric       FnStats.NumLocalVarSourceLocations++;
4450b57cec5SDimitry Andric     if (HasLoc)
4465ffd83dbSDimitry Andric       FnStats.NumLocalVarLocations++;
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric 
450fe6060f1SDimitry Andric /// Recursively collect variables from subprogram with DW_AT_inline attribute.
451fe6060f1SDimitry Andric static void collectAbstractOriginFnInfo(
452fe6060f1SDimitry Andric     DWARFDie Die, uint64_t SPOffset,
453fe6060f1SDimitry Andric     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo) {
454fe6060f1SDimitry Andric   DWARFDie Child = Die.getFirstChild();
455fe6060f1SDimitry Andric   while (Child) {
456fe6060f1SDimitry Andric     const dwarf::Tag ChildTag = Child.getTag();
457fe6060f1SDimitry Andric     if (ChildTag == dwarf::DW_TAG_formal_parameter ||
458fe6060f1SDimitry Andric         ChildTag == dwarf::DW_TAG_variable)
459fe6060f1SDimitry Andric       GlobalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
460fe6060f1SDimitry Andric     else if (ChildTag == dwarf::DW_TAG_lexical_block)
461fe6060f1SDimitry Andric       collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo);
462fe6060f1SDimitry Andric     Child = Child.getSibling();
463fe6060f1SDimitry Andric   }
464fe6060f1SDimitry Andric }
465fe6060f1SDimitry Andric 
4660b57cec5SDimitry Andric /// Recursively collect debug info quality metrics.
467fe6060f1SDimitry Andric static void collectStatsRecursive(
468fe6060f1SDimitry Andric     DWARFDie Die, std::string FnPrefix, std::string VarPrefix,
469fe6060f1SDimitry Andric     uint64_t BytesInScope, uint32_t InlineDepth,
470fe6060f1SDimitry Andric     StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats,
471fe6060f1SDimitry Andric     LocationStats &LocStats,
472fe6060f1SDimitry Andric     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
473fe6060f1SDimitry Andric     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed,
474fe6060f1SDimitry Andric     AbstractOriginVarsTy *AbstractOriginVarsPtr = nullptr) {
475fe6060f1SDimitry Andric   // Skip NULL nodes.
476fe6060f1SDimitry Andric   if (Die.isNULL())
477fe6060f1SDimitry Andric     return;
478fe6060f1SDimitry Andric 
4790b57cec5SDimitry Andric   const dwarf::Tag Tag = Die.getTag();
4805ffd83dbSDimitry Andric   // Skip function types.
4815ffd83dbSDimitry Andric   if (Tag == dwarf::DW_TAG_subroutine_type)
4825ffd83dbSDimitry Andric     return;
4835ffd83dbSDimitry Andric 
4845ffd83dbSDimitry Andric   // Handle any kind of lexical scope.
485fe6060f1SDimitry Andric   const bool HasAbstractOrigin = Die.find(dwarf::DW_AT_abstract_origin) != None;
4860b57cec5SDimitry Andric   const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
4870b57cec5SDimitry Andric   const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
4880b57cec5SDimitry Andric   const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
489fe6060f1SDimitry Andric   // We want to know how many variables (with abstract_origin) don't have
490fe6060f1SDimitry Andric   // location info.
491fe6060f1SDimitry Andric   const bool IsCandidateForZeroLocCovTracking =
492fe6060f1SDimitry Andric       (IsInlinedFunction || (IsFunction && HasAbstractOrigin));
4930b57cec5SDimitry Andric 
494fe6060f1SDimitry Andric   AbstractOriginVarsTy AbstractOriginVars;
495fe6060f1SDimitry Andric 
496fe6060f1SDimitry Andric   // Get the vars of the inlined fn, so the locstats
497fe6060f1SDimitry Andric   // reports the missing vars (with coverage 0%).
498fe6060f1SDimitry Andric   if (IsCandidateForZeroLocCovTracking) {
499fe6060f1SDimitry Andric     auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin);
500fe6060f1SDimitry Andric     if (OffsetFn) {
501fe6060f1SDimitry Andric       uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue();
502fe6060f1SDimitry Andric       if (GlobalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) {
503fe6060f1SDimitry Andric         AbstractOriginVars = GlobalAbstractOriginFnInfo[OffsetOfInlineFnCopy];
504fe6060f1SDimitry Andric         AbstractOriginVarsPtr = &AbstractOriginVars;
505fe6060f1SDimitry Andric       } else {
506fe6060f1SDimitry Andric         // This means that the DW_AT_inline fn copy is out of order,
507fe6060f1SDimitry Andric         // so this abstract origin instance will be processed later.
508fe6060f1SDimitry Andric         FnsWithAbstractOriginToBeProcessed.push_back(Die.getOffset());
509fe6060f1SDimitry Andric         AbstractOriginVarsPtr = nullptr;
510fe6060f1SDimitry Andric       }
511fe6060f1SDimitry Andric     }
512fe6060f1SDimitry Andric   }
513fe6060f1SDimitry Andric 
514fe6060f1SDimitry Andric   if (IsFunction || IsInlinedFunction || IsBlock) {
5150b57cec5SDimitry Andric     // Reset VarPrefix when entering a new function.
516fe6060f1SDimitry Andric     if (IsFunction || IsInlinedFunction)
5170b57cec5SDimitry Andric       VarPrefix = "v";
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric     // Ignore forward declarations.
5200b57cec5SDimitry Andric     if (Die.find(dwarf::DW_AT_declaration))
5210b57cec5SDimitry Andric       return;
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric     // Check for call sites.
5240b57cec5SDimitry Andric     if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
5250b57cec5SDimitry Andric       GlobalStats.CallSiteEntries++;
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric     // PC Ranges.
5280b57cec5SDimitry Andric     auto RangesOrError = Die.getAddressRanges();
5290b57cec5SDimitry Andric     if (!RangesOrError) {
5300b57cec5SDimitry Andric       llvm::consumeError(RangesOrError.takeError());
5310b57cec5SDimitry Andric       return;
5320b57cec5SDimitry Andric     }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric     auto Ranges = RangesOrError.get();
5350b57cec5SDimitry Andric     uint64_t BytesInThisScope = 0;
5360b57cec5SDimitry Andric     for (auto Range : Ranges)
5370b57cec5SDimitry Andric       BytesInThisScope += Range.HighPC - Range.LowPC;
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric     // Count the function.
5400b57cec5SDimitry Andric     if (!IsBlock) {
541fe6060f1SDimitry Andric       // Skip over abstract origins, but collect variables
542fe6060f1SDimitry Andric       // from it so it can be used for location statistics
543fe6060f1SDimitry Andric       // for inlined instancies.
544fe6060f1SDimitry Andric       if (Die.find(dwarf::DW_AT_inline)) {
545fe6060f1SDimitry Andric         uint64_t SPOffset = Die.getOffset();
546fe6060f1SDimitry Andric         collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo);
5470b57cec5SDimitry Andric         return;
548fe6060f1SDimitry Andric       }
549fe6060f1SDimitry Andric 
5505ffd83dbSDimitry Andric       std::string FnID = constructDieID(Die);
5515ffd83dbSDimitry Andric       // We've seen an instance of this function.
5525ffd83dbSDimitry Andric       auto &FnStats = FnStatMap[FnID];
5535ffd83dbSDimitry Andric       FnStats.IsFunction = true;
5540b57cec5SDimitry Andric       if (IsInlinedFunction) {
5550b57cec5SDimitry Andric         FnStats.NumFnInlined++;
5560b57cec5SDimitry Andric         if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
5570b57cec5SDimitry Andric           FnStats.NumAbstractOrigins++;
5585ffd83dbSDimitry Andric       } else {
5595ffd83dbSDimitry Andric         FnStats.NumFnOutOfLine++;
5600b57cec5SDimitry Andric       }
5610b57cec5SDimitry Andric       if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
5620b57cec5SDimitry Andric           Die.findRecursively(dwarf::DW_AT_decl_line))
5630b57cec5SDimitry Andric         FnStats.HasSourceLocation = true;
5645ffd83dbSDimitry Andric       // Update function prefix.
5655ffd83dbSDimitry Andric       FnPrefix = FnID;
5660b57cec5SDimitry Andric     }
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric     if (BytesInThisScope) {
5690b57cec5SDimitry Andric       BytesInScope = BytesInThisScope;
5700b57cec5SDimitry Andric       if (IsFunction)
5710b57cec5SDimitry Andric         GlobalStats.FunctionSize += BytesInThisScope;
5720b57cec5SDimitry Andric       else if (IsInlinedFunction && InlineDepth == 0)
5730b57cec5SDimitry Andric         GlobalStats.InlineFunctionSize += BytesInThisScope;
5740b57cec5SDimitry Andric     }
5750b57cec5SDimitry Andric   } else {
5760b57cec5SDimitry Andric     // Not a scope, visit the Die itself. It could be a variable.
577480093f4SDimitry Andric     collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
578fe6060f1SDimitry Andric                        FnStatMap, GlobalStats, LocStats, AbstractOriginVarsPtr);
5790b57cec5SDimitry Andric   }
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric   // Set InlineDepth correctly for child recursion
5820b57cec5SDimitry Andric   if (IsFunction)
5830b57cec5SDimitry Andric     InlineDepth = 0;
5840b57cec5SDimitry Andric   else if (IsInlinedFunction)
5850b57cec5SDimitry Andric     ++InlineDepth;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   // Traverse children.
5880b57cec5SDimitry Andric   unsigned LexicalBlockIndex = 0;
5895ffd83dbSDimitry Andric   unsigned FormalParameterIndex = 0;
5900b57cec5SDimitry Andric   DWARFDie Child = Die.getFirstChild();
5910b57cec5SDimitry Andric   while (Child) {
5920b57cec5SDimitry Andric     std::string ChildVarPrefix = VarPrefix;
5930b57cec5SDimitry Andric     if (Child.getTag() == dwarf::DW_TAG_lexical_block)
5940b57cec5SDimitry Andric       ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
5955ffd83dbSDimitry Andric     if (Child.getTag() == dwarf::DW_TAG_formal_parameter)
5965ffd83dbSDimitry Andric       ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.';
5970b57cec5SDimitry Andric 
598fe6060f1SDimitry Andric     collectStatsRecursive(
599fe6060f1SDimitry Andric         Child, FnPrefix, ChildVarPrefix, BytesInScope, InlineDepth, FnStatMap,
600fe6060f1SDimitry Andric         GlobalStats, LocStats, GlobalAbstractOriginFnInfo,
601fe6060f1SDimitry Andric         FnsWithAbstractOriginToBeProcessed, AbstractOriginVarsPtr);
6020b57cec5SDimitry Andric     Child = Child.getSibling();
6030b57cec5SDimitry Andric   }
604fe6060f1SDimitry Andric 
605fe6060f1SDimitry Andric   if (!IsCandidateForZeroLocCovTracking)
606fe6060f1SDimitry Andric     return;
607fe6060f1SDimitry Andric 
608fe6060f1SDimitry Andric   // After we have processed all vars of the inlined function (or function with
609fe6060f1SDimitry Andric   // an abstract_origin), we want to know how many variables have no location.
610fe6060f1SDimitry Andric   for (auto Offset : AbstractOriginVars) {
611fe6060f1SDimitry Andric     LocStats.NumVarParam++;
612fe6060f1SDimitry Andric     LocStats.VarParamLocStats[ZeroCoverageBucket]++;
613fe6060f1SDimitry Andric     auto FnDie = Die.getDwarfUnit()->getDIEForOffset(Offset);
614fe6060f1SDimitry Andric     if (!FnDie)
615fe6060f1SDimitry Andric       continue;
616fe6060f1SDimitry Andric     auto Tag = FnDie.getTag();
617fe6060f1SDimitry Andric     if (Tag == dwarf::DW_TAG_formal_parameter) {
618fe6060f1SDimitry Andric       LocStats.NumParam++;
619fe6060f1SDimitry Andric       LocStats.ParamLocStats[ZeroCoverageBucket]++;
620fe6060f1SDimitry Andric     } else if (Tag == dwarf::DW_TAG_variable) {
621fe6060f1SDimitry Andric       LocStats.NumVar++;
622fe6060f1SDimitry Andric       LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
623fe6060f1SDimitry Andric     }
624fe6060f1SDimitry Andric   }
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
627e8d8bef9SDimitry Andric /// Print human-readable output.
6280b57cec5SDimitry Andric /// \{
629e8d8bef9SDimitry Andric static void printDatum(json::OStream &J, const char *Key, json::Value Value) {
630*349cc55cSDimitry Andric   if (Value == OverflowValue)
631*349cc55cSDimitry Andric     J.attribute(Key, "overflowed");
632*349cc55cSDimitry Andric   else
633e8d8bef9SDimitry Andric     J.attribute(Key, Value);
634*349cc55cSDimitry Andric 
6350b57cec5SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
6360b57cec5SDimitry Andric }
6375ffd83dbSDimitry Andric 
638e8d8bef9SDimitry Andric static void printLocationStats(json::OStream &J, const char *Key,
639*349cc55cSDimitry Andric                                std::vector<SaturatingUINT64> &LocationStats) {
640*349cc55cSDimitry Andric   if (LocationStats[0].Value == OverflowValue)
641*349cc55cSDimitry Andric     J.attribute((Twine(Key) +
642*349cc55cSDimitry Andric                  " with (0%,10%) of parent scope covered by DW_AT_location")
643*349cc55cSDimitry Andric                     .str(),
644*349cc55cSDimitry Andric                 "overflowed");
645*349cc55cSDimitry Andric   else
646e8d8bef9SDimitry Andric     J.attribute(
647*349cc55cSDimitry Andric         (Twine(Key) + " with 0% of parent scope covered by DW_AT_location")
648*349cc55cSDimitry Andric             .str(),
649*349cc55cSDimitry Andric         LocationStats[0].Value);
6505ffd83dbSDimitry Andric   LLVM_DEBUG(
6515ffd83dbSDimitry Andric       llvm::dbgs() << Key
6525ffd83dbSDimitry Andric                    << " with 0% of parent scope covered by DW_AT_location: \\"
653*349cc55cSDimitry Andric                    << LocationStats[0].Value << '\n');
654*349cc55cSDimitry Andric 
655*349cc55cSDimitry Andric   if (LocationStats[1].Value == OverflowValue)
656*349cc55cSDimitry Andric     J.attribute((Twine(Key) +
657*349cc55cSDimitry Andric                  " with (0%,10%) of parent scope covered by DW_AT_location")
658e8d8bef9SDimitry Andric                     .str(),
659*349cc55cSDimitry Andric                 "overflowed");
660*349cc55cSDimitry Andric   else
661*349cc55cSDimitry Andric     J.attribute((Twine(Key) +
662*349cc55cSDimitry Andric                  " with (0%,10%) of parent scope covered by DW_AT_location")
663*349cc55cSDimitry Andric                     .str(),
664*349cc55cSDimitry Andric                 LocationStats[1].Value);
6655ffd83dbSDimitry Andric   LLVM_DEBUG(llvm::dbgs()
6665ffd83dbSDimitry Andric              << Key
6675ffd83dbSDimitry Andric              << " with (0%,10%) of parent scope covered by DW_AT_location: "
668*349cc55cSDimitry Andric              << LocationStats[1].Value << '\n');
669*349cc55cSDimitry Andric 
6708bcb0991SDimitry Andric   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
671*349cc55cSDimitry Andric     if (LocationStats[i].Value == OverflowValue)
672e8d8bef9SDimitry Andric       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
673*349cc55cSDimitry Andric                    Twine(i * 10) +
674*349cc55cSDimitry Andric                    "%) of parent scope covered by DW_AT_location")
675e8d8bef9SDimitry Andric                       .str(),
676*349cc55cSDimitry Andric                   "overflowed");
677*349cc55cSDimitry Andric     else
678*349cc55cSDimitry Andric       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
679*349cc55cSDimitry Andric                    Twine(i * 10) +
680*349cc55cSDimitry Andric                    "%) of parent scope covered by DW_AT_location")
681*349cc55cSDimitry Andric                       .str(),
682*349cc55cSDimitry Andric                   LocationStats[i].Value);
6838bcb0991SDimitry Andric     LLVM_DEBUG(llvm::dbgs()
684480093f4SDimitry Andric                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
6855ffd83dbSDimitry Andric                << "%) of parent scope covered by DW_AT_location: "
686*349cc55cSDimitry Andric                << LocationStats[i].Value);
6878bcb0991SDimitry Andric   }
688*349cc55cSDimitry Andric   if (LocationStats[NumOfCoverageCategories - 1].Value == OverflowValue)
689e8d8bef9SDimitry Andric     J.attribute(
690e8d8bef9SDimitry Andric         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
691e8d8bef9SDimitry Andric             .str(),
692*349cc55cSDimitry Andric         "overflowed");
693*349cc55cSDimitry Andric   else
694*349cc55cSDimitry Andric     J.attribute(
695*349cc55cSDimitry Andric         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
696*349cc55cSDimitry Andric             .str(),
697*349cc55cSDimitry Andric         LocationStats[NumOfCoverageCategories - 1].Value);
6985ffd83dbSDimitry Andric   LLVM_DEBUG(
6995ffd83dbSDimitry Andric       llvm::dbgs() << Key
7005ffd83dbSDimitry Andric                    << " with 100% of parent scope covered by DW_AT_location: "
701*349cc55cSDimitry Andric                    << LocationStats[NumOfCoverageCategories - 1].Value);
7028bcb0991SDimitry Andric }
7035ffd83dbSDimitry Andric 
704e8d8bef9SDimitry Andric static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) {
705fe6060f1SDimitry Andric   for (const auto &It : Sizes.DebugSectionSizes)
706fe6060f1SDimitry Andric     J.attribute((Twine("#bytes in ") + It.first).str(), int64_t(It.second));
707fe6060f1SDimitry Andric }
708fe6060f1SDimitry Andric 
709fe6060f1SDimitry Andric /// Stop tracking variables that contain abstract_origin with a location.
710fe6060f1SDimitry Andric /// This is used for out-of-order DW_AT_inline subprograms only.
711fe6060f1SDimitry Andric static void updateVarsWithAbstractOriginLocCovInfo(
712fe6060f1SDimitry Andric     DWARFDie FnDieWithAbstractOrigin,
713fe6060f1SDimitry Andric     AbstractOriginVarsTy &AbstractOriginVars) {
714fe6060f1SDimitry Andric   DWARFDie Child = FnDieWithAbstractOrigin.getFirstChild();
715fe6060f1SDimitry Andric   while (Child) {
716fe6060f1SDimitry Andric     const dwarf::Tag ChildTag = Child.getTag();
717fe6060f1SDimitry Andric     if ((ChildTag == dwarf::DW_TAG_formal_parameter ||
718fe6060f1SDimitry Andric          ChildTag == dwarf::DW_TAG_variable) &&
719fe6060f1SDimitry Andric         (Child.find(dwarf::DW_AT_location) ||
720fe6060f1SDimitry Andric          Child.find(dwarf::DW_AT_const_value))) {
721fe6060f1SDimitry Andric       auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin);
722fe6060f1SDimitry Andric       if (OffsetVar)
723fe6060f1SDimitry Andric         llvm::erase_value(AbstractOriginVars, (*OffsetVar).getRawUValue());
724fe6060f1SDimitry Andric     } else if (ChildTag == dwarf::DW_TAG_lexical_block)
725fe6060f1SDimitry Andric       updateVarsWithAbstractOriginLocCovInfo(Child, AbstractOriginVars);
726fe6060f1SDimitry Andric     Child = Child.getSibling();
727fe6060f1SDimitry Andric   }
728fe6060f1SDimitry Andric }
729fe6060f1SDimitry Andric 
730fe6060f1SDimitry Andric /// Collect zero location coverage for inlined variables which refer to
731fe6060f1SDimitry Andric /// a DW_AT_inline copy of subprogram that is out of order in the DWARF.
732fe6060f1SDimitry Andric /// Also cover the variables of a concrete function (represented with
733fe6060f1SDimitry Andric /// the DW_TAG_subprogram) with an abstract_origin attribute.
734fe6060f1SDimitry Andric static void collectZeroLocCovForVarsWithAbstractOrigin(
735fe6060f1SDimitry Andric     DWARFUnit *DwUnit, GlobalStats &GlobalStats, LocationStats &LocStats,
736fe6060f1SDimitry Andric     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
737fe6060f1SDimitry Andric     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed) {
738fe6060f1SDimitry Andric   for (auto FnOffset : FnsWithAbstractOriginToBeProcessed) {
739fe6060f1SDimitry Andric     DWARFDie FnDieWithAbstractOrigin = DwUnit->getDIEForOffset(FnOffset);
740fe6060f1SDimitry Andric     auto FnCopy = FnDieWithAbstractOrigin.find(dwarf::DW_AT_abstract_origin);
741fe6060f1SDimitry Andric     AbstractOriginVarsTy AbstractOriginVars;
742fe6060f1SDimitry Andric     if (!FnCopy)
743fe6060f1SDimitry Andric       continue;
744fe6060f1SDimitry Andric 
745fe6060f1SDimitry Andric     AbstractOriginVars = GlobalAbstractOriginFnInfo[(*FnCopy).getRawUValue()];
746fe6060f1SDimitry Andric     updateVarsWithAbstractOriginLocCovInfo(FnDieWithAbstractOrigin,
747fe6060f1SDimitry Andric                                            AbstractOriginVars);
748fe6060f1SDimitry Andric 
749fe6060f1SDimitry Andric     for (auto Offset : AbstractOriginVars) {
750fe6060f1SDimitry Andric       LocStats.NumVarParam++;
751fe6060f1SDimitry Andric       LocStats.VarParamLocStats[ZeroCoverageBucket]++;
752fe6060f1SDimitry Andric       auto Tag = DwUnit->getDIEForOffset(Offset).getTag();
753fe6060f1SDimitry Andric       if (Tag == dwarf::DW_TAG_formal_parameter) {
754fe6060f1SDimitry Andric         LocStats.NumParam++;
755fe6060f1SDimitry Andric         LocStats.ParamLocStats[ZeroCoverageBucket]++;
756fe6060f1SDimitry Andric       } else if (Tag == dwarf::DW_TAG_variable) {
757fe6060f1SDimitry Andric         LocStats.NumVar++;
758fe6060f1SDimitry Andric         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
759fe6060f1SDimitry Andric       }
760fe6060f1SDimitry Andric     }
761fe6060f1SDimitry Andric   }
7625ffd83dbSDimitry Andric }
7635ffd83dbSDimitry Andric 
7640b57cec5SDimitry Andric /// \}
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric /// Collect debug info quality metrics for an entire DIContext.
7670b57cec5SDimitry Andric ///
7680b57cec5SDimitry Andric /// Do the impossible and reduce the quality of the debug info down to a few
7690b57cec5SDimitry Andric /// numbers. The idea is to condense the data into numbers that can be tracked
7700b57cec5SDimitry Andric /// over time to identify trends in newer compiler versions and gauge the effect
7710b57cec5SDimitry Andric /// of particular optimizations. The raw numbers themselves are not particularly
7720b57cec5SDimitry Andric /// useful, only the delta between compiling the same program with different
7730b57cec5SDimitry Andric /// compilers is.
7745ffd83dbSDimitry Andric bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
7755ffd83dbSDimitry Andric                                           const Twine &Filename,
7765ffd83dbSDimitry Andric                                           raw_ostream &OS) {
7770b57cec5SDimitry Andric   StringRef FormatName = Obj.getFileFormatName();
7780b57cec5SDimitry Andric   GlobalStats GlobalStats;
7798bcb0991SDimitry Andric   LocationStats LocStats;
7800b57cec5SDimitry Andric   StringMap<PerFunctionStats> Statistics;
781fe6060f1SDimitry Andric   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
782fe6060f1SDimitry Andric     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
783fe6060f1SDimitry Andric       // These variables are being reset for each CU, since there could be
784fe6060f1SDimitry Andric       // a situation where we have two subprogram DIEs with the same offsets
785fe6060f1SDimitry Andric       // in two diferent CUs, and we can end up using wrong variables info
786fe6060f1SDimitry Andric       // when trying to resolve abstract_origin attribute.
787fe6060f1SDimitry Andric       // TODO: Handle LTO cases where the abstract origin of
788fe6060f1SDimitry Andric       // the function is in a different CU than the one it's
789fe6060f1SDimitry Andric       // referenced from or inlined into.
790fe6060f1SDimitry Andric       AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo;
791fe6060f1SDimitry Andric       FunctionsWithAbstractOriginTy FnsWithAbstractOriginToBeProcessed;
792fe6060f1SDimitry Andric 
793480093f4SDimitry Andric       collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
794fe6060f1SDimitry Andric                             LocStats, GlobalAbstractOriginFnInfo,
795fe6060f1SDimitry Andric                             FnsWithAbstractOriginToBeProcessed);
796fe6060f1SDimitry Andric 
797fe6060f1SDimitry Andric       collectZeroLocCovForVarsWithAbstractOrigin(
798fe6060f1SDimitry Andric           CUDie.getDwarfUnit(), GlobalStats, LocStats,
799fe6060f1SDimitry Andric           GlobalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
800fe6060f1SDimitry Andric     }
801fe6060f1SDimitry Andric   }
8020b57cec5SDimitry Andric 
8035ffd83dbSDimitry Andric   /// Collect the sizes of debug sections.
8045ffd83dbSDimitry Andric   SectionSizes Sizes;
8055ffd83dbSDimitry Andric   calculateSectionSizes(Obj, Sizes, Filename);
8065ffd83dbSDimitry Andric 
8070b57cec5SDimitry Andric   /// The version number should be increased every time the algorithm is changed
8080b57cec5SDimitry Andric   /// (including bug fixes). New metrics may be added without increasing the
8090b57cec5SDimitry Andric   /// version.
810*349cc55cSDimitry Andric   unsigned Version = 9;
811*349cc55cSDimitry Andric   SaturatingUINT64 VarParamTotal = 0;
812*349cc55cSDimitry Andric   SaturatingUINT64 VarParamUnique = 0;
813*349cc55cSDimitry Andric   SaturatingUINT64 VarParamWithLoc = 0;
814*349cc55cSDimitry Andric   SaturatingUINT64 NumFunctions = 0;
815*349cc55cSDimitry Andric   SaturatingUINT64 NumInlinedFunctions = 0;
816*349cc55cSDimitry Andric   SaturatingUINT64 NumFuncsWithSrcLoc = 0;
817*349cc55cSDimitry Andric   SaturatingUINT64 NumAbstractOrigins = 0;
818*349cc55cSDimitry Andric   SaturatingUINT64 ParamTotal = 0;
819*349cc55cSDimitry Andric   SaturatingUINT64 ParamWithType = 0;
820*349cc55cSDimitry Andric   SaturatingUINT64 ParamWithLoc = 0;
821*349cc55cSDimitry Andric   SaturatingUINT64 ParamWithSrcLoc = 0;
822*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarTotal = 0;
823*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarWithType = 0;
824*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarWithSrcLoc = 0;
825*349cc55cSDimitry Andric   SaturatingUINT64 LocalVarWithLoc = 0;
8260b57cec5SDimitry Andric   for (auto &Entry : Statistics) {
8270b57cec5SDimitry Andric     PerFunctionStats &Stats = Entry.getValue();
828*349cc55cSDimitry Andric     uint64_t TotalVars = Stats.VarsInFunction.size() *
8295ffd83dbSDimitry Andric                          (Stats.NumFnInlined + Stats.NumFnOutOfLine);
8305ffd83dbSDimitry Andric     // Count variables in global scope.
8315ffd83dbSDimitry Andric     if (!Stats.IsFunction)
8325ffd83dbSDimitry Andric       TotalVars =
8335ffd83dbSDimitry Andric           Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial;
834*349cc55cSDimitry Andric     uint64_t Constants = Stats.ConstantMembers;
8350b57cec5SDimitry Andric     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
8360b57cec5SDimitry Andric     VarParamTotal += TotalVars;
8370b57cec5SDimitry Andric     VarParamUnique += Stats.VarsInFunction.size();
8380b57cec5SDimitry Andric     LLVM_DEBUG(for (auto &V
8390b57cec5SDimitry Andric                     : Stats.VarsInFunction) llvm::dbgs()
8400b57cec5SDimitry Andric                << Entry.getKey() << ": " << V.getKey() << "\n");
8410b57cec5SDimitry Andric     NumFunctions += Stats.IsFunction;
8420b57cec5SDimitry Andric     NumFuncsWithSrcLoc += Stats.HasSourceLocation;
8430b57cec5SDimitry Andric     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
8440b57cec5SDimitry Andric     NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
8450b57cec5SDimitry Andric     ParamTotal += Stats.NumParams;
8460b57cec5SDimitry Andric     ParamWithType += Stats.NumParamTypes;
8470b57cec5SDimitry Andric     ParamWithLoc += Stats.NumParamLocations;
8480b57cec5SDimitry Andric     ParamWithSrcLoc += Stats.NumParamSourceLocations;
8495ffd83dbSDimitry Andric     LocalVarTotal += Stats.NumLocalVars;
8505ffd83dbSDimitry Andric     LocalVarWithType += Stats.NumLocalVarTypes;
8515ffd83dbSDimitry Andric     LocalVarWithLoc += Stats.NumLocalVarLocations;
8525ffd83dbSDimitry Andric     LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations;
8530b57cec5SDimitry Andric   }
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   // Print summary.
8560b57cec5SDimitry Andric   OS.SetBufferSize(1024);
857e8d8bef9SDimitry Andric   json::OStream J(OS, 2);
858e8d8bef9SDimitry Andric   J.objectBegin();
859e8d8bef9SDimitry Andric   J.attribute("version", Version);
8600b57cec5SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
8610b57cec5SDimitry Andric              llvm::dbgs() << "---------------------------------\n");
8625ffd83dbSDimitry Andric 
863e8d8bef9SDimitry Andric   printDatum(J, "file", Filename.str());
864e8d8bef9SDimitry Andric   printDatum(J, "format", FormatName);
8655ffd83dbSDimitry Andric 
866*349cc55cSDimitry Andric   printDatum(J, "#functions", NumFunctions.Value);
867*349cc55cSDimitry Andric   printDatum(J, "#functions with location", NumFuncsWithSrcLoc.Value);
868*349cc55cSDimitry Andric   printDatum(J, "#inlined functions", NumInlinedFunctions.Value);
869*349cc55cSDimitry Andric   printDatum(J, "#inlined functions with abstract origins",
870*349cc55cSDimitry Andric              NumAbstractOrigins.Value);
8715ffd83dbSDimitry Andric 
8725ffd83dbSDimitry Andric   // This includes local variables and formal parameters.
873*349cc55cSDimitry Andric   printDatum(J, "#unique source variables", VarParamUnique.Value);
874*349cc55cSDimitry Andric   printDatum(J, "#source variables", VarParamTotal.Value);
875*349cc55cSDimitry Andric   printDatum(J, "#source variables with location", VarParamWithLoc.Value);
8765ffd83dbSDimitry Andric 
877*349cc55cSDimitry Andric   printDatum(J, "#call site entries", GlobalStats.CallSiteEntries.Value);
878*349cc55cSDimitry Andric   printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs.Value);
879*349cc55cSDimitry Andric   printDatum(J, "#call site parameter DIEs",
880*349cc55cSDimitry Andric              GlobalStats.CallSiteParamDIEs.Value);
8815ffd83dbSDimitry Andric 
882e8d8bef9SDimitry Andric   printDatum(J, "sum_all_variables(#bytes in parent scope)",
883*349cc55cSDimitry Andric              GlobalStats.ScopeBytes.Value);
884e8d8bef9SDimitry Andric   printDatum(J,
885e8d8bef9SDimitry Andric              "sum_all_variables(#bytes in any scope covered by DW_AT_location)",
886*349cc55cSDimitry Andric              GlobalStats.TotalBytesCovered.Value);
887e8d8bef9SDimitry Andric   printDatum(J,
8885ffd83dbSDimitry Andric              "sum_all_variables(#bytes in parent scope covered by "
8895ffd83dbSDimitry Andric              "DW_AT_location)",
890*349cc55cSDimitry Andric              GlobalStats.ScopeBytesCovered.Value);
891e8d8bef9SDimitry Andric   printDatum(J,
8925ffd83dbSDimitry Andric              "sum_all_variables(#bytes in parent scope covered by "
8935ffd83dbSDimitry Andric              "DW_OP_entry_value)",
894*349cc55cSDimitry Andric              GlobalStats.ScopeEntryValueBytesCovered.Value);
8955ffd83dbSDimitry Andric 
896e8d8bef9SDimitry Andric   printDatum(J, "sum_all_params(#bytes in parent scope)",
897*349cc55cSDimitry Andric              GlobalStats.ParamScopeBytes.Value);
898e8d8bef9SDimitry Andric   printDatum(J,
8995ffd83dbSDimitry Andric              "sum_all_params(#bytes in parent scope covered by DW_AT_location)",
900*349cc55cSDimitry Andric              GlobalStats.ParamScopeBytesCovered.Value);
901e8d8bef9SDimitry Andric   printDatum(J,
9025ffd83dbSDimitry Andric              "sum_all_params(#bytes in parent scope covered by "
9035ffd83dbSDimitry Andric              "DW_OP_entry_value)",
904*349cc55cSDimitry Andric              GlobalStats.ParamScopeEntryValueBytesCovered.Value);
9055ffd83dbSDimitry Andric 
906e8d8bef9SDimitry Andric   printDatum(J, "sum_all_local_vars(#bytes in parent scope)",
907*349cc55cSDimitry Andric              GlobalStats.LocalVarScopeBytes.Value);
908e8d8bef9SDimitry Andric   printDatum(J,
9095ffd83dbSDimitry Andric              "sum_all_local_vars(#bytes in parent scope covered by "
9105ffd83dbSDimitry Andric              "DW_AT_location)",
911*349cc55cSDimitry Andric              GlobalStats.LocalVarScopeBytesCovered.Value);
912e8d8bef9SDimitry Andric   printDatum(J,
9135ffd83dbSDimitry Andric              "sum_all_local_vars(#bytes in parent scope covered by "
9145ffd83dbSDimitry Andric              "DW_OP_entry_value)",
915*349cc55cSDimitry Andric              GlobalStats.LocalVarScopeEntryValueBytesCovered.Value);
9165ffd83dbSDimitry Andric 
917*349cc55cSDimitry Andric   printDatum(J, "#bytes within functions", GlobalStats.FunctionSize.Value);
918e8d8bef9SDimitry Andric   printDatum(J, "#bytes within inlined functions",
919*349cc55cSDimitry Andric              GlobalStats.InlineFunctionSize.Value);
9205ffd83dbSDimitry Andric 
9215ffd83dbSDimitry Andric   // Print the summary for formal parameters.
922*349cc55cSDimitry Andric   printDatum(J, "#params", ParamTotal.Value);
923*349cc55cSDimitry Andric   printDatum(J, "#params with source location", ParamWithSrcLoc.Value);
924*349cc55cSDimitry Andric   printDatum(J, "#params with type", ParamWithType.Value);
925*349cc55cSDimitry Andric   printDatum(J, "#params with binary location", ParamWithLoc.Value);
9265ffd83dbSDimitry Andric 
9275ffd83dbSDimitry Andric   // Print the summary for local variables.
928*349cc55cSDimitry Andric   printDatum(J, "#local vars", LocalVarTotal.Value);
929*349cc55cSDimitry Andric   printDatum(J, "#local vars with source location", LocalVarWithSrcLoc.Value);
930*349cc55cSDimitry Andric   printDatum(J, "#local vars with type", LocalVarWithType.Value);
931*349cc55cSDimitry Andric   printDatum(J, "#local vars with binary location", LocalVarWithLoc.Value);
9325ffd83dbSDimitry Andric 
9335ffd83dbSDimitry Andric   // Print the debug section sizes.
934e8d8bef9SDimitry Andric   printSectionSizes(J, Sizes);
9355ffd83dbSDimitry Andric 
9365ffd83dbSDimitry Andric   // Print the location statistics for variables (includes local variables
9375ffd83dbSDimitry Andric   // and formal parameters).
938e8d8bef9SDimitry Andric   printDatum(J, "#variables processed by location statistics",
939*349cc55cSDimitry Andric              LocStats.NumVarParam.Value);
940e8d8bef9SDimitry Andric   printLocationStats(J, "#variables", LocStats.VarParamLocStats);
941e8d8bef9SDimitry Andric   printLocationStats(J, "#variables - entry values",
9428bcb0991SDimitry Andric                      LocStats.VarParamNonEntryValLocStats);
9435ffd83dbSDimitry Andric 
9445ffd83dbSDimitry Andric   // Print the location statistics for formal parameters.
945*349cc55cSDimitry Andric   printDatum(J, "#params processed by location statistics",
946*349cc55cSDimitry Andric              LocStats.NumParam.Value);
947e8d8bef9SDimitry Andric   printLocationStats(J, "#params", LocStats.ParamLocStats);
948e8d8bef9SDimitry Andric   printLocationStats(J, "#params - entry values",
9498bcb0991SDimitry Andric                      LocStats.ParamNonEntryValLocStats);
9505ffd83dbSDimitry Andric 
9515ffd83dbSDimitry Andric   // Print the location statistics for local variables.
952e8d8bef9SDimitry Andric   printDatum(J, "#local vars processed by location statistics",
953*349cc55cSDimitry Andric              LocStats.NumVar.Value);
954e8d8bef9SDimitry Andric   printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
955e8d8bef9SDimitry Andric   printLocationStats(J, "#local vars - entry values",
9565ffd83dbSDimitry Andric                      LocStats.LocalVarNonEntryValLocStats);
957e8d8bef9SDimitry Andric   J.objectEnd();
958e8d8bef9SDimitry Andric   OS << '\n';
959*349cc55cSDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Total Availability: "
960*349cc55cSDimitry Andric                           << (int)std::round((VarParamWithLoc.Value * 100.0) /
961*349cc55cSDimitry Andric                                              VarParamTotal.Value)
9620b57cec5SDimitry Andric                           << "%\n";
9630b57cec5SDimitry Andric              llvm::dbgs() << "PC Ranges covered: "
964*349cc55cSDimitry Andric                           << (int)std::round(
965*349cc55cSDimitry Andric                                  (GlobalStats.ScopeBytesCovered.Value * 100.0) /
966*349cc55cSDimitry Andric                                  GlobalStats.ScopeBytes.Value)
9670b57cec5SDimitry Andric                           << "%\n");
9680b57cec5SDimitry Andric   return true;
9690b57cec5SDimitry Andric }
970