[llvm] c450e47 - [llvm-dwarfdump] Fix unsigned overflow when calculating stats

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 15 03:16:15 PDT 2021


Author: djtodoro
Date: 2021-10-15T12:15:58+02:00
New Revision: c450e47a8c2d7f73ddeb370725e163d418e215e7

URL: https://github.com/llvm/llvm-project/commit/c450e47a8c2d7f73ddeb370725e163d418e215e7
DIFF: https://github.com/llvm/llvm-project/commit/c450e47a8c2d7f73ddeb370725e163d418e215e7.diff

LOG: [llvm-dwarfdump] Fix unsigned overflow when calculating stats

This fixes https://bugs.llvm.org/show_bug.cgi?id=51652.

The idea is to bump all the stat fields to 64-bit wide
unsigned integers. I've confirmed this resolves
the use case for chromium.

Differential Revision: https://reviews.llvm.org/D109217

Added: 
    llvm/test/tools/llvm-dwarfdump/X86/locstats-big-number-of-bytes.yaml
    llvm/test/tools/llvm-dwarfdump/X86/locstats-bytes-overflow.yaml

Modified: 
    llvm/test/tools/llvm-dwarfdump/X86/locstats-for-absctract-origin-vars.yaml
    llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
    llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
    llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
    llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
    llvm/tools/llvm-dwarfdump/Statistics.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/locstats-big-number-of-bytes.yaml b/llvm/test/tools/llvm-dwarfdump/X86/locstats-big-number-of-bytes.yaml
new file mode 100644
index 0000000000000..76cb9d115ef3b
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/locstats-big-number-of-bytes.yaml
@@ -0,0 +1,92 @@
+# RUN: yaml2obj %s | llvm-dwarfdump --statistics - | FileCheck %s
+
+## Check that we are covering the situation when
+## sum of bytes in scope is a huge (uint64_t) number.
+##
+## The yaml represents this DWARF:
+##
+## DW_TAG_compile_unit
+##   DW_AT_low_pc	(0x0000000000000000)
+##   DW_AT_high_pc	(0x000000000000000b)
+##
+##   DW_TAG_subprogram
+##     DW_AT_low_pc	(0x0000000000000000)
+##     DW_AT_high_pc	(0x00000000ffffffff)
+##       DW_TAG_variable
+##         DW_AT_location	(0x00000023:
+##            [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
+##   DW_TAG_subprogram
+##     DW_AT_low_pc    (0x0000000000000000)
+##     DW_AT_high_pc   (0x00000000ffffffff)
+##     DW_TAG_variable
+##       DW_AT_location        (0x00000023:
+##             [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
+
+# CHECK: "version": 9,
+# CHECK: "sum_all_variables(#bytes in parent scope)": 8589934590
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:         .debug_loc
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x01
+    Content:      '00000000000000000600000000000000010055000000000000000000000000000000000300000000000000050000000000000001005200000000000000000000000000000000'
+  - Name:         .debug_ranges
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x01
+    Content:      '000000000000000003000000000000000500000000000000080000000000000000000000000000000000000000000000'
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data4
+      - Code:     2
+        Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data4
+      - Code:     3
+        Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_location
+            Form:      DW_FORM_sec_offset
+  debug_info:
+    - Version:    4
+      AbbrOffset: 0x00
+      Entries:
+        - AbbrCode: 1 ## DW_TAG_compile_unit
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0x0b ## DW_AT_high_pc
+        - AbbrCode: 2 ## DW_TAG_subprogram
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0xFFFFFFFF ## DW_AT_high_pc
+        - AbbrCode: 3 ## DW_TAG_variable
+          Values:
+            - Value: 0x23 ## DW_AT_sec_offset
+        - AbbrCode: 0 ## NULL
+        - AbbrCode: 2 ## DW_TAG_subprogram
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0xFFFFFFFF ## DW_AT_high_pc
+        - AbbrCode: 3 ## DW_TAG_variable
+          Values:
+            - Value: 0x23 ## DW_AT_sec_offset
+        - AbbrCode: 0 ## NULL
+        - AbbrCode: 0 ## NULL

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/locstats-bytes-overflow.yaml b/llvm/test/tools/llvm-dwarfdump/X86/locstats-bytes-overflow.yaml
new file mode 100644
index 0000000000000..0fb82404c72fb
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/locstats-bytes-overflow.yaml
@@ -0,0 +1,90 @@
+# RUN: yaml2obj %s | llvm-dwarfdump --statistics - 2>&1 | FileCheck %s
+
+## Check that we are covering the situation when a stat field overflows.
+##
+## The yaml represents this DWARF:
+##
+## DW_TAG_compile_unit
+##   DW_AT_low_pc (0x0000000000000000)
+##   DW_AT_high_pc  (0x000000000000000b)
+##
+##   DW_TAG_subprogram
+##     DW_AT_low_pc (0x0000000000000000)
+##     DW_AT_high_pc  (0xffffffffffffffff)
+##       DW_TAG_variable
+##         DW_AT_location (0x00000023:
+##            [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
+##   DW_TAG_subprogram
+##     DW_AT_low_pc    (0x0000000000000000)
+##     DW_AT_high_pc   (0xffffffffffffffff)
+##     DW_TAG_variable
+##       DW_AT_location        (0x00000023:
+##             [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
+
+# CHECK: "sum_all_variables(#bytes in parent scope)": "overflowed"
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS[[BITS=64]]
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:         .debug_loc
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x01
+    Content:      '00000000000000000600000000000000010055000000000000000000000000000000000300000000000000050000000000000001005200000000000000000000000000000000'
+  - Name:         .debug_ranges
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x01
+    Content:      '000000000000000003000000000000000500000000000000080000000000000000000000000000000000000000000000'
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+      - Code:     2
+        Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+      - Code:     3
+        Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_location
+            Form:      DW_FORM_sec_offset
+  debug_info:
+    - Version:    4
+      AbbrOffset: 0x00
+      Entries:
+        - AbbrCode: 1 ## DW_TAG_compile_unit
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0x0b ## DW_AT_high_pc
+        - AbbrCode: 2 ## DW_TAG_subprogram
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0xFFFFFFFFFFFFFFFF ## DW_AT_high_pc
+        - AbbrCode: 3 ## DW_TAG_variable
+          Values:
+            - Value: 0x23 ## DW_AT_sec_offset
+        - AbbrCode: 0 ## NULL
+        - AbbrCode: 2 ## DW_TAG_subprogram
+          Values:
+            - Value: 0x00 ## DW_AT_low_pc
+            - Value: 0xFFFFFFFFFFFFFFFF ## DW_AT_high_pc
+        - AbbrCode: 3 ## DW_TAG_variable
+          Values:
+            - Value: 0x23 ## DW_AT_sec_offset
+        - AbbrCode: 0 ## NULL
+        - AbbrCode: 0 ## NULL

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-absctract-origin-vars.yaml b/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-absctract-origin-vars.yaml
index 8a1e1af4a7630..458b556856eba 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-absctract-origin-vars.yaml
+++ b/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-absctract-origin-vars.yaml
@@ -120,7 +120,7 @@
 ##    DW_TAG_subprogram
 ##        DW_AT_abstract_origin (0x000000f0)
 
-# CHECK: "version": 8,
+# CHECK: "version": 9,
 # CHECK: "#variables processed by location statistics": 17,
 # CHECK: "#variables with 0% of parent scope covered by DW_AT_location": 13,
 # CHECK: "#variables with 100% of parent scope covered by DW_AT_location": 4,

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test b/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
index 8d6700562fe31..3e39591c46dce 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
@@ -69,7 +69,7 @@ RUN: llvm-dwarfdump --statistics statistics-fib.split-dwarf.o | FileCheck %s
 # }
 #
 
-CHECK:      "version": 8,
+CHECK:      "version": 9,
 CHECK:      "#functions": 3,
 CHECK:      "#functions with location": 3,
 CHECK:      "#inlined functions": 7,

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test b/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
index a2a495c1346ce..855dcedc76f0b 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
@@ -64,7 +64,7 @@ RUN: llvm-dwarfdump --statistics %t-statistics-fib.o | FileCheck %s
 # }
 #
 
-CHECK:      "version": 8,
+CHECK:      "version": 9,
 CHECK:      "#functions": 3,
 CHECK:      "#functions with location": 3,
 CHECK:      "#inlined functions": 8,

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
index ced2f4686b59e..08d1d25286ec6 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
@@ -1,6 +1,6 @@
 ; RUN: llc -O0 %s -o - -filetype=obj \
 ; RUN:   | llvm-dwarfdump -statistics - | FileCheck %s
-; CHECK: "version": 8,
+; CHECK: "version": 9,
 
 ; namespace test {
 ;  extern int a;

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml b/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
index 5be144113c709..3d4e9d33f24ab 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
+++ b/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
@@ -33,7 +33,7 @@
 ##         DW_AT_location	(0x00000023:
 ##            [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
 
-# CHECK: "version": 8,
+# CHECK: "version": 9,
 # CHECK: "sum_all_variables(#bytes in parent scope)": 12,
 # CHECK: "sum_all_variables(#bytes in any scope covered by DW_AT_location)": 8
 # CHECK: "sum_all_variables(#bytes in parent scope covered by DW_AT_location)": 4

diff  --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp
index 19a971afa3111..8e91a6be7b084 100644
--- a/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -29,6 +29,9 @@ constexpr int NumOfCoverageCategories = 12;
 /// This is used for zero location coverage bucket.
 constexpr unsigned ZeroCoverageBucket = 0;
 
+/// The UINT64_MAX is used as an indication of the overflow.
+constexpr uint64_t OverflowValue = std::numeric_limits<uint64_t>::max();
+
 /// This represents variables DIE offsets.
 using AbstractOriginVarsTy = llvm::SmallVector<uint64_t>;
 /// This maps function DIE offset to its variables.
@@ -36,22 +39,43 @@ using AbstractOriginVarsTyMap = llvm::DenseMap<uint64_t, AbstractOriginVarsTy>;
 /// This represents function DIE offsets containing an abstract_origin.
 using FunctionsWithAbstractOriginTy = llvm::SmallVector<uint64_t>;
 
+/// This represents a data type for the stats and it helps us to
+/// detect an overflow.
+/// NOTE: This can be implemented as a template if there is an another type
+/// needing this.
+struct SaturatingUINT64 {
+  /// Number that represents the stats.
+  uint64_t Value;
+
+  SaturatingUINT64(uint64_t Value_) : Value(Value_) {}
+
+  void operator++(int) { return *this += 1; }
+  void operator+=(uint64_t Value_) {
+    if (Value != OverflowValue) {
+      if (Value < OverflowValue - Value_)
+        Value += Value_;
+      else
+        Value = OverflowValue;
+    }
+  }
+};
+
 /// Holds statistics for one function (or other entity that has a PC range and
 /// contains variables, such as a compile unit).
 struct PerFunctionStats {
   /// Number of inlined instances of this function.
-  unsigned NumFnInlined = 0;
+  uint64_t NumFnInlined = 0;
   /// Number of out-of-line instances of this function.
-  unsigned NumFnOutOfLine = 0;
+  uint64_t NumFnOutOfLine = 0;
   /// Number of inlined instances that have abstract origins.
-  unsigned NumAbstractOrigins = 0;
+  uint64_t NumAbstractOrigins = 0;
   /// Number of variables and parameters with location across all inlined
   /// instances.
-  unsigned TotalVarWithLoc = 0;
+  uint64_t TotalVarWithLoc = 0;
   /// Number of constants with location across all inlined instances.
-  unsigned ConstantMembers = 0;
+  uint64_t ConstantMembers = 0;
   /// Number of arificial variables, parameters or members across all instances.
-  unsigned NumArtificial = 0;
+  uint64_t NumArtificial = 0;
   /// List of all Variables and parameters in this function.
   StringSet<> VarsInFunction;
   /// Compile units also cover a PC range, but have this flag set to false.
@@ -59,63 +83,63 @@ struct PerFunctionStats {
   /// Function has source location information.
   bool HasSourceLocation = false;
   /// Number of function parameters.
-  unsigned NumParams = 0;
+  uint64_t NumParams = 0;
   /// Number of function parameters with source location.
-  unsigned NumParamSourceLocations = 0;
+  uint64_t NumParamSourceLocations = 0;
   /// Number of function parameters with type.
-  unsigned NumParamTypes = 0;
+  uint64_t NumParamTypes = 0;
   /// Number of function parameters with a DW_AT_location.
-  unsigned NumParamLocations = 0;
+  uint64_t NumParamLocations = 0;
   /// Number of local variables.
-  unsigned NumLocalVars = 0;
+  uint64_t NumLocalVars = 0;
   /// Number of local variables with source location.
-  unsigned NumLocalVarSourceLocations = 0;
+  uint64_t NumLocalVarSourceLocations = 0;
   /// Number of local variables with type.
-  unsigned NumLocalVarTypes = 0;
+  uint64_t NumLocalVarTypes = 0;
   /// Number of local variables with DW_AT_location.
-  unsigned NumLocalVarLocations = 0;
+  uint64_t NumLocalVarLocations = 0;
 };
 
 /// Holds accumulated global statistics about DIEs.
 struct GlobalStats {
   /// Total number of PC range bytes covered by DW_AT_locations.
-  unsigned TotalBytesCovered = 0;
+  SaturatingUINT64 TotalBytesCovered = 0;
   /// Total number of parent DIE PC range bytes covered by DW_AT_Locations.
-  unsigned ScopeBytesCovered = 0;
+  SaturatingUINT64 ScopeBytesCovered = 0;
   /// Total number of PC range bytes in each variable's enclosing scope.
-  unsigned ScopeBytes = 0;
+  SaturatingUINT64 ScopeBytes = 0;
   /// Total number of PC range bytes covered by DW_AT_locations with
   /// the debug entry values (DW_OP_entry_value).
-  unsigned ScopeEntryValueBytesCovered = 0;
+  SaturatingUINT64 ScopeEntryValueBytesCovered = 0;
   /// Total number of PC range bytes covered by DW_AT_locations of
   /// formal parameters.
-  unsigned ParamScopeBytesCovered = 0;
+  SaturatingUINT64 ParamScopeBytesCovered = 0;
   /// Total number of PC range bytes in each parameter's enclosing scope.
-  unsigned ParamScopeBytes = 0;
+  SaturatingUINT64 ParamScopeBytes = 0;
   /// Total number of PC range bytes covered by DW_AT_locations with
   /// the debug entry values (DW_OP_entry_value) (only for parameters).
-  unsigned ParamScopeEntryValueBytesCovered = 0;
+  SaturatingUINT64 ParamScopeEntryValueBytesCovered = 0;
   /// Total number of PC range bytes covered by DW_AT_locations (only for local
   /// variables).
-  unsigned LocalVarScopeBytesCovered = 0;
+  SaturatingUINT64 LocalVarScopeBytesCovered = 0;
   /// Total number of PC range bytes in each local variable's enclosing scope.
-  unsigned LocalVarScopeBytes = 0;
+  SaturatingUINT64 LocalVarScopeBytes = 0;
   /// Total number of PC range bytes covered by DW_AT_locations with
   /// the debug entry values (DW_OP_entry_value) (only for local variables).
-  unsigned LocalVarScopeEntryValueBytesCovered = 0;
+  SaturatingUINT64 LocalVarScopeEntryValueBytesCovered = 0;
   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
-  unsigned CallSiteEntries = 0;
+  SaturatingUINT64 CallSiteEntries = 0;
   /// Total number of call site DIEs (DW_TAG_call_site).
-  unsigned CallSiteDIEs = 0;
+  SaturatingUINT64 CallSiteDIEs = 0;
   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
-  unsigned CallSiteParamDIEs = 0;
+  SaturatingUINT64 CallSiteParamDIEs = 0;
   /// Total byte size of concrete functions. This byte size includes
   /// inline functions contained in the concrete functions.
-  unsigned FunctionSize = 0;
+  SaturatingUINT64 FunctionSize = 0;
   /// Total byte size of inlined functions. This is the total number of bytes
   /// for the top inline functions within concrete functions. This can help
   /// tune the inline settings when compiling to match user expectations.
-  unsigned InlineFunctionSize = 0;
+  SaturatingUINT64 InlineFunctionSize = 0;
 };
 
 /// Holds accumulated debug location statistics about local variables and
@@ -126,37 +150,37 @@ struct LocationStats {
   /// of variables with the no debug location at all, but the last element
   /// in the vector represents the number of fully covered variables within
   /// its scope.
-  std::vector<unsigned> VarParamLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> VarParamLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// Map non debug entry values coverage.
-  std::vector<unsigned> VarParamNonEntryValLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> VarParamNonEntryValLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// The debug location statistics for formal parameters.
-  std::vector<unsigned> ParamLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> ParamLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// Map non debug entry values coverage for formal parameters.
-  std::vector<unsigned> ParamNonEntryValLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> ParamNonEntryValLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// The debug location statistics for local variables.
-  std::vector<unsigned> LocalVarLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> LocalVarLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// Map non debug entry values coverage for local variables.
-  std::vector<unsigned> LocalVarNonEntryValLocStats{
-      std::vector<unsigned>(NumOfCoverageCategories, 0)};
+  std::vector<SaturatingUINT64> LocalVarNonEntryValLocStats{
+      std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
   /// Total number of local variables and function parameters processed.
-  unsigned NumVarParam = 0;
+  SaturatingUINT64 NumVarParam = 0;
   /// Total number of formal parameters processed.
-  unsigned NumParam = 0;
+  SaturatingUINT64 NumParam = 0;
   /// Total number of local variables processed.
-  unsigned NumVar = 0;
+  SaturatingUINT64 NumVar = 0;
 };
 } // namespace
 
 /// Collect debug location statistics for one DIE.
 static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
-                            std::vector<unsigned> &VarParamLocStats,
-                            std::vector<unsigned> &ParamLocStats,
-                            std::vector<unsigned> &LocalVarLocStats,
+                            std::vector<SaturatingUINT64> &VarParamLocStats,
+                            std::vector<SaturatingUINT64> &ParamLocStats,
+                            std::vector<SaturatingUINT64> &LocalVarLocStats,
                             bool IsParam, bool IsLocalVar) {
   auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned {
     // No debug location at all for the variable.
@@ -173,11 +197,11 @@ static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
 
   unsigned CoverageBucket = getCoverageBucket();
 
-  VarParamLocStats[CoverageBucket]++;
+  VarParamLocStats[CoverageBucket].Value++;
   if (IsParam)
-    ParamLocStats[CoverageBucket]++;
+    ParamLocStats[CoverageBucket].Value++;
   else if (IsLocalVar)
-    LocalVarLocStats[CoverageBucket]++;
+    LocalVarLocStats[CoverageBucket].Value++;
 }
 
 /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
@@ -350,11 +374,11 @@ static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
 
   // Calculate the debug location statistics.
   if (BytesInScope && !DeferLocStats) {
-    LocStats.NumVarParam++;
+    LocStats.NumVarParam.Value++;
     if (IsParam)
-      LocStats.NumParam++;
+      LocStats.NumParam.Value++;
     else if (IsLocalVar)
-      LocStats.NumVar++;
+      LocStats.NumVar.Value++;
 
     collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats,
                     LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam,
@@ -389,7 +413,7 @@ static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
       GlobalStats.LocalVarScopeEntryValueBytesCovered +=
           BytesEntryValuesCovered;
     }
-    assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes);
+    assert(GlobalStats.ScopeBytesCovered.Value <= GlobalStats.ScopeBytes.Value);
   }
 
   if (IsConstantMember) {
@@ -603,45 +627,78 @@ static void collectStatsRecursive(
 /// Print human-readable output.
 /// \{
 static void printDatum(json::OStream &J, const char *Key, json::Value Value) {
-  J.attribute(Key, Value);
+  if (Value == OverflowValue)
+    J.attribute(Key, "overflowed");
+  else
+    J.attribute(Key, Value);
+
   LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
 }
 
 static void printLocationStats(json::OStream &J, const char *Key,
-                               std::vector<unsigned> &LocationStats) {
-  J.attribute(
-      (Twine(Key) + " with 0% of parent scope covered by DW_AT_location").str(),
-      LocationStats[0]);
+                               std::vector<SaturatingUINT64> &LocationStats) {
+  if (LocationStats[0].Value == OverflowValue)
+    J.attribute((Twine(Key) +
+                 " with (0%,10%) of parent scope covered by DW_AT_location")
+                    .str(),
+                "overflowed");
+  else
+    J.attribute(
+        (Twine(Key) + " with 0% of parent scope covered by DW_AT_location")
+            .str(),
+        LocationStats[0].Value);
   LLVM_DEBUG(
       llvm::dbgs() << Key
                    << " with 0% of parent scope covered by DW_AT_location: \\"
-                   << LocationStats[0] << '\n');
-  J.attribute(
-      (Twine(Key) + " with (0%,10%) of parent scope covered by DW_AT_location")
-          .str(),
-      LocationStats[1]);
+                   << LocationStats[0].Value << '\n');
+
+  if (LocationStats[1].Value == OverflowValue)
+    J.attribute((Twine(Key) +
+                 " with (0%,10%) of parent scope covered by DW_AT_location")
+                    .str(),
+                "overflowed");
+  else
+    J.attribute((Twine(Key) +
+                 " with (0%,10%) of parent scope covered by DW_AT_location")
+                    .str(),
+                LocationStats[1].Value);
   LLVM_DEBUG(llvm::dbgs()
              << Key
              << " with (0%,10%) of parent scope covered by DW_AT_location: "
-             << LocationStats[1] << '\n');
+             << LocationStats[1].Value << '\n');
+
   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
-    J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
-                 Twine(i * 10) + "%) of parent scope covered by DW_AT_location")
-                    .str(),
-                LocationStats[i]);
+    if (LocationStats[i].Value == OverflowValue)
+      J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
+                   Twine(i * 10) +
+                   "%) of parent scope covered by DW_AT_location")
+                      .str(),
+                  "overflowed");
+    else
+      J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
+                   Twine(i * 10) +
+                   "%) of parent scope covered by DW_AT_location")
+                      .str(),
+                  LocationStats[i].Value);
     LLVM_DEBUG(llvm::dbgs()
                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
                << "%) of parent scope covered by DW_AT_location: "
-               << LocationStats[i]);
+               << LocationStats[i].Value);
   }
-  J.attribute(
-      (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
-          .str(),
-      LocationStats[NumOfCoverageCategories - 1]);
+  if (LocationStats[NumOfCoverageCategories - 1].Value == OverflowValue)
+    J.attribute(
+        (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
+            .str(),
+        "overflowed");
+  else
+    J.attribute(
+        (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
+            .str(),
+        LocationStats[NumOfCoverageCategories - 1].Value);
   LLVM_DEBUG(
       llvm::dbgs() << Key
                    << " with 100% of parent scope covered by DW_AT_location: "
-                   << LocationStats[NumOfCoverageCategories - 1]);
+                   << LocationStats[NumOfCoverageCategories - 1].Value);
 }
 
 static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) {
@@ -750,31 +807,31 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
   /// The version number should be increased every time the algorithm is changed
   /// (including bug fixes). New metrics may be added without increasing the
   /// version.
-  unsigned Version = 8;
-  unsigned VarParamTotal = 0;
-  unsigned VarParamUnique = 0;
-  unsigned VarParamWithLoc = 0;
-  unsigned NumFunctions = 0;
-  unsigned NumInlinedFunctions = 0;
-  unsigned NumFuncsWithSrcLoc = 0;
-  unsigned NumAbstractOrigins = 0;
-  unsigned ParamTotal = 0;
-  unsigned ParamWithType = 0;
-  unsigned ParamWithLoc = 0;
-  unsigned ParamWithSrcLoc = 0;
-  unsigned LocalVarTotal = 0;
-  unsigned LocalVarWithType = 0;
-  unsigned LocalVarWithSrcLoc = 0;
-  unsigned LocalVarWithLoc = 0;
+  unsigned Version = 9;
+  SaturatingUINT64 VarParamTotal = 0;
+  SaturatingUINT64 VarParamUnique = 0;
+  SaturatingUINT64 VarParamWithLoc = 0;
+  SaturatingUINT64 NumFunctions = 0;
+  SaturatingUINT64 NumInlinedFunctions = 0;
+  SaturatingUINT64 NumFuncsWithSrcLoc = 0;
+  SaturatingUINT64 NumAbstractOrigins = 0;
+  SaturatingUINT64 ParamTotal = 0;
+  SaturatingUINT64 ParamWithType = 0;
+  SaturatingUINT64 ParamWithLoc = 0;
+  SaturatingUINT64 ParamWithSrcLoc = 0;
+  SaturatingUINT64 LocalVarTotal = 0;
+  SaturatingUINT64 LocalVarWithType = 0;
+  SaturatingUINT64 LocalVarWithSrcLoc = 0;
+  SaturatingUINT64 LocalVarWithLoc = 0;
   for (auto &Entry : Statistics) {
     PerFunctionStats &Stats = Entry.getValue();
-    unsigned TotalVars = Stats.VarsInFunction.size() *
+    uint64_t TotalVars = Stats.VarsInFunction.size() *
                          (Stats.NumFnInlined + Stats.NumFnOutOfLine);
     // Count variables in global scope.
     if (!Stats.IsFunction)
       TotalVars =
           Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial;
-    unsigned Constants = Stats.ConstantMembers;
+    uint64_t Constants = Stats.ConstantMembers;
     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
     VarParamTotal += TotalVars;
     VarParamUnique += Stats.VarsInFunction.size();
@@ -806,70 +863,72 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
   printDatum(J, "file", Filename.str());
   printDatum(J, "format", FormatName);
 
-  printDatum(J, "#functions", NumFunctions);
-  printDatum(J, "#functions with location", NumFuncsWithSrcLoc);
-  printDatum(J, "#inlined functions", NumInlinedFunctions);
-  printDatum(J, "#inlined functions with abstract origins", NumAbstractOrigins);
+  printDatum(J, "#functions", NumFunctions.Value);
+  printDatum(J, "#functions with location", NumFuncsWithSrcLoc.Value);
+  printDatum(J, "#inlined functions", NumInlinedFunctions.Value);
+  printDatum(J, "#inlined functions with abstract origins",
+             NumAbstractOrigins.Value);
 
   // This includes local variables and formal parameters.
-  printDatum(J, "#unique source variables", VarParamUnique);
-  printDatum(J, "#source variables", VarParamTotal);
-  printDatum(J, "#source variables with location", VarParamWithLoc);
+  printDatum(J, "#unique source variables", VarParamUnique.Value);
+  printDatum(J, "#source variables", VarParamTotal.Value);
+  printDatum(J, "#source variables with location", VarParamWithLoc.Value);
 
-  printDatum(J, "#call site entries", GlobalStats.CallSiteEntries);
-  printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs);
-  printDatum(J, "#call site parameter DIEs", GlobalStats.CallSiteParamDIEs);
+  printDatum(J, "#call site entries", GlobalStats.CallSiteEntries.Value);
+  printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs.Value);
+  printDatum(J, "#call site parameter DIEs",
+             GlobalStats.CallSiteParamDIEs.Value);
 
   printDatum(J, "sum_all_variables(#bytes in parent scope)",
-             GlobalStats.ScopeBytes);
+             GlobalStats.ScopeBytes.Value);
   printDatum(J,
              "sum_all_variables(#bytes in any scope covered by DW_AT_location)",
-             GlobalStats.TotalBytesCovered);
+             GlobalStats.TotalBytesCovered.Value);
   printDatum(J,
              "sum_all_variables(#bytes in parent scope covered by "
              "DW_AT_location)",
-             GlobalStats.ScopeBytesCovered);
+             GlobalStats.ScopeBytesCovered.Value);
   printDatum(J,
              "sum_all_variables(#bytes in parent scope covered by "
              "DW_OP_entry_value)",
-             GlobalStats.ScopeEntryValueBytesCovered);
+             GlobalStats.ScopeEntryValueBytesCovered.Value);
 
   printDatum(J, "sum_all_params(#bytes in parent scope)",
-             GlobalStats.ParamScopeBytes);
+             GlobalStats.ParamScopeBytes.Value);
   printDatum(J,
              "sum_all_params(#bytes in parent scope covered by DW_AT_location)",
-             GlobalStats.ParamScopeBytesCovered);
+             GlobalStats.ParamScopeBytesCovered.Value);
   printDatum(J,
              "sum_all_params(#bytes in parent scope covered by "
              "DW_OP_entry_value)",
-             GlobalStats.ParamScopeEntryValueBytesCovered);
+             GlobalStats.ParamScopeEntryValueBytesCovered.Value);
 
   printDatum(J, "sum_all_local_vars(#bytes in parent scope)",
-             GlobalStats.LocalVarScopeBytes);
+             GlobalStats.LocalVarScopeBytes.Value);
   printDatum(J,
              "sum_all_local_vars(#bytes in parent scope covered by "
              "DW_AT_location)",
-             GlobalStats.LocalVarScopeBytesCovered);
+             GlobalStats.LocalVarScopeBytesCovered.Value);
   printDatum(J,
              "sum_all_local_vars(#bytes in parent scope covered by "
              "DW_OP_entry_value)",
-             GlobalStats.LocalVarScopeEntryValueBytesCovered);
+             GlobalStats.LocalVarScopeEntryValueBytesCovered.Value);
 
-  printDatum(J, "#bytes within functions", GlobalStats.FunctionSize);
+  printDatum(J, "#bytes within functions", GlobalStats.FunctionSize.Value);
   printDatum(J, "#bytes within inlined functions",
-             GlobalStats.InlineFunctionSize);
+             GlobalStats.InlineFunctionSize.Value);
 
   // Print the summary for formal parameters.
-  printDatum(J, "#params", ParamTotal);
-  printDatum(J, "#params with source location", ParamWithSrcLoc);
-  printDatum(J, "#params with type", ParamWithType);
-  printDatum(J, "#params with binary location", ParamWithLoc);
+  printDatum(J, "#params", ParamTotal.Value);
+  printDatum(J, "#params with source location", ParamWithSrcLoc.Value);
+  printDatum(J, "#params with type", ParamWithType.Value);
+  printDatum(J, "#params with binary location", ParamWithLoc.Value);
 
   // Print the summary for local variables.
-  printDatum(J, "#local vars", LocalVarTotal);
-  printDatum(J, "#local vars with source location", LocalVarWithSrcLoc);
-  printDatum(J, "#local vars with type", LocalVarWithType);
-  printDatum(J, "#local vars with binary location", LocalVarWithLoc);
+  printDatum(J, "#local vars", LocalVarTotal.Value);
+  printDatum(J, "#local vars with source location", LocalVarWithSrcLoc.Value);
+  printDatum(J, "#local vars with type", LocalVarWithType.Value);
+  printDatum(J, "#local vars with binary location", LocalVarWithLoc.Value);
 
   // Print the debug section sizes.
   printSectionSizes(J, Sizes);
@@ -877,32 +936,34 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
   // Print the location statistics for variables (includes local variables
   // and formal parameters).
   printDatum(J, "#variables processed by location statistics",
-             LocStats.NumVarParam);
+             LocStats.NumVarParam.Value);
   printLocationStats(J, "#variables", LocStats.VarParamLocStats);
   printLocationStats(J, "#variables - entry values",
                      LocStats.VarParamNonEntryValLocStats);
 
   // Print the location statistics for formal parameters.
-  printDatum(J, "#params processed by location statistics", LocStats.NumParam);
+  printDatum(J, "#params processed by location statistics",
+             LocStats.NumParam.Value);
   printLocationStats(J, "#params", LocStats.ParamLocStats);
   printLocationStats(J, "#params - entry values",
                      LocStats.ParamNonEntryValLocStats);
 
   // Print the location statistics for local variables.
   printDatum(J, "#local vars processed by location statistics",
-             LocStats.NumVar);
+             LocStats.NumVar.Value);
   printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
   printLocationStats(J, "#local vars - entry values",
                      LocStats.LocalVarNonEntryValLocStats);
   J.objectEnd();
   OS << '\n';
-  LLVM_DEBUG(
-      llvm::dbgs() << "Total Availability: "
-                   << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
-                   << "%\n";
-      llvm::dbgs() << "PC Ranges covered: "
-                   << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
-                                      GlobalStats.ScopeBytes)
-                   << "%\n");
+  LLVM_DEBUG(llvm::dbgs() << "Total Availability: "
+                          << (int)std::round((VarParamWithLoc.Value * 100.0) /
+                                             VarParamTotal.Value)
+                          << "%\n";
+             llvm::dbgs() << "PC Ranges covered: "
+                          << (int)std::round(
+                                 (GlobalStats.ScopeBytesCovered.Value * 100.0) /
+                                 GlobalStats.ScopeBytes.Value)
+                          << "%\n");
   return true;
 }


        


More information about the llvm-commits mailing list