oracle/graal · critical · OutOfRegistersException
There are no allocatable registers for kind %s, consider ass
Error message
There are no allocatable registers for kind %s, consider assigning fixed registers.
What it means
initVarsForAlloc asks the RegisterAllocationConfig for the allocatable registers of the interval's platform kind; if the backend never registered any allocatable register for that kind, allocatableRegisters is null and an OutOfRegistersException is thrown with the suggestion 'consider assigning fixed registers'. It means the target configuration is fundamentally unable to hold values of that kind, not merely that pressure is high.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanWalker.java:1146
if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
DebugContext debug = allocator.getDebug();
if (debug.isLogEnabled()) {
debug.log("free register cannot be available because all registers blocked by following call");
}
// safety check that there is really no register available
assert !allocFreeRegister(interval) : "found a register for this interval";
return true;
}
}
}
return false;
}
void initVarsForAlloc(Interval interval) {
AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
if (allocatableRegisters == null) {
throw new OutOfRegistersException("There are no allocatable registers for kind " + interval.kind().getPlatformKind() + ", consider assigning fixed registers.");
}
availableRegs = allocatableRegisters.allocatableRegisters.toArray(Register[]::new);
minReg = allocatableRegisters.minRegisterNumber;
maxReg = allocatableRegisters.maxRegisterNumber;
}
static boolean isMove(LIRInstruction op, Interval from, Interval to) {
if (StandardOp.ValueMoveOp.isValueMoveOp(op)) {
StandardOp.ValueMoveOp move = StandardOp.ValueMoveOp.asValueMoveOp(op);
if (LIRValueUtil.isVariable(move.getInput()) && LIRValueUtil.isVariable(move.getResult())) {
return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
}
}
return false;
}
// optimization (especially for phi functions of nested loops):
// assign same spill slot to non-intersecting intervalsView on GitHub (pinned to a66e9ccd1d)
Solutions
- In the backend's RegisterConfig/CompilationSetup, define allocatable (or at minimum fixed) registers for the failing platform kind named in the message
- Verify the kind reaches LIR correctly: if the value should have been lowered to a supported kind before allocation, fix the lowering so unallocatable kinds never survive to LSRA
- If the kind is only used behind a feature flag/arch check, ensure the frontend does not emit it on architectures where it is unsupported
- Search the repo for existing backends handling the same kind (grep getAllocatableRegisters in compiler/src/jdk.graal.compiler/src/com.oracle.graal.lir) and mirror their configuration
Example fix
// before: new vector kind has no register class -> null allocatable registers
// in MyArchRegisterConfig:
// (no entry for V512_MASK)
// after: assign registers for the kind
// map Kind.V512_MASK -> allocatable set {k0..k7} in the RegisterAllocationConfig builder Defensive patterns
Strategy: validation
Validate before calling
// Backend author: assert during setup that every kind you emit has registers
for (PlatformKind kind : arch.getPlatformKinds()) {
AllocatableRegisters regs = registerConfig.getAllocatableRegisters(kind);
if (regs == null && frontendEmits(kind)) {
throw new IllegalStateException("No allocatable registers configured for " + kind);
}
} Try / catch
try { compile(m); } catch (OutOfRegistersException e) { /* config-level bug: fail fast in tests */ throw e; } Prevention
- When adding a PlatformKind to a backend, add its register set in the same change
- Run backend smoke tests that emit every supported kind through LSRA
- Gate experimental kinds behind arch checks so they never reach allocation unconfigured
When it happens
Trigger: An interval whose LIRKind carries a PlatformKind (often a vector kind like AVX512 mask registers, or a custom kind added to a new backend) for which RegisterConfig.getAllocatableRegisters returns null. Happens with custom/new architectures, misconfigured RegisterAllocationConfig, or when a generic phase emits a kind the current backend does not allocate registers for.
Common situations: Developing or backporting a Graal backend for a new architecture; using an experimental vector kind not yet wired into the register configuration; porting a patch where RegisterConfig.registerAllocationConfig was built without an entry for the new kind.
Related errors
- register %s is not allocatable
- LogFile substitution %s cannot be combined with any other ch
- Profile file for path %s exists already
- too many counters, reduce number of counters or increase -XX
- invalid arguments to BenchmarkDynamicCounters: (err|out),sta
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/593683d738dd1eed.
Report an issue: GitHub.