[all-commits] [llvm/llvm-project] 6dc547: [BOLT] Fix shifted DWARF inline-scope ranges; trac...

Rafael Auler via All-commits all-commits at lists.llvm.org
Tue Jul 14 16:40:27 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 6dc5473fa6846830134f3ffe2257113382200391
      https://github.com/llvm/llvm-project/commit/6dc5473fa6846830134f3ffe2257113382200391
  Author: Rafael Auler <rafaelauler at meta.com>
  Date:   2026-07-14 (Tue, 14 Jul 2026)

  Changed paths:
    M bolt/include/bolt/Core/BinaryContext.h
    M bolt/include/bolt/Core/BinaryFunction.h
    M bolt/lib/Core/BinaryContext.cpp
    M bolt/lib/Core/BinaryEmitter.cpp
    M bolt/lib/Core/BinaryFunction.cpp
    M bolt/lib/Rewrite/RewriteInstance.cpp
    A bolt/test/X86/dwarf-inline-range-plt-shift.s

  Log Message:
  -----------
  [BOLT] Fix shifted DWARF inline-scope ranges; track scope boundaries (#207291)

Summary:
BOLT updated DWARF lexical-scope ranges (DW_TAG_inlined_subroutine /
lexical_block low_pc/high_pc and DW_AT_ranges) via
translateInputToOutputRange(), which mapped a boundary using its input
offset relative to the start of the containing basic block:

OutAddr = BB.getOutputAddressRange().first + (InputOffset -
BB.getOffset())

This assumes intra-block byte offsets are preserved input->output. Any
pass that changes instruction sizes within a block ahead of a scope
boundary breaks that assumption. With --plt=all, each `call foo at PLT` (5
bytes, e8+rel32) is rewritten to `call *foo at GOT(%rip)` (6 bytes, ff
15+rel32); N such calls before a boundary shift its emitted low_pc/
high_pc N bytes too early, onto the preceding instruction. The range
stays within the parent so `llvm-dwarfdump --verify` does not catch it;
symbolizers then attribute samples on those instructions to the wrong
inlined frames.

Fix is to resolve scope-range boundaries through the precise
per-instruction input-to-output AddressMap (the same map BAT already
uses) instead of input-relative block offsets. Boundary instructions are
arbitrary (not just calls/branches), so they are normally absent from
that map; to make them resolvable, disassembly now keeps an offset for
the boundary instructions (only the boundaries, to keep the AddressMap
small) and those offsets are emitted as AddressMap entries whenever an
address map is required (requiresAddressMap(), which includes
--update-debug-sections via requiresPreciseAddressMap()), not only under
BAT.

Boundary collection (BinaryContext::collectDebugScopeBoundaries) runs in
readDebugInfo() after preprocessDebugInfo(). It streams the DIEs of the
CUs that will be updated directly from the already-loaded DWARFContext
with DWARFDebugInfoEntry::extractFast, decoding one DIE at a time into a
single reusable entry, so no DIE forest is materialized and no second
DWARF context is created. For split DWARF the .dwo DIEs are already
extracted by preprocessDWODebugInfo(), so the cached array is reused
instead. Boundaries are stored per function in a sorted, deduplicated
vector (BinaryFunction::DebugScopeBoundaryOffsets), queried during
disassembly with a monotonic cursor, and freed once the function is
disassembled, so the feature adds no global state.

The behavior is on by default and can be disabled with
--accurate-debug-ranges=0, which falls back to the old block-relative
mapping.

Test on big binaries with split dwarf, -lite=0:
                                wall                Max RSS
      -accurate-debug-ranges=0  1070.1s             94.91
      -accurate-debug-ranges=1  1173.0s             100.07
      delta                     +102.9s             +5.16   (+4.6% CPU,
                                                             +5.4% RSS)

Test on big binaries with split dwarf, lite=1:
      -accurate-debug-ranges=0  433.9s              83.23
      -accurate-debug-ranges=1  434.7s              83.79   (+0.7% RSS)

    --time-rewrite shows the boundary-collection phase itself is cheap:
    "read debug ranges" is 5.8s of 4960s total user time on one binary
    (0.1%) and 18.8s of 6307s on another binary; the feature's
cost is dominated by emitting/translating the extra AddressMap entries,
    not by collection.



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list