diff --git a/cranelift/filetests/regalloc/spill.cton b/cranelift/filetests/regalloc/spill.cton index 8f00c93184..adafc89b43 100644 --- a/cranelift/filetests/regalloc/spill.cton +++ b/cranelift/filetests/regalloc/spill.cton @@ -145,6 +145,30 @@ ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: return v33 } +; Spilling an EBB argument to make room for a branch operand. +function %brargs(i32) -> i32 { +ebb0(v1: i32): + ; check: $v1 = spill + v2 = iconst.i32 1 + brnz v1, ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2) + return v1 + +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 +} + ; In straight-line code, the first value defined is spilled. ; That is in order: ; 1. The argument v1. diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/cretonne/src/regalloc/spilling.rs index 6eef88141d..4c5b8b9ec7 100644 --- a/lib/cretonne/src/regalloc/spilling.rs +++ b/lib/cretonne/src/regalloc/spilling.rs @@ -155,8 +155,10 @@ impl<'a> Context<'a> { fn free_regs(&mut self, kills: &[LiveValue]) { for lv in kills { if let Affinity::Reg(rci) = lv.affinity { - let rc = self.reginfo.rc(rci); - self.pressure.free(rc); + if !self.spills.contains(&lv.value) { + let rc = self.reginfo.rc(rci); + self.pressure.free(rc); + } } } } @@ -402,8 +404,17 @@ impl<'a> Context<'a> { dbg!("Copy of {} reg causes spill", rc); // Spill a live register that is *not* used by the current instruction. // Spilling a use wouldn't help. + // + // Do allow spilling of EBB arguments on branches. This is safe since we spill + // the whole virtual register which includes the matching EBB parameter value + // at the branch destination. It is also necessary since there can be + // arbitrarily many EBB arguments. match { - let args = self.cur.func.dfg.inst_args(inst); + let args = if self.cur.func.dfg[inst].opcode().is_branch() { + self.cur.func.dfg.inst_fixed_args(inst) + } else { + self.cur.func.dfg.inst_args(inst) + }; self.spill_candidate( mask, tracker.live().iter().filter(|lv| !args.contains(&lv.value)),