More efficient live-range creation re: uses

This commit is contained in:
Chris Fallin
2021-05-07 20:12:40 -07:00
parent a6e3128821
commit 4185eab441

View File

@@ -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();