feat(asm): Phase A.1 — parse asm { … } into AsmExpr; loud lowering bail
`asm volatile? { "tmpl", [name]? "constraint" (-> Type | = expr), …,
clobbers(.…) }` now parses into a flat-operand AsmExpr/AsmOperand (ast.zig +
parser.zig parseAsmExpr, dispatched from parsePrimary on .kw_asm). `volatile`
and `clobbers` are recognized contextually (not reserved). `-> @place`
write-through is rejected with a clear "Phase 2" parse error.
Codegen is not implemented yet (IR op + LLVM emit are Phases C–E), so lowering
bails LOUD + named via an explicit .asm_expr arm in lower/expr.zig (not the
generic unknown_expr else) — emitPlaceholder makes hasErrors() abort the build
on the message.
The new asm_expr tag forced (and got) arms in three exhaustive Node.Data
switches: sema.zig analyzeNode + findNodeAtOffset, semantic_diagnostics.zig
checkBindingNames — each recurses into template + operand payloads.
Design: adopted the operand auto-naming rule (design §II.5) — name auto-derived
from a {reg} pin, explicit [name] only when it differs or for register-class
operands, echo form rejected. Typing-stage rule; parser stores name: ?[]const u8.
Locked with examples/1640-platform-asm-parse.sx (multi-output divmod: named
operands, register pins, clobbers — parses then bails, called from main).
Also files issue 0137 (pre-existing, orthogonal: `sx run` with no `main`
segfaults via an unguarded JIT entry lookup in target.zig — not an asm bug).
zig build test green (648 corpus, 445 unit).
This commit is contained in:
@@ -549,6 +549,40 @@ Lexer/token: add `kw_asm` to the `Token.Tag` enum + keyword `StaticStringMap` in
|
||||
* Every `%[name]` referenced in the template must name an operand (best surfaced as
|
||||
a Sema diagnostic; also caught at codegen during the rewrite — §II.6).
|
||||
|
||||
### Operand naming rule (auto-name from a `{reg}` pin) — DECIDED
|
||||
|
||||
The `[name]` label on an operand is purely an sx-surface convenience: it provides
|
||||
the `%[name]` template alias and (for `out_value`) the result tuple's field name.
|
||||
LLVM never sees it (it sees positional `${N}` + the constraint). To kill the
|
||||
common redundancy where a label just echoes its pinned register
|
||||
(`[eax] "={eax}"`), the **operand name is derived as follows**, uniformly across
|
||||
every operand kind (`out_value` / `out_place` / read-write / `input`):
|
||||
|
||||
1. **Explicit `[name]` wins** — use it verbatim (the `%[name]` alias / field name).
|
||||
2. **Else, if the constraint pins a single register** — `"={eax}"`, `"{rdi}"`,
|
||||
`"+{rax}"`, i.e. a `{reg}` body (optionally with a `=`/`+` prefix) — the operand
|
||||
is **auto-named after that register** (`eax`, `rdi`, `rax`). Usable as
|
||||
`%[eax]` and as the tuple field name.
|
||||
3. **Else (register-class `=r`/`+r`/`r`, or memory `=m`, …)** — the operand has
|
||||
**no implicit name**. A `[name]` is then **required** if the template
|
||||
references it (`%[name]`) or, for `out_value`, if a named result field is
|
||||
wanted; otherwise it is anonymous (positional tuple field).
|
||||
|
||||
Corollaries:
|
||||
|
||||
* **Reject the echo form.** An explicit `[name]` that is identical to the
|
||||
register its own constraint pins (`[eax] "={eax}"`) carries no information —
|
||||
emit a diagnostic ("redundant operand name `eax` — it already names the pinned
|
||||
register; drop the `[eax]`"). The useful form is a label that *differs* from the
|
||||
register (`[quot] "={rax}"` → field `quot` over register `rax`).
|
||||
* **Result field names** (the §II.5 result-type rule above) come from each
|
||||
`out_value`'s *effective* name — explicit `[name]`, else the auto-derived
|
||||
register name; positional only when neither exists (a class-constrained output
|
||||
with no `[name]`).
|
||||
* This is a **typing-stage** rule: the parser still stores `name: ?[]const u8`
|
||||
(null when no `[name]` was written); Sema computes the effective name. No
|
||||
parser change.
|
||||
|
||||
Note: there is **no** "≤1 output" rule (that was Zig's limit; sx's tuples lift it).
|
||||
|
||||
## II.6 sx IR + LLVM codegen (the part that must match Zig bit-for-bit)
|
||||
|
||||
Reference in New Issue
Block a user