Insert copies to support a value being used as multiple return values.
When one value is used multiple times for separate return values, we need to copy it to produce a new value, so that each value can be allocated a different register.
This commit is contained in:
committed by
Benjamin Bouvier
parent
5ea6c57b95
commit
05c0b3bdd1
13
cranelift/filetests/regalloc/multiple-returns.clif
Normal file
13
cranelift/filetests/regalloc/multiple-returns.clif
Normal file
@@ -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
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
use cursor::{Cursor, EncCursor};
|
use cursor::{Cursor, EncCursor};
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use ir::{Ebb, Function, Inst, InstBuilder, SigRef, Value, ValueLoc};
|
use ir::{ArgumentLoc, Ebb, Function, Inst, InstBuilder, SigRef, Value, ValueLoc};
|
||||||
use isa::registers::{RegClassIndex, RegClassMask};
|
use isa::registers::{RegClass, RegClassIndex, RegClassMask, RegUnit};
|
||||||
use isa::{ConstraintKind, EncInfo, RecipeConstraints, RegInfo, TargetIsa};
|
use isa::{ConstraintKind, EncInfo, RecipeConstraints, RegInfo, TargetIsa};
|
||||||
use regalloc::affinity::Affinity;
|
use regalloc::affinity::Affinity;
|
||||||
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
||||||
@@ -30,6 +30,15 @@ use std::vec::Vec;
|
|||||||
use timing;
|
use timing;
|
||||||
use topo_order::TopoOrder;
|
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.
|
/// Persistent data structures for the spilling pass.
|
||||||
pub struct Spilling {
|
pub struct Spilling {
|
||||||
spills: Vec<Value>,
|
spills: Vec<Value>,
|
||||||
@@ -335,6 +344,29 @@ impl<'a> Context<'a> {
|
|||||||
self.reg_uses.push(reguse);
|
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.
|
// Collect register uses from the ABI input constraints.
|
||||||
|
|||||||
Reference in New Issue
Block a user