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:
20
examples/1640-platform-asm-parse.sx
Normal file
20
examples/1640-platform-asm-parse.sx
Normal file
@@ -0,0 +1,20 @@
|
||||
// ASM stream Phase A.1 — `asm { … }` PARSES into an AsmExpr: template, named
|
||||
// value outputs (`[quot] "={rax}" -> u64`), register-pinned inputs, and a
|
||||
// `clobbers(.…)` clause are all accepted with no parse error. Codegen is not
|
||||
// implemented yet (the IR op + LLVM emit land in Phases C–E), so lowering bails
|
||||
// LOUD + named. This example pins that intermediate diagnostic; a later phase
|
||||
// turns it into a running multi-return example. Called from `main` so lowering
|
||||
// actually reaches the asm body (lazy lowering skips uncalled functions).
|
||||
divmod :: (n: u64, d: u64) -> (quot: u64, rem: u64) {
|
||||
return asm {
|
||||
"divq %[d]",
|
||||
[quot] "={rax}" -> u64,
|
||||
[rem] "={rdx}" -> u64,
|
||||
"{rax}" = n, "{rdx}" = 0, [d] "r" = d,
|
||||
clobbers(.cc),
|
||||
};
|
||||
}
|
||||
|
||||
main :: () {
|
||||
q, r := divmod(17, 5);
|
||||
}
|
||||
1
examples/expected/1640-platform-asm-parse.exit
Normal file
1
examples/expected/1640-platform-asm-parse.exit
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
17
examples/expected/1640-platform-asm-parse.stderr
Normal file
17
examples/expected/1640-platform-asm-parse.stderr
Normal file
@@ -0,0 +1,17 @@
|
||||
error: inline assembly codegen is not yet implemented (ASM stream: lowering + emit land in Phases C–E)
|
||||
--> examples/1640-platform-asm-parse.sx:9:12
|
||||
|
|
||||
9 | return asm {
|
||||
| ^^^^^
|
||||
10 | "divq %[d]",
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
11 | [quot] "={rax}" -> u64,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
12 | [rem] "={rdx}" -> u64,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
13 | "{rax}" = n, "{rdx}" = 0, [d] "r" = d,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
14 | clobbers(.cc),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
15 | };
|
||||
| ^^^^^
|
||||
1
examples/expected/1640-platform-asm-parse.stdout
Normal file
1
examples/expected/1640-platform-asm-parse.stdout
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user