Skip to content

Commit 2c63d5b

Browse files
committed
Redefine a minimal bundle to have only one LiveRange.
When exerting additional pressure on regalloc with bytecodealliance/wasmtime#10502, which can lead to call instructions that have significantly more (`any`-constrained) defs, we hit panics in RA2 where (i) a bundle merged several LiveRanges, (ii) one of these LiveRanges had a fixed-reg constraint on an early use, (iii) this fixed-reg constraint conflicted with a clobber (which always happens at the late-point), (iv) the bundle merged in another LiveRange of some arbitrary def at the late point. This would make a bundle (which is the atomic unit of allocation) that covers the whole inst, including the late point; and is required to be in the fixed reg; this is unallocatable because the clobber is also at the late point in that reg. Our allocate-or-split-and-retry logic does not split if a bundle is "minimal". This is meant to give a base case to the retries: when bundles break down into their minimal pieces, any solvable set of constraints should result in allocations. Unfortunately the "is minimal" predicate definition did not account for multiple LiveRanges, but rather only tested whether the total program-point range of the bundle was over one instruction. If there are multiple LiveRanges, we can still split them off, and the resulting split bundles may cover only half the instruction, avoiding the clobbers.
1 parent 3b6f83a commit 2c63d5b

File tree

1 file changed

+7
-3
lines changed

1 file changed

+7
-3
lines changed

src/ion/process.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ impl<'a, F: Function> Env<'a, F> {
268268
let mut fixed = false;
269269
let mut fixed_def = false;
270270
let bundledata = &self.ctx.bundles[bundle];
271+
let num_ranges = bundledata.ranges.len();
271272
let first_range = bundledata.ranges[0].index;
272273
let first_range_data = &self.ctx.ranges[first_range];
273274

@@ -277,7 +278,7 @@ impl<'a, F: Function> Env<'a, F> {
277278
trace!(" -> no vreg; minimal and fixed");
278279
minimal = true;
279280
fixed = true;
280-
} else {
281+
} else if num_ranges == 1 {
281282
for u in &first_range_data.uses {
282283
trace!(" -> use: {:?}", u);
283284
if let OperandConstraint::FixedReg(_) = u.operand.constraint() {
@@ -291,15 +292,18 @@ impl<'a, F: Function> Env<'a, F> {
291292
break;
292293
}
293294
}
294-
// Minimal if the range covers only one instruction. Note
295-
// that it could cover just one ProgPoint,
295+
// Minimal if there is only one LR and the ProgPoint range
296+
// covers only one instruction. Note that it could cover
297+
// just one ProgPoint,
296298
// i.e. X.Before..X.After, or two ProgPoints,
297299
// i.e. X.Before..X+1.Before.
298300
trace!(" -> first range has range {:?}", first_range_data.range);
299301
let bundle_start = self.ctx.bundles[bundle].ranges.first().unwrap().range.from;
300302
let bundle_end = self.ctx.bundles[bundle].ranges.last().unwrap().range.to;
301303
minimal = bundle_start.inst() == bundle_end.prev().inst();
302304
trace!(" -> minimal: {}", minimal);
305+
} else {
306+
minimal = false;
303307
}
304308

305309
let spill_weight = if minimal {

0 commit comments

Comments
 (0)