docs(debugger): point DWARF/Frame wiring at backend/llvm helpers (A9.2)

Refresh the debugging architecture reference for the A7.2 relocation:
DWARF emission lives in src/backend/llvm/debug.zig (DebugInfo) and the
interned Frame / tag-name tables in src/backend/llvm/reflection.zig
(Reflection); emit_llvm.zig is the orchestrator that owns LLVMEmitter and
dispatches to them. Behavior is unchanged; only the file-and-function map,
the 'what's emitted' home, and the debugEnabled() owner are corrected.
This commit is contained in:
agra
2026-06-03 13:52:38 +03:00
parent d319cef367
commit badf2af298

View File

@@ -105,10 +105,12 @@ niladic, span-stamped IR op** — the same pattern as `is_comptime` /
`interp_print_frames`. It carries **no operands and no global reference**;
each backend derives the frame from its own context:
- **`emit_llvm`:** resolves the op's `span` + current function →
`{file, line, col, func}` (reusing the source map wired in for DWARF),
**interns and builds the `Frame` global in `emit_llvm`** (the same
mechanism as the tag-name table), then emits `call sx_trace_push(ptr)`.
- **`emit_llvm` (the `.trace_frame` arm):** resolves the op's `span` +
current function → `{file, line, col, func}` (reusing the source map
wired in for DWARF), **interns and builds the `Frame` global** in
[`src/backend/llvm/reflection.zig`](../src/backend/llvm/reflection.zig)
(the same mechanism, in the same file, as the tag-name table), then emits
`call sx_trace_push(ptr)`.
- **`interp`:** pushes the packed `(func_id, ir_offset)` from its own
execution context.
@@ -118,8 +120,9 @@ alternative — an op carrying a `GlobalId` to an IR-level `Frame` global —
would make the global visible to the interpreter (forcing comptime onto
the pointer-deref path) and fatten the lowerer; **do not do this.**
`Frame` is defined **once** in sx (`trace.sx`/std); `emit_llvm` builds the
interned global off that `TypeId` through the normal struct-emission path,
`Frame` is defined **once** in sx (`trace.sx`/std); the reflection builder
(`src/backend/llvm/reflection.zig`) builds the interned global off that
`TypeId` through the normal struct-emission path,
never a bespoke byte layout (which would risk the "8-bytes-assumed"
clobber class of bug). `file`/`func` strings are interned into a shared
pool so a path shared by N push sites is stored once — the table stays
@@ -193,8 +196,9 @@ stripped without affecting traces.
### What's emitted
In [`src/ir/emit_llvm.zig`](../src/ir/emit_llvm.zig), gated on the same
debug opt levels + a wired source map (`setDebugContext`):
In [`src/backend/llvm/debug.zig`](../src/backend/llvm/debug.zig) (the
`DebugInfo` helper, driven from `emit_llvm`'s `emit()` pipeline), gated on
the same debug opt levels + a wired source map (`setDebugContext`):
- one `DICompileUnit` + `DIFile` on the main file,
- a `DISubprogram` per emitted function (`LLVMSetSubprogram`),
@@ -237,7 +241,9 @@ both the trace path and the DWARF path. Items marked ✅ exist today;
|---|---|
| [`src/core.zig`](../src/core.zig) | `Compilation`: owns `import_sources` (file→source map), constructs the emitter, calls `setDebugContext` + `emit`; re-enters the interpreter for `#run`/post-link |
| [`src/ir/lower.zig`](../src/ir/lower.zig) | AST→IR. Stamps `Inst.span`; emits push/clear at failure/absorb sites; `tracesEnabled` gate; declares the `sx_trace_*` externs |
| [`src/ir/emit_llvm.zig`](../src/ir/emit_llvm.zig) | IR→LLVM. Builds the interned `Frame` table; lowers the push op to a pointer push; emits all DWARF metadata |
| [`src/ir/emit_llvm.zig`](../src/ir/emit_llvm.zig) | IR→LLVM orchestrator. Owns `LLVMEmitter` + the source map (`setDebugContext`); dispatches the push op and the DWARF passes to the helpers below |
| [`src/backend/llvm/reflection.zig`](../src/backend/llvm/reflection.zig) | `Reflection`: builds the interned `Frame` table + the tag-name / type-name tables; lowers the push op to a pointer push |
| [`src/backend/llvm/debug.zig`](../src/backend/llvm/debug.zig) | `DebugInfo`: builds all DWARF metadata (compile unit, per-function subprograms, per-instruction `DILocation`) |
| [`src/ir/interp.zig`](../src/ir/interp.zig) | Comptime IR interpreter. Lowers the push op to a packed `(func_id, offset)`; resolves comptime frames |
| [`src/errors.zig`](../src/errors.zig) | `SourceLoc.compute(source, offset) → {line, col}`; the `import_sources` map type |
| [`src/ir/inst.zig`](../src/ir/inst.zig) | `Inst.span`, `Function.source_file`, the `Op` union (home of the trace-push op) |
@@ -330,8 +336,8 @@ the failable-`main` wrapper, whose `ret` path in `emit_llvm`
### The gate: one switch, two consumers
`Lowering.tracesEnabled()` (lower.zig) and `LLVMEmitter.debugEnabled()`
(emit_llvm) both reduce to `opt_level == .none or .less`. The `Frame`
`Lowering.tracesEnabled()` (lower.zig) and `DebugInfo.debugEnabled()`
(backend/llvm/debug.zig) both reduce to `opt_level == .none or .less`. The `Frame`
table + push/clear ride `tracesEnabled`; DWARF rides `debugEnabled`.
Release (`-O2`/`-O3`) emits neither. `sx run` defaults to `-O0` (both on);
`sx ir`/`sx asm` default to `-O2` (both off) — which is why the `.ir`