feat(asm): Phase B.1 — operand-name validation (echo + duplicates)

Extends lowerAsmExpr with a pinnedRegister(constraint) helper and two §II.5
operand-naming checks, in the compile path before the codegen bail:

- reject the echo form `[eax] "={eax}"` — a label identical to the register its
  own constraint pins is redundant (the operand is already auto-named after the
  register); the useful form is a label that differs (`[quot] "={rax}"`);
- reject duplicate operand names (ambiguous %[name] / result field).

Locked with 1643-platform-asm-echo-name and 1644-platform-asm-duplicate-name.

zig build test green (652 corpus, 445 unit).
This commit is contained in:
agra
2026-06-15 20:41:41 +03:00
parent 1040b8c776
commit 5f444aae26
10 changed files with 86 additions and 15 deletions

View File

@@ -6,7 +6,17 @@ commit, one step at a time per the cadence rule (no commit may both add a test
and make it pass).
## Last completed step
**B.0** — asm shape validation (compile-path diagnostics). Restructured the
**B.1** — operand-name validation (design §II.5 auto-naming rule). Extended
`lowerAsmExpr` with a `pinnedRegister(constraint)` helper (`"={eax}"``eax`,
`"+{rax}"``rax`, `"=r"`→null) and two checks: (1) **reject the echo form**
`[eax] "={eax}"` — a label identical to its own pinned register is redundant
(the operand is already auto-named after the register); (2) **reject duplicate
operand names** (ambiguous `%[name]` / result field). Locked with
`examples/1643-platform-asm-echo-name.sx` + `1644-platform-asm-duplicate-name.sx`.
`zig build test` green (652 corpus, 0 failed; 445 unit). Files:
`src/ir/lower/expr.zig`.
Prior: **B.0** — asm shape validation (compile-path diagnostics). Restructured the
`.asm_expr` lowering arm into `lowerAsmExpr` (`src/ir/lower/expr.zig`, mixed into
`Lowering` in `src/ir/lower.zig`): it validates BEFORE the not-yet-implemented
codegen bail, so the user sees the real problem first. Two checklist items now
@@ -83,20 +93,19 @@ Phase BE feasibility already confirmed against the live tree
`extern`, 60 sites; `--target` a global CLI flag).
## Next step
**B.1 / C.0** — two viable directions:
- **B.1 (more validation, testable now):** remaining checklist items that fire
pre-codegen — echo-name rejection (`[eax] "={eax}"`, §II.5 auto-naming),
duplicate operand names, `%[name]` references that name no operand. Add to
`lowerAsmExpr` (same compile-path pattern). Each is a pinnable error example.
- **C.0 (IR op, unlocks the rest):** add `inline_asm: InlineAsm` to `Op`
(`src/ir/inst.zig`) + interp `bailDetail`; then `lowerAsmExpr` stops bailing
and builds the op, at which point **result-type derivation becomes observable**
(so the auto-naming rule + tuple result typing in `expr_typer.zig` can be
tested end-to-end). See `PLAN-ASM.md` Phase C + design §II.6.
**C.0** (Phase C — IR op) — add `inline_asm: InlineAsm` to `Op` (`src/ir/inst.zig`,
next to `objc_msg_send`) + the `AsmOperand` IR struct (role/name/constraint/operand
as `StringId`/`Ref`), and an interp `bailDetail` arm (`src/ir/interp.zig`) — inline
asm can never be comptime-evaluated. Unit-test the IR shape. This is a `lock`
commit (no behavior change yet — `lowerAsmExpr` keeps bailing). Then C.1 wires
`lowerAsmExpr` to actually intern strings + lower input `Ref`s + build the op and
compute the result `TypeId`, at which point **result-type derivation becomes
observable** and the auto-naming/tuple typing (`expr_typer.zig`, deferred from B)
can be tested end-to-end. See `PLAN-ASM.md` Phase C + design §II.6.
Recommended: finish the cheap B.1 validation diagnostics, then move to C.0.
(Result-type derivation in `expr_typer.zig` is intentionally deferred until C
makes it observable — see Current state.)
Remaining deferred validation (do alongside C, once template scanning is worth
it): `%[name]` references in the template that name no operand. Needs effective-
name resolution (explicit `[name]` auto-derived register names).
## Log
- (init) Plan + design doc written; ASM stream opened.
@@ -120,6 +129,9 @@ makes it observable — see Current state.)
no-output⇒volatile, with named diagnostics before the codegen bail. Locked with
1641 (volatile error) + 1642 (volatile accepted). `zig build test` green (650
corpus, 445 unit).
- (B.1) operand-name validation: `pinnedRegister` helper + reject echo form
(`[eax] "={eax}"`) and duplicate names. Locked with 1643 + 1644. `zig build
test` green (652 corpus, 445 unit).
## Known issues
- **0137** — `sx run` on a program with no `main` segfaults (unguarded JIT entry