Skip to content

if/else-with-result lowering has no result-register reconciliation — arms agree only by register-pressure luck #313

@avrabe

Description

@avrabe

Found while building the #311 repro. select_with_stack's If/Else/End lowering tracks the operand stack textually through both arms with no checkpoint at If, no restore at Else, and no reconciliation move at End. The two arms' result registers agree only when both arms happen to consume identical temp counts.

Failing shape (i64-heavy then-arm vs trivial else-arm — the widths diverge the temp counter):

(if (result i32)
  (i32.eq (i32.wrap_i64 (i64.and (local.get $r) (i64.const 255))) (i32.const 1))
  (then (i32.wrap_i64 (i64.shr_u (local.get $r) (i64.const 32))))
  (else (i32.const 0xDEAD)))

Observed codegen (v0.11.35 + #311 fix): then-arm leaves its result in r2, else-arm materializes 0xDEAD into r3, and the End/return path reads r3 unconditionally — the then-path returns garbage. Repro: take scripts/repro/u64_unpack.wat, replace the select with the if-form above; check_call(3,4) = 0 instead of 8.

Why nothing caught it before: the frozen fixtures' if/else sites are register-symmetric; gale's production seams use select (IT-blocks). The class is latent in any module where loom emits branching conditionals with asymmetric arms.

Fix sketch: checkpoint the vstack + temp counter at If; at Else, pop the then-result (remember its register R_then) and restore the checkpoint; at End-with-result, emit mov R_then, R_else as the else-arm's last instruction and push R_then. Needs the block result arity from the If's blocktype (decoder currently drops it — same threading pattern as #311's result types).

Severity: silent wrong-code (same class as #311) but no known production hit yet. Should ride the queue ahead of perf work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions