Skip to content

cortex-m PANICS (exit 101) on a multi-value if with block parameters — spec-suite if.wast 'params'; aarch64/rv32 decline cleanly, and --no-optimize does NOT avoid it #1093

Description

@avrabe

synth compile --cortex-m panics (exit 101) on a multi-value if — a block type that takes
parameters. The same construct is detected and cleanly declined on aarch64 and rv32, so the guard
exists in the codebase; the ARM selector just lacks it.

The input is params from if.wast in the official spec suite — which v0.60.0 now vendors as
tests/spec-testsuite, so it is already in the tree.

Verified on v0.60.0 (4e7a179).

Minimal repro

(module
  (func (export "params") (param i32) (result i32)
    (i32.const 1)
    (i32.const 2)
    (if (param i32 i32) (result i32) (local.get 0)
      (then (i32.add))
      (else (i32.sub)))))

Valid module; wasmtime gives params(1) = 3.

$ synth compile mv.wat --cortex-m --all-exports -o /tmp/m.o
thread 'main' panicked at crates/synth-synthesis/src/instruction_selector/select_with_stack.rs:3674:65:
`at` split index (is 2) should be <= len (is 1)
$ echo $?
101

Two values are pushed before the if, and the if (param i32 i32) consumes them as block
parameters. The selector tries to split 2 values off a stack it believes holds 1, so the block
parameters are not being accounted for when the block is entered.

The other two backends already handle it

backend exit behaviour
--cortex-m 101 panic
-b aarch64 1 clean decline
-b riscv -t rv32imac 1 clean decline

aarch64 even names the exact condition:

aarch64 selector: if #0 has type (2, 1) — a PARAMETER-taking block type (multi-value)
is not lowered on aarch64

So this is not a missing capability question — it is one backend reaching an unhandled state
through split_off instead of the (params, results) arity check the other two perform.

--no-optimize does not avoid it

tests/spec/run_supported.sh documents the workaround:

--no-optimize      # Bypass optimizer (avoids regalloc panics)
...
echo "Compile PANIC: $COMPILE_PANIC  (optimizer regalloc — all pass with --no-optimize)"

That does not hold for this file:

$ synth compile if.wast --cortex-m --all-exports --no-optimize -o /tmp/if2.elf ; echo $?
101          # still panics

So the runner's summary line would under-report: a reader is told the panics are an optimizer
artifact that --no-optimize clears, when at least this one survives it and is in instruction
selection rather than regalloc. Worth correcting the message even independently of the fix.

Scope

Scanning all 257 spec-suite files on v0.60.0:

  • --cortex-m, optimizer on: 1 panic (if.wast) out of 257
  • -b aarch64, optimizer on: 0 panics out of 257

So the ARM backend is otherwise solid across the suite; this is one unhandled construct.

Suggested fix

Give the ARM selector the same arity check aarch64 performs at block entry — if the block type has
a non-zero parameter count that the path cannot lower, decline with a message naming the type
(params, results) rather than reaching the split_off. A bounds-checked split (split_off only
when len >= at, else an error) would also convert the whole class from panic to diagnostic.

Related

Same shape as #1013 but with the backends reversed — there aarch64 panicked while arm and riscv
exited cleanly. A sweep for split_off / direct indexing on the value stack across all three
selectors would likely find siblings of both.

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