rust-lang/rust · error

cannot allocate registers

Error message

cannot allocate registers

What it means

Panics in InlineAssemblyGenerator::allocate_registers when register allocation for an inline asm block cannot find a free physical register for an Out(non-late) or InOut operand whose constraint is a RegClass (not an explicit register). These operand kinds are allocated first because they need a register that is free for both input and output, i.e. neither the input nor output slot may already be taken.

Source

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

                | CInlineAsmOperand::InOut {
                    reg: InlineAsmRegOrRegClass::RegClass(class), ..
                } => {
                    let mut alloc_reg = None;
                    for &reg in &map[&class] {
                        let mut used = false;
                        reg.overlapping_regs(|r| {
                            if allocated.contains_key(&r) {
                                used = true;
                            }
                        });

                        if !used {
                            alloc_reg = Some(reg);
                            break;
                        }
                    }

                    let reg = alloc_reg.expect("cannot allocate registers");
                    regs[i] = Some(reg);
                    allocated.insert(reg, (true, true));
                }
                _ => (),
            }
        }

        // Allocate in/lateout.
        for (i, operand) in self.operands.iter().enumerate() {
            match *operand {
                CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => {
                    let mut alloc_reg = None;
                    for &reg in &map[&class] {
                        let mut used = false;
                        reg.overlapping_regs(|r| {
                            if allocated.get(&r).copied().unwrap_or_default().0 {
                                used = true;
                            }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Reduce register pressure inside the asm! block: fewer explicit clobbers/operands, or split into multiple blocks.
  2. For class-constrained operands, prefer narrower register classes or let the compiler pick (omit explicit registers) so the allocator has freedom.
  3. Verify the target features: compile with the features the asm assumes (e.g. `-Ctarget-feature=+avx`) so allocatable_registers returns the full set.
  4. Check the relocation model: PIC steals a register on some targets; try `-Crelocation-model=static` if appropriate.
  5. If the asm works under LLVM but not cg_clif, file an issue — the allocator is simpler than LLVM's and may need improvement.

Example fix

// before
// out: reg("eax"), inout("ecx") ..., out(reg) class operand with no free reg
let reg = alloc_reg.expect("cannot allocate registers");
// after (user-side: drop an explicit clobber to free a reg)
// before
asm!("...", out("eax") _, out("ecx") y, out(reg) z);
// after
asm!("...", out("eax") _, out(reg) y, out(reg) z);
Defensive patterns

Strategy: fallback

Validate before calling

// No runtime pre-check exists; register demand is determined by the asm template.
// Static lint in your build: forbid inline asm with > (avail_regs - clobbered) clobbers.
// Rule of thumb on x86_64: keep clobbered GPRs <= 12; on aarch64 <= 12 GPRs.

Try / catch

use std::panic;
let r = panic::catch_unwind(|| codegen_inline_asm(...));
if r.is_err() {
    eprintln!("register allocation failed; rebuilding asm with fewer clobbers");
    // fall back: replace inline asm with an extern function or out-of-line .S file
}

Prevention

When it happens

Trigger: Reached at inline_asm.rs:321 inside the first allocation loop. alloc_reg stays None when every register in the class (and its overlapping aliases) is already in the `allocated` map — typically because explicit-register operands earlier in the same asm! reserved them.

Common situations: A single asm! block names many explicit registers (clobber list or in(out)rax etc.) leaving none free for a class-constrained operand on x86; target features disabled (e.g. AVX off) shrink the allocatable set returned by allocatable_registers; relocation model or ABI reserve registers (e.g. PIC reserves a register on x86); inline asm written for a different architecture compiled for a register-poor target; legitimate register-pressure bug in cg_clif's allocator.

Related errors


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