How to Fix: Cranelift: unimplemented for > 64 bits
Cranelift “unimplemented for > 64 bits”: why this test fails and how to fix it
This failure happens when a Cranelift pipeline reaches an operation, legalization path, or ABI-related lowering step that requires handling an integer or value type wider than 64 bits, but the selected backend path only implements support up to native machine widths. In practice, the bug often appears in .clif test cases targeting x86_64 when multi-value returns, aggregate lowering, stack passing, or legalization produces an i128 or another oversized value that the backend does not know how to lower.
Understanding the Root Cause
The key detail is that x86_64 is a 64-bit target, but intermediate representations can still contain values wider than 64 bits. Cranelift can represent such values in IR, yet not every backend stage supports them directly. The message “unimplemented for > 64 bits” usually means one of these things happened:
- A legalization rule for an operation on i128 or a larger integer does not exist for the target.
- An ABI lowering path attempted to pass or return a value larger than the backend currently supports in that form.
- A test option such as enable_multi_ret_implicit_sret=true changed how values are returned, exposing an unsupported wide-value path.
- An aggregate, vector, or bitcast was transformed into a wide scalar that exceeds the implemented lowering width.
In your test configuration, several flags matter:
- target x86_64 means the legal native integer width is centered around 64-bit lowering behavior.
- enable_multi_ret_implicit_sret=true can force certain return-value handling through an implicit structure-return convention, which may expose backend code paths for oversized values.
- opt_level=none can preserve IR shapes that optimized pipelines might otherwise split, simplify, or rewrite before lowering.
So the root cause is not that Cranelift cannot represent the value at all. The problem is that the selected backend phase does not implement the required lowering strategy for values wider than 64 bits in that exact context.
Step-by-Step Solution
The correct fix depends on whether you are writing the test, debugging Cranelift, or patching the backend. Start by identifying which instruction or function signature introduces the oversized value.
1. Reduce the failing test to the smallest reproducer
Strip the .clif file down until only the failing function remains. Look for:
- i128 parameters or returns
- bitcast or concat/split-style transformations
- multi-value returns
- stack loads/stores involving aggregate-like wide values
test run
set enable_nan_canonicalization=true
set preserve_frame_pointers=true
set enable_multi_ret_implicit_sret=true
set opt_level=none
target x86_64 sse42 has_avx
function %problem() -> i128 {
block0:
v0 = iconst.i128 1
return v0
}
If a minimal case like this fails, you have confirmed that the unsupported path is directly tied to wide integer return lowering.
2. Check whether the failure is caused by a return, argument, or instruction legalization
Change one dimension at a time:
- Replace an i128 return with two i64 returns.
- Replace an i128 argument with two i64 arguments.
- Replace wide arithmetic with explicit low/high-half operations.
For example, this rewrite often avoids the unsupported path:
function %problem_fixed() -> i64, i64 {
block0:
lo = iconst.i64 1
hi = iconst.i64 0
return lo, hi
}
If this version works, the issue is specifically in single-value >64-bit ABI lowering, not general multi-value return support.
3. If you only need the test to pass, avoid unsupported wide scalar types
For many test scenarios, the simplest resolution is to express the same intent using multiple 64-bit values instead of one value wider than 64 bits.
; Instead of:
function %mul128(a: i128, b: i128) -> i128
; Use:
function %mul128_parts(a_lo: i64, a_hi: i64, b_lo: i64, b_hi: i64) -> i64, i64
This is the best approach if your goal is to validate surrounding logic rather than backend support for wide integers.
4. If you are fixing Cranelift itself, add or route legalization for >64-bit values
When the bug is in the compiler, the backend must either:
- Legalize the wide value into smaller machine-supported pieces, or
- Reject the IR earlier with a clearer verifier or frontend error, or
- Lower the operation through helper sequences or runtime conventions such as explicit stack passing.
The typical implementation strategy is to split i128 into two i64 halves:
// Pseudocode for legalization strategy
if value_type.bits() > 64 {
let lo = lower_half(value);
let hi = upper_half(value);
// Lower arithmetic, moves, args, or returns using lo/hi pairs.
}
For ABI handling, use explicit decomposition:
// Pseudocode
match abi_value_type {
I128 => {
assign_ret_reg_or_stack(lo_i64);
assign_ret_reg_or_stack(hi_i64);
}
_ => lower_normally()
}
If the failure occurs in instruction selection rather than ABI code, add a legalization rule that rewrites the unsupported operation into 64-bit pieces before final lowering.
5. Re-run the test with and without implicit sret
Because your issue includes enable_multi_ret_implicit_sret=true, test both behaviors.
set enable_multi_ret_implicit_sret=true
set enable_multi_ret_implicit_sret=false
If only one configuration fails, the bug is likely inside the return convention lowering path rather than the core arithmetic or value representation.
6. Validate with a narrower equivalent test
Create a control case using i64 only. If the i64 version passes and the i128 version fails, your diagnosis is confirmed.
function %control() -> i64 {
block0:
v0 = iconst.i64 1
return v0
}
7. Write a regression test after the fix
Once you fix lowering or rewrite the test, preserve the behavior with a focused regression case. Keep the test minimal so future failures clearly identify unsupported >64-bit handling.
test run
set enable_multi_ret_implicit_sret=true
set opt_level=none
target x86_64
function %regression() -> i64, i64 {
block0:
lo = iconst.i64 42
hi = iconst.i64 0
return lo, hi
}
Common Edge Cases
- Bitcasts to oversized scalars: You may not see an explicit
i128in source form, but a transform can still create one internally. - ABI mismatch across platforms: A test might behave differently on another target where wide values are split differently or passed on the stack.
- Multi-return interactions: Returning two
i64values may work while returning onei128does not, even though both represent 128 bits overall. - Verifier passes but backend fails: IR validity does not guarantee backend support for every legal-looking type and operation combination.
- Optimization-level differences: With opt_level=none, unsupported forms may survive longer. At higher optimization levels, they may be rewritten away, hiding the underlying bug.
- Stack-slot lowering: Values larger than 64 bits may fail when moved between registers and stack slots if the move/assign code assumes a single machine word.
FAQ
Why does Cranelift allow i128 in IR if x86_64 cannot handle it directly?
Because IR expressiveness and backend lowering support are different concerns. The IR can model wide values, but the backend still needs explicit rules to split or lower them into machine-supported operations.
Is splitting i128 into two i64 values a real fix or just a workaround?
It is both, depending on your goal. For application code or tests, it is often a practical workaround. For Cranelift itself, the real fix is implementing proper legalization and ABI lowering so wide values are handled automatically.
Why does enable_multi_ret_implicit_sret make this issue more visible?
That setting changes how return values are represented and passed through the calling convention. If the backend has incomplete support for oversized values in the sret or multi-return path, the failure appears immediately.
The most reliable resolution is to either avoid single values wider than 64 bits in the test or implement backend splitting/legalization for those values. If you are preparing a patch for Cranelift, focus first on the exact phase that emits “unimplemented for > 64 bits”: instruction legalization, register/stack assignment, or ABI return lowering.