Odd-Width Mask Sculptor

Algorithms & Data

Values masked to odd widths — 20, 24, and 28 bits — then zero-extended to 64 bits and multiplied. This is compiler stress-test #103: it re-runs the exact legalization shape a real llvm-mos 64-bit crash once hit — an odd-width value with no clean 16-bit-lane decomposition, widened into 64-bit arithmetic — and confirms the fix (patch 0017) holds.

loading core…

Self-running — four bands, each masked to a different width, terrace and flow.

Click the screen to focus, then watch. Tab away and it pauses.

What it is

Odd-width integers are the awkward case for a 16-bit machine: a 20- or 24- or 28-bit value has no neat split into 16-bit halves, yet the compiler must zero-extend it to 64 bits to do 64-bit math on it. This demo builds exactly those values and multiplies them wide.

// a 20/24/28-bit value, then widened to 64 bits and multiplied
uint32_t x = (uint32_t)v * 2654435761u + rot;   // 32-bit multiply
uint64_t w20 = (uint64_t)((x ^ y) & 0x000FFFFF);  // 20-bit → zero-extend to 64
uint64_t w24 = (uint64_t)((x + y) & 0x00FFFFFF);  // 24-bit → zero-extend to 64
uint64_t a   = w20 * w24;                          // 64-bit multiply

// the compiler narrows each masked value to an ODD width (20, 24, 28 bits),
// then must zero-extend that odd width to 64 — a shape with no clean
// decomposition into 16-bit lanes, which once crashed the backend.

Each step folds the 64-bit result into a CRC. The picture is the proof: a wrong odd-width extend or a wrong 64-bit split would corrupt the arithmetic and change the CRC.

Compiler stress-test #103 — Round 6: hardening the fixes

ItemWhat it exercises
odd-width integersMost integers are 8, 16, 32, or 64 bits wide. But mask a value to 20 bits and the compiler tracks it as a 20-bit quantity — an “odd” width. When that narrow value is then widened to 64 bits and fed to 64-bit arithmetic, the backend must extend an odd width into four 16-bit lanes, which has no tidy decomposition.
the bug this guards (#61, patch 0017)A 64-bit Diffie-Hellman demo once crashed the 16-bit-accumulator backend on exactly this: a 20-bit-masked value zero-extended to 64 bits (“unable to legalize”), plus splitting a 64-bit value into 16-bit lanes. Patch 0017 taught the legalizer both moves. This demo re-runs the odd-width extend at 20, 24, and 28 bits, threaded through a 64-bit multiply, and confirms the fix holds.
what actually forms the odd widthA measured detail: masking a 64-bit value directly (v & 0xFFFFF) does NOT create an odd-width type — it stays 64-bit with some bits known-zero. The odd width only appears when a 32-bit value is masked and an operation is applied, then the result is widened to 64 bits. So widths above 32 (40, 48) can’t arise this way; the reachable odd widths here are 20, 24, and 28.
a 64-bit multiply on topThe two zero-extended narrow values are multiplied at 64 bits, which exercises the other half of the fix — the 64-bit multiply glue that composes a product from 32-bit pieces without ever widening to 128 bits. So a single step touches both the odd-width extend and the 64-bit (un)merge legalization.
keeping it honestThe computation runs from a volatile seed so the compiler can’t precompute the whole thing to a constant and skip the code entirely. Without that, a pure function with fixed inputs folds away and tests nothing — a trap worth flagging.
result: bit-exact, and the visual64-bit integer arithmetic on masked values is exact, so the result is identical on host and SNES: host == default == +mos-a16 == +mos-xy16 on both MAME and bsnes-jg, -verify-machineinstrs clean (the modes that used to crash). On screen, a field is split into horizontal bands, each masking the running 64-bit state to a different width — so a band’s terrace granularity tracks its mask — and the terraces flow as the state mixes.

Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg and MAME. Hit Verify fidelity to reproduce the build gate's WRAM assert (gate CRC 0x1FD9 — a fold of 40 mix steps) live in this tab. No far pointers — host == default == +mos-a16 == +mos-xy16, -verify clean.