test(asm): x86_64 Linux syscall-write example (ir-only lock)

Adds examples/1651-platform-asm-x86-syscall-write.sx — the canonical
inline-asm use case: `write(2)` via a raw x86_64 `syscall` (SYS_write
in rax, fd/buf/count pinned to rdi/rsi/rdx, rcx+r11+memory clobbered,
byte count returned in rax). Exercises register-pinned inputs, a pinned
value output, a pointer input (*u8 -> rsi), and clobbers(.…) lowering
together.

x86-pinned via .build { "target": "x86_64-linux" }: ir-only on this
aarch64 host (the .ir snapshot locks the exact constraint string
`={rax},{rax},{rdi},{rsi},{rdx},~{rcx},~{r11},~{memory}` — the §II.11
silent-miscompile risk zone), runs natively on x86_64-linux printing
"ok\n" (hand-authored .stdout, asserted only in execute mode).

Pure additive test coverage — no compiler change (lock commit).
zig build test green (660 corpus, 446 unit).
This commit is contained in:
agra
2026-06-16 06:38:13 +03:00
parent 9e7661b915
commit cdd920b692
6 changed files with 59 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
// ASM stream — x86_64 Linux `write(2)` via a raw `syscall`. The canonical inline-
// asm use case: SYS_write (rax=1) with fd/buf/count pinned to rdi/rsi/rdx, the
// `syscall` instruction clobbering rcx + r11 (+ memory), and the byte count
// returned in rax. Demonstrates register-pinned inputs, a pinned value output,
// a pointer input (`*u8` → rsi), and `clobbers(.…)` lowering all at once.
//
// x86-pinned via `.build`: ir-only on a non-x86 host — the `.ir` snapshot locks
// the exact constraint string (`={rax},{rax},{rdi},{rsi},{rdx},~{rcx},~{r11},
// ~{memory}`), which is the §II.11 silent-miscompile risk zone — and runs
// natively on x86_64-linux (printing "ok\n"). See 1640 for an x86 multi-output
// example, 1645/1647/1649/1650 for aarch64 examples that execute on this host.
sys_write :: (fd: i64, buf: *u8, count: i64) -> i64 {
return asm volatile {
"syscall",
[ret] "={rax}" -> i64, // return: bytes written, in rax
"{rax}" = 1, // SYS_write (x86_64 Linux)
"{rdi}" = fd, // fd
"{rsi}" = buf, // buf
"{rdx}" = count, // count
clobbers(.rcx, .r11, .memory),
};
}
main :: () {
msg : [3]u8 = .[111, 107, 10]; // "ok\n"
n := sys_write(1, @msg[0], 3);
}

View File

@@ -0,0 +1 @@
{ "target": "x86_64-linux" }

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,28 @@
; Function Attrs: nounwind
define internal i64 @sys_write(i64 %0, ptr %1, i64 %2) #0 {
entry:
%alloca = alloca i64, align 8
store i64 %0, ptr %alloca, align 8
%allocaN = alloca ptr, align 8
store ptr %1, ptr %allocaN, align 8
%allocaN = alloca i64, align 8
store i64 %2, ptr %allocaN, align 8
%load = load i64, ptr %alloca, align 8
%loadN = load ptr, ptr %allocaN, align 8
%loadN = load i64, ptr %allocaN, align 8
%asm = call i64 asm sideeffect "syscall", "={rax},{rax},{rdi},{rsi},{rdx},~{rcx},~{r11},~{memory}"(i64 1, i64 %load, ptr %loadN, i64 %loadN)
ret i64 %asm
}
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%alloca = alloca [3 x i8], align 1
store [3 x i8] c"ok\0A", ptr %alloca, align 1
%igp.ptr = getelementptr i8, ptr %alloca, i64 0
%call = call i64 @sys_write(i64 1, ptr %igp.ptr, i64 3)
%allocaN = alloca i64, align 8
store i64 %call, ptr %allocaN, align 8
ret i32 0
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
ok