Skip to content

refactor(delib-1b): wasi path-based ops use Linux direct syscalls#48

Merged
chaploud merged 1 commit intomainfrom
develop/delib-phase1b
Apr 24, 2026
Merged

refactor(delib-1b): wasi path-based ops use Linux direct syscalls#48
chaploud merged 1 commit intomainfrom
develop/delib-phase1b

Conversation

@chaploud
Copy link
Copy Markdown
Contributor

Summary

Second step of the W46 un-link-libc migration, building on #47.

  • Add pfdMkdirAt, pfdUnlinkAt, pfdRenameAt, pfdReadlinkAt, pfdDup to src/platform.zig. Each uses std.os.linux.* direct syscalls on Linux, std.c.* on Mac/BSD, returns -1 on Windows (never reached — callers already branch to std.Io.Dir first).
  • Update src/wasi.zig path-based ops: path_create_directory, path_remove_directory, path_unlink_file, path_rename, path_readlink, fd_renumber.
  • Inline switch (comptime builtin.os.tag) for fd_filestat_set_times — Linux uses utimensat(fd, null, &times, 0) which is equivalent to futimens(fd, &times).

Behavior unchanged: existing cErrnoToWasi callers still work because the Linux branch mirrors the syscall errno into std.c._errno().* before returning.

Still not ready to flip link_libc = false

Remaining std.c.* references that will block un-linking:

  • src/platform.zig:331,352std.c.getenv(...) (app-cache dir / env lookup)
  • src/trace.zig:71std.c.write(stderr_fd, ...) (should be platform.pfdWrite)
  • src/wasi.zig:525std.c._errno().* in cErrnoToWasi (need an alt errno source)
  • src/wasi.zig path_filestat_set_times already uses std.c.utimensat on non-Linux (OK for Mac)

Those are W46 Phase 1c-1e, intentionally out of scope here.

Test plan

  • zig build test (Mac aarch64) — all pass.
  • zig build -Dtarget=x86_64-linux-gnu — clean.
  • zig build -Dtarget=x86_64-windows-gnu — clean.
  • bash test/realworld/run_compat.sh (Mac ReleaseSafe) — PASS: 50 / FAIL: 0.
  • Full CI — Mac + Ubuntu + Windows green (46/46 real-world compat on Windows).

Tracks: W46 in .dev/checklist.md.

Second step of the W46 un-link-libc migration. Add `pfdMkdirAt`,
`pfdUnlinkAt`, `pfdRenameAt`, `pfdReadlinkAt`, `pfdDup` to
`src/platform.zig`, each using `std.os.linux.*` direct syscalls on
Linux and `std.c.*` on Mac/BSD. `.windows` arms return -1 so the
helpers compile on Windows; they are never reached at runtime
(every caller already branches to `std.Io.Dir.{createDir,
deleteFile, deleteDir, rename, readLink}` before this point).

Update `src/wasi.zig` callers in:

- path_create_directory (mkdirat)
- path_remove_directory (unlinkat + AT_REMOVEDIR)
- path_unlink_file (unlinkat + 0)
- path_rename (renameat)
- path_readlink (readlinkat)
- fd_renumber (dup)

And inline a `switch (comptime builtin.os.tag)` for
`fd_filestat_set_times`, calling `linux.utimensat(fd, null, &times, 0)`
(equivalent to `futimens(fd, &times)`) on Linux and `std.c.futimens`
elsewhere.

Behavior unchanged: existing `cErrnoToWasi` callers keep working
because the Linux branch mirrors the syscall errno into
`std.c._errno().*` before returning.

Verified:
- `zig build test` (Mac aarch64) — all pass.
- `zig build -Dtarget=x86_64-linux-gnu` — clean.
- `zig build -Dtarget=x86_64-windows-gnu` — clean.
- `bash test/realworld/run_compat.sh` (Mac) — PASS: 50 / FAIL: 0.
@chaploud chaploud merged commit fbaf926 into main Apr 24, 2026
5 checks passed
@chaploud chaploud deleted the develop/delib-phase1b branch April 30, 2026 15:15
chaploud added a commit that referenced this pull request May 9, 2026
Lands `qLoadSpilled` / `qDefSpilled` / `qStoreSpilled` in
`src/engine/codegen/arm64/gpr.zig`. Q-form (16-byte) analog of
the existing D-form (8-byte) `fp*Spilled` trio.

Key properties:
- Uses the same `abi.fp_spill_stage_vregs` (V29/V30) staging
  registers as the D-form fp* helpers — Q view of the same
  V registers, so no new ABI reservation needed.
- Encoders: `inst_neon.encLdrQImm` / `encStrQImm` with SP=31
  base register. SP-relative addressing works identically to
  the D-form path; the only difference is 16-byte stride
  (Q-form imm12 × 16) vs 8-byte (D-form imm12 × 8).
- Alignment check: rejects abs_off > 65520 (= 4095 × 16, the
  imm12 cap) and abs_off & 0xF != 0 (16-byte alignment).
- Graceful spill-overflow surface — diagnostic stderr line
  matching the existing fp* helpers.

Caller-responsibility note: `Allocation.slot(vreg, .fpr)` uses
an 8-byte spill-stride formula `(slot_id - max_reg_slots_gpr) *
8`. For 16-byte-aligned v128 spills the caller must lay slots
at even-pair indices — slots 14, 16, 18, 20 produce offsets
48, 64, 80, 96 (all 16-byte aligned). Odd slot_ids fail the
helper's alignment check. The 9.5-c-ii caller migration
(lifting op_simd's SPILL-EXEMPT degradation) handles even-pair
discipline at v128 spill-slot allocation.

Per ADR-0041 §"Negative" / "Conservative spill-frame size":
the conservative per-vreg-pays-its-stride packing means
mixed-shape spill frames may have idle bytes; tighter packing
defers to Phase 15 alongside the class-aware allocator
(ADR-0038).

6 unit tests:
- qLoadSpilled in-V-reg (no bytes emitted)
- qLoadSpilled spilled (slot 14 → off 48 → LDR Q29, [SP, #48])
- qLoadSpilled rejects 8-byte-aligned-only offset
- qDefSpilled in-V-reg returns the V-reg
- qDefSpilled spilled returns stage V29/V30
- qStoreSpilled in-V-reg no-op
- qStoreSpilled spilled (slot 14, base 16 → STR Q29, [SP, #64])

Mac gates: zone ✓, file_size ✓, spill ✓, lint ✓, test 1205/0/12
(was 1199; +6 q* helper tests).

Refs: ADR-0041 §"Decision" / 2 (FP-class register pool reuse
with shape-tag axis), ADR-0027 (callee-saved pool) + D-037
(V29/V30 fp_spill_stage_vregs source), `single_slot_dual_
meaning.md` (§14 enforcement preserved — slot id remains the
single semantic axis; shape lives on a separate axis).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant