diff --git a/cranelift/filetests/regalloc/multiple-returns.clif b/cranelift/filetests/regalloc/multiple-returns.clif new file mode 100644 index 0000000000..6e36c9b9b8 --- /dev/null +++ b/cranelift/filetests/regalloc/multiple-returns.clif @@ -0,0 +1,13 @@ +test regalloc +target x86_64 + +; Return the same value twice. This needs a copy so that each value can be +; allocated its own register. +function %multiple_returns() -> i64, i64 { +ebb0: + v2 = iconst.i64 0 + return v2, v2 +} +; check: v2 = iconst.i64 0 +; check: v3 = copy v2 +; check: return v2, v3 diff --git a/lib/codegen/src/regalloc/spilling.rs b/lib/codegen/src/regalloc/spilling.rs index 92b632c30a..132c98be92 100644 --- a/lib/codegen/src/regalloc/spilling.rs +++ b/lib/codegen/src/regalloc/spilling.rs @@ -17,8 +17,8 @@ use cursor::{Cursor, EncCursor}; use dominator_tree::DominatorTree; -use ir::{Ebb, Function, Inst, InstBuilder, SigRef, Value, ValueLoc}; -use isa::registers::{RegClassIndex, RegClassMask}; +use ir::{ArgumentLoc, Ebb, Function, Inst, InstBuilder, SigRef, Value, ValueLoc}; +use isa::registers::{RegClass, RegClassIndex, RegClassMask, RegUnit}; use isa::{ConstraintKind, EncInfo, RecipeConstraints, RegInfo, TargetIsa}; use regalloc::affinity::Affinity; use regalloc::live_value_tracker::{LiveValue, LiveValueTracker}; @@ -30,6 +30,15 @@ use std::vec::Vec; use timing; use topo_order::TopoOrder; +/// Return a top-level register class which contains `unit`. +fn toprc_containing_regunit(unit: RegUnit, reginfo: &RegInfo) -> RegClass { + let bank = reginfo.bank_containing_regunit(unit).unwrap(); + reginfo.classes[bank.first_toprc..(bank.first_toprc + bank.num_toprcs)] + .iter() + .find(|&rc| rc.contains(unit)) + .expect("reg unit should be in a toprc") +} + /// Persistent data structures for the spilling pass. pub struct Spilling { spills: Vec, @@ -335,6 +344,29 @@ impl<'a> Context<'a> { self.reg_uses.push(reguse); } } + + // Similarly, for return instructions, collect uses of ABI-defined + // return values. + if self.cur.func.dfg[inst].opcode().is_return() { + for (ret_idx, (ret, &arg)) in + self.cur.func.signature.returns.iter().zip(args).enumerate() + { + let idx = constraints.ins.len() + ret_idx; + let unit = match ret.location { + ArgumentLoc::Unassigned => { + panic!("function return signature should be legalized") + } + ArgumentLoc::Reg(unit) => unit, + ArgumentLoc::Stack(_) => continue, + }; + let toprc = toprc_containing_regunit(unit, &self.reginfo); + let mut reguse = RegUse::new(arg, idx, toprc.into()); + reguse.fixed = true; + + debug!(" reguse: {}", reguse); + self.reg_uses.push(reguse); + } + } } // Collect register uses from the ABI input constraints.