Misc refactorings (#116)
* Use a while-let instead of checking is_empty and popping * This conditional should always be true, as we expect the input is in ssa * Use iter_mut instead of iterating the index * We don't support multiple defs of the same vreg anymore * Drain instead of clear
This commit is contained in:
@@ -334,8 +334,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
workqueue_set.insert(block);
|
workqueue_set.insert(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
while !workqueue.is_empty() {
|
while let Some(block) = workqueue.pop_front() {
|
||||||
let block = workqueue.pop_front().unwrap();
|
|
||||||
workqueue_set.remove(&block);
|
workqueue_set.remove(&block);
|
||||||
let insns = self.func.block_insns(block);
|
let insns = self.func.block_insns(block);
|
||||||
|
|
||||||
@@ -522,140 +521,141 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
|
|
||||||
// If this is a move, handle specially.
|
// If this is a move, handle specially.
|
||||||
if let Some((src, dst)) = self.func.is_move(inst) {
|
if let Some((src, dst)) = self.func.is_move(inst) {
|
||||||
// We can completely skip the move if it is
|
assert!(
|
||||||
// trivial (vreg to same vreg).
|
src.vreg() != dst.vreg(),
|
||||||
if src.vreg() != dst.vreg() {
|
"Invalid move: overwriting an SSA value"
|
||||||
trace!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(src.class(), dst.class());
|
trace!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst);
|
||||||
debug_assert_eq!(src.kind(), OperandKind::Use);
|
|
||||||
debug_assert_eq!(src.pos(), OperandPos::Early);
|
|
||||||
debug_assert_eq!(dst.kind(), OperandKind::Def);
|
|
||||||
debug_assert_eq!(dst.pos(), OperandPos::Late);
|
|
||||||
|
|
||||||
// Redefine src and dst operands to have
|
debug_assert_eq!(src.class(), dst.class());
|
||||||
// positions of After and Before respectively
|
debug_assert_eq!(src.kind(), OperandKind::Use);
|
||||||
// (see note below), and to have Any
|
debug_assert_eq!(src.pos(), OperandPos::Early);
|
||||||
// constraints if they were originally Reg.
|
debug_assert_eq!(dst.kind(), OperandKind::Def);
|
||||||
let src_constraint = match src.constraint() {
|
debug_assert_eq!(dst.pos(), OperandPos::Late);
|
||||||
OperandConstraint::Reg => OperandConstraint::Any,
|
|
||||||
x => x,
|
// Redefine src and dst operands to have
|
||||||
};
|
// positions of After and Before respectively
|
||||||
let dst_constraint = match dst.constraint() {
|
// (see note below), and to have Any
|
||||||
OperandConstraint::Reg => OperandConstraint::Any,
|
// constraints if they were originally Reg.
|
||||||
x => x,
|
let src_constraint = match src.constraint() {
|
||||||
};
|
OperandConstraint::Reg => OperandConstraint::Any,
|
||||||
let src = Operand::new(
|
x => x,
|
||||||
src.vreg(),
|
};
|
||||||
src_constraint,
|
let dst_constraint = match dst.constraint() {
|
||||||
OperandKind::Use,
|
OperandConstraint::Reg => OperandConstraint::Any,
|
||||||
OperandPos::Late,
|
x => x,
|
||||||
|
};
|
||||||
|
let src = Operand::new(
|
||||||
|
src.vreg(),
|
||||||
|
src_constraint,
|
||||||
|
OperandKind::Use,
|
||||||
|
OperandPos::Late,
|
||||||
|
);
|
||||||
|
let dst = Operand::new(
|
||||||
|
dst.vreg(),
|
||||||
|
dst_constraint,
|
||||||
|
OperandKind::Def,
|
||||||
|
OperandPos::Early,
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.annotations_enabled {
|
||||||
|
self.annotate(
|
||||||
|
ProgPoint::after(inst),
|
||||||
|
format!(
|
||||||
|
" prog-move v{} ({:?}) -> v{} ({:?})",
|
||||||
|
src.vreg().vreg(),
|
||||||
|
src_constraint,
|
||||||
|
dst.vreg().vreg(),
|
||||||
|
dst_constraint,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
let dst = Operand::new(
|
}
|
||||||
dst.vreg(),
|
|
||||||
dst_constraint,
|
// N.B.: in order to integrate with the move
|
||||||
OperandKind::Def,
|
// resolution that joins LRs in general, we
|
||||||
OperandPos::Early,
|
// conceptually treat the move as happening
|
||||||
|
// between the move inst's After and the next
|
||||||
|
// inst's Before. Thus the src LR goes up to
|
||||||
|
// (exclusive) next-inst-pre, and the dst LR
|
||||||
|
// starts at next-inst-pre. We have to take
|
||||||
|
// care in our move insertion to handle this
|
||||||
|
// like other inter-inst moves, i.e., at
|
||||||
|
// `Regular` priority, so it properly happens
|
||||||
|
// in parallel with other inter-LR moves.
|
||||||
|
//
|
||||||
|
// Why the progpoint between move and next
|
||||||
|
// inst, and not the progpoint between prev
|
||||||
|
// inst and move? Because a move can be the
|
||||||
|
// first inst in a block, but cannot be the
|
||||||
|
// last; so the following progpoint is always
|
||||||
|
// within the same block, while the previous
|
||||||
|
// one may be an inter-block point (and the
|
||||||
|
// After of the prev inst in a different
|
||||||
|
// block).
|
||||||
|
|
||||||
|
// Handle the def w.r.t. liveranges: trim the
|
||||||
|
// start of the range and mark it dead at this
|
||||||
|
// point in our backward scan.
|
||||||
|
let pos = ProgPoint::before(inst.next());
|
||||||
|
let mut dst_lr = vreg_ranges[dst.vreg().vreg()];
|
||||||
|
if !live.get(dst.vreg().vreg()) {
|
||||||
|
let from = pos;
|
||||||
|
let to = pos.next();
|
||||||
|
dst_lr = self.add_liverange_to_vreg(
|
||||||
|
VRegIndex::new(dst.vreg().vreg()),
|
||||||
|
CodeRange { from, to },
|
||||||
);
|
);
|
||||||
|
trace!(" -> invalid LR for def; created {:?}", dst_lr);
|
||||||
|
}
|
||||||
|
trace!(" -> has existing LR {:?}", dst_lr);
|
||||||
|
// Trim the LR to start here.
|
||||||
|
if self.ranges[dst_lr.index()].range.from
|
||||||
|
== self.cfginfo.block_entry[block.index()]
|
||||||
|
{
|
||||||
|
trace!(" -> started at block start; trimming to {:?}", pos);
|
||||||
|
self.ranges[dst_lr.index()].range.from = pos;
|
||||||
|
}
|
||||||
|
self.ranges[dst_lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
|
||||||
|
live.set(dst.vreg().vreg(), false);
|
||||||
|
vreg_ranges[dst.vreg().vreg()] = LiveRangeIndex::invalid();
|
||||||
|
|
||||||
if self.annotations_enabled {
|
// Handle the use w.r.t. liveranges: make it live
|
||||||
self.annotate(
|
// and create an initial LR back to the start of
|
||||||
ProgPoint::after(inst),
|
// the block.
|
||||||
format!(
|
let pos = ProgPoint::after(inst);
|
||||||
" prog-move v{} ({:?}) -> v{} ({:?})",
|
let src_lr = if !live.get(src.vreg().vreg()) {
|
||||||
src.vreg().vreg(),
|
let range = CodeRange {
|
||||||
src_constraint,
|
from: self.cfginfo.block_entry[block.index()],
|
||||||
dst.vreg().vreg(),
|
to: pos.next(),
|
||||||
dst_constraint,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// N.B.: in order to integrate with the move
|
|
||||||
// resolution that joins LRs in general, we
|
|
||||||
// conceptually treat the move as happening
|
|
||||||
// between the move inst's After and the next
|
|
||||||
// inst's Before. Thus the src LR goes up to
|
|
||||||
// (exclusive) next-inst-pre, and the dst LR
|
|
||||||
// starts at next-inst-pre. We have to take
|
|
||||||
// care in our move insertion to handle this
|
|
||||||
// like other inter-inst moves, i.e., at
|
|
||||||
// `Regular` priority, so it properly happens
|
|
||||||
// in parallel with other inter-LR moves.
|
|
||||||
//
|
|
||||||
// Why the progpoint between move and next
|
|
||||||
// inst, and not the progpoint between prev
|
|
||||||
// inst and move? Because a move can be the
|
|
||||||
// first inst in a block, but cannot be the
|
|
||||||
// last; so the following progpoint is always
|
|
||||||
// within the same block, while the previous
|
|
||||||
// one may be an inter-block point (and the
|
|
||||||
// After of the prev inst in a different
|
|
||||||
// block).
|
|
||||||
|
|
||||||
// Handle the def w.r.t. liveranges: trim the
|
|
||||||
// start of the range and mark it dead at this
|
|
||||||
// point in our backward scan.
|
|
||||||
let pos = ProgPoint::before(inst.next());
|
|
||||||
let mut dst_lr = vreg_ranges[dst.vreg().vreg()];
|
|
||||||
if !live.get(dst.vreg().vreg()) {
|
|
||||||
let from = pos;
|
|
||||||
let to = pos.next();
|
|
||||||
dst_lr = self.add_liverange_to_vreg(
|
|
||||||
VRegIndex::new(dst.vreg().vreg()),
|
|
||||||
CodeRange { from, to },
|
|
||||||
);
|
|
||||||
trace!(" -> invalid LR for def; created {:?}", dst_lr);
|
|
||||||
}
|
|
||||||
trace!(" -> has existing LR {:?}", dst_lr);
|
|
||||||
// Trim the LR to start here.
|
|
||||||
if self.ranges[dst_lr.index()].range.from
|
|
||||||
== self.cfginfo.block_entry[block.index()]
|
|
||||||
{
|
|
||||||
trace!(" -> started at block start; trimming to {:?}", pos);
|
|
||||||
self.ranges[dst_lr.index()].range.from = pos;
|
|
||||||
}
|
|
||||||
self.ranges[dst_lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
|
|
||||||
live.set(dst.vreg().vreg(), false);
|
|
||||||
vreg_ranges[dst.vreg().vreg()] = LiveRangeIndex::invalid();
|
|
||||||
|
|
||||||
// Handle the use w.r.t. liveranges: make it live
|
|
||||||
// and create an initial LR back to the start of
|
|
||||||
// the block.
|
|
||||||
let pos = ProgPoint::after(inst);
|
|
||||||
let src_lr = if !live.get(src.vreg().vreg()) {
|
|
||||||
let range = CodeRange {
|
|
||||||
from: self.cfginfo.block_entry[block.index()],
|
|
||||||
to: pos.next(),
|
|
||||||
};
|
|
||||||
let src_lr = self
|
|
||||||
.add_liverange_to_vreg(VRegIndex::new(src.vreg().vreg()), range);
|
|
||||||
vreg_ranges[src.vreg().vreg()] = src_lr;
|
|
||||||
src_lr
|
|
||||||
} else {
|
|
||||||
vreg_ranges[src.vreg().vreg()]
|
|
||||||
};
|
};
|
||||||
|
let src_lr =
|
||||||
|
self.add_liverange_to_vreg(VRegIndex::new(src.vreg().vreg()), range);
|
||||||
|
vreg_ranges[src.vreg().vreg()] = src_lr;
|
||||||
|
src_lr
|
||||||
|
} else {
|
||||||
|
vreg_ranges[src.vreg().vreg()]
|
||||||
|
};
|
||||||
|
|
||||||
trace!(" -> src LR {:?}", src_lr);
|
trace!(" -> src LR {:?}", src_lr);
|
||||||
|
|
||||||
// Add to live-set.
|
// Add to live-set.
|
||||||
let src_is_dead_after_move = !live.get(src.vreg().vreg());
|
let src_is_dead_after_move = !live.get(src.vreg().vreg());
|
||||||
live.set(src.vreg().vreg(), true);
|
live.set(src.vreg().vreg(), true);
|
||||||
|
|
||||||
// Add to program-moves lists.
|
// Add to program-moves lists.
|
||||||
self.prog_move_srcs.push((
|
self.prog_move_srcs.push((
|
||||||
(VRegIndex::new(src.vreg().vreg()), inst),
|
(VRegIndex::new(src.vreg().vreg()), inst),
|
||||||
Allocation::none(),
|
Allocation::none(),
|
||||||
));
|
));
|
||||||
self.prog_move_dsts.push((
|
self.prog_move_dsts.push((
|
||||||
(VRegIndex::new(dst.vreg().vreg()), inst.next()),
|
(VRegIndex::new(dst.vreg().vreg()), inst.next()),
|
||||||
Allocation::none(),
|
Allocation::none(),
|
||||||
));
|
));
|
||||||
self.stats.prog_moves += 1;
|
self.stats.prog_moves += 1;
|
||||||
if src_is_dead_after_move {
|
if src_is_dead_after_move {
|
||||||
self.stats.prog_moves_dead_src += 1;
|
self.stats.prog_moves_dead_src += 1;
|
||||||
self.prog_move_merges.push((src_lr, dst_lr));
|
self.prog_move_merges.push((src_lr, dst_lr));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -959,12 +959,9 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for range in 0..self.ranges.len() {
|
for range in &mut self.ranges {
|
||||||
self.ranges[range].uses.reverse();
|
range.uses.reverse();
|
||||||
debug_assert!(self.ranges[range]
|
debug_assert!(range.uses.windows(2).all(|win| win[0].pos <= win[1].pos));
|
||||||
.uses
|
|
||||||
.windows(2)
|
|
||||||
.all(|win| win[0].pos <= win[1].pos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert safepoint virtual stack uses, if needed.
|
// Insert safepoint virtual stack uses, if needed.
|
||||||
@@ -1032,7 +1029,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
|
|
||||||
pub fn fixup_multi_fixed_vregs(&mut self) {
|
pub fn fixup_multi_fixed_vregs(&mut self) {
|
||||||
// Do a fixed-reg cleanup pass: if there are any LiveRanges with
|
// Do a fixed-reg cleanup pass: if there are any LiveRanges with
|
||||||
// multiple uses (or defs) at the same ProgPoint and there is
|
// multiple uses at the same ProgPoint and there is
|
||||||
// more than one FixedReg constraint at that ProgPoint, we
|
// more than one FixedReg constraint at that ProgPoint, we
|
||||||
// need to record all but one of them in a special fixup list
|
// need to record all but one of them in a special fixup list
|
||||||
// and handle them later; otherwise, bundle-splitting to
|
// and handle them later; otherwise, bundle-splitting to
|
||||||
@@ -1154,15 +1151,13 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for &(clobber, pos) in &extra_clobbers {
|
for (clobber, pos) in extra_clobbers.drain(..) {
|
||||||
let range = CodeRange {
|
let range = CodeRange {
|
||||||
from: pos,
|
from: pos,
|
||||||
to: pos.next(),
|
to: pos.next(),
|
||||||
};
|
};
|
||||||
self.add_liverange_to_preg(range, clobber);
|
self.add_liverange_to_preg(range, clobber);
|
||||||
}
|
}
|
||||||
|
|
||||||
extra_clobbers.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user