More efficient live-range creation re: uses
This commit is contained in:
218
src/ion/mod.rs
218
src/ion/mod.rs
@@ -1350,108 +1350,145 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process defs and uses.
|
// Process defs and uses.
|
||||||
for i in 0..self.func.inst_operands(inst).len() {
|
for &cur_pos in &[InstPosition::After, InstPosition::Before] {
|
||||||
// don't borrow `self`
|
for i in 0..self.func.inst_operands(inst).len() {
|
||||||
let operand = self.func.inst_operands(inst)[i];
|
// don't borrow `self`
|
||||||
match operand.kind() {
|
let operand = self.func.inst_operands(inst)[i];
|
||||||
OperandKind::Def | OperandKind::Mod => {
|
let pos = match (operand.kind(), operand.pos()) {
|
||||||
// Create the Def object.
|
(OperandKind::Mod, _) => ProgPoint::before(inst),
|
||||||
let pos = match (operand.kind(), operand.pos()) {
|
(OperandKind::Def, OperandPos::Before) => ProgPoint::before(inst),
|
||||||
(OperandKind::Mod, _) => ProgPoint::before(inst),
|
(OperandKind::Def, OperandPos::After) => ProgPoint::after(inst),
|
||||||
(_, OperandPos::Before) => ProgPoint::before(inst),
|
(OperandKind::Use, OperandPos::After) => ProgPoint::after(inst),
|
||||||
(_, OperandPos::After) => ProgPoint::after(inst),
|
// If this is a branch, extend `pos` to
|
||||||
};
|
// the end of the block. (Branch uses are
|
||||||
let u = UseIndex(self.uses.len() as u32);
|
// blockparams and need to be live at the
|
||||||
self.uses
|
// end of the block.)
|
||||||
.push(Use::new(operand, pos, UseIndex::invalid(), i as u8));
|
(OperandKind::Use, _) if self.func.is_branch(inst) => {
|
||||||
|
self.cfginfo.block_exit[block.index()]
|
||||||
log::debug!("Def of {} at {:?}", operand.vreg(), pos);
|
|
||||||
|
|
||||||
// Fill in vreg's actual data.
|
|
||||||
self.vreg_regs[operand.vreg().vreg()] = operand.vreg();
|
|
||||||
|
|
||||||
let mut lr = vreg_ranges[operand.vreg().vreg()];
|
|
||||||
log::debug!(" -> has existing LR {:?}", lr);
|
|
||||||
// If there was no liverange (dead def), create a trivial one.
|
|
||||||
if !live.get(operand.vreg().vreg()) {
|
|
||||||
lr = self.add_liverange_to_vreg(
|
|
||||||
VRegIndex::new(operand.vreg().vreg()),
|
|
||||||
CodeRange {
|
|
||||||
from: pos,
|
|
||||||
to: pos.next(),
|
|
||||||
},
|
|
||||||
&mut num_ranges,
|
|
||||||
);
|
|
||||||
log::debug!(" -> invalid; created {:?}", lr);
|
|
||||||
}
|
}
|
||||||
self.insert_use_into_liverange_and_update_stats(lr, u);
|
|
||||||
|
|
||||||
if operand.kind() == OperandKind::Def {
|
|
||||||
// Trim the range for this vreg to start
|
|
||||||
// at `pos` if it previously ended at the
|
|
||||||
// start of this block (i.e. was not
|
|
||||||
// merged into some larger LiveRange due
|
|
||||||
// to out-of-order blocks).
|
|
||||||
if self.ranges[lr.index()].range.from
|
|
||||||
== self.cfginfo.block_entry[block.index()]
|
|
||||||
{
|
|
||||||
log::debug!(
|
|
||||||
" -> started at block start; trimming to {:?}",
|
|
||||||
pos
|
|
||||||
);
|
|
||||||
self.ranges[lr.index()].range.from = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from live-set.
|
|
||||||
live.set(operand.vreg().vreg(), false);
|
|
||||||
vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OperandKind::Use => {
|
|
||||||
// Establish where the use occurs.
|
|
||||||
let mut pos = match operand.pos() {
|
|
||||||
OperandPos::Before => ProgPoint::before(inst),
|
|
||||||
OperandPos::After => ProgPoint::after(inst),
|
|
||||||
};
|
|
||||||
// If there are any reused inputs in this
|
// If there are any reused inputs in this
|
||||||
// instruction, and this is *not* the
|
// instruction, and this is *not* the
|
||||||
// reused input, force `pos` to
|
// reused input, force `pos` to
|
||||||
// `After`. (See note below for why; it's
|
// `After`. (See note below for why; it's
|
||||||
// very subtle!)
|
// very subtle!)
|
||||||
if reused_input.is_some() && reused_input.unwrap() != i {
|
(OperandKind::Use, OperandPos::Before)
|
||||||
pos = ProgPoint::after(inst);
|
if reused_input.is_some() && reused_input.unwrap() != i =>
|
||||||
|
{
|
||||||
|
ProgPoint::after(inst)
|
||||||
}
|
}
|
||||||
// If this is a branch, extend `pos` to
|
(OperandKind::Use, OperandPos::Before) => ProgPoint::before(inst),
|
||||||
// the end of the block. (Branch uses are
|
};
|
||||||
// blockparams and need to be live at the
|
|
||||||
// end of the block.)
|
if pos.pos() != cur_pos {
|
||||||
if self.func.is_branch(inst) {
|
continue;
|
||||||
pos = self.cfginfo.block_exit[block.index()];
|
}
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"processing inst{} operand at {:?}: {:?}",
|
||||||
|
inst.index(),
|
||||||
|
pos,
|
||||||
|
operand
|
||||||
|
);
|
||||||
|
|
||||||
|
match operand.kind() {
|
||||||
|
OperandKind::Def | OperandKind::Mod => {
|
||||||
|
// Create the use object.
|
||||||
|
let u = UseIndex(self.uses.len() as u32);
|
||||||
|
self.uses.push(Use::new(
|
||||||
|
operand,
|
||||||
|
pos,
|
||||||
|
UseIndex::invalid(),
|
||||||
|
i as u8,
|
||||||
|
));
|
||||||
|
|
||||||
|
log::debug!("Def of {} at {:?}", operand.vreg(), pos);
|
||||||
|
|
||||||
|
// Fill in vreg's actual data.
|
||||||
|
self.vreg_regs[operand.vreg().vreg()] = operand.vreg();
|
||||||
|
|
||||||
|
let mut lr = vreg_ranges[operand.vreg().vreg()];
|
||||||
|
log::debug!(" -> has existing LR {:?}", lr);
|
||||||
|
// If there was no liverange (dead def), create a trivial one.
|
||||||
|
if !live.get(operand.vreg().vreg()) {
|
||||||
|
let from = match operand.kind() {
|
||||||
|
OperandKind::Def => pos,
|
||||||
|
OperandKind::Mod => self.cfginfo.block_entry[block.index()],
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
lr = self.add_liverange_to_vreg(
|
||||||
|
VRegIndex::new(operand.vreg().vreg()),
|
||||||
|
CodeRange {
|
||||||
|
from,
|
||||||
|
to: pos.next(),
|
||||||
|
},
|
||||||
|
&mut num_ranges,
|
||||||
|
);
|
||||||
|
log::debug!(" -> invalid; created {:?}", lr);
|
||||||
|
}
|
||||||
|
self.insert_use_into_liverange_and_update_stats(lr, u);
|
||||||
|
|
||||||
|
if operand.kind() == OperandKind::Def {
|
||||||
|
// Trim the range for this vreg to start
|
||||||
|
// at `pos` if it previously ended at the
|
||||||
|
// start of this block (i.e. was not
|
||||||
|
// merged into some larger LiveRange due
|
||||||
|
// to out-of-order blocks).
|
||||||
|
if self.ranges[lr.index()].range.from
|
||||||
|
== self.cfginfo.block_entry[block.index()]
|
||||||
|
{
|
||||||
|
log::debug!(
|
||||||
|
" -> started at block start; trimming to {:?}",
|
||||||
|
pos
|
||||||
|
);
|
||||||
|
self.ranges[lr.index()].range.from = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from live-set.
|
||||||
|
live.set(operand.vreg().vreg(), false);
|
||||||
|
vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
OperandKind::Use => {
|
||||||
|
// Create the use object.
|
||||||
|
let u = UseIndex(self.uses.len() as u32);
|
||||||
|
self.uses.push(Use::new(
|
||||||
|
operand,
|
||||||
|
pos,
|
||||||
|
UseIndex::invalid(),
|
||||||
|
i as u8,
|
||||||
|
));
|
||||||
|
|
||||||
// Create the actual use object.
|
// Create/extend the LiveRange if it
|
||||||
let u = UseIndex(self.uses.len() as u32);
|
// doesn't already exist, and add the use
|
||||||
self.uses
|
// to the range.
|
||||||
.push(Use::new(operand, pos, UseIndex::invalid(), i as u8));
|
let mut lr = vreg_ranges[operand.vreg().vreg()];
|
||||||
|
if !live.get(operand.vreg().vreg()) {
|
||||||
|
let range = CodeRange {
|
||||||
|
from: self.cfginfo.block_entry[block.index()],
|
||||||
|
to: pos.next(),
|
||||||
|
};
|
||||||
|
lr = self.add_liverange_to_vreg(
|
||||||
|
VRegIndex::new(operand.vreg().vreg()),
|
||||||
|
range,
|
||||||
|
&mut num_ranges,
|
||||||
|
);
|
||||||
|
vreg_ranges[operand.vreg().vreg()] = lr;
|
||||||
|
}
|
||||||
|
assert!(lr.is_valid());
|
||||||
|
|
||||||
// Create/extend the LiveRange and add the use to the range.
|
log::debug!(
|
||||||
let range = CodeRange {
|
"Use of {:?} at {:?} -> {:?} -> {:?}",
|
||||||
from: self.cfginfo.block_entry[block.index()],
|
operand,
|
||||||
to: pos.next(),
|
pos,
|
||||||
};
|
u,
|
||||||
let lr = self.add_liverange_to_vreg(
|
lr
|
||||||
VRegIndex::new(operand.vreg().vreg()),
|
);
|
||||||
range,
|
|
||||||
&mut num_ranges,
|
|
||||||
);
|
|
||||||
vreg_ranges[operand.vreg().vreg()] = lr;
|
|
||||||
|
|
||||||
log::debug!("Use of {:?} at {:?} -> {:?} -> {:?}", operand, pos, u, lr);
|
self.insert_use_into_liverange_and_update_stats(lr, u);
|
||||||
|
|
||||||
self.insert_use_into_liverange_and_update_stats(lr, u);
|
// Add to live-set.
|
||||||
|
live.set(operand.vreg().vreg(), true);
|
||||||
// Add to live-set.
|
}
|
||||||
live.set(operand.vreg().vreg(), true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3741,6 +3778,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
let mut use_iter = self.ranges[iter.index()].first_use;
|
let mut use_iter = self.ranges[iter.index()].first_use;
|
||||||
while use_iter.is_valid() {
|
while use_iter.is_valid() {
|
||||||
let usedata = &self.uses[use_iter.index()];
|
let usedata = &self.uses[use_iter.index()];
|
||||||
|
log::debug!("applying to use: {:?}", usedata);
|
||||||
debug_assert!(range.contains_point(usedata.pos));
|
debug_assert!(range.contains_point(usedata.pos));
|
||||||
let inst = usedata.pos.inst();
|
let inst = usedata.pos.inst();
|
||||||
let slot = usedata.slot();
|
let slot = usedata.slot();
|
||||||
|
|||||||
Reference in New Issue
Block a user