rust-lang/rust · error

save_register for {:?}

Error message

save_register for {:?}

What it means

Thrown by rustc_codegen_cranelift when saving a clobbered register to a stack slot before a user asm! block. save_register() emits the architecture-specific store instruction for the base-pointer-relative slot (e.g. mov [rbx+off], reg). Only X86_64, AArch64, and RiscV64 are implemented; other arches hit `_ => unimplemented!("save_register for {:?}", arch)`.

Source

Thrown at compiler/rustc_codegen_cranelift/src/inline_asm.rs:773

                generated_asm.push('\n');
            }
            InlineAsmArch::AArch64 => {
                generated_asm.push_str("    str ");
                match reg {
                    InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => {
                        // rustc emits v0 rather than q0
                        reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap()
                    }
                    _ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(),
                }
                writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
            }
            InlineAsmArch::RiscV64 => {
                generated_asm.push_str("    sd ");
                reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
                writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap();
            }
            _ => unimplemented!("save_register for {:?}", arch),
        }
    }

    fn restore_register(
        generated_asm: &mut String,
        arch: InlineAsmArch,
        reg: InlineAsmReg,
        offset: Size,
    ) {
        match arch {
            InlineAsmArch::X86_64 => {
                match reg {
                    InlineAsmReg::X86(reg)
                        if matches!(
                            reg.reg_class(),
                            X86InlineAsmRegClass::xmm_reg
                                | X86InlineAsmRegClass::ymm_reg
                                | X86InlineAsmRegClass::zmm_reg

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Switch to the LLVM backend for that target.
  2. Reduce the asm to arches Cranelift supports (x86_64/aarch64/riscv64) via cfg.
  3. Avoid explicit register clobbers in asm operands where a plain Rust intrinsic or builtin is available.
  4. Implement save_register for the arch (emit the store to the base-pointer-relative offset, mirroring the existing arms) upstream.

Example fix

// before
let r: u64;
asm!("mov {}, 1", out("rax") r, options(nostack));

// after - avoid register-clobber asm, use a plain expression
let r: u64 = 1;
Defensive patterns

Strategy: validation

Validate before calling

// Detect asm! blocks that explicitly list registers in `out("reg")` /
// `inout("reg")` — save_register path triggers on named-register operands.
let re = regex::Regex::new(r#"asm!\([^)]*\b(out|inout|lateout)\("(?:rax|rbx|rcx|rdx|rsi|rdi|rbp|r[0-9]+)""#).unwrap();
if re.is_match(&src) {
    eprintln!("cg_clif cannot save_named_register for asm; use LLVM.");
}

Try / catch

// Compiler-process panic; not catchable. Use LLVM backend for any crate
// that performs explicit register save/restore via asm!.

Prevention

When it happens

Trigger: Compiling asm! with out("reg") / inout("reg") operands that clobber registers, on a target other than X86_64/AArch64/RiscV64 using the Cranelift backend. The backend must spill each clobbered register to a stack slot before the asm and reload it after.

Common situations: Inline asm with multiple register operands (e.g. SIMD/DSP intrinsics) targeting a tier-3 arch under cg_clif; porting a crate that relies on per-register asm operands to a new architecture before the cranelift backend has the save/restore sequences.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/c257c86d76ac6b56.json. Report an issue: GitHub.