{"id":"dce14c93019b864f","repo":"rust-lang/rust","slug":"cannot-allocate-registers","errorCode":null,"errorMessage":"cannot allocate registers","messagePattern":"cannot allocate registers","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_cranelift/src/inline_asm.rs","lineNumber":321,"sourceCode":"                | CInlineAsmOperand::InOut {\n                    reg: InlineAsmRegOrRegClass::RegClass(class), ..\n                } => {\n                    let mut alloc_reg = None;\n                    for &reg in &map[&class] {\n                        let mut used = false;\n                        reg.overlapping_regs(|r| {\n                            if allocated.contains_key(&r) {\n                                used = true;\n                            }\n                        });\n\n                        if !used {\n                            alloc_reg = Some(reg);\n                            break;\n                        }\n                    }\n\n                    let reg = alloc_reg.expect(\"cannot allocate registers\");\n                    regs[i] = Some(reg);\n                    allocated.insert(reg, (true, true));\n                }\n                _ => (),\n            }\n        }\n\n        // Allocate in/lateout.\n        for (i, operand) in self.operands.iter().enumerate() {\n            match *operand {\n                CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => {\n                    let mut alloc_reg = None;\n                    for &reg in &map[&class] {\n                        let mut used = false;\n                        reg.overlapping_regs(|r| {\n                            if allocated.get(&r).copied().unwrap_or_default().0 {\n                                used = true;\n                            }","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_cranelift/src/inline_asm.rs#L303-L339","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// out: reg(\"eax\"), inout(\"ecx\") ..., out(reg) class operand with no free reg\nlet reg = alloc_reg.expect(\"cannot allocate registers\");\n// after (user-side: drop an explicit clobber to free a reg)\n// before\nasm!(\"...\", out(\"eax\") _, out(\"ecx\") y, out(reg) z);\n// after\nasm!(\"...\", out(\"eax\") _, out(reg) y, out(reg) z);","handlingStrategy":"fallback","validationCode":"// No runtime pre-check exists; register demand is determined by the asm template.\n// Static lint in your build: forbid inline asm with > (avail_regs - clobbered) clobbers.\n// Rule of thumb on x86_64: keep clobbered GPRs <= 12; on aarch64 <= 12 GPRs.","typeGuard":null,"tryCatchPattern":"use std::panic;\nlet r = panic::catch_unwind(|| codegen_inline_asm(...));\nif r.is_err() {\n    eprintln!(\"register allocation failed; rebuilding asm with fewer clobbers\");\n    // fall back: replace inline asm with an extern function or out-of-line .S file\n}","preventionTips":["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."],"tags":["cg-clif","inline-asm","register-allocation","codegen","panic"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}