wasmerio/wasmer · critical

unsupported move: {size:?} {source:?} {dest:?}

Error message

unsupported move: {size:?} {source:?} {dest:?}

What it means

emit_move_location in the RISC-V singlepass backend panics when it sees a (size, source, dest) combination it cannot move between, i.e. a Location pair not covered by the GPR/SIMD match arms above. This is a codegen completeness gap: the move instruction selector lacks an arm for that operand pairing.

Source

Thrown at lib/compiler-singlepass/src/machine_riscv.rs:2395

                let addr = if ImmType::Bits12.compatible_imm(offset as _) {
                    source
                } else {
                    self.assembler
                        .emit_mov_imm(Location::GPR(SCRATCH_REG), offset as _)?;
                    self.assembler.emit_add(
                        Size::S64,
                        Location::GPR(addr),
                        Location::GPR(SCRATCH_REG),
                        Location::GPR(SCRATCH_REG),
                    )?;
                    Location::Memory(SCRATCH_REG, 0)
                };
                self.assembler.emit_ld(size, false, dest, addr)
            }
            (Location::GPR(_), Location::SIMD(_)) => self.assembler.emit_mov(size, source, dest),
            (Location::SIMD(_), Location::GPR(_)) => self.assembler.emit_mov(size, source, dest),
            (Location::SIMD(_), Location::SIMD(_)) => self.assembler.emit_mov(size, source, dest),
            _ => todo!("unsupported move: {size:?} {source:?} {dest:?}"),
        }
    }

    fn move_location_extend(
        &mut self,
        size_val: Size,
        signed: bool,
        source: Location,
        size_op: Size,
        dest: Location,
    ) -> Result<(), CompileError> {
        if size_op != Size::S64 {
            codegen_error!("singlepass move_location_extend unreachable");
        }
        let mut temps = vec![];
        let dst = self.location_to_reg(size_op, dest, &mut temps, ImmType::None, false, None)?;
        let src = match (size_val, signed, source) {
            (Size::S64, _, _) => source,

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Use the cranelift compiler on riscv64 instead of singlepass
  2. Upgrade wasmer to a build where this match in machine_riscv.rs is complete
  3. For backend developers: add the missing (source, dest) arm emitting the appropriate RISC-V move sequence
  4. Report the triggering module/opcode combination upstream

Example fix

// before
_ => todo!("unsupported move: {size:?} {source:?} {dest:?}"),
// after
(Location::Imm(v), Location::GPR(_)) => self.assembler.emit_load_const(size, v, dest),
pair => Err(CompileError::Codegen(format!("unsupported move {pair:?}"))),
Defensive patterns

Strategy: fallback

Validate before calling

// select a backend that supports moves on riscv
let cfg: Box<dyn CompilerConfig> = if target_is_riscv() { Box::new(Cranelift::new()) } else { Box::new(Singlepass::new()) };

Type guard

fn move_is_supported(source: &Location, dest: &Location) -> bool {
    matches!(source, Location::GPR(_) | Location::SIMD(_)) && matches!(dest, Location::GPR(_) | Location::SIMD(_))
}

Prevention

When it happens

Trigger: Compiling wasm via singlepass on riscv64 when a move is requested with a source/dest pairing outside (GPR,GPR), (GPR,SIMD), (SIMD,GPR), (SIMD,SIMD) — e.g. Immediate/label locations in get_move_location — during any instruction-emitting compile (compile_wasm path).

Common situations: Early/alpha RISC-V singlepass support; modules with constant-heavy or unusual register-assignment patterns hitting the unhandled arm; mixing wasmer versions where the RISC-V backend is still behind x86 completeness.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/78a99f54bd42cc6a. Report an issue: GitHub.