Use bforest::Map for representing live ranges.

Get rid of the per-value Vec in the LiveRange data type and use a
bforest::Map instead to represent the live-in intervals for non-local
live ranges.

This has some advantages:

- The memory footprint of a local live range is reduced from 40 to 20
  bytes, and
- Clearing the Liveness data structure is now a constant time operation
  which doesn't call free().
- The potentially quadratic behavior when computing large live ranges is
  controlled by the logarithmic B-tree operations.
This commit is contained in:
Jakob Stoklund Olesen
2017-12-04 13:43:10 -08:00
parent 27d5543adc
commit feaea238bc
9 changed files with 279 additions and 215 deletions

View File

@@ -89,7 +89,8 @@ impl<'a> CssaVerifier<'a> {
// Knowing that values are in RPO order, we can check for interference this
// way.
if self.liveness[prev_val].overlaps_def(def, def_ebb, &self.func.layout) {
let ctx = self.liveness.context(&self.func.layout);
if self.liveness[prev_val].overlaps_def(def, def_ebb, ctx) {
return err!(val, "Value def in {} interferes with {}", vreg, prev_val);
}
}

View File

@@ -129,18 +129,18 @@ impl<'a> LivenessVerifier<'a> {
/// Is `lr` live at the use `inst`?
fn live_at_use(&self, lr: &LiveRange, inst: Inst) -> bool {
let l = &self.func.layout;
let ctx = self.liveness.context(&self.func.layout);
// Check if `inst` is in the def range, not including the def itself.
if l.cmp(lr.def(), inst) == Ordering::Less &&
l.cmp(inst, lr.def_local_end()) != Ordering::Greater
if ctx.order.cmp(lr.def(), inst) == Ordering::Less &&
ctx.order.cmp(inst, lr.def_local_end()) != Ordering::Greater
{
return true;
}
// Otherwise see if `inst` is in one of the live-in ranges.
match lr.livein_local_end(l.inst_ebb(inst).unwrap(), l) {
Some(end) => l.cmp(inst, end) != Ordering::Greater,
match lr.livein_local_end(ctx.order.inst_ebb(inst).unwrap(), ctx) {
Some(end) => ctx.order.cmp(inst, end) != Ordering::Greater,
None => false,
}
}
@@ -205,12 +205,11 @@ impl<'a> LivenessVerifier<'a> {
}
// Now check the live-in intervals against the CFG.
for &livein in lr.liveins() {
let mut ebb = livein.begin;
for (mut ebb, end) in lr.liveins(self.liveness.context(l)) {
if !l.is_ebb_inserted(ebb) {
return err!(loc, "{} livein at {} which is not in the layout", val, ebb);
}
let end_ebb = match l.inst_ebb(livein.end) {
let end_ebb = match l.inst_ebb(end) {
Some(e) => e,
None => {
return err!(
@@ -218,7 +217,7 @@ impl<'a> LivenessVerifier<'a> {
"{} livein for {} ends at {} which is not in the layout",
val,
ebb,
livein.end
end
)
}
};

View File

@@ -282,7 +282,7 @@ impl<'a> LocationVerifier<'a> {
SingleDest(ebb, _) => {
for d in divert.all() {
let lr = &liveness[d.value];
if lr.is_livein(ebb, &self.func.layout) {
if lr.is_livein(ebb, liveness.context(&self.func.layout)) {
return err!(
inst,
"{} is diverted to {} and live in to {}",
@@ -297,7 +297,7 @@ impl<'a> LocationVerifier<'a> {
for d in divert.all() {
let lr = &liveness[d.value];
for (_, ebb) in self.func.jump_tables[jt].entries() {
if lr.is_livein(ebb, &self.func.layout) {
if lr.is_livein(ebb, liveness.context(&self.func.layout)) {
return err!(
inst,
"{} is diverted to {} and live in to {}",