diff --git a/filetests/regalloc/spill.cton b/filetests/regalloc/spill.cton index d30903dc2d..71c16ed50a 100644 --- a/filetests/regalloc/spill.cton +++ b/filetests/regalloc/spill.cton @@ -121,3 +121,26 @@ ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32): v10 = iadd v6, v7 return v10 } + +; More EBB arguments than registers. +function %ebbargs(i32) -> i32 { +ebb0(v1: i32): + ; check: $v1 = spill + v2 = iconst.i32 1 + jump ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2) + +ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32): + v22 = iadd v10, v11 + v23 = iadd v22, v12 + v24 = iadd v23, v13 + v25 = iadd v24, v14 + v26 = iadd v25, v15 + v27 = iadd v26, v16 + v28 = iadd v27, v17 + v29 = iadd v28, v18 + v30 = iadd v29, v19 + v31 = iadd v30, v20 + v32 = iadd v31, v21 + v33 = iadd v32, v1 + return v33 +} diff --git a/lib/cretonne/src/regalloc/pressure.rs b/lib/cretonne/src/regalloc/pressure.rs index 4839c7451a..3bf1e68f54 100644 --- a/lib/cretonne/src/regalloc/pressure.rs +++ b/lib/cretonne/src/regalloc/pressure.rs @@ -224,6 +224,14 @@ impl Pressure { e.transient_count = 0; } } + + /// Preserve the transient counts by transferring them to the base counts. + pub fn preserve_transient(&mut self) { + for e in &mut self.toprc { + e.base_count += e.transient_count; + e.transient_count = 0; + } + } } impl fmt::Display for Pressure { diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/cretonne/src/regalloc/spilling.rs index 1b438a7b50..2a05fbb8c3 100644 --- a/lib/cretonne/src/regalloc/spilling.rs +++ b/lib/cretonne/src/regalloc/spilling.rs @@ -200,8 +200,42 @@ impl<'a> Context<'a> { self.pressure.reset(); self.take_live_regs(liveins); - // TODO: Process and count EBB arguments. Some may need spilling. - self.take_live_regs(args); + // An EBB can have an arbitrary (up to 2^16...) number of EBB arguments, so they are not + // guaranteed to fit in registers. + for lv in args { + if let Affinity::Reg(rci) = lv.affinity { + let rc = self.reginfo.rc(rci); + 'try_take: while let Err(mask) = self.pressure.take_transient(rc) { + dbg!("Need {} reg for EBB argument {} from {} live-ins", + rc, + lv.value, + liveins.len()); + match self.spill_candidate(mask, liveins, dfg, layout) { + Some(cand) => { + dbg!("Spilling live-in {} to make room for {} EBB argument {}", + cand, + rc, + lv.value); + self.spill_reg(cand, dfg); + } + None => { + // We can't spill any of the live-in registers, so we have to spill an + // EBB argument. Since the current spill metric would consider all the + // EBB arguments equal, just spill the present register. + dbg!("Spilling {} EBB argument {}", rc, lv.value); + + // Since `spill_reg` will free a register, add the current one here. + self.pressure.take(rc); + self.spill_reg(lv.value, dfg); + break 'try_take; + } + } + } + } + } + + // The transient pressure counts for the EBB arguments are accurate. Just preserve them. + self.pressure.preserve_transient(); } fn visit_inst(&mut self,