Determinism corpus
This is one public slice of a much larger determinism test suite. The cases demonstrate the exact results Wax requires across platforms without exposing compiler internals. The corpus is runnable so anyone can check the results.
Download the runnable corpus (.zip) · macOS/Linux/Windows · unpack and run node run.mjs
Requires Node.js 25 or newer, the native runtime files installed with Wax, and a C compiler on macOS or Linux.
Tests
The named cases show each operation and required result. The machine code digest at the end checks the same scalar rules as one combined value.
Wax source · expected results · digest source · digest result
Float byte images and hashes
Stores mixed NaNs, infinities, signed zero, and finite values as bytes, then hashes the same images. This catches representation changes and stdlib hashing drift.
bytes.f32.mixed0000C07F0000807F000080FF00000000000000800000803F000080BF0000C07F
Stores eight f32 values in order: NaN, positive infinity, negative infinity, positive zero, negative zero, positive one, negative one, and a generated NaN. The expectation shows the exact bytes of each array element in that order.
bytes.f64.mixed000000000000F87F000000000000F07F000000000000F0FF00000000000000000000000000000080000000000000F03F000000000000F0BF000000000000F87F
Stores eight f64 values in order: NaN, positive infinity, negative infinity, positive zero, negative zero, positive one, negative one, and a generated NaN. The expectation shows the exact bytes of each array element in that order.
digest.f32.mixed9AD8409206FE0A15
Hashes the mixed f32 byte image to check the stdlib hash path used by snapshots and other raw memory observers.
digest.f64.mixed185FAA00C166A40D
Hashes the mixed f64 byte image to check the stdlib hash path used by snapshots and other raw memory observers.
NaN generation and observation
Creates NaNs through constants and runtime operations, converts widths, reinterprets bits, and stores scalar and vector values. Every observable NaN must become Wax’s canonical pattern.
nan.bitconv.f320000C07F
Reads a stored f32 NaN through the generic byte conversion path and checks its canonical memory representation.
nan.bitconv.f64000000000000F87F
Reads a stored f64 NaN through the generic byte conversion path and checks its canonical memory representation.
nan.const.f32.divzero7FC00000
Observes an f32 NaN folded at compile time from zero divided by zero and requires the canonical bit pattern.
nan.const.f32.infmul7FC00000
Observes an f32 NaN folded at compile time from infinity multiplied by zero and requires the canonical bit pattern.
nan.const.f32.infsub7FC00000
Observes an f32 NaN folded at compile time from infinity minus itself and requires the canonical bit pattern.
nan.const.f32.sqrtneg7FC00000
Observes an f32 NaN folded at compile time from the square root of a negative value and requires the canonical bit pattern.
nan.const.f64.divzero7FF8000000000000
Observes an f64 NaN folded at compile time from zero divided by zero and requires the canonical bit pattern.
nan.const.f64.infmul7FF8000000000000
Observes an f64 NaN folded at compile time from infinity multiplied by zero and requires the canonical bit pattern.
nan.const.f64.infsub7FF8000000000000
Observes an f64 NaN folded at compile time from infinity minus itself and requires the canonical bit pattern.
nan.const.f64.sqrtneg7FF8000000000000
Observes an f64 NaN folded at compile time from the square root of a negative value and requires the canonical bit pattern.
nan.opaque.demote.f64.to.f327FC00000
Demotes an f64 NaN produced at runtime and checks that the observed result uses the canonical f32 pattern.
nan.opaque.f32.divzero7FC00000
Observes an f32 NaN produced at runtime from zero divided by zero and requires the canonical bit pattern.
nan.opaque.f32.infmul7FC00000
Observes an f32 NaN produced at runtime from infinity multiplied by zero and requires the canonical bit pattern.
nan.opaque.f32.infsub7FC00000
Observes an f32 NaN produced at runtime from infinity minus itself and requires the canonical bit pattern.
nan.opaque.f32.sqrtneg7FC00000
Observes an f32 NaN produced at runtime from the square root of a negative value and requires the canonical bit pattern.
nan.opaque.f64.divzero7FF8000000000000
Observes an f64 NaN produced at runtime from zero divided by zero and requires the canonical bit pattern.
nan.opaque.f64.infmul7FF8000000000000
Observes an f64 NaN produced at runtime from infinity multiplied by zero and requires the canonical bit pattern.
nan.opaque.f64.infsub7FF8000000000000
Observes an f64 NaN produced at runtime from infinity minus itself and requires the canonical bit pattern.
nan.opaque.f64.sqrtneg7FF8000000000000
Observes an f64 NaN produced at runtime from the square root of a negative value and requires the canonical bit pattern.
nan.opaque.promote.f32.to.f647FF8000000000000
Promotes an f32 NaN produced at runtime and checks that the observed result uses the canonical f64 pattern.
nan.store.f32.bytes0000C07F0000C07F0000C07F0000C07F
Stores several independently produced f32 NaNs and checks their raw heap bytes.
nan.store.f64.bytes000000000000F87F000000000000F87F000000000000F87F000000000000F87F
Stores several independently produced f64 NaNs and checks their raw heap bytes.
nan.store.v4.div.bytes0000C07F0000803F0000803F0000803F
Stores a vector containing a NaN produced by division and finite lanes, checking canonicalization without disturbing the other lanes.
nan.store.v4.sqrt.bytes0000C07F0000803F0000008000000040
Stores a vector containing a NaN produced by square root, signed zero, and finite lanes, checking every observed bit.
Saturating float to integer conversion
Covers NaN, infinities, and exact limit values across signed and unsigned 32 and 64 bit destinations. These cases deliberately disagree across bare CPU instructions.
conv.f32.i32.maxplus17FFFFFFF
Converts f32 the first exactly representable value above the destination maximum to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.i32.nan00000000
Converts f32 NaN to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.i32.neginf80000000
Converts f32 negative infinity to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.i32.posinf7FFFFFFF
Converts f32 positive infinity to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.u32.maxplus1FFFFFFFF
Converts f32 the first exactly representable value above the destination maximum to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.u32.nan00000000
Converts f32 NaN to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.u32.neginf00000000
Converts f32 negative infinity to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f32.u32.posinfFFFFFFFF
Converts f32 positive infinity to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i32.nan00000000
Converts f64 NaN to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i32.neginf80000000
Converts f64 negative infinity to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i32.posinf7FFFFFFF
Converts f64 positive infinity to i32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i64.nan0000000000000000
Converts f64 NaN to i64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i64.neginf8000000000000000
Converts f64 negative infinity to i64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.i64.posinf7FFFFFFFFFFFFFFF
Converts f64 positive infinity to i64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u32.nan00000000
Converts f64 NaN to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u32.neginf00000000
Converts f64 negative infinity to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u32.posinfFFFFFFFF
Converts f64 positive infinity to u32 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u64.nan0000000000000000
Converts f64 NaN to u64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u64.neginf0000000000000000
Converts f64 negative infinity to u64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
conv.f64.u64.posinfFFFFFFFFFFFFFFFF
Converts f64 positive infinity to u64 and checks Wax's saturating result instead of the host CPU's conversion behavior.
Host composite marshalling
Passes NaNs with payloads, finite floats, integer fields, and nonzero padding through arrays and structs passed by value. Float leaves canonicalize while every unrelated byte stays intact.
hostcomposite.array.bytes000000000000F87F0000C07F0100C07F0000C07FA5A5A5A500000000000004C0000090400100C0FF0000C07F5A5A5A5A
Passes an array of mixed width float structs from the host and checks that float leaves canonicalize without changing integers or padding.
hostcomposite.raw.array.bytes010000000000F07F0100C0FF0100C07F0100807FA5A5A5A500000000000004C0000090400100C0FF0100C07F5A5A5A5A
Carries the host array payload through an untyped byte crossing, proving which noncanonical bytes the typed array probe received.
hostcomposite.raw.value.bytes000000000000F8FF0100807F0100F07F0000A03F3C3C3C3C
Carries the host value payload through an untyped byte crossing, proving which noncanonical bytes the typed value probe received.
hostcomposite.value.bytes000000000000F87F0000C07F0100F07F0000A03F3C3C3C3C
Passes a mixed width float struct by value from the host and checks canonical float leaves plus exact byte assignment and padding.
Masked shifts
Exercises shift counts at, above, and below the operand width. Wax masks counts consistently instead of inheriting C undefined behavior or instructions that vary by architecture.
shift.i32.sar.by33C0000000
Applies an i32 arithmetic right shift by 33 and checks Wax's masked shift count rule.
shift.i32.sar.byneg1FFFFFFFF
Applies an i32 arithmetic right shift by -1 and checks Wax's masked shift count rule.
shift.i32.shl.by3200000001
Applies an i32 left shift by 32 and checks Wax's masked shift count rule.
shift.i32.shl.by3300000002
Applies an i32 left shift by 33 and checks Wax's masked shift count rule.
shift.i32.shl.byneg180000000
Applies an i32 left shift by -1 and checks Wax's masked shift count rule.
shift.i64.sar.by65C000000000000000
Applies an i64 arithmetic right shift by 65 and checks Wax's masked shift count rule.
shift.i64.sar.byneg1FFFFFFFFFFFFFFFF
Applies an i64 arithmetic right shift by -1 and checks Wax's masked shift count rule.
shift.i64.shl.by640000000000000001
Applies an i64 left shift by 64 and checks Wax's masked shift count rule.
shift.i64.shl.by650000000000000002
Applies an i64 left shift by 65 and checks Wax's masked shift count rule.
shift.i64.shl.byneg18000000000000000
Applies an i64 left shift by -1 and checks Wax's masked shift count rule.
shift.u32.shr.by3340000000
Applies an u32 logical right shift by 33 and checks Wax's masked shift count rule.
shift.u64.shr.by654000000000000000
Applies an u64 logical right shift by 65 and checks Wax's masked shift count rule.
Defined integer traps
Checks division and remainder by zero plus signed minimum divided or remaindered by negative one. Every backend must report the same named panic.
panic.div.i32.by-zerodivide_by_zero
Runs i32 division with a zero divisor and requires the same named panic on every backend.
panic.div.i32.min-by-neg1integer_overflow
Runs i32 division with the signed minimum value and negative one and requires the same named panic on every backend.
panic.div.i64.by-zerodivide_by_zero
Runs i64 division with a zero divisor and requires the same named panic on every backend.
panic.div.i64.min-by-neg1integer_overflow
Runs i64 division with the signed minimum value and negative one and requires the same named panic on every backend.
panic.rem.i32.by-zerodivide_by_zero
Runs i32 remainder with a zero divisor and requires the same named panic on every backend.
panic.rem.i32.min-by-neg1integer_overflow
Runs i32 remainder with the signed minimum value and negative one and requires the same named panic on every backend.
panic.rem.i64.by-zerodivide_by_zero
Runs i64 remainder with a zero divisor and requires the same named panic on every backend.
panic.rem.i64.min-by-neg1integer_overflow
Runs i64 remainder with the signed minimum value and negative one and requires the same named panic on every backend.
Subnormal limits and rounding
Checks gradual underflow, ties to even, signed underflow, normal and subnormal limits, and exact float width conversion at the smallest representable values.
subnormal.convert.f32-min.to-f6436A0000000000000
Promotes the minimum f32 subnormal to f64 and checks its exact widened representation.
subnormal.convert.f64-f32-min.to-f3200000001
Demotes the exact f64 representation of the minimum f32 subnormal and checks that the smallest f32 value survives.
subnormal.convert.f64-min.to-f3200000000
Demotes the minimum f64 subnormal to f32 and checks that it underflows to zero.
subnormal.f32.max.plus.min00800000
For f32, adds the minimum subnormal to the maximum subnormal, carrying into the minimum normal.
subnormal.f32.min.times.half00000000
For f32, halves the minimum subnormal, testing ties to even underflow to zero.
subnormal.f32.negative-min.times.half80000000
For f32, halves the negative minimum subnormal, testing the sign of underflowed zero.
subnormal.f32.normal.minus.min007FFFFF
For f32, subtracts the minimum subnormal from the minimum normal.
subnormal.f32.normal.times.half00400000
For f32, halves the minimum normal into the subnormal range.
subnormal.f32.three-min.times.half00000002
For f32, halves three minimum subnormals, testing ties to even rounding upward.
subnormal.f64.max.plus.min0010000000000000
For f64, adds the minimum subnormal to the maximum subnormal, carrying into the minimum normal.
subnormal.f64.min.times.half0000000000000000
For f64, halves the minimum subnormal, testing ties to even underflow to zero.
subnormal.f64.negative-min.times.half8000000000000000
For f64, halves the negative minimum subnormal, testing the sign of underflowed zero.
subnormal.f64.normal.minus.min000FFFFFFFFFFFFF
For f64, subtracts the minimum subnormal from the minimum normal.
subnormal.f64.normal.times.half0008000000000000
For f64, halves the minimum normal into the subnormal range.
subnormal.f64.three-min.times.half0000000000000002
For f64, halves three minimum subnormals, testing ties to even rounding upward.
Machine scalar digest
One digest combines hundreds of scalar operations that are also run through the other backends. Matching it checks the machine code path without repeating the full list above.
machine.scalar.digest96BF94EB
Hashes hundreds of scalar reinterpretations plus NaN, subnormal, signed underflow, and contraction sensitive operations shared by every executable backend.
Every file matches the required results and can be compared directly with the others in its group.
Named cases
- C · instant tier · linux x64 · raw artifact
- C · instant tier · macos arm64 · raw artifact
- C / host Clang · optimized tier · macos arm64 · raw artifact
- Wasm / Binaryen · macos arm64 · raw artifact
- C · instant tier · windows arm64 · raw artifact
- C / host Clang · optimized tier · windows arm64 · raw artifact
- C · instant tier · windows x64 · raw artifact
- C / host Clang · optimized tier · windows x64 · raw artifact
Machine code digest
- Wax machine code · linux x64 · raw artifact
- Wax machine code · macos arm64 · raw artifact
- C · instant tier · macos arm64 · raw artifact
- C / host Clang · optimized tier · macos arm64 · raw artifact
- Wasm / Binaryen · macos arm64 · raw artifact
- C · instant tier · windows arm64 · raw artifact
- C / host Clang · optimized tier · windows arm64 · raw artifact
- C · instant tier · windows x64 · raw artifact
- C / host Clang · optimized tier · windows x64 · raw artifact
Run it yourself
Run the ZIP on any macOS, Linux, or Windows machine with waxc, its native runtime files, and Node.js 25 or newer installed. On macOS and Linux it also needs a C compiler. Windows uses the compiler included with Wax. The runner writes its results and compares them with the results published here. Copy the output from several machines into one place to compare them directly.