Files
wasm2go/testdata/f16_init_loop.wat
8b87a233f0 Auto-detect runtime-built f16 tables; fail the build on stale asserts (#53)
* codegen: auto-detect runtime-built f16 tables; fail on stale asserts

The f16->f32 table's address had to be asserted from outside
(-f16-table): ggml-style engines build the table at runtime, so the
static byte-check cannot see it. That external magic number proved a
liability twice over — the address moves with any layout shift
(source changes, even build-cache state), a stale value silently
disables every table-keyed rewrite (the llama-wasm v0.2.1 release
shipped ~35% slower decode this way), and the existing staleness
warning never ran for multi-package modules because that layout
returns before the check.

Derive the address from the module's own initialization code instead:
an init loop that streams constant-strided stores from a constant
base and provably covers the table's whole 256KiB range. Detection is
structural over the lowered SSA — a loop-carried pointer phi with
constant start and advance, a counter phi with a computable trip
count, stores through the pointer — so it does not depend on how the
compiler vectorized the conversion arithmetic inside the loop. The
scan runs lazily on the first gather-site query.

-f16-table remains as an explicit override, now cross-checked: a set
address that contradicts a module-verified base FAILS the build,
naming the address to adopt; the no-evidence case keeps the old
warning, which now also runs on the multi-package path.

Verified against the llama engine module: flagless transpile
auto-detects the table and produces a byte-identical bundle to the
correctly-asserted build (121 FCVT conversions intact); a stale
assert aborts with the actionable error.

Co-Authored-By: Claude Fable 5 <[email protected]>

* codegen: drop the f16-table address input; keep only a boolean opt-out

With auto-detection proven equivalent (flagless transpile of the
engine module is byte-identical to the previously asserted build),
an address-carrying override has no remaining legitimate use — it
only reintroduces the stale-value hazard. -f16-table is gone;
-no-f16-table disables the table-keyed rewrites outright. The
end-of-translation diagnostic is now unconditional: gather sites
whose base verified neither statically nor through init-loop
coverage are reported, so a detection miss after a module change is
loud in every pipeline log.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-24 16:57:54 +09:00

31 lines
1.1 KiB
WebAssembly Text Format

;; Runtime f16-table initialization idiom: a loop streaming
;; constant-strided stores from a constant base, covering the full
;; 65536-entry x 4-byte range. The value computation is irrelevant to
;; the detection (real modules vectorize a bit-manipulation convert);
;; only the pointer/counter recurrences and the store coverage matter.
(module
(memory 5)
(func $init_full
(local $p i32) (local $q i32)
(local.set $p (i32.const 4096))
(local.set $q (i32.const -65536))
(loop $L
(f32.store (local.get $p) (f32.const 1))
(local.set $p (i32.add (local.get $p) (i32.const 4)))
(local.set $q (i32.add (local.get $q) (i32.const 1)))
(br_if $L (i32.ne (local.get $q) (i32.const 0)))
)
)
(func $init_half
(local $p i32) (local $q i32)
(local.set $p (i32.const 266240))
(local.set $q (i32.const -32768))
(loop $L
(f32.store (local.get $p) (f32.const 1))
(local.set $p (i32.add (local.get $p) (i32.const 4)))
(local.set $q (i32.add (local.get $q) (i32.const 1)))
(br_if $L (i32.ne (local.get $q) (i32.const 0)))
)
)
)