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: tools/llvm-dwarfdump/Statistics.cpp =================================================================== --- tools/llvm-dwarfdump/Statistics.cpp +++ tools/llvm-dwarfdump/Statistics.cpp @@ -146,6 +146,40 @@ return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0); } +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 a variable is outside a 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 +210,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 +223,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 +290,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 +334,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 +378,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 +414,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 +450,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 +468,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,7 +523,7 @@ 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