Simplify pinned-vreg API: don't require slice of all pinned vregs. (#28)
Simplify pinned-vreg API: don't require slice of all pinned vregs. Previously, we kept a bool flag `is_pinned` in the `VRegData`, and we required a `&[VReg]` of all pinned vregs to be provided by `Function::pinned_vregs()`. This was (I think) done for convenience, but it turns out not to really be necessary, as we can just query `is_pinned_vreg` where needed (and in the likely implementation, e.g. in Cranelift, this will be a `< NUM_PINNED_VREGS` check that can be inlined). This adds convenience for the embedder (the main benefit), and also reduces complexity, removes some state, and avoids some work initializing the regalloc state for a run.
This commit is contained in:
@@ -259,7 +259,6 @@ pub struct VRegData {
|
||||
pub ranges: LiveRangeList,
|
||||
pub blockparam: Block,
|
||||
pub is_ref: bool,
|
||||
pub is_pinned: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -119,16 +119,12 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
ranges: smallvec![],
|
||||
blockparam: Block::invalid(),
|
||||
is_ref: false,
|
||||
is_pinned: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
for v in self.func.reftype_vregs() {
|
||||
self.vregs[v.vreg()].is_ref = true;
|
||||
}
|
||||
for v in self.func.pinned_vregs() {
|
||||
self.vregs[v.vreg()].is_pinned = true;
|
||||
}
|
||||
// Create allocations too.
|
||||
for inst in 0..self.func.num_insts() {
|
||||
let start = self.allocs.len() as u32;
|
||||
@@ -507,11 +503,13 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
debug_assert_eq!(dst.kind(), OperandKind::Def);
|
||||
debug_assert_eq!(dst.pos(), OperandPos::Late);
|
||||
|
||||
// If both src and dest are pinned, emit the
|
||||
// move right here, right now.
|
||||
if self.vregs[src.vreg().vreg()].is_pinned
|
||||
&& self.vregs[dst.vreg().vreg()].is_pinned
|
||||
{
|
||||
let src_pinned = self.func.is_pinned_vreg(src.vreg());
|
||||
let dst_pinned = self.func.is_pinned_vreg(dst.vreg());
|
||||
|
||||
match (src_pinned, dst_pinned) {
|
||||
// If both src and dest are pinned, emit
|
||||
// the move right here, right now.
|
||||
(Some(src_preg), Some(dst_preg)) => {
|
||||
// Update LRs.
|
||||
if !live.get(src.vreg().vreg()) {
|
||||
let lr = self.add_liverange_to_vreg(
|
||||
@@ -538,14 +536,6 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
);
|
||||
}
|
||||
|
||||
let src_preg = match src.constraint() {
|
||||
OperandConstraint::FixedReg(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let dst_preg = match dst.constraint() {
|
||||
OperandConstraint::FixedReg(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.insert_move(
|
||||
ProgPoint::before(inst),
|
||||
InsertMovePrio::MultiFixedReg,
|
||||
@@ -554,19 +544,19 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
Some(dst.vreg()),
|
||||
);
|
||||
}
|
||||
// If exactly one of source and dest (but not
|
||||
// both) is a pinned-vreg, convert this into a
|
||||
// ghost use on the other vreg with a FixedReg
|
||||
// constraint.
|
||||
else if self.vregs[src.vreg().vreg()].is_pinned
|
||||
|| self.vregs[dst.vreg().vreg()].is_pinned
|
||||
{
|
||||
trace!(" -> exactly one of src/dst is pinned; converting to ghost use");
|
||||
let (preg, vreg, pinned_vreg, kind, pos, progpoint) =
|
||||
if self.vregs[src.vreg().vreg()].is_pinned {
|
||||
|
||||
// If exactly one of source and dest (but
|
||||
// not both) is a pinned-vreg, convert
|
||||
// this into a ghost use on the other vreg
|
||||
// with a FixedReg constraint.
|
||||
(Some(preg), None) | (None, Some(preg)) => {
|
||||
trace!(
|
||||
" -> exactly one of src/dst is pinned; converting to ghost use"
|
||||
);
|
||||
let (vreg, pinned_vreg, kind, pos, progpoint) =
|
||||
if src_pinned.is_some() {
|
||||
// Source is pinned: this is a def on the dst with a pinned preg.
|
||||
(
|
||||
self.func.is_pinned_vreg(src.vreg()).unwrap(),
|
||||
dst.vreg(),
|
||||
src.vreg(),
|
||||
OperandKind::Def,
|
||||
@@ -576,7 +566,6 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
} else {
|
||||
// Dest is pinned: this is a use on the src with a pinned preg.
|
||||
(
|
||||
self.func.is_pinned_vreg(dst.vreg()).unwrap(),
|
||||
src.vreg(),
|
||||
dst.vreg(),
|
||||
OperandKind::Use,
|
||||
@@ -669,7 +658,8 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
pinned_lr,
|
||||
progpoint.next()
|
||||
);
|
||||
self.ranges[pinned_lr.index()].range.from = progpoint.next();
|
||||
self.ranges[pinned_lr.index()].range.from =
|
||||
progpoint.next();
|
||||
let new_lr = self.add_liverange_to_vreg(
|
||||
VRegIndex::new(pinned_vreg.vreg()),
|
||||
CodeRange {
|
||||
@@ -736,7 +726,8 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
// defined above.
|
||||
if live.get(pinned_vreg.vreg()) {
|
||||
let pinned_lr = vreg_ranges[pinned_vreg.vreg()];
|
||||
self.ranges[pinned_lr.index()].range.from = progpoint.next();
|
||||
self.ranges[pinned_lr.index()].range.from =
|
||||
progpoint.next();
|
||||
trace!(
|
||||
" -> was live with LR {:?}; truncated start to {:?}",
|
||||
pinned_lr,
|
||||
@@ -764,7 +755,10 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
// fixed-reg operand constraint, but
|
||||
// it's a dead move anyway).
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
// Ordinary move between two non-pinned vregs.
|
||||
(None, None) => {
|
||||
// Redefine src and dst operands to have
|
||||
// positions of After and Before respectively
|
||||
// (see note below), and to have Any
|
||||
@@ -893,6 +887,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -1089,8 +1084,8 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
}
|
||||
|
||||
// Insert safepoint virtual stack uses, if needed.
|
||||
for vreg in self.func.reftype_vregs() {
|
||||
if self.vregs[vreg.vreg()].is_pinned {
|
||||
for &vreg in self.func.reftype_vregs() {
|
||||
if self.func.is_pinned_vreg(vreg).is_some() {
|
||||
continue;
|
||||
}
|
||||
let vreg = VRegIndex::new(vreg.vreg());
|
||||
|
||||
@@ -234,12 +234,8 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
|
||||
// If this is a pinned vreg, go ahead and add it to the
|
||||
// commitment map, and avoid creating a bundle entirely.
|
||||
if self.vregs[vreg.index()].is_pinned {
|
||||
if let Some(preg) = self.func.is_pinned_vreg(self.vreg_regs[vreg.index()]) {
|
||||
for entry in &self.vregs[vreg.index()].ranges {
|
||||
let preg = self
|
||||
.func
|
||||
.is_pinned_vreg(self.vreg_regs[vreg.index()])
|
||||
.unwrap();
|
||||
let key = LiveRangeKey::from_range(&entry.range);
|
||||
self.pregs[preg.index()]
|
||||
.allocations
|
||||
@@ -308,8 +304,8 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
if let OperandConstraint::Reuse(reuse_idx) = op.constraint() {
|
||||
let src_vreg = op.vreg();
|
||||
let dst_vreg = self.func.inst_operands(inst)[reuse_idx].vreg();
|
||||
if self.vregs[src_vreg.vreg()].is_pinned
|
||||
|| self.vregs[dst_vreg.vreg()].is_pinned
|
||||
if self.func.is_pinned_vreg(src_vreg).is_some()
|
||||
|| self.func.is_pinned_vreg(dst_vreg).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -367,21 +363,21 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
|
||||
let dst_vreg = self.vreg_regs[self.ranges[dst.index()].vreg.index()];
|
||||
let src_vreg = self.vreg_regs[self.ranges[src.index()].vreg.index()];
|
||||
if self.vregs[src_vreg.vreg()].is_pinned && self.vregs[dst_vreg.vreg()].is_pinned {
|
||||
if self.func.is_pinned_vreg(src_vreg).is_some()
|
||||
&& self.func.is_pinned_vreg(dst_vreg).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if self.vregs[src_vreg.vreg()].is_pinned {
|
||||
if let Some(preg) = self.func.is_pinned_vreg(src_vreg) {
|
||||
let dest_bundle = self.ranges[dst.index()].bundle;
|
||||
let spillset = self.bundles[dest_bundle.index()].spillset;
|
||||
self.spillsets[spillset.index()].reg_hint =
|
||||
self.func.is_pinned_vreg(src_vreg).unwrap();
|
||||
self.spillsets[spillset.index()].reg_hint = preg;
|
||||
continue;
|
||||
}
|
||||
if self.vregs[dst_vreg.vreg()].is_pinned {
|
||||
if let Some(preg) = self.func.is_pinned_vreg(dst_vreg) {
|
||||
let src_bundle = self.ranges[src.index()].bundle;
|
||||
let spillset = self.bundles[src_bundle.index()].spillset;
|
||||
self.spillsets[spillset.index()].reg_hint =
|
||||
self.func.is_pinned_vreg(dst_vreg).unwrap();
|
||||
self.spillsets[spillset.index()].reg_hint = preg;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,11 +209,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
for vreg in 0..self.vregs.len() {
|
||||
let vreg = VRegIndex::new(vreg);
|
||||
|
||||
let pinned_alloc = if self.vregs[vreg.index()].is_pinned {
|
||||
self.func.is_pinned_vreg(self.vreg_regs[vreg.index()])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let pinned_alloc = self.func.is_pinned_vreg(self.vreg_regs[vreg.index()]);
|
||||
|
||||
// For each range in each vreg, insert moves or
|
||||
// half-moves. We also scan over `blockparam_ins` and
|
||||
|
||||
@@ -981,11 +981,6 @@ pub trait Function {
|
||||
None
|
||||
}
|
||||
|
||||
/// Return a list of all pinned vregs.
|
||||
fn pinned_vregs(&self) -> &[VReg] {
|
||||
&[]
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Spills/reloads
|
||||
// --------------
|
||||
|
||||
Reference in New Issue
Block a user