feat(asm): Phase C.1 + D — inline asm codegen (runs end-to-end)

lowerAsmExpr stops bailing and builds the inline_asm op: resolves each operand's
effective name (§II.5 — explicit [name] else the {reg} pin), interns
template/constraints/clobbers, lowers input Refs, derives the result TypeId
(0→void, 1→T). Adds the last deferred validation (every %[name] must name an
operand). Multi-output (N>1) bails with a named "Phase E" diagnostic.

emitInlineAsm (backend/llvm/ops.zig) ports Zig's airAssembly: assembles the LLVM
constraint string (outputs → inputs → ~{clobber}, ',' → '|'), rewrites the
template (%[name]→${N}, %%→%, $→$$, %=→${:uid}), then LLVMGetInlineAsm +
LLVMBuildCall2 (AT&T dialect). Dispatch wired in emit_llvm.zig (replacing the C.0
@panic tripwire).

inferType gains an .asm_expr arm (expr_typer.zig) so a bare `x := asm {…-> T}`
binding types correctly — without it the binding inferred .unresolved and
silently produced 0.

llvm_shim.c: LLVMInitializeNativeAsmParser() — the JIT must assemble inline asm
at run time.

Verified end-to-end on the aarch64 host: `mov`/`add` with register-class inputs
and a value output run (exit 42/99), `nop volatile` runs (exit 0). IR is
textbook: `call i64 asm "add ${0},${1},${2}", "=r,r,r"(…)`.

Locked with 1645 (aarch64 add, runs; ir-only on non-aarch64) + 1646 (:= binding).
Updated 1640 (now Phase-E bail) + 1642 (now runs).

zig build test green (654 corpus, 446 unit).
This commit is contained in:
agra
2026-06-15 21:39:54 +03:00
parent 6c08de8ec1
commit 5a5e04c6d5
23 changed files with 395 additions and 50 deletions

View File

@@ -1,4 +1,4 @@
error: inline assembly codegen is not yet implemented (ASM stream: lowering + emit land in Phases CE)
error: multi-output (tuple-returning) inline assembly is not yet implemented (ASM stream Phase E)
--> examples/1640-platform-asm-parse.sx:9:12
|
9 | return asm {

View File

@@ -1,5 +1 @@
error: inline assembly codegen is not yet implemented (ASM stream: lowering + emit land in Phases CE)
--> examples/1642-platform-asm-nop-volatile.sx:4:13
|
4 | nop :: () { asm volatile { "nop" }; }
| ^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -0,0 +1 @@
{ "target": "macos" }

View File

@@ -0,0 +1 @@
42

View File

@@ -0,0 +1,21 @@
; Function Attrs: nounwind
define internal i64 @add_asm(i64 %0, i64 %1) #0 {
entry:
%alloca = alloca i64, align 8
store i64 %0, ptr %alloca, align 8
%allocaN = alloca i64, align 8
store i64 %1, ptr %allocaN, align 8
%load = load i64, ptr %alloca, align 8
%loadN = load i64, ptr %allocaN, align 8
%asm = call i64 asm "add ${0}, ${1}, ${2}", "=r,r,r"(i64 %load, i64 %loadN)
ret i64 %asm
}
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%call = call i64 @add_asm(i64 40, i64 2)
%ca.tr = trunc i64 %call to i32
ret i32 %ca.tr
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
{ "target": "macos" }

View File

@@ -0,0 +1 @@
99

View File

@@ -0,0 +1,11 @@
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%asm = call i64 asm "mov ${0}, #99", "=r"()
%alloca = alloca i64, align 8
store i64 %asm, ptr %alloca, align 8
%load = load i64, ptr %alloca, align 8
%ca.tr = trunc i64 %load to i32
ret i32 %ca.tr
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@