Index: test/tools/llvm-dwarfdump/X86/locstats.ll =================================================================== --- test/tools/llvm-dwarfdump/X86/locstats.ll +++ test/tools/llvm-dwarfdump/X86/locstats.ll @@ -15,10 +15,10 @@ ; CHECK: "variables with 20-29% of its scope covered":0 ; CHECK: "variables with 30-39% of its scope covered":0 ; CHECK: "variables with 40-49% of its scope covered":0 -; CHECK: "variables with 50-59% of its scope covered":1 +; CHECK: "variables with 50-59% of its scope covered":0 ; CHECK: "variables with 60-69% of its scope covered":0 ; CHECK: "variables with 70-79% of its scope covered":0 -; CHECK: "variables with 80-89% of its scope covered":1 +; CHECK: "variables with 80-89% of its scope covered":2 ; CHECK: "variables with 90-99% of its scope covered":0 ; CHECK: "variables with 100% of its scope covered":3 ; CHECK: "variables (excluding the debug entry values) with 0% of its scope covered":1 @@ -27,10 +27,10 @@ ; CHECK: "variables (excluding the debug entry values) with 20-29% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 30-39% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 40-49% of its scope covered":0 -; CHECK: "variables (excluding the debug entry values) with 50-59% of its scope covered":2 +; CHECK: "variables (excluding the debug entry values) with 50-59% of its scope covered":1 ; CHECK: "variables (excluding the debug entry values) with 60-69% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 70-79% of its scope covered":0 -; CHECK: "variables (excluding the debug entry values) with 80-89% of its scope covered":1 +; CHECK: "variables (excluding the debug entry values) with 80-89% of its scope covered":2 ; CHECK: "variables (excluding the debug entry values) with 90-99% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 100% of its scope covered":2 ; CHECK: "total params procesed by location statistics":2 @@ -65,10 +65,10 @@ ; CHECK: "vars with 20-29% of its scope covered":0 ; CHECK: "vars with 30-39% of its scope covered":0 ; CHECK: "vars with 40-49% of its scope covered":0 -; CHECK: "vars with 50-59% of its scope covered":1 +; CHECK: "vars with 50-59% of its scope covered":0 ; CHECK: "vars with 60-69% of its scope covered":0 ; CHECK: "vars with 70-79% of its scope covered":0 -; CHECK: "vars with 80-89% of its scope covered":1 +; CHECK: "vars with 80-89% of its scope covered":2 ; CHECK: "vars with 90-99% of its scope covered":0 ; CHECK: "vars with 100% of its scope covered":1 ; CHECK: "vars (excluding the debug entry values) with 0% of its scope covered":1 @@ -77,10 +77,10 @@ ; CHECK: "vars (excluding the debug entry values) with 20-29% of its scope covered":0 ; CHECK: "vars (excluding the debug entry values) with 30-39% of its scope covered":0 ; CHECK: "vars (excluding the debug entry values) with 40-49% of its scope covered":0 -; CHECK: "vars (excluding the debug entry values) with 50-59% of its scope covered":1 +; CHECK: "vars (excluding the debug entry values) with 50-59% of its scope covered":0 ; CHECK: "vars (excluding the debug entry values) with 60-69% of its scope covered":0 ; CHECK: "vars (excluding the debug entry values) with 70-79% of its scope covered":0 -; CHECK: "vars (excluding the debug entry values) with 80-89% of its scope covered":1 +; CHECK: "vars (excluding the debug entry values) with 80-89% of its scope covered":2 ; CHECK: "vars (excluding the debug entry values) with 90-99% of its scope covered":0 ; CHECK: "vars (excluding the debug entry values) with 100% of its scope covered":1 ; Index: test/tools/llvm-dwarfdump/X86/statistics-dwo.test =================================================================== --- test/tools/llvm-dwarfdump/X86/statistics-dwo.test +++ test/tools/llvm-dwarfdump/X86/statistics-dwo.test @@ -1,5 +1,5 @@ # Test of the llmv-dwarfdump --statistics with split dwarf (dwo files) -# (version 3). +# (version >= 3). # # Create a directory in which to put all files, so .o file can find .dwo file. RUN: rm -rf %t && mkdir -p %t @@ -69,7 +69,7 @@ # } # -CHECK: "version":3 +CHECK: "version":4 CHECK: "source functions":3 CHECK: "source functions with location":3 CHECK: "inlined functions":7 Index: test/tools/llvm-dwarfdump/X86/statistics-v3.test =================================================================== --- test/tools/llvm-dwarfdump/X86/statistics-v3.test +++ test/tools/llvm-dwarfdump/X86/statistics-v3.test @@ -1,4 +1,4 @@ -# Test of the llmv-dwarfdump --statistics newly added stats (version 3). +# Test of the llmv-dwarfdump --statistics newly added stats (version >= 3). # RUN: llvm-mc -triple x86_64-unknown-linux-gnu %S/Inputs/statistics-fib.s -filetype=obj -o %t-statistics-fib.o RUN: llvm-dwarfdump --statistics %t-statistics-fib.o | FileCheck %s @@ -64,7 +64,7 @@ # } # -CHECK: "version":3 +CHECK: "version":4 CHECK: "source functions":3 CHECK: "source functions with location":3 CHECK: "inlined functions":8 Index: test/tools/llvm-dwarfdump/X86/statistics.ll =================================================================== --- test/tools/llvm-dwarfdump/X86/statistics.ll +++ 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":3 +; CHECK: "version":4 ; int GlobalConst = 42; ; int Global; Index: test/tools/llvm-locstats/locstats.ll =================================================================== --- test/tools/llvm-locstats/locstats.ll +++ test/tools/llvm-locstats/locstats.ll @@ -7,15 +7,15 @@ ; LOCSTATS: 0% 0 0% ; LOCSTATS: 1-9% 0 0% ; LOCSTATS: 10-19% 0 0% -; LOCSTATS: 20-29% 1 11% +; LOCSTATS: 20-29% 0 0% ; LOCSTATS: 30-39% 0 0% ; LOCSTATS: 40-49% 1 11% ; LOCSTATS: 50-59% 1 11% -; LOCSTATS: 60-69% 1 11% +; LOCSTATS: 60-69% 0 0% ; LOCSTATS: 70-79% 0 0% -; LOCSTATS: 80-89% 2 22% -; LOCSTATS: 90-99% 1 11% -; LOCSTATS: 100% 2 22% +; LOCSTATS: 80-89% 1 11% +; LOCSTATS: 90-99% 2 22% +; LOCSTATS: 100% 4 44% ; ; The source code of the test case: ;extern int fn2 (int); Index: tools/llvm-dwarfdump/Statistics.cpp =================================================================== --- tools/llvm-dwarfdump/Statistics.cpp +++ tools/llvm-dwarfdump/Statistics.cpp @@ -146,6 +146,43 @@ return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0); } +/// Adjust the size of a scope \BytesInScope to closely match a +/// variable's lexical scope assuming the latter starts at the +/// variable's first definition address \FirstDef. +static uint64_t adjustScopeToFirstDef(uint64_t BytesInScope, uint64_t FirstDef, + const DWARFDie &ScopeDie, + uint64_t UnitLowPC) { + // Ranges sometimes start before the lexical scope. + uint64_t ScopeLowPC = getLowPC(ScopeDie); + if (UnitLowPC + FirstDef <= ScopeLowPC) + return BytesInScope; + + uint64_t OffsetToFirstDefinition = 0; + DWARFAddressRangesVector ScopeRanges; + auto ScopeRangesOrError = ScopeDie.getAddressRanges(); + if (ScopeRangesOrError) + ScopeRanges = ScopeRangesOrError.get(); + else + llvm::consumeError(ScopeRangesOrError.takeError()); + + if (ScopeRanges.size() > 0) { + for (const auto &R : ScopeRanges) { + if (UnitLowPC + FirstDef < R.HighPC) { + OffsetToFirstDefinition += UnitLowPC + FirstDef - R.LowPC; + break; + } + OffsetToFirstDefinition += R.HighPC - R.LowPC; + } + } else { + OffsetToFirstDefinition = UnitLowPC + FirstDef - ScopeLowPC; + } + // If ranges are outside the lexical scope, count that as a failure. + if (OffsetToFirstDefinition >= BytesInScope) + OffsetToFirstDefinition = 0; + + return BytesInScope - OffsetToFirstDefinition; +} + /// Collect debug location statistics for one DIE. static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, std::vector &VarParamLocStats, @@ -176,9 +213,10 @@ } /// Collect debug info quality metrics for one DIE. -static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, - std::string VarPrefix, uint64_t ScopeLowPC, - uint64_t BytesInScope, uint32_t InlineDepth, +static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, + std::string FnPrefix, std::string VarPrefix, + const DWARFDie &ScopeDie, uint64_t BytesInScope, + uint32_t InlineDepth, StringMap &FnStatMap, GlobalStats &GlobalStats, LocationStats &LocStats) { @@ -188,7 +226,6 @@ bool IsArtificial = false; uint64_t BytesCovered = 0; uint64_t BytesEntryValuesCovered = 0; - uint64_t OffsetToFirstDefinition = 0; auto &FnStats = FnStatMap[FnPrefix]; bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; @@ -256,15 +293,12 @@ if (IsEntryValue(Entry.Loc)) BytesEntryValuesCovered += BytesEntryCovered; } - if (List->Entries.size()) { + // Adjust for the fact the variables often start their lifetime in + // the middle of the scope. + if (IsLocalVar && List->Entries.size()) { uint64_t FirstDef = List->Entries[0].Begin; - uint64_t UnitOfs = UnitLowPC; - // Ranges sometimes start before the lexical scope. - if (UnitOfs + FirstDef >= ScopeLowPC) - OffsetToFirstDefinition = UnitOfs + FirstDef - ScopeLowPC; - // Or even after it. Count that as a failure. - if (OffsetToFirstDefinition > BytesInScope) - OffsetToFirstDefinition = 0; + BytesInScope = adjustScopeToFirstDef(BytesInScope, FirstDef, + ScopeDie, UnitLowPC); } } assert(BytesInScope); @@ -303,9 +337,6 @@ FnStats.VarsInFunction.insert(VarPrefix + VarName); if (BytesInScope) { FnStats.TotalVarWithLoc += (unsigned)HasLoc; - // Adjust for the fact the variables often start their lifetime in the - // middle of the scope. - BytesInScope -= OffsetToFirstDefinition; // Turns out we have a lot of ranges that extend past the lexical scope. GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope; @@ -350,7 +381,7 @@ /// Recursively collect debug info quality metrics. static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, - std::string VarPrefix, uint64_t ScopeLowPC, + std::string VarPrefix, DWARFDie &ScopeDie, uint64_t BytesInScope, uint32_t InlineDepth, StringMap &FnStatMap, GlobalStats &GlobalStats, @@ -386,7 +417,7 @@ uint64_t BytesInThisScope = 0; for (auto Range : Ranges) BytesInThisScope += Range.HighPC - Range.LowPC; - ScopeLowPC = getLowPC(Die); + ScopeDie = Die; // Count the function. if (!IsBlock) { @@ -422,7 +453,7 @@ } } else { // Not a scope, visit the Die itself. It could be a variable. - collectStatsForDie(Die, UnitLowPC, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope, + collectStatsForDie(Die, UnitLowPC, FnPrefix, VarPrefix, ScopeDie, BytesInScope, InlineDepth, FnStatMap, GlobalStats, LocStats); } @@ -440,7 +471,7 @@ if (Child.getTag() == dwarf::DW_TAG_lexical_block) ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; - collectStatsRecursive(Child, UnitLowPC, FnPrefix, ChildVarPrefix, ScopeLowPC, + collectStatsRecursive(Child, UnitLowPC, FnPrefix, ChildVarPrefix, ScopeDie, BytesInScope, InlineDepth, FnStatMap, GlobalStats, LocStats); Child = Child.getSibling(); @@ -495,13 +526,13 @@ StringMap Statistics; for (const auto &CU : static_cast(&DICtx)->compile_units()) if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) - collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", 0, 0, 0, + collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", CUDie, 0, 0, Statistics, GlobalStats, LocStats); /// 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 = 3; + unsigned Version = 4; unsigned VarParamTotal = 0; unsigned VarParamUnique = 0; unsigned VarParamWithLoc = 0;