Cranelift: update to latest regalloc2: (#4324)
- Handle call instructions' clobbers with the clobbers API, using RA2's clobbers bitmask (bytecodealliance/regalloc2#58) rather than clobbers list; - Pull in changes from bytecodealliance/regalloc2#59 for much more sane edge-case behavior w.r.t. liverange splitting.
This commit is contained in:
@@ -125,7 +125,6 @@
|
||||
|
||||
use super::abi::*;
|
||||
use crate::binemit::StackMap;
|
||||
use crate::fx::FxHashSet;
|
||||
use crate::ir::types::*;
|
||||
use crate::ir::{ArgumentExtension, ArgumentPurpose, StackSlot};
|
||||
use crate::machinst::*;
|
||||
@@ -133,6 +132,7 @@ use crate::settings;
|
||||
use crate::CodegenResult;
|
||||
use crate::{ir, isa};
|
||||
use alloc::vec::Vec;
|
||||
use regalloc2::{PReg, PRegSet};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::convert::TryFrom;
|
||||
use std::marker::PhantomData;
|
||||
@@ -475,8 +475,9 @@ pub trait ABIMachineSpec {
|
||||
/// temporary register to use to synthesize the called address, if needed.
|
||||
fn gen_call(
|
||||
dest: &CallDest,
|
||||
uses: Vec<Reg>,
|
||||
defs: Vec<Writable<Reg>>,
|
||||
uses: SmallVec<[Reg; 8]>,
|
||||
defs: SmallVec<[Writable<Reg>; 8]>,
|
||||
clobbers: PRegSet,
|
||||
opcode: ir::Opcode,
|
||||
tmp: Writable<Reg>,
|
||||
callee_conv: isa::CallConv,
|
||||
@@ -504,7 +505,7 @@ pub trait ABIMachineSpec {
|
||||
|
||||
/// Get all caller-save registers, that is, registers that we expect
|
||||
/// not to be saved across a call to a callee with the given ABI.
|
||||
fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> Vec<Writable<Reg>>;
|
||||
fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> PRegSet;
|
||||
|
||||
/// Get the needed extension mode, given the mode attached to the argument
|
||||
/// in the signature and the calling convention. The input (the attribute in
|
||||
@@ -1356,15 +1357,17 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
|
||||
}
|
||||
}
|
||||
|
||||
fn abisig_to_uses_and_defs<M: ABIMachineSpec>(sig: &ABISig) -> (Vec<Reg>, Vec<Writable<Reg>>) {
|
||||
fn abisig_to_uses_defs_clobbers<M: ABIMachineSpec>(
|
||||
sig: &ABISig,
|
||||
) -> (SmallVec<[Reg; 8]>, SmallVec<[Writable<Reg>; 8]>, PRegSet) {
|
||||
// Compute uses: all arg regs.
|
||||
let mut uses = FxHashSet::default();
|
||||
let mut uses = smallvec![];
|
||||
for arg in &sig.args {
|
||||
if let &ABIArg::Slots { ref slots, .. } = arg {
|
||||
for slot in slots {
|
||||
match slot {
|
||||
&ABIArgSlot::Reg { reg, .. } => {
|
||||
uses.insert(Reg::from(reg));
|
||||
uses.push(Reg::from(reg));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -1372,16 +1375,19 @@ fn abisig_to_uses_and_defs<M: ABIMachineSpec>(sig: &ABISig) -> (Vec<Reg>, Vec<Wr
|
||||
}
|
||||
}
|
||||
|
||||
// Get clobbers: all caller-saves. These may include return value
|
||||
// regs, which we will remove from the clobber set below.
|
||||
let mut clobbers = M::get_regs_clobbered_by_call(sig.call_conv);
|
||||
|
||||
// Compute defs: all retval regs, and all caller-save (clobbered) regs.
|
||||
let mut defs: FxHashSet<_> = M::get_regs_clobbered_by_call(sig.call_conv)
|
||||
.into_iter()
|
||||
.collect();
|
||||
let mut defs = smallvec![];
|
||||
for ret in &sig.rets {
|
||||
if let &ABIArg::Slots { ref slots, .. } = ret {
|
||||
for slot in slots {
|
||||
match slot {
|
||||
&ABIArgSlot::Reg { reg, .. } => {
|
||||
defs.insert(Writable::from_reg(Reg::from(reg)));
|
||||
defs.push(Writable::from_reg(Reg::from(reg)));
|
||||
clobbers.remove(PReg::from(reg));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -1389,12 +1395,7 @@ fn abisig_to_uses_and_defs<M: ABIMachineSpec>(sig: &ABISig) -> (Vec<Reg>, Vec<Wr
|
||||
}
|
||||
}
|
||||
|
||||
let mut uses = uses.into_iter().collect::<Vec<_>>();
|
||||
let mut defs = defs.into_iter().collect::<Vec<_>>();
|
||||
uses.sort_unstable();
|
||||
defs.sort_unstable();
|
||||
|
||||
(uses, defs)
|
||||
(uses, defs, clobbers)
|
||||
}
|
||||
|
||||
/// ABI object for a callsite.
|
||||
@@ -1404,9 +1405,11 @@ pub struct ABICallerImpl<M: ABIMachineSpec> {
|
||||
/// The called function's signature.
|
||||
sig: ABISig,
|
||||
/// All uses for the callsite, i.e., function args.
|
||||
uses: Vec<Reg>,
|
||||
/// All defs for the callsite, i.e., return values and caller-saves.
|
||||
defs: Vec<Writable<Reg>>,
|
||||
uses: SmallVec<[Reg; 8]>,
|
||||
/// All defs for the callsite, i.e., return values.
|
||||
defs: SmallVec<[Writable<Reg>; 8]>,
|
||||
/// Caller-save clobbers.
|
||||
clobbers: PRegSet,
|
||||
/// Call destination.
|
||||
dest: CallDest,
|
||||
/// Actual call opcode; used to distinguish various types of calls.
|
||||
@@ -1439,12 +1442,13 @@ impl<M: ABIMachineSpec> ABICallerImpl<M> {
|
||||
) -> CodegenResult<ABICallerImpl<M>> {
|
||||
let ir_sig = ensure_struct_return_ptr_is_returned(sig);
|
||||
let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?;
|
||||
let (uses, defs) = abisig_to_uses_and_defs::<M>(&sig);
|
||||
let (uses, defs, clobbers) = abisig_to_uses_defs_clobbers::<M>(&sig);
|
||||
Ok(ABICallerImpl {
|
||||
ir_sig,
|
||||
sig,
|
||||
uses,
|
||||
defs,
|
||||
clobbers,
|
||||
dest: CallDest::ExtName(extname.clone(), dist),
|
||||
opcode: ir::Opcode::Call,
|
||||
caller_conv,
|
||||
@@ -1464,12 +1468,13 @@ impl<M: ABIMachineSpec> ABICallerImpl<M> {
|
||||
) -> CodegenResult<ABICallerImpl<M>> {
|
||||
let ir_sig = ensure_struct_return_ptr_is_returned(sig);
|
||||
let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?;
|
||||
let (uses, defs) = abisig_to_uses_and_defs::<M>(&sig);
|
||||
let (uses, defs, clobbers) = abisig_to_uses_defs_clobbers::<M>(&sig);
|
||||
Ok(ABICallerImpl {
|
||||
ir_sig,
|
||||
sig,
|
||||
uses,
|
||||
defs,
|
||||
clobbers,
|
||||
dest: CallDest::Reg(ptr),
|
||||
opcode,
|
||||
caller_conv,
|
||||
@@ -1695,6 +1700,7 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
|
||||
&self.dest,
|
||||
uses,
|
||||
defs,
|
||||
self.clobbers,
|
||||
self.opcode,
|
||||
tmp,
|
||||
self.sig.call_conv,
|
||||
|
||||
@@ -16,7 +16,6 @@ pub type ValueArray2 = [Value; 2];
|
||||
pub type ValueArray3 = [Value; 3];
|
||||
pub type WritableReg = Writable<Reg>;
|
||||
pub type VecReg = Vec<Reg>;
|
||||
pub type VecWritableReg = Vec<WritableReg>;
|
||||
pub type ValueRegs = crate::machinst::ValueRegs<Reg>;
|
||||
pub type InstOutput = SmallVec<[ValueRegs; 2]>;
|
||||
pub type InstOutputBuilder = Cell<InstOutput>;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use crate::machinst::MachInst;
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::{fmt::Debug, hash::Hash};
|
||||
use regalloc2::{Allocation, Operand, PReg, VReg};
|
||||
use regalloc2::{Allocation, Operand, PReg, PRegSet, VReg};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
#[cfg(feature = "enable-serde")]
|
||||
@@ -290,7 +290,7 @@ pub type RegClass = regalloc2::RegClass;
|
||||
pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> {
|
||||
operands: &'a mut Vec<Operand>,
|
||||
operands_start: usize,
|
||||
clobbers: Vec<PReg>,
|
||||
clobbers: PRegSet,
|
||||
renamer: F,
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
|
||||
Self {
|
||||
operands,
|
||||
operands_start,
|
||||
clobbers: vec![],
|
||||
clobbers: PRegSet::default(),
|
||||
renamer,
|
||||
}
|
||||
}
|
||||
@@ -313,15 +313,10 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
|
||||
self.operands.push(operand);
|
||||
}
|
||||
|
||||
/// Add a clobber.
|
||||
fn add_clobber(&mut self, clobber: PReg) {
|
||||
self.clobbers.push(clobber);
|
||||
}
|
||||
|
||||
/// Finish the operand collection and return the tuple giving the
|
||||
/// range of indices in the flattened operand array, and the
|
||||
/// clobber array.
|
||||
pub fn finish(self) -> ((u32, u32), Vec<PReg>) {
|
||||
/// clobber set.
|
||||
pub fn finish(self) -> ((u32, u32), PRegSet) {
|
||||
let start = self.operands_start as u32;
|
||||
let end = self.operands.len() as u32;
|
||||
((start, end), self.clobbers)
|
||||
@@ -403,12 +398,11 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
|
||||
));
|
||||
}
|
||||
|
||||
/// Add a register clobber. This is a register that is written by
|
||||
/// the instruction, so must be reserved (not used) for the whole
|
||||
/// instruction, but is not used afterward.
|
||||
#[allow(dead_code)] // FIXME: use clobbers rather than defs for calls!
|
||||
pub fn reg_clobber(&mut self, reg: Writable<RealReg>) {
|
||||
self.add_clobber(PReg::from(reg.to_reg()));
|
||||
/// Add a register clobber set. This is a set of registers that
|
||||
/// are written by the instruction, so must be reserved (not used)
|
||||
/// for the whole instruction, but are not used afterward.
|
||||
pub fn reg_clobbers(&mut self, regs: PRegSet) {
|
||||
self.clobbers.union_from(regs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::machinst::*;
|
||||
use crate::timing;
|
||||
use crate::ValueLocRange;
|
||||
use regalloc2::{
|
||||
Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PReg,
|
||||
Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PReg, PRegSet,
|
||||
RegClass, VReg,
|
||||
};
|
||||
|
||||
@@ -79,12 +79,8 @@ pub struct VCode<I: VCodeInst> {
|
||||
/// instruction's operands.
|
||||
operand_ranges: Vec<(u32, u32)>,
|
||||
|
||||
/// Clobbers: a sparse map from instruction indices to clobber lists.
|
||||
clobber_ranges: FxHashMap<InsnIndex, (u32, u32)>,
|
||||
|
||||
/// A flat list of clobbered registers, with index ranges held by
|
||||
/// `clobber_ranges`.
|
||||
clobbers: Vec<PReg>,
|
||||
/// Clobbers: a sparse map from instruction indices to clobber masks.
|
||||
clobbers: FxHashMap<InsnIndex, PRegSet>,
|
||||
|
||||
/// Move information: for a given InsnIndex, (src, dst) operand pair.
|
||||
is_move: FxHashMap<InsnIndex, (Operand, Operand)>,
|
||||
@@ -568,13 +564,8 @@ impl<I: VCodeInst> VCodeBuilder<I> {
|
||||
let (ops, clobbers) = op_collector.finish();
|
||||
self.vcode.operand_ranges.push(ops);
|
||||
|
||||
if !clobbers.is_empty() {
|
||||
let start = self.vcode.clobbers.len();
|
||||
self.vcode.clobbers.extend(clobbers.into_iter());
|
||||
let end = self.vcode.clobbers.len();
|
||||
self.vcode
|
||||
.clobber_ranges
|
||||
.insert(InsnIndex::new(i), (start as u32, end as u32));
|
||||
if clobbers != PRegSet::default() {
|
||||
self.vcode.clobbers.insert(InsnIndex::new(i), clobbers);
|
||||
}
|
||||
|
||||
if let Some((dst, src)) = insn.is_move() {
|
||||
@@ -628,8 +619,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
insts: Vec::with_capacity(10 * n_blocks),
|
||||
operands: Vec::with_capacity(30 * n_blocks),
|
||||
operand_ranges: Vec::with_capacity(10 * n_blocks),
|
||||
clobber_ranges: FxHashMap::default(),
|
||||
clobbers: vec![],
|
||||
clobbers: FxHashMap::default(),
|
||||
is_move: FxHashMap::default(),
|
||||
srclocs: Vec::with_capacity(10 * n_blocks),
|
||||
entry: BlockIndex::new(0),
|
||||
@@ -710,13 +700,15 @@ impl<I: VCodeInst> VCode<I> {
|
||||
}
|
||||
|
||||
// Also add explicitly-clobbered registers.
|
||||
if let Some(&(start, end)) = self.clobber_ranges.get(&InsnIndex::new(i)) {
|
||||
let inst_clobbers = &self.clobbers[(start as usize)..(end as usize)];
|
||||
for &preg in inst_clobbers {
|
||||
let reg = RealReg::from(preg);
|
||||
if clobbered_set.insert(reg) {
|
||||
clobbered.push(Writable::from_reg(reg));
|
||||
}
|
||||
for preg in self
|
||||
.clobbers
|
||||
.get(&InsnIndex::new(i))
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
let reg = RealReg::from(preg);
|
||||
if clobbered_set.insert(reg) {
|
||||
clobbered.push(Writable::from_reg(reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1192,12 +1184,8 @@ impl<I: VCodeInst> RegallocFunction for VCode<I> {
|
||||
&self.operands[start as usize..end as usize]
|
||||
}
|
||||
|
||||
fn inst_clobbers(&self, insn: InsnIndex) -> &[PReg] {
|
||||
if let Some(&(start, end)) = self.clobber_ranges.get(&insn) {
|
||||
&self.clobbers[start as usize..end as usize]
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet {
|
||||
self.clobbers.get(&insn).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn num_vregs(&self) -> usize {
|
||||
|
||||
Reference in New Issue
Block a user