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 ® 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 ® 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
- Reduce register pressure inside the asm! block: fewer explicit clobbers/operands, or split into multiple blocks.
- For class-constrained operands, prefer narrower register classes or let the compiler pick (omit explicit registers) so the allocator has freedom.
- Verify the target features: compile with the features the asm assumes (e.g. `-Ctarget-feature=+avx`) so allocatable_registers returns the full set.
- Check the relocation model: PIC steals a register on some targets; try `-Crelocation-model=static` if appropriate.
- 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
- Reduce the number of explicit clobbers in inline asm; let the allocator pick registers via out/inout operands instead of pinning specific registers.
- Prefer `inout(reg)` over fixed `in("rax")` so the backend can choose a free register.
- Move large or register-heavy asm into a separate extern "C" function compiled by the system assembler; call it from Rust.
- Avoid inline asm inside hot loops that already spill; lower surrounding register pressure first.
- On x86 prefer using the reserved callee-saved set only when necessary; on aarch64/llvm the same applies to x0-x18.
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
- failed to create {dst:?}: {e}
- failed to copy {src:?}->{dst:?}: {e}
- Path component {:?} of path {} is an invalid filename
- prologue for {:?}
- epilogue for {:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/dce14c93019b864f.json.
Report an issue: GitHub.