# The value half of the cross-architecture determinism gate.
#
# Every entry is a byte the language pins, so that no architecture gets an
# opinion about it. Read this file as the contract in executable form: if a
# value here is wrong, the fix is a compiler change, never an edit to this
# file to match what the machine happened to produce.
#
# `run-probes.mjs` checks every leg against this on every run, and requires the
# two sets to match exactly -- an unlisted probe fails as loudly as a wrong one,
# so adding a probe forces a deliberate decision about its pinned value.
#
# Scalars are rendered as plain hex at their own width (8 hex digits for a
# 32-bit probe, 16 for a 64-bit one); `*.bytes` probes are a raw byte-by-byte
# rendering of a heap region in memory order, which on little-endian layout is
# why their nibbles read byte-reversed relative to the scalar spelling of the
# same number.
#
# --- NaN -------------------------------------------------------------------
# The contract: NaN payload and sign are unspecified, and any operation that
# observes the bits of a NaN yields the canonical quiet NaN -- 0x7FC00000 (f32)
# / 0x7FF8000000000000 (f64). That is bit-for-bit the WebAssembly deterministic
# profile's constant, not a Wax invention. Left to the hardware these would read
# 0xFFC00000 on x86-64 (sign bit set) and 0x7FC00000 on AArch64, which is the
# divergence the whole gate exists to close. Width conversion canonicalizes at
# the destination width, so a promoted f32 NaN is the f64 pattern rather than a
# widened f32 one.
#
# --- Shifts ----------------------------------------------------------------
# The count is masked to the operand width -- `n & 31` for 32-bit, `n & 63` for
# 64-bit -- with no trap and no undefined case, including negative counts. So
# `x << 32` is `x`, `x << 33` is `x << 1`, and `x << -1` is `x << 31`. This is
# the wasm rule adopted as the language rule; x86 masks the same way, AArch64's
# variable shifts do not, and C leaves it undefined.
#
# --- Float -> int ----------------------------------------------------------
# `as` saturates and never traps: NaN converts to 0, anything above the
# destination maximum to that maximum, anything below the minimum to that
# minimum. Bare hardware disagrees here too -- x86 produces the "integer
# indefinite" pattern where AArch64 saturates. The `maxplus1` rows are the exact
# boundary rather than an infinity, because a clamp written with the wrong
# comparison passes every infinity and fails only there.
#
# --- Signed zero -----------------------------------------------------------
# The `bytes.*.mixed` rows carry both zeros and both infinities alongside the
# NaNs, so a negation lowered as `0 - x` instead of a sign-bit flip -- which
# turns -0.0 into +0.0 under IEEE -- moves exactly one quad and names itself.
# The `digest.*` rows hash those same bytes: with both present, a mismatch in
# the digest alone means the stdlib hash function changed, not determinism.
#
# --- Subnormal boundaries --------------------------------------------------
# Gradual underflow is mandatory. The minimum subnormal times one half is the
# exact halfway case and rounds to zero under ties-to-even; three minimum
# subnormals times one half rounds to two. Negative underflow retains its sign,
# and adding the minimum subnormal to the maximum carries into the minimum
# normal. The width-conversion rows pin both an underflowing conversion and the
# exact f64 spelling of the f32 minimum subnormal.
#
# --- Host composites -------------------------------------------------------
# The `hostcomposite.*` rows come from the host-bearing HostProbe project rather
# than the arithmetic one, and they pin bytes a host wrote. The element is
# `{ double wide; float narrow; int32 tag; float trailing; }`, 24 bytes with four
# of tail padding. Float leaves arrive canonical no matter what the host wrote;
# the integer field and the padding arrive exactly as written, which is why the
# driver fills the padding with 0xA5 / 0x5A / 0x3C rather than zero and puts a
# NaN-shaped pattern in `tag`. Finite lanes are in there too -- -2.5, 4.5, 1.25 --
# so a canonicalizer that swept by width instead of by lane moves them and names
# itself.
#
# The `raw.*` rows carry the identical payload across a `uint8[]`, which has no
# float lanes, so they read back the host's own bits. run-probes.mjs derives what
# each composite row must be from the control it is paired with, so that half of
# the gate does not read this file at all -- regenerating expectations cannot
# launder a regression past it, whether it lost one lane or all of them.
#
# The two composite rows are not measuring quite the same thing. `array` reads
# heap memory the unmarshal step wrote and nothing else touched. `value` reads a
# by-value aggregate after one whole-struct assignment landed it somewhere
# observable, so it pins a second contract alongside the first: that assignment
# moves the element's bytes rather than its fields. The padding is what proves
# it, and if assignment lowering ever changed, this row moves and reports it as
# a canonicalization failure -- look there first.
#
# --- Traps -----------------------------------------------------------------
# The integer edges that genuinely have no value trap instead, with a named
# panic, on every backend. INT_MIN % -1 panics as well as INT_MIN / -1, which
# is deliberately stricter than C, where the remainder case is 0 on some
# implementations and a fault on others.

bytes.f32.mixed 0000C07F0000807F000080FF00000000000000800000803F000080BF0000C07F
bytes.f64.mixed 000000000000F87F000000000000F07F000000000000F0FF00000000000000000000000000000080000000000000F03F000000000000F0BF000000000000F87F
conv.f32.i32.maxplus1 7FFFFFFF
conv.f32.i32.nan 00000000
conv.f32.i32.neginf 80000000
conv.f32.i32.posinf 7FFFFFFF
conv.f32.u32.maxplus1 FFFFFFFF
conv.f32.u32.nan 00000000
conv.f32.u32.neginf 00000000
conv.f32.u32.posinf FFFFFFFF
conv.f64.i32.nan 00000000
conv.f64.i32.neginf 80000000
conv.f64.i32.posinf 7FFFFFFF
conv.f64.i64.nan 0000000000000000
conv.f64.i64.neginf 8000000000000000
conv.f64.i64.posinf 7FFFFFFFFFFFFFFF
conv.f64.u32.nan 00000000
conv.f64.u32.neginf 00000000
conv.f64.u32.posinf FFFFFFFF
conv.f64.u64.nan 0000000000000000
conv.f64.u64.neginf 0000000000000000
conv.f64.u64.posinf FFFFFFFFFFFFFFFF
digest.f32.mixed 9AD8409206FE0A15
digest.f64.mixed 185FAA00C166A40D
hostcomposite.array.bytes 000000000000F87F0000C07F0100C07F0000C07FA5A5A5A500000000000004C0000090400100C0FF0000C07F5A5A5A5A
hostcomposite.raw.array.bytes 010000000000F07F0100C0FF0100C07F0100807FA5A5A5A500000000000004C0000090400100C0FF0100C07F5A5A5A5A
hostcomposite.raw.value.bytes 000000000000F8FF0100807F0100F07F0000A03F3C3C3C3C
hostcomposite.value.bytes 000000000000F87F0000C07F0100F07F0000A03F3C3C3C3C
nan.bitconv.f32 0000C07F
nan.bitconv.f64 000000000000F87F
nan.const.f32.divzero 7FC00000
nan.const.f32.infmul 7FC00000
nan.const.f32.infsub 7FC00000
nan.const.f32.sqrtneg 7FC00000
nan.const.f64.divzero 7FF8000000000000
nan.const.f64.infmul 7FF8000000000000
nan.const.f64.infsub 7FF8000000000000
nan.const.f64.sqrtneg 7FF8000000000000
nan.opaque.demote.f64.to.f32 7FC00000
nan.opaque.f32.divzero 7FC00000
nan.opaque.f32.infmul 7FC00000
nan.opaque.f32.infsub 7FC00000
nan.opaque.f32.sqrtneg 7FC00000
nan.opaque.f64.divzero 7FF8000000000000
nan.opaque.f64.infmul 7FF8000000000000
nan.opaque.f64.infsub 7FF8000000000000
nan.opaque.f64.sqrtneg 7FF8000000000000
nan.opaque.promote.f32.to.f64 7FF8000000000000
nan.store.f32.bytes 0000C07F0000C07F0000C07F0000C07F
nan.store.f64.bytes 000000000000F87F000000000000F87F000000000000F87F000000000000F87F
nan.store.v4.div.bytes 0000C07F0000803F0000803F0000803F
nan.store.v4.sqrt.bytes 0000C07F0000803F0000008000000040
panic.div.i32.by-zero divide_by_zero
panic.div.i32.min-by-neg1 integer_overflow
panic.div.i64.by-zero divide_by_zero
panic.div.i64.min-by-neg1 integer_overflow
panic.rem.i32.by-zero divide_by_zero
panic.rem.i32.min-by-neg1 integer_overflow
panic.rem.i64.by-zero divide_by_zero
panic.rem.i64.min-by-neg1 integer_overflow
shift.i32.sar.by33 C0000000
shift.i32.sar.byneg1 FFFFFFFF
shift.i32.shl.by32 00000001
shift.i32.shl.by33 00000002
shift.i32.shl.byneg1 80000000
shift.i64.sar.by65 C000000000000000
shift.i64.sar.byneg1 FFFFFFFFFFFFFFFF
shift.i64.shl.by64 0000000000000001
shift.i64.shl.by65 0000000000000002
shift.i64.shl.byneg1 8000000000000000
shift.u32.shr.by33 40000000
shift.u64.shr.by65 4000000000000000
subnormal.convert.f32-min.to-f64 36A0000000000000
subnormal.convert.f64-f32-min.to-f32 00000001
subnormal.convert.f64-min.to-f32 00000000
subnormal.f32.max.plus.min 00800000
subnormal.f32.min.times.half 00000000
subnormal.f32.negative-min.times.half 80000000
subnormal.f32.normal.minus.min 007FFFFF
subnormal.f32.normal.times.half 00400000
subnormal.f32.three-min.times.half 00000002
subnormal.f64.max.plus.min 0010000000000000
subnormal.f64.min.times.half 0000000000000000
subnormal.f64.negative-min.times.half 8000000000000000
subnormal.f64.normal.minus.min 000FFFFFFFFFFFFF
subnormal.f64.normal.times.half 0008000000000000
subnormal.f64.three-min.times.half 0000000000000002
