Skip to content

Commit b5d2ff5

Browse files
authored
Cranelift: update regalloc2 to 0.15.0 to permit more VRegs. (#12611)
* Cranelift: update regalloc2 to 0.15.0 to permit more VRegs. This pulls in bytecodealliance/regalloc2#257 to permit more VRegs to be used in a single function body, addressing #12229 and our followup discussions about supporting function body sizes up to the Wasm implementation limit standard. In addition to the RA2 upgrade, this also includes a bit more explicit limit-checking on the Cranelift side: note that we don't directly use `regalloc2::VReg` but instead we further bitpack it into `Reg`, which is logically a sum type of `VReg`, `PReg` and `SpillSlot` (the last one needed to represent stack allocation locations on defs, e.g. on callsites with many returns). `PReg`s are packed into the beginning of the `VReg` index space but `SpillSlot`s are distinguished by stealing the upper bit of a `u32`. This was previously not a problem given the smaller `VReg` index space but now we need to check explicitly; hence `Reg::from_virtual_reg_checked` and its use in the lowering vreg allocator. Because the `VReg` index packs the class into the bottom two bits, and index into the upper 30, but we steal one bit at the top, the true limit for VReg count is thus actually 2^29, or 512M. Fixes #12229. * Drop `code_too_large` test.
1 parent e581aa8 commit b5d2ff5

7 files changed

Lines changed: 36 additions & 80 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ component-async-tests = { path = "crates/misc/component-async-tests" }
322322

323323
# Bytecode Alliance maintained dependencies:
324324
# ---------------------------
325-
regalloc2 = "0.14.0"
325+
regalloc2 = "0.15.0"
326326
wasip1 = { version = "1.0.0", default-features = false }
327327

328328
# cap-std family:

cranelift/codegen/src/machinst/reg.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,28 @@ const REG_SPILLSLOT_MASK: u32 = !REG_SPILLSLOT_BIT;
5454
impl Reg {
5555
/// Const constructor: create a new Reg from a regalloc2 VReg.
5656
pub const fn from_virtual_reg(vreg: regalloc2::VReg) -> Reg {
57-
Reg(vreg.bits() as u32)
57+
let bits = vreg.bits() as u32;
58+
debug_assert!(bits <= REG_SPILLSLOT_MASK);
59+
Reg(bits)
5860
}
5961

6062
/// Const constructor: create a new Reg from a regalloc2 PReg.
6163
pub const fn from_real_reg(preg: regalloc2::PReg) -> Reg {
62-
Reg(preg_to_pinned_vreg(preg).bits() as u32)
64+
let vreg = preg_to_pinned_vreg(preg);
65+
let bits = vreg.bits() as u32;
66+
debug_assert!(bits <= REG_SPILLSLOT_MASK);
67+
Reg(bits)
68+
}
69+
70+
/// Maybe construct from a `regalloc2::VReg`, checking if the
71+
/// index is in-range for our bit-packing.
72+
pub fn from_virtual_reg_checked(vreg: regalloc2::VReg) -> Option<Reg> {
73+
let bits = vreg.bits() as u32;
74+
if bits <= REG_SPILLSLOT_MASK {
75+
Some(Reg(bits))
76+
} else {
77+
None
78+
}
6379
}
6480

6581
/// Get the physical register (`RealReg`), if this register is

cranelift/codegen/src/machinst/vcode.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,13 +1780,23 @@ impl<I: VCodeInst> VRegAllocator<I> {
17801780
}
17811781
let v = self.vreg_types.len();
17821782
let (regclasses, tys) = I::rc_for_type(ty)?;
1783-
if v + regclasses.len() >= VReg::MAX {
1783+
1784+
// Check that new indices are in-bounds for regalloc2's
1785+
// VReg/Operand representation.
1786+
if v + regclasses.len() > VReg::MAX {
17841787
return Err(CodegenError::CodeTooLarge);
17851788
}
17861789

1790+
// Check that new indices are in-bounds for our Reg
1791+
// bit-packing on top of the RA2 types, which represents
1792+
// spillslots as well.
1793+
let check = |vreg: regalloc2::VReg| -> CodegenResult<Reg> {
1794+
Reg::from_virtual_reg_checked(vreg).ok_or(CodegenError::CodeTooLarge)
1795+
};
1796+
17871797
let regs: ValueRegs<Reg> = match regclasses {
1788-
&[rc0] => ValueRegs::one(VReg::new(v, rc0).into()),
1789-
&[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()),
1798+
&[rc0] => ValueRegs::one(check(VReg::new(v, rc0))?),
1799+
&[rc0, rc1] => ValueRegs::two(check(VReg::new(v, rc0))?, check(VReg::new(v + 1, rc1))?),
17901800
// We can extend this if/when we support 32-bit targets; e.g.,
17911801
// an i128 on a 32-bit machine will need up to four machine regs
17921802
// for a `Value`.

supply-chain/imports.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,8 @@ user-login = "dtolnay"
11121112
user-name = "David Tolnay"
11131113

11141114
[[publisher.regalloc2]]
1115-
version = "0.14.0"
1116-
when = "2026-02-14"
1115+
version = "0.15.0"
1116+
when = "2026-02-17"
11171117
user-id = 3726
11181118
user-login = "cfallin"
11191119
user-name = "Chris Fallin"

tests/all/code_too_large.rs

Lines changed: 0 additions & 69 deletions
This file was deleted.

tests/all/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ mod arrays;
66
mod async_functions;
77
mod call_hook;
88
mod cli_tests;
9-
mod code_too_large;
109
mod compile_time_builtins;
1110
mod component_model;
1211
mod coredump;

0 commit comments

Comments
 (0)