Skip to content

optimized path: i64.clz / i64.ctz / i64.popcnt leave the HIGH word uncleared (hi = the input's high word) on the default self-contained image, exit 0 — direct selector correct (the #916 class on the other selector) #1240

Description

@avrabe

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"

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions