feat(asm): Phase B.0 — validate asm shape in the compile path

Restructures the .asm_expr lowering arm into lowerAsmExpr, which validates the
asm shape with specific named diagnostics BEFORE the not-yet-implemented codegen
bail, so the user sees the real problem first. Two checklist items enforced:

- template must be a compile-time-known string ("..." or #string), not a
  runtime expression;
- an asm with no value outputs must be `volatile` (else its effects could be
  deleted) — mirrors Zig's rule.

Valid shapes still bail with the "codegen not yet implemented" message. Result-
type derivation + the operand auto-naming rule stay deferred to Phase C, where a
real IR op makes the result type observable/testable.

Locked with 1641-platform-asm-missing-volatile (the volatile error) and
1642-platform-asm-nop-volatile (no-output + volatile accepted → codegen bail).

zig build test green (650 corpus, 445 unit).
This commit is contained in:
agra
2026-06-15 20:35:43 +03:00
parent f8e029d719
commit 1040b8c776
11 changed files with 97 additions and 19 deletions

View File

@@ -6,7 +6,21 @@ commit, one step at a time per the cadence rule (no commit may both add a test
and make it pass).
## Last completed step
**A.1** — parse `asm { … }` + loud lowering bail (folded A.1+A.2 into one honest
**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
enforced with named diagnostics: (1) **template must be a compile-time-known
string** (`"..."` / `#string`); (2) **no value outputs ⇒ must be `volatile`**
(mirrors Zig — a result-less asm could be deleted). Valid shapes still bail with
the "codegen not yet implemented" message. Result-type derivation + auto-naming
stay deferred to a later step (observable only once Phase C produces a real IR
op). Locked with `examples/1641-platform-asm-missing-volatile.sx` (volatile
error) + `1642-platform-asm-nop-volatile.sx` (volatile no-output accepted →
codegen bail). `zig build test` green (650 corpus, 0 failed; 445 unit). Files:
`src/ir/lower/expr.zig`, `src/ir/lower.zig`, `examples/164{1,2}-*`.
Prior: **A.1** — parse `asm { … }` + loud lowering bail (folded A.1+A.2 into one honest
lock commit, since the loud bail IS current correct behavior — cadence option
(a)). Added `AsmExpr`/`AsmOperand` to `src/ast.zig` + the `asm_expr` `Node.Data`
arm; `parseAsmExpr` in `src/parser.zig` (`parsePrimary` `.kw_asm` dispatch) —
@@ -69,14 +83,20 @@ Phase BE feasibility already confirmed against the live tree
`extern`, 60 sites; `--target` a global CLI flag).
## Next step
**B.0/B.1** (Phase B — sema/typing) — derive the asm result type from the
`out_value` operands (0→`void` + require `volatile`; 1→`T`; N→tuple, named via the
§II.5 auto-naming rule), in the expression typer (`src/ir/expr_typer.zig` /
`inferExprType`). Implement the validation checklist (no-output⇒volatile; layout;
comptime-string template; coerce comptime int→i64/float→f64) + the auto-naming /
echo-rejection diagnostics. On failure return the `.unresolved` sentinel, never a
silent default. Pin error-message examples. See `PLAN-ASM.md` Phase B + design
§II.5. (Lowering keeps bailing until Phase C adds the IR op.)
**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.
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.)
## Log
- (init) Plan + design doc written; ASM stream opened.
@@ -96,6 +116,10 @@ silent default. Pin error-message examples. See `PLAN-ASM.md` Phase B + design
exhaustive `Node.Data` switches; `-> @place` rejected (Phase 2). Adopted operand
auto-naming rule (design §II.5). Locked with 1640 fixture. Filed orthogonal
issue 0137 (no-`main` JIT segfault). `zig build test` green (648 corpus, 445 unit).
- (B.0) asm shape validation in `lowerAsmExpr`: comptime-string template +
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).
## Known issues
- **0137** — `sx run` on a program with no `main` segfaults (unguarded JIT entry