Found by RQ-66-WATCHED (#1189) — the new self_contained_boot_sweep_1189_differential.py, which boots every self-contained corpus image through its shipped Reset_Handler under unicorn and executes every register-signature export against wasmtime. First run on main (a73d5ac).
What is wrong
On the DEFAULT self-contained image (--all-exports --target cortex-m4, the optimized ir_to_arm path), i64.clz, i64.ctz and i64.popcnt return the correct count in the LOW word and leave the HIGH word equal to the INPUT's high word instead of 0. The --no-optimize image (direct selector) is correct on every vector — this is the #916 defect class (the direct selector's zero-fill was fixed in v0.5x) on the OTHER selector.
Measured (want = wasmtime, got = R0:R1 after the call):
| module |
export |
input |
want |
got |
scripts/repro/i64_high_reg_zero_fill_916.wat |
clz64 (i64.clz (i64.extend_i32_u x)) |
1 |
0x1f, 0x0 |
0x1f, 0x1 |
| same |
clz64 |
0xffffffff |
0x0, 0x0 |
0x0, 0xffffffff |
| same |
ctz64 |
100 |
0x22, 0x0 |
0x22, 0x64 |
scripts/repro/i64_result_pair_1189.wat |
popcnt64 (i64.popcnt (i64.extend_i32_s x)) |
-1 |
0x40, 0x0 |
0x40, 0xffffffff |
| same |
popcnt64 |
-12345 |
0x3b, 0x0 |
0x3b, 0xffffffff |
10 of 16 clz64 vectors, 10 of 16 ctz64 vectors and 3 of 16 popcnt64 vectors are wrong (the ones whose input high word is nonzero — for the extend_i32_u shapes that is every input with bit 31 clear and nonzero; for extend_i32_s every negative input). Exit 0, no decline. Each wrong vector also reports R9 clobbered with that same high word — the pair was parked in R8:R9 (the alloc_i64_pair fallback, #1204's class), so the uncleared half is also visible as a contract violation.
Where
optimizer_bridge.rs ir_to_arm lowering of the i64 unary count ops — the expansion computes the count into the low register and never writes the high register (the direct selector's I64Clz/I64Ctz/I64Popcnt encoder expansions zero-fill it unconditionally since #916).
Status
Pinned in scripts/repro/self_contained_boot_sweep_1189_differential.py (KNOWN, exact per-export counts: clz64 10, ctz64 10, popcnt64 3 — the oracle goes red when a count moves in either direction) and in i64_result_pair_1189_differential.py (popcnt64, 3). The fix must move the pins.
Repro:
cargo build -p synth-cli
SYNTH=./target/debug/synth python3 scripts/repro/self_contained_boot_sweep_1189_differential.py | grep -E "clz64|ctz64|popcnt64"
Found by RQ-66-WATCHED (#1189) — the new
self_contained_boot_sweep_1189_differential.py, which boots every self-contained corpus image through its shippedReset_Handlerunder unicorn and executes every register-signature export against wasmtime. First run onmain(a73d5ac).What is wrong
On the DEFAULT self-contained image (
--all-exports --target cortex-m4, the optimizedir_to_armpath),i64.clz,i64.ctzandi64.popcntreturn the correct count in the LOW word and leave the HIGH word equal to the INPUT's high word instead of 0. The--no-optimizeimage (direct selector) is correct on every vector — this is the #916 defect class (the direct selector's zero-fill was fixed in v0.5x) on the OTHER selector.Measured (
want= wasmtime,got= R0:R1 after the call):scripts/repro/i64_high_reg_zero_fill_916.watclz64(i64.clz (i64.extend_i32_u x))0x1f, 0x00x1f, 0x1clz640x0, 0x00x0, 0xffffffffctz640x22, 0x00x22, 0x64scripts/repro/i64_result_pair_1189.watpopcnt64(i64.popcnt (i64.extend_i32_s x))0x40, 0x00x40, 0xffffffffpopcnt640x3b, 0x00x3b, 0xffffffff10 of 16
clz64vectors, 10 of 16ctz64vectors and 3 of 16popcnt64vectors are wrong (the ones whose input high word is nonzero — for theextend_i32_ushapes that is every input with bit 31 clear and nonzero; forextend_i32_severy negative input). Exit 0, no decline. Each wrong vector also reports R9 clobbered with that same high word — the pair was parked in R8:R9 (thealloc_i64_pairfallback, #1204's class), so the uncleared half is also visible as a contract violation.Where
optimizer_bridge.rsir_to_armlowering of the i64 unary count ops — the expansion computes the count into the low register and never writes the high register (the direct selector'sI64Clz/I64Ctz/I64Popcntencoder expansions zero-fill it unconditionally since #916).Status
Pinned in
scripts/repro/self_contained_boot_sweep_1189_differential.py(KNOWN, exact per-export counts:clz6410,ctz6410,popcnt643 — the oracle goes red when a count moves in either direction) and ini64_result_pair_1189_differential.py(popcnt64, 3). The fix must move the pins.Repro: