From febe8e0e517f91ff831c01bc77f25d3f5fe49b9c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Thu, 14 Dec 2017 10:57:10 -0600 Subject: [PATCH] Allow spilling of EBB arguments. When the spiller needs to make a register available for a conditional branch instruction, it can be necessary to spill some of the EBB arguments on the branch instruction. This is ok because EBB argument values belong to the same virtual register as the corresponding EBB parameter and we spill the whole virtreg to the same slot. Also make sure free_regs() can handle values that are killed by the current instruction *and* spilled. --- cranelift/filetests/regalloc/spill.cton | 24 ++++++++++++++++++++++++ lib/cretonne/src/regalloc/spilling.rs | 17 ++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) 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)),