Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clobbers: use a more efficient bitmask representation in API. #58

Merged
merged 2 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ impl<'a, F: Function> Checker<'a, F> {
else if !self.f.is_branch(inst) {
let operands: Vec<_> = self.f.inst_operands(inst).iter().cloned().collect();
let allocs: Vec<_> = out.inst_allocs(inst).iter().cloned().collect();
let clobbers: Vec<_> = self.f.inst_clobbers(inst).iter().cloned().collect();
let clobbers: Vec<_> = self.f.inst_clobbers(inst).into_iter().collect();
let checkinst = CheckerInst::Op {
inst,
operands,
Expand Down
10 changes: 7 additions & 3 deletions src/fuzzing/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use crate::{
domtree, postorder, Allocation, Block, Function, Inst, InstRange, MachineEnv, Operand,
OperandConstraint, OperandKind, OperandPos, PReg, RegClass, VReg,
OperandConstraint, OperandKind, OperandPos, PReg, PRegMask, RegClass, VReg,
};

use arbitrary::Result as ArbitraryResult;
Expand Down Expand Up @@ -132,8 +132,12 @@ impl Function for Func {
&self.insts[insn.index()].operands[..]
}

fn inst_clobbers(&self, insn: Inst) -> &[PReg] {
&self.insts[insn.index()].clobbers[..]
fn inst_clobbers(&self, insn: Inst) -> PRegMask {
let mut mask = PRegMask::default();
for &preg in &self.insts[insn.index()].clobbers {
mask = mask.with(preg);
}
mask
}

fn num_vregs(&self) -> usize {
Expand Down
2 changes: 1 addition & 1 deletion src/ion/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl<'a, F: Function> Env<'a, F> {
let clobbers = self
.func
.inst_clobbers(inst)
.iter()
.into_iter()
.map(|preg| format!("{}", preg))
.collect::<Vec<_>>();
let allocs = (0..ops.len())
Expand Down
4 changes: 1 addition & 3 deletions src/ion/liveranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,9 +491,7 @@ impl<'a, F: Function> Env<'a, F> {
// operands and clobbers.
for inst in insns.rev().iter() {
// Mark clobbers with CodeRanges on PRegs.
for i in 0..self.func.inst_clobbers(inst).len() {
// don't borrow `self`
let clobber = self.func.inst_clobbers(inst)[i];
for clobber in self.func.inst_clobbers(inst) {
// Clobber range is at After point only: an
// instruction can still take an input in a reg
// that it later clobbers. (In other words, the
Expand Down
2 changes: 1 addition & 1 deletion src/ion/moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ impl<'a, F: Function> Env<'a, F> {
}
}
for reg in this.func.inst_clobbers(inst) {
redundant_moves.clear_alloc(Allocation::reg(*reg));
redundant_moves.clear_alloc(Allocation::reg(reg));
}
}
}
Expand Down
84 changes: 80 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,13 @@ impl PReg {
/// all physical registers. Allows one to maintain an array of data for
/// all PRegs and index it efficiently.
#[inline(always)]
pub fn index(self) -> usize {
pub const fn index(self) -> usize {
self.bits as usize
}

/// Construct a PReg from the value returned from `.index()`.
#[inline(always)]
pub fn from_index(index: usize) -> Self {
pub const fn from_index(index: usize) -> Self {
PReg {
bits: (index & (Self::NUM_INDEX - 1)) as u8,
}
Expand Down Expand Up @@ -165,6 +165,75 @@ impl std::fmt::Display for PReg {
}
}

/// A physical register mask: a set of physical registers. Used to
/// represent clobbers efficiently.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct PRegMask {
cfallin marked this conversation as resolved.
Show resolved Hide resolved
bits: u128,
}

impl PRegMask {
/// Create an empty mask.
pub const fn empty() -> Self {
Self { bits: 0 }
}

/// Add a physical register (PReg) to the mask, returning the new value.
pub const fn with(self, reg: PReg) -> Self {
let bit = reg.index();
debug_assert!(bit < 128);
Self {
bits: self.bits | (1u128 << bit),
}
}

/// Add a physical register (PReg) to the mask.
pub fn add(&mut self, reg: PReg) {
let bit = reg.index();
debug_assert!(bit < 128);
self.bits |= 1u128 << bit;
}

/// Remove a physical register (PReg) from the mask.
pub fn remove(&mut self, reg: PReg) {
let bit = reg.index();
debug_assert!(bit < 128);
self.bits &= !(1u128 << bit);
}

/// Add all of the registers in one clobber mask to this one,
/// mutating in place.
pub fn add_all(&mut self, other: PRegMask) {
cfallin marked this conversation as resolved.
Show resolved Hide resolved
self.bits |= other.bits;
}
}

impl IntoIterator for PRegMask {
type Item = PReg;
type IntoIter = PRegMaskIter;
fn into_iter(self) -> PRegMaskIter {
PRegMaskIter { bits: self.bits }
}
}

pub struct PRegMaskIter {
bits: u128,
}

impl Iterator for PRegMaskIter {
type Item = PReg;
fn next(&mut self) -> Option<PReg> {
if self.bits == 0 {
None
} else {
let index = self.bits.trailing_zeros();
self.bits &= !(1u128 << index);
Some(PReg::from_index(index as usize))
}
}
}

/// A virtual register. Contains a virtual register number and a
/// class.
///
Expand Down Expand Up @@ -198,7 +267,7 @@ impl VReg {
}

#[inline(always)]
pub fn vreg(self) -> usize {
pub const fn vreg(self) -> usize {
let vreg = (self.bits >> 1) as usize;
vreg
}
Expand Down Expand Up @@ -972,7 +1041,14 @@ pub trait Function {
/// fixed physical registers written by an instruction but not
/// used as a vreg output, or fixed physical registers used as
/// temps within an instruction out of necessity.
fn inst_clobbers(&self, insn: Inst) -> &[PReg];
///
/// Note that it is legal for a register to be both a clobber and
/// an actual def (via pinned vreg or via operand constrained to
/// the reg). This is for convenience: e.g., a call instruction
/// might have a constant clobber mask determined by the ABI, but
/// some of those clobbered registers are sometimes return
/// value(s).
fn inst_clobbers(&self, insn: Inst) -> PRegMask;

/// Get the number of `VReg` in use in this function.
fn num_vregs(&self) -> usize;
Expand Down