xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
1 //===-- Statistics.cpp - Debug Info quality metrics -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm-dwarfdump.h"
10 #include "llvm/ADT/DenseMap.h"
11 #include "llvm/ADT/StringSet.h"
12 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/Object/ObjectFile.h"
16 #include "llvm/Support/JSON.h"
17 
18 #define DEBUG_TYPE "dwarfdump"
19 using namespace llvm;
20 using namespace llvm::dwarfdump;
21 using namespace llvm::object;
22 
23 namespace {
24 /// This represents the number of categories of debug location coverage being
25 /// calculated. The first category is the number of variables with 0% location
26 /// coverage, but the last category is the number of variables with 100%
27 /// location coverage.
28 constexpr int NumOfCoverageCategories = 12;
29 
30 /// This is used for zero location coverage bucket.
31 constexpr unsigned ZeroCoverageBucket = 0;
32 
33 /// The UINT64_MAX is used as an indication of the overflow.
34 constexpr uint64_t OverflowValue = std::numeric_limits<uint64_t>::max();
35 
36 /// This represents variables DIE offsets.
37 using AbstractOriginVarsTy = llvm::SmallVector<uint64_t>;
38 /// This maps function DIE offset to its variables.
39 using AbstractOriginVarsTyMap = llvm::DenseMap<uint64_t, AbstractOriginVarsTy>;
40 /// This represents function DIE offsets containing an abstract_origin.
41 using FunctionsWithAbstractOriginTy = llvm::SmallVector<uint64_t>;
42 
43 /// This represents a data type for the stats and it helps us to
44 /// detect an overflow.
45 /// NOTE: This can be implemented as a template if there is an another type
46 /// needing this.
47 struct SaturatingUINT64 {
48   /// Number that represents the stats.
49   uint64_t Value;
50 
51   SaturatingUINT64(uint64_t Value_) : Value(Value_) {}
52 
53   void operator++(int) { return *this += 1; }
54   void operator+=(uint64_t Value_) {
55     if (Value != OverflowValue) {
56       if (Value < OverflowValue - Value_)
57         Value += Value_;
58       else
59         Value = OverflowValue;
60     }
61   }
62 };
63 
64 /// Utility struct to store the full location of a DIE - its CU and offset.
65 struct DIELocation {
66   DWARFUnit *DwUnit;
67   uint64_t DIEOffset;
68   DIELocation(DWARFUnit *_DwUnit, uint64_t _DIEOffset)
69       : DwUnit(_DwUnit), DIEOffset(_DIEOffset) {}
70 };
71 /// This represents DWARF locations of CrossCU referencing DIEs.
72 using CrossCUReferencingDIELocationTy = llvm::SmallVector<DIELocation>;
73 
74 /// This maps function DIE offset to its DWARF CU.
75 using FunctionDIECUTyMap = llvm::DenseMap<uint64_t, DWARFUnit *>;
76 
77 /// Holds statistics for one function (or other entity that has a PC range and
78 /// contains variables, such as a compile unit).
79 struct PerFunctionStats {
80   /// Number of inlined instances of this function.
81   uint64_t NumFnInlined = 0;
82   /// Number of out-of-line instances of this function.
83   uint64_t NumFnOutOfLine = 0;
84   /// Number of inlined instances that have abstract origins.
85   uint64_t NumAbstractOrigins = 0;
86   /// Number of variables and parameters with location across all inlined
87   /// instances.
88   uint64_t TotalVarWithLoc = 0;
89   /// Number of constants with location across all inlined instances.
90   uint64_t ConstantMembers = 0;
91   /// Number of arificial variables, parameters or members across all instances.
92   uint64_t NumArtificial = 0;
93   /// List of all Variables and parameters in this function.
94   StringSet<> VarsInFunction;
95   /// Compile units also cover a PC range, but have this flag set to false.
96   bool IsFunction = false;
97   /// Function has source location information.
98   bool HasSourceLocation = false;
99   /// Number of function parameters.
100   uint64_t NumParams = 0;
101   /// Number of function parameters with source location.
102   uint64_t NumParamSourceLocations = 0;
103   /// Number of function parameters with type.
104   uint64_t NumParamTypes = 0;
105   /// Number of function parameters with a DW_AT_location.
106   uint64_t NumParamLocations = 0;
107   /// Number of local variables.
108   uint64_t NumLocalVars = 0;
109   /// Number of local variables with source location.
110   uint64_t NumLocalVarSourceLocations = 0;
111   /// Number of local variables with type.
112   uint64_t NumLocalVarTypes = 0;
113   /// Number of local variables with DW_AT_location.
114   uint64_t NumLocalVarLocations = 0;
115 };
116 
117 /// Holds accumulated global statistics about DIEs.
118 struct GlobalStats {
119   /// Total number of PC range bytes covered by DW_AT_locations.
120   SaturatingUINT64 TotalBytesCovered = 0;
121   /// Total number of parent DIE PC range bytes covered by DW_AT_Locations.
122   SaturatingUINT64 ScopeBytesCovered = 0;
123   /// Total number of PC range bytes in each variable's enclosing scope.
124   SaturatingUINT64 ScopeBytes = 0;
125   /// Total number of PC range bytes covered by DW_AT_locations with
126   /// the debug entry values (DW_OP_entry_value).
127   SaturatingUINT64 ScopeEntryValueBytesCovered = 0;
128   /// Total number of PC range bytes covered by DW_AT_locations of
129   /// formal parameters.
130   SaturatingUINT64 ParamScopeBytesCovered = 0;
131   /// Total number of PC range bytes in each parameter's enclosing scope.
132   SaturatingUINT64 ParamScopeBytes = 0;
133   /// Total number of PC range bytes covered by DW_AT_locations with
134   /// the debug entry values (DW_OP_entry_value) (only for parameters).
135   SaturatingUINT64 ParamScopeEntryValueBytesCovered = 0;
136   /// Total number of PC range bytes covered by DW_AT_locations (only for local
137   /// variables).
138   SaturatingUINT64 LocalVarScopeBytesCovered = 0;
139   /// Total number of PC range bytes in each local variable's enclosing scope.
140   SaturatingUINT64 LocalVarScopeBytes = 0;
141   /// Total number of PC range bytes covered by DW_AT_locations with
142   /// the debug entry values (DW_OP_entry_value) (only for local variables).
143   SaturatingUINT64 LocalVarScopeEntryValueBytesCovered = 0;
144   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
145   SaturatingUINT64 CallSiteEntries = 0;
146   /// Total number of call site DIEs (DW_TAG_call_site).
147   SaturatingUINT64 CallSiteDIEs = 0;
148   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
149   SaturatingUINT64 CallSiteParamDIEs = 0;
150   /// Total byte size of concrete functions. This byte size includes
151   /// inline functions contained in the concrete functions.
152   SaturatingUINT64 FunctionSize = 0;
153   /// Total byte size of inlined functions. This is the total number of bytes
154   /// for the top inline functions within concrete functions. This can help
155   /// tune the inline settings when compiling to match user expectations.
156   SaturatingUINT64 InlineFunctionSize = 0;
157 };
158 
159 /// Holds accumulated debug location statistics about local variables and
160 /// formal parameters.
161 struct LocationStats {
162   /// Map the scope coverage decile to the number of variables in the decile.
163   /// The first element of the array (at the index zero) represents the number
164   /// of variables with the no debug location at all, but the last element
165   /// in the vector represents the number of fully covered variables within
166   /// its scope.
167   std::vector<SaturatingUINT64> VarParamLocStats{
168       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
169   /// Map non debug entry values coverage.
170   std::vector<SaturatingUINT64> VarParamNonEntryValLocStats{
171       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
172   /// The debug location statistics for formal parameters.
173   std::vector<SaturatingUINT64> ParamLocStats{
174       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
175   /// Map non debug entry values coverage for formal parameters.
176   std::vector<SaturatingUINT64> ParamNonEntryValLocStats{
177       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
178   /// The debug location statistics for local variables.
179   std::vector<SaturatingUINT64> LocalVarLocStats{
180       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
181   /// Map non debug entry values coverage for local variables.
182   std::vector<SaturatingUINT64> LocalVarNonEntryValLocStats{
183       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
184   /// Total number of local variables and function parameters processed.
185   SaturatingUINT64 NumVarParam = 0;
186   /// Total number of formal parameters processed.
187   SaturatingUINT64 NumParam = 0;
188   /// Total number of local variables processed.
189   SaturatingUINT64 NumVar = 0;
190 };
191 } // namespace
192 
193 /// Collect debug location statistics for one DIE.
194 static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
195                             std::vector<SaturatingUINT64> &VarParamLocStats,
196                             std::vector<SaturatingUINT64> &ParamLocStats,
197                             std::vector<SaturatingUINT64> &LocalVarLocStats,
198                             bool IsParam, bool IsLocalVar) {
199   auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned {
200     // No debug location at all for the variable.
201     if (ScopeBytesCovered == 0)
202       return 0;
203     // Fully covered variable within its scope.
204     if (ScopeBytesCovered >= BytesInScope)
205       return NumOfCoverageCategories - 1;
206     // Get covered range (e.g. 20%-29%).
207     unsigned LocBucket = 100 * (double)ScopeBytesCovered / BytesInScope;
208     LocBucket /= 10;
209     return LocBucket + 1;
210   };
211 
212   unsigned CoverageBucket = getCoverageBucket();
213 
214   VarParamLocStats[CoverageBucket].Value++;
215   if (IsParam)
216     ParamLocStats[CoverageBucket].Value++;
217   else if (IsLocalVar)
218     LocalVarLocStats[CoverageBucket].Value++;
219 }
220 
221 /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
222 /// and DeclLine. The identifier aims to be unique for any unique entities,
223 /// but keeping the same among different instances of the same entity.
224 static std::string constructDieID(DWARFDie Die,
225                                   StringRef Prefix = StringRef()) {
226   std::string IDStr;
227   llvm::raw_string_ostream ID(IDStr);
228   ID << Prefix
229      << Die.getName(DINameKind::LinkageName);
230 
231   // Prefix + Name is enough for local variables and parameters.
232   if (!Prefix.empty() && !Prefix.equals("g"))
233     return ID.str();
234 
235   auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file);
236   std::string File;
237   if (DeclFile) {
238     DWARFUnit *U = Die.getDwarfUnit();
239     if (const auto *LT = U->getContext().getLineTableForUnit(U))
240       if (LT->getFileNameByIndex(
241               dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(),
242               DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
243         File = std::string(sys::path::filename(File));
244   }
245   ID << ":" << (File.empty() ? "/" : File);
246   ID << ":"
247      << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0);
248   return ID.str();
249 }
250 
251 /// Return the number of bytes in the overlap of ranges A and B.
252 static uint64_t calculateOverlap(DWARFAddressRange A, DWARFAddressRange B) {
253   uint64_t Lower = std::max(A.LowPC, B.LowPC);
254   uint64_t Upper = std::min(A.HighPC, B.HighPC);
255   if (Lower >= Upper)
256     return 0;
257   return Upper - Lower;
258 }
259 
260 /// Collect debug info quality metrics for one DIE.
261 static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
262                                const std::string &VarPrefix,
263                                uint64_t BytesInScope, uint32_t InlineDepth,
264                                StringMap<PerFunctionStats> &FnStatMap,
265                                GlobalStats &GlobalStats,
266                                LocationStats &LocStats,
267                                AbstractOriginVarsTy *AbstractOriginVariables) {
268   const dwarf::Tag Tag = Die.getTag();
269   // Skip CU node.
270   if (Tag == dwarf::DW_TAG_compile_unit)
271     return;
272 
273   bool HasLoc = false;
274   bool HasSrcLoc = false;
275   bool HasType = false;
276   uint64_t TotalBytesCovered = 0;
277   uint64_t ScopeBytesCovered = 0;
278   uint64_t BytesEntryValuesCovered = 0;
279   auto &FnStats = FnStatMap[FnPrefix];
280   bool IsParam = Tag == dwarf::DW_TAG_formal_parameter;
281   bool IsLocalVar = Tag == dwarf::DW_TAG_variable;
282   bool IsConstantMember = Tag == dwarf::DW_TAG_member &&
283                           Die.find(dwarf::DW_AT_const_value);
284 
285   // For zero covered inlined variables the locstats will be
286   // calculated later.
287   bool DeferLocStats = false;
288 
289   if (Tag == dwarf::DW_TAG_call_site || Tag == dwarf::DW_TAG_GNU_call_site) {
290     GlobalStats.CallSiteDIEs++;
291     return;
292   }
293 
294   if (Tag == dwarf::DW_TAG_call_site_parameter ||
295       Tag == dwarf::DW_TAG_GNU_call_site_parameter) {
296     GlobalStats.CallSiteParamDIEs++;
297     return;
298   }
299 
300   if (!IsParam && !IsLocalVar && !IsConstantMember) {
301     // Not a variable or constant member.
302     return;
303   }
304 
305   // Ignore declarations of global variables.
306   if (IsLocalVar && Die.find(dwarf::DW_AT_declaration))
307     return;
308 
309   if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
310       Die.findRecursively(dwarf::DW_AT_decl_line))
311     HasSrcLoc = true;
312 
313   if (Die.findRecursively(dwarf::DW_AT_type))
314     HasType = true;
315 
316   if (Die.find(dwarf::DW_AT_abstract_origin)) {
317     if (Die.find(dwarf::DW_AT_location) || Die.find(dwarf::DW_AT_const_value)) {
318       if (AbstractOriginVariables) {
319         auto Offset = Die.find(dwarf::DW_AT_abstract_origin);
320         // Do not track this variable any more, since it has location
321         // coverage.
322         llvm::erase_value(*AbstractOriginVariables, (*Offset).getRawUValue());
323       }
324     } else {
325       // The locstats will be handled at the end of
326       // the collectStatsRecursive().
327       DeferLocStats = true;
328     }
329   }
330 
331   auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
332     DWARFUnit *U = Die.getDwarfUnit();
333     DataExtractor Data(toStringRef(D),
334                        Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
335     DWARFExpression Expression(Data, U->getAddressByteSize(),
336                                U->getFormParams().Format);
337     // Consider the expression containing the DW_OP_entry_value as
338     // an entry value.
339     return llvm::any_of(Expression, [](const DWARFExpression::Operation &Op) {
340       return Op.getCode() == dwarf::DW_OP_entry_value ||
341              Op.getCode() == dwarf::DW_OP_GNU_entry_value;
342     });
343   };
344 
345   if (Die.find(dwarf::DW_AT_const_value)) {
346     // This catches constant members *and* variables.
347     HasLoc = true;
348     ScopeBytesCovered = BytesInScope;
349     TotalBytesCovered = BytesInScope;
350   } else {
351     // Handle variables and function arguments.
352     Expected<std::vector<DWARFLocationExpression>> Loc =
353         Die.getLocations(dwarf::DW_AT_location);
354     if (!Loc) {
355       consumeError(Loc.takeError());
356     } else {
357       HasLoc = true;
358       // Get PC coverage.
359       auto Default = find_if(
360           *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
361       if (Default != Loc->end()) {
362         // Assume the entire range is covered by a single location.
363         ScopeBytesCovered = BytesInScope;
364         TotalBytesCovered = BytesInScope;
365       } else {
366         // Caller checks this Expected result already, it cannot fail.
367         auto ScopeRanges = cantFail(Die.getParent().getAddressRanges());
368         for (auto Entry : *Loc) {
369           TotalBytesCovered += Entry.Range->HighPC - Entry.Range->LowPC;
370           uint64_t ScopeBytesCoveredByEntry = 0;
371           // Calculate how many bytes of the parent scope this entry covers.
372           // FIXME: In section 2.6.2 of the DWARFv5 spec it says that "The
373           // address ranges defined by the bounded location descriptions of a
374           // location list may overlap". So in theory a variable can have
375           // multiple simultaneous locations, which would make this calculation
376           // misleading because we will count the overlapped areas
377           // twice. However, clang does not currently emit DWARF like this.
378           for (DWARFAddressRange R : ScopeRanges) {
379             ScopeBytesCoveredByEntry += calculateOverlap(*Entry.Range, R);
380           }
381           ScopeBytesCovered += ScopeBytesCoveredByEntry;
382           if (IsEntryValue(Entry.Expr))
383             BytesEntryValuesCovered += ScopeBytesCoveredByEntry;
384         }
385       }
386     }
387   }
388 
389   // Calculate the debug location statistics.
390   if (BytesInScope && !DeferLocStats) {
391     LocStats.NumVarParam.Value++;
392     if (IsParam)
393       LocStats.NumParam.Value++;
394     else if (IsLocalVar)
395       LocStats.NumVar.Value++;
396 
397     collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats,
398                     LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam,
399                     IsLocalVar);
400     // Non debug entry values coverage statistics.
401     collectLocStats(ScopeBytesCovered - BytesEntryValuesCovered, BytesInScope,
402                     LocStats.VarParamNonEntryValLocStats,
403                     LocStats.ParamNonEntryValLocStats,
404                     LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar);
405   }
406 
407   // Collect PC range coverage data.
408   if (DWARFDie D =
409           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
410     Die = D;
411 
412   std::string VarID = constructDieID(Die, VarPrefix);
413   FnStats.VarsInFunction.insert(VarID);
414 
415   GlobalStats.TotalBytesCovered += TotalBytesCovered;
416   if (BytesInScope) {
417     GlobalStats.ScopeBytesCovered += ScopeBytesCovered;
418     GlobalStats.ScopeBytes += BytesInScope;
419     GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
420     if (IsParam) {
421       GlobalStats.ParamScopeBytesCovered += ScopeBytesCovered;
422       GlobalStats.ParamScopeBytes += BytesInScope;
423       GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
424     } else if (IsLocalVar) {
425       GlobalStats.LocalVarScopeBytesCovered += ScopeBytesCovered;
426       GlobalStats.LocalVarScopeBytes += BytesInScope;
427       GlobalStats.LocalVarScopeEntryValueBytesCovered +=
428           BytesEntryValuesCovered;
429     }
430     assert(GlobalStats.ScopeBytesCovered.Value <= GlobalStats.ScopeBytes.Value);
431   }
432 
433   if (IsConstantMember) {
434     FnStats.ConstantMembers++;
435     return;
436   }
437 
438   FnStats.TotalVarWithLoc += (unsigned)HasLoc;
439 
440   if (Die.find(dwarf::DW_AT_artificial)) {
441     FnStats.NumArtificial++;
442     return;
443   }
444 
445   if (IsParam) {
446     FnStats.NumParams++;
447     if (HasType)
448       FnStats.NumParamTypes++;
449     if (HasSrcLoc)
450       FnStats.NumParamSourceLocations++;
451     if (HasLoc)
452       FnStats.NumParamLocations++;
453   } else if (IsLocalVar) {
454     FnStats.NumLocalVars++;
455     if (HasType)
456       FnStats.NumLocalVarTypes++;
457     if (HasSrcLoc)
458       FnStats.NumLocalVarSourceLocations++;
459     if (HasLoc)
460       FnStats.NumLocalVarLocations++;
461   }
462 }
463 
464 /// Recursively collect variables from subprogram with DW_AT_inline attribute.
465 static void collectAbstractOriginFnInfo(
466     DWARFDie Die, uint64_t SPOffset,
467     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
468     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo) {
469   DWARFDie Child = Die.getFirstChild();
470   while (Child) {
471     const dwarf::Tag ChildTag = Child.getTag();
472     if (ChildTag == dwarf::DW_TAG_formal_parameter ||
473         ChildTag == dwarf::DW_TAG_variable) {
474       GlobalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
475       LocalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
476     } else if (ChildTag == dwarf::DW_TAG_lexical_block)
477       collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo,
478                                   LocalAbstractOriginFnInfo);
479     Child = Child.getSibling();
480   }
481 }
482 
483 /// Recursively collect debug info quality metrics.
484 static void collectStatsRecursive(
485     DWARFDie Die, std::string FnPrefix, std::string VarPrefix,
486     uint64_t BytesInScope, uint32_t InlineDepth,
487     StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats,
488     LocationStats &LocStats, FunctionDIECUTyMap &AbstractOriginFnCUs,
489     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
490     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
491     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed,
492     AbstractOriginVarsTy *AbstractOriginVarsPtr = nullptr) {
493   // Skip NULL nodes.
494   if (Die.isNULL())
495     return;
496 
497   const dwarf::Tag Tag = Die.getTag();
498   // Skip function types.
499   if (Tag == dwarf::DW_TAG_subroutine_type)
500     return;
501 
502   // Handle any kind of lexical scope.
503   const bool HasAbstractOrigin = Die.find(dwarf::DW_AT_abstract_origin) != None;
504   const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
505   const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
506   const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
507   // We want to know how many variables (with abstract_origin) don't have
508   // location info.
509   const bool IsCandidateForZeroLocCovTracking =
510       (IsInlinedFunction || (IsFunction && HasAbstractOrigin));
511 
512   AbstractOriginVarsTy AbstractOriginVars;
513 
514   // Get the vars of the inlined fn, so the locstats
515   // reports the missing vars (with coverage 0%).
516   if (IsCandidateForZeroLocCovTracking) {
517     auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin);
518     if (OffsetFn) {
519       uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue();
520       if (LocalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) {
521         AbstractOriginVars = LocalAbstractOriginFnInfo[OffsetOfInlineFnCopy];
522         AbstractOriginVarsPtr = &AbstractOriginVars;
523       } else {
524         // This means that the DW_AT_inline fn copy is out of order
525         // or that the abstract_origin references another CU,
526         // so this abstract origin instance will be processed later.
527         FnsWithAbstractOriginToBeProcessed.push_back(Die.getOffset());
528         AbstractOriginVarsPtr = nullptr;
529       }
530     }
531   }
532 
533   if (IsFunction || IsInlinedFunction || IsBlock) {
534     // Reset VarPrefix when entering a new function.
535     if (IsFunction || IsInlinedFunction)
536       VarPrefix = "v";
537 
538     // Ignore forward declarations.
539     if (Die.find(dwarf::DW_AT_declaration))
540       return;
541 
542     // Check for call sites.
543     if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
544       GlobalStats.CallSiteEntries++;
545 
546     // PC Ranges.
547     auto RangesOrError = Die.getAddressRanges();
548     if (!RangesOrError) {
549       llvm::consumeError(RangesOrError.takeError());
550       return;
551     }
552 
553     auto Ranges = RangesOrError.get();
554     uint64_t BytesInThisScope = 0;
555     for (auto Range : Ranges)
556       BytesInThisScope += Range.HighPC - Range.LowPC;
557 
558     // Count the function.
559     if (!IsBlock) {
560       // Skip over abstract origins, but collect variables
561       // from it so it can be used for location statistics
562       // for inlined instancies.
563       if (Die.find(dwarf::DW_AT_inline)) {
564         uint64_t SPOffset = Die.getOffset();
565         AbstractOriginFnCUs[SPOffset] = Die.getDwarfUnit();
566         collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo,
567                                     LocalAbstractOriginFnInfo);
568         return;
569       }
570 
571       std::string FnID = constructDieID(Die);
572       // We've seen an instance of this function.
573       auto &FnStats = FnStatMap[FnID];
574       FnStats.IsFunction = true;
575       if (IsInlinedFunction) {
576         FnStats.NumFnInlined++;
577         if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
578           FnStats.NumAbstractOrigins++;
579       } else {
580         FnStats.NumFnOutOfLine++;
581       }
582       if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
583           Die.findRecursively(dwarf::DW_AT_decl_line))
584         FnStats.HasSourceLocation = true;
585       // Update function prefix.
586       FnPrefix = FnID;
587     }
588 
589     if (BytesInThisScope) {
590       BytesInScope = BytesInThisScope;
591       if (IsFunction)
592         GlobalStats.FunctionSize += BytesInThisScope;
593       else if (IsInlinedFunction && InlineDepth == 0)
594         GlobalStats.InlineFunctionSize += BytesInThisScope;
595     }
596   } else {
597     // Not a scope, visit the Die itself. It could be a variable.
598     collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
599                        FnStatMap, GlobalStats, LocStats, AbstractOriginVarsPtr);
600   }
601 
602   // Set InlineDepth correctly for child recursion
603   if (IsFunction)
604     InlineDepth = 0;
605   else if (IsInlinedFunction)
606     ++InlineDepth;
607 
608   // Traverse children.
609   unsigned LexicalBlockIndex = 0;
610   unsigned FormalParameterIndex = 0;
611   DWARFDie Child = Die.getFirstChild();
612   while (Child) {
613     std::string ChildVarPrefix = VarPrefix;
614     if (Child.getTag() == dwarf::DW_TAG_lexical_block)
615       ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
616     if (Child.getTag() == dwarf::DW_TAG_formal_parameter)
617       ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.';
618 
619     collectStatsRecursive(
620         Child, FnPrefix, ChildVarPrefix, BytesInScope, InlineDepth, FnStatMap,
621         GlobalStats, LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
622         LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed,
623         AbstractOriginVarsPtr);
624     Child = Child.getSibling();
625   }
626 
627   if (!IsCandidateForZeroLocCovTracking)
628     return;
629 
630   // After we have processed all vars of the inlined function (or function with
631   // an abstract_origin), we want to know how many variables have no location.
632   for (auto Offset : AbstractOriginVars) {
633     LocStats.NumVarParam++;
634     LocStats.VarParamLocStats[ZeroCoverageBucket]++;
635     auto FnDie = Die.getDwarfUnit()->getDIEForOffset(Offset);
636     if (!FnDie)
637       continue;
638     auto Tag = FnDie.getTag();
639     if (Tag == dwarf::DW_TAG_formal_parameter) {
640       LocStats.NumParam++;
641       LocStats.ParamLocStats[ZeroCoverageBucket]++;
642     } else if (Tag == dwarf::DW_TAG_variable) {
643       LocStats.NumVar++;
644       LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
645     }
646   }
647 }
648 
649 /// Print human-readable output.
650 /// \{
651 static void printDatum(json::OStream &J, const char *Key, json::Value Value) {
652   if (Value == OverflowValue)
653     J.attribute(Key, "overflowed");
654   else
655     J.attribute(Key, Value);
656 
657   LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
658 }
659 
660 static void printLocationStats(json::OStream &J, const char *Key,
661                                std::vector<SaturatingUINT64> &LocationStats) {
662   if (LocationStats[0].Value == OverflowValue)
663     J.attribute((Twine(Key) +
664                  " with (0%,10%) of parent scope covered by DW_AT_location")
665                     .str(),
666                 "overflowed");
667   else
668     J.attribute(
669         (Twine(Key) + " with 0% of parent scope covered by DW_AT_location")
670             .str(),
671         LocationStats[0].Value);
672   LLVM_DEBUG(
673       llvm::dbgs() << Key
674                    << " with 0% of parent scope covered by DW_AT_location: \\"
675                    << LocationStats[0].Value << '\n');
676 
677   if (LocationStats[1].Value == OverflowValue)
678     J.attribute((Twine(Key) +
679                  " with (0%,10%) of parent scope covered by DW_AT_location")
680                     .str(),
681                 "overflowed");
682   else
683     J.attribute((Twine(Key) +
684                  " with (0%,10%) of parent scope covered by DW_AT_location")
685                     .str(),
686                 LocationStats[1].Value);
687   LLVM_DEBUG(llvm::dbgs()
688              << Key
689              << " with (0%,10%) of parent scope covered by DW_AT_location: "
690              << LocationStats[1].Value << '\n');
691 
692   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
693     if (LocationStats[i].Value == OverflowValue)
694       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
695                    Twine(i * 10) +
696                    "%) of parent scope covered by DW_AT_location")
697                       .str(),
698                   "overflowed");
699     else
700       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
701                    Twine(i * 10) +
702                    "%) of parent scope covered by DW_AT_location")
703                       .str(),
704                   LocationStats[i].Value);
705     LLVM_DEBUG(llvm::dbgs()
706                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
707                << "%) of parent scope covered by DW_AT_location: "
708                << LocationStats[i].Value);
709   }
710   if (LocationStats[NumOfCoverageCategories - 1].Value == OverflowValue)
711     J.attribute(
712         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
713             .str(),
714         "overflowed");
715   else
716     J.attribute(
717         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
718             .str(),
719         LocationStats[NumOfCoverageCategories - 1].Value);
720   LLVM_DEBUG(
721       llvm::dbgs() << Key
722                    << " with 100% of parent scope covered by DW_AT_location: "
723                    << LocationStats[NumOfCoverageCategories - 1].Value);
724 }
725 
726 static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) {
727   for (const auto &It : Sizes.DebugSectionSizes)
728     J.attribute((Twine("#bytes in ") + It.first).str(), int64_t(It.second));
729 }
730 
731 /// Stop tracking variables that contain abstract_origin with a location.
732 /// This is used for out-of-order DW_AT_inline subprograms only.
733 static void updateVarsWithAbstractOriginLocCovInfo(
734     DWARFDie FnDieWithAbstractOrigin,
735     AbstractOriginVarsTy &AbstractOriginVars) {
736   DWARFDie Child = FnDieWithAbstractOrigin.getFirstChild();
737   while (Child) {
738     const dwarf::Tag ChildTag = Child.getTag();
739     if ((ChildTag == dwarf::DW_TAG_formal_parameter ||
740          ChildTag == dwarf::DW_TAG_variable) &&
741         (Child.find(dwarf::DW_AT_location) ||
742          Child.find(dwarf::DW_AT_const_value))) {
743       auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin);
744       if (OffsetVar)
745         llvm::erase_value(AbstractOriginVars, (*OffsetVar).getRawUValue());
746     } else if (ChildTag == dwarf::DW_TAG_lexical_block)
747       updateVarsWithAbstractOriginLocCovInfo(Child, AbstractOriginVars);
748     Child = Child.getSibling();
749   }
750 }
751 
752 /// Collect zero location coverage for inlined variables which refer to
753 /// a DW_AT_inline copy of subprogram that is out of order in the DWARF.
754 /// Also cover the variables of a concrete function (represented with
755 /// the DW_TAG_subprogram) with an abstract_origin attribute.
756 static void collectZeroLocCovForVarsWithAbstractOrigin(
757     DWARFUnit *DwUnit, GlobalStats &GlobalStats, LocationStats &LocStats,
758     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
759     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed) {
760   // The next variable is used to filter out functions that have been processed,
761   // leaving FnsWithAbstractOriginToBeProcessed with just CrossCU references.
762   FunctionsWithAbstractOriginTy ProcessedFns;
763   for (auto FnOffset : FnsWithAbstractOriginToBeProcessed) {
764     DWARFDie FnDieWithAbstractOrigin = DwUnit->getDIEForOffset(FnOffset);
765     auto FnCopy = FnDieWithAbstractOrigin.find(dwarf::DW_AT_abstract_origin);
766     AbstractOriginVarsTy AbstractOriginVars;
767     if (!FnCopy)
768       continue;
769     uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
770     // If there is no entry within LocalAbstractOriginFnInfo for the given
771     // FnCopyRawUValue, function isn't out-of-order in DWARF. Rather, we have
772     // CrossCU referencing.
773     if (!LocalAbstractOriginFnInfo.count(FnCopyRawUValue))
774       continue;
775     AbstractOriginVars = LocalAbstractOriginFnInfo[FnCopyRawUValue];
776     updateVarsWithAbstractOriginLocCovInfo(FnDieWithAbstractOrigin,
777                                            AbstractOriginVars);
778 
779     for (auto Offset : AbstractOriginVars) {
780       LocStats.NumVarParam++;
781       LocStats.VarParamLocStats[ZeroCoverageBucket]++;
782       auto Tag = DwUnit->getDIEForOffset(Offset).getTag();
783       if (Tag == dwarf::DW_TAG_formal_parameter) {
784         LocStats.NumParam++;
785         LocStats.ParamLocStats[ZeroCoverageBucket]++;
786       } else if (Tag == dwarf::DW_TAG_variable) {
787         LocStats.NumVar++;
788         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
789       }
790     }
791     ProcessedFns.push_back(FnOffset);
792   }
793   for (auto ProcessedFn : ProcessedFns)
794     llvm::erase_value(FnsWithAbstractOriginToBeProcessed, ProcessedFn);
795 }
796 
797 /// Collect zero location coverage for inlined variables which refer to
798 /// a DW_AT_inline copy of subprogram that is in a different CU.
799 static void collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
800     LocationStats &LocStats, FunctionDIECUTyMap AbstractOriginFnCUs,
801     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
802     CrossCUReferencingDIELocationTy &CrossCUReferencesToBeResolved) {
803   for (const auto &CrossCUReferenceToBeResolved :
804        CrossCUReferencesToBeResolved) {
805     DWARFUnit *DwUnit = CrossCUReferenceToBeResolved.DwUnit;
806     DWARFDie FnDIEWithCrossCUReferencing =
807         DwUnit->getDIEForOffset(CrossCUReferenceToBeResolved.DIEOffset);
808     auto FnCopy =
809         FnDIEWithCrossCUReferencing.find(dwarf::DW_AT_abstract_origin);
810     if (!FnCopy)
811       continue;
812     uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
813     AbstractOriginVarsTy AbstractOriginVars =
814         GlobalAbstractOriginFnInfo[FnCopyRawUValue];
815     updateVarsWithAbstractOriginLocCovInfo(FnDIEWithCrossCUReferencing,
816                                            AbstractOriginVars);
817     for (auto Offset : AbstractOriginVars) {
818       LocStats.NumVarParam++;
819       LocStats.VarParamLocStats[ZeroCoverageBucket]++;
820       auto Tag = (AbstractOriginFnCUs[FnCopyRawUValue])
821                      ->getDIEForOffset(Offset)
822                      .getTag();
823       if (Tag == dwarf::DW_TAG_formal_parameter) {
824         LocStats.NumParam++;
825         LocStats.ParamLocStats[ZeroCoverageBucket]++;
826       } else if (Tag == dwarf::DW_TAG_variable) {
827         LocStats.NumVar++;
828         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
829       }
830     }
831   }
832 }
833 
834 /// \}
835 
836 /// Collect debug info quality metrics for an entire DIContext.
837 ///
838 /// Do the impossible and reduce the quality of the debug info down to a few
839 /// numbers. The idea is to condense the data into numbers that can be tracked
840 /// over time to identify trends in newer compiler versions and gauge the effect
841 /// of particular optimizations. The raw numbers themselves are not particularly
842 /// useful, only the delta between compiling the same program with different
843 /// compilers is.
844 bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
845                                           const Twine &Filename,
846                                           raw_ostream &OS) {
847   StringRef FormatName = Obj.getFileFormatName();
848   GlobalStats GlobalStats;
849   LocationStats LocStats;
850   StringMap<PerFunctionStats> Statistics;
851   // This variable holds variable information for functions with
852   // abstract_origin globally, across all CUs.
853   AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo;
854   // This variable holds information about the CU of a function with
855   // abstract_origin.
856   FunctionDIECUTyMap AbstractOriginFnCUs;
857   CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
858   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
859     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
860       // This variable holds variable information for functions with
861       // abstract_origin, but just for the current CU.
862       AbstractOriginVarsTyMap LocalAbstractOriginFnInfo;
863       FunctionsWithAbstractOriginTy FnsWithAbstractOriginToBeProcessed;
864 
865       collectStatsRecursive(
866           CUDie, "/", "g", 0, 0, Statistics, GlobalStats, LocStats,
867           AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
868           LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
869 
870       // collectZeroLocCovForVarsWithAbstractOrigin will filter out all
871       // out-of-order DWARF functions that have been processed within it,
872       // leaving FnsWithAbstractOriginToBeProcessed with only CrossCU
873       // references.
874       collectZeroLocCovForVarsWithAbstractOrigin(
875           CUDie.getDwarfUnit(), GlobalStats, LocStats,
876           LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
877 
878       // Collect all CrossCU references into CrossCUReferencesToBeResolved.
879       for (auto CrossCUReferencingDIEOffset :
880            FnsWithAbstractOriginToBeProcessed)
881         CrossCUReferencesToBeResolved.push_back(
882             DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset));
883     }
884   }
885 
886   /// Resolve CrossCU references.
887   collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
888       LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
889       CrossCUReferencesToBeResolved);
890 
891   /// Collect the sizes of debug sections.
892   SectionSizes Sizes;
893   calculateSectionSizes(Obj, Sizes, Filename);
894 
895   /// The version number should be increased every time the algorithm is changed
896   /// (including bug fixes). New metrics may be added without increasing the
897   /// version.
898   unsigned Version = 9;
899   SaturatingUINT64 VarParamTotal = 0;
900   SaturatingUINT64 VarParamUnique = 0;
901   SaturatingUINT64 VarParamWithLoc = 0;
902   SaturatingUINT64 NumFunctions = 0;
903   SaturatingUINT64 NumInlinedFunctions = 0;
904   SaturatingUINT64 NumFuncsWithSrcLoc = 0;
905   SaturatingUINT64 NumAbstractOrigins = 0;
906   SaturatingUINT64 ParamTotal = 0;
907   SaturatingUINT64 ParamWithType = 0;
908   SaturatingUINT64 ParamWithLoc = 0;
909   SaturatingUINT64 ParamWithSrcLoc = 0;
910   SaturatingUINT64 LocalVarTotal = 0;
911   SaturatingUINT64 LocalVarWithType = 0;
912   SaturatingUINT64 LocalVarWithSrcLoc = 0;
913   SaturatingUINT64 LocalVarWithLoc = 0;
914   for (auto &Entry : Statistics) {
915     PerFunctionStats &Stats = Entry.getValue();
916     uint64_t TotalVars = Stats.VarsInFunction.size() *
917                          (Stats.NumFnInlined + Stats.NumFnOutOfLine);
918     // Count variables in global scope.
919     if (!Stats.IsFunction)
920       TotalVars =
921           Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial;
922     uint64_t Constants = Stats.ConstantMembers;
923     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
924     VarParamTotal += TotalVars;
925     VarParamUnique += Stats.VarsInFunction.size();
926     LLVM_DEBUG(for (auto &V
927                     : Stats.VarsInFunction) llvm::dbgs()
928                << Entry.getKey() << ": " << V.getKey() << "\n");
929     NumFunctions += Stats.IsFunction;
930     NumFuncsWithSrcLoc += Stats.HasSourceLocation;
931     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
932     NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
933     ParamTotal += Stats.NumParams;
934     ParamWithType += Stats.NumParamTypes;
935     ParamWithLoc += Stats.NumParamLocations;
936     ParamWithSrcLoc += Stats.NumParamSourceLocations;
937     LocalVarTotal += Stats.NumLocalVars;
938     LocalVarWithType += Stats.NumLocalVarTypes;
939     LocalVarWithLoc += Stats.NumLocalVarLocations;
940     LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations;
941   }
942 
943   // Print summary.
944   OS.SetBufferSize(1024);
945   json::OStream J(OS, 2);
946   J.objectBegin();
947   J.attribute("version", Version);
948   LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
949              llvm::dbgs() << "---------------------------------\n");
950 
951   printDatum(J, "file", Filename.str());
952   printDatum(J, "format", FormatName);
953 
954   printDatum(J, "#functions", NumFunctions.Value);
955   printDatum(J, "#functions with location", NumFuncsWithSrcLoc.Value);
956   printDatum(J, "#inlined functions", NumInlinedFunctions.Value);
957   printDatum(J, "#inlined functions with abstract origins",
958              NumAbstractOrigins.Value);
959 
960   // This includes local variables and formal parameters.
961   printDatum(J, "#unique source variables", VarParamUnique.Value);
962   printDatum(J, "#source variables", VarParamTotal.Value);
963   printDatum(J, "#source variables with location", VarParamWithLoc.Value);
964 
965   printDatum(J, "#call site entries", GlobalStats.CallSiteEntries.Value);
966   printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs.Value);
967   printDatum(J, "#call site parameter DIEs",
968              GlobalStats.CallSiteParamDIEs.Value);
969 
970   printDatum(J, "sum_all_variables(#bytes in parent scope)",
971              GlobalStats.ScopeBytes.Value);
972   printDatum(J,
973              "sum_all_variables(#bytes in any scope covered by DW_AT_location)",
974              GlobalStats.TotalBytesCovered.Value);
975   printDatum(J,
976              "sum_all_variables(#bytes in parent scope covered by "
977              "DW_AT_location)",
978              GlobalStats.ScopeBytesCovered.Value);
979   printDatum(J,
980              "sum_all_variables(#bytes in parent scope covered by "
981              "DW_OP_entry_value)",
982              GlobalStats.ScopeEntryValueBytesCovered.Value);
983 
984   printDatum(J, "sum_all_params(#bytes in parent scope)",
985              GlobalStats.ParamScopeBytes.Value);
986   printDatum(J,
987              "sum_all_params(#bytes in parent scope covered by DW_AT_location)",
988              GlobalStats.ParamScopeBytesCovered.Value);
989   printDatum(J,
990              "sum_all_params(#bytes in parent scope covered by "
991              "DW_OP_entry_value)",
992              GlobalStats.ParamScopeEntryValueBytesCovered.Value);
993 
994   printDatum(J, "sum_all_local_vars(#bytes in parent scope)",
995              GlobalStats.LocalVarScopeBytes.Value);
996   printDatum(J,
997              "sum_all_local_vars(#bytes in parent scope covered by "
998              "DW_AT_location)",
999              GlobalStats.LocalVarScopeBytesCovered.Value);
1000   printDatum(J,
1001              "sum_all_local_vars(#bytes in parent scope covered by "
1002              "DW_OP_entry_value)",
1003              GlobalStats.LocalVarScopeEntryValueBytesCovered.Value);
1004 
1005   printDatum(J, "#bytes within functions", GlobalStats.FunctionSize.Value);
1006   printDatum(J, "#bytes within inlined functions",
1007              GlobalStats.InlineFunctionSize.Value);
1008 
1009   // Print the summary for formal parameters.
1010   printDatum(J, "#params", ParamTotal.Value);
1011   printDatum(J, "#params with source location", ParamWithSrcLoc.Value);
1012   printDatum(J, "#params with type", ParamWithType.Value);
1013   printDatum(J, "#params with binary location", ParamWithLoc.Value);
1014 
1015   // Print the summary for local variables.
1016   printDatum(J, "#local vars", LocalVarTotal.Value);
1017   printDatum(J, "#local vars with source location", LocalVarWithSrcLoc.Value);
1018   printDatum(J, "#local vars with type", LocalVarWithType.Value);
1019   printDatum(J, "#local vars with binary location", LocalVarWithLoc.Value);
1020 
1021   // Print the debug section sizes.
1022   printSectionSizes(J, Sizes);
1023 
1024   // Print the location statistics for variables (includes local variables
1025   // and formal parameters).
1026   printDatum(J, "#variables processed by location statistics",
1027              LocStats.NumVarParam.Value);
1028   printLocationStats(J, "#variables", LocStats.VarParamLocStats);
1029   printLocationStats(J, "#variables - entry values",
1030                      LocStats.VarParamNonEntryValLocStats);
1031 
1032   // Print the location statistics for formal parameters.
1033   printDatum(J, "#params processed by location statistics",
1034              LocStats.NumParam.Value);
1035   printLocationStats(J, "#params", LocStats.ParamLocStats);
1036   printLocationStats(J, "#params - entry values",
1037                      LocStats.ParamNonEntryValLocStats);
1038 
1039   // Print the location statistics for local variables.
1040   printDatum(J, "#local vars processed by location statistics",
1041              LocStats.NumVar.Value);
1042   printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
1043   printLocationStats(J, "#local vars - entry values",
1044                      LocStats.LocalVarNonEntryValLocStats);
1045   J.objectEnd();
1046   OS << '\n';
1047   LLVM_DEBUG(
1048       llvm::dbgs() << "Total Availability: "
1049                    << (VarParamTotal.Value
1050                            ? (int)std::round((VarParamWithLoc.Value * 100.0) /
1051                                              VarParamTotal.Value)
1052                            : 0)
1053                    << "%\n";
1054       llvm::dbgs() << "PC Ranges covered: "
1055                    << (GlobalStats.ScopeBytes.Value
1056                            ? (int)std::round(
1057                                  (GlobalStats.ScopeBytesCovered.Value * 100.0) /
1058                                  GlobalStats.ScopeBytes.Value)
1059                            : 0)
1060                    << "%\n");
1061   return true;
1062 }
1063