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:
Dan Gohman
2018-10-19 11:09:39 -07:00
committed by Benjamin Bouvier
parent 5ea6c57b95
commit 05c0b3bdd1
2 changed files with 47 additions and 2 deletions

View 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

View File

@@ -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.