merge bundles much faster by just concatenating range-lists and unstable-sorting, rather than a merge-sort-like traversal. Rust stdlib sort is very optimized. clang.wasm 9.1s -> 6.8s now.
This commit is contained in:
102
src/ion/mod.rs
102
src/ion/mod.rs
@@ -264,6 +264,16 @@ impl LiveBundle {
|
|||||||
self.spill_weight_and_props & (1 << 29) != 0
|
self.spill_weight_and_props & (1 << 29) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_cached_fixed(&mut self) {
|
||||||
|
self.spill_weight_and_props |= 1 << 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_cached_stack(&mut self) {
|
||||||
|
self.spill_weight_and_props |= 1 << 29;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cached_spill_weight(&self) -> u32 {
|
fn cached_spill_weight(&self) -> u32 {
|
||||||
self.spill_weight_and_props & ((1 << 29) - 1)
|
self.spill_weight_and_props & ((1 << 29) - 1)
|
||||||
@@ -2071,6 +2081,11 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for a requirements conflict.
|
// Check for a requirements conflict.
|
||||||
|
if self.bundles[from.index()].cached_stack()
|
||||||
|
|| self.bundles[from.index()].cached_fixed()
|
||||||
|
|| self.bundles[to.index()].cached_stack()
|
||||||
|
|| self.bundles[to.index()].cached_fixed()
|
||||||
|
{
|
||||||
let req = self
|
let req = self
|
||||||
.compute_requirement(from)
|
.compute_requirement(from)
|
||||||
.merge(self.compute_requirement(to));
|
.merge(self.compute_requirement(to));
|
||||||
@@ -2078,6 +2093,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
log::debug!(" -> conflicting requirements; aborting merge");
|
log::debug!(" -> conflicting requirements; aborting merge");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log::debug!(" -> committing to merge");
|
log::debug!(" -> committing to merge");
|
||||||
|
|
||||||
@@ -2085,8 +2101,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
// them! We do this with a merge-sort-like scan over both
|
// them! We do this with a merge-sort-like scan over both
|
||||||
// lists, building a new range list and replacing the list on
|
// lists, building a new range list and replacing the list on
|
||||||
// `to` when we're done.
|
// `to` when we're done.
|
||||||
let mut idx_from = 0;
|
|
||||||
let mut idx_to = 0;
|
|
||||||
if ranges_from.is_empty() {
|
if ranges_from.is_empty() {
|
||||||
// `from` bundle is empty -- trivial merge.
|
// `from` bundle is empty -- trivial merge.
|
||||||
log::debug!(" -> from bundle{} is empty; trivial merge", from.index());
|
log::debug!(" -> from bundle{} is empty; trivial merge", from.index());
|
||||||
@@ -2115,52 +2129,47 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
self.bundles[to.index()].ranges = list;
|
self.bundles[to.index()].ranges = list;
|
||||||
|
|
||||||
|
if self.bundles[from.index()].cached_stack() {
|
||||||
|
self.bundles[to.index()].set_cached_stack();
|
||||||
|
}
|
||||||
|
if self.bundles[from.index()].cached_fixed() {
|
||||||
|
self.bundles[to.index()].set_cached_fixed();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two non-empty lists of LiveRanges: traverse both simultaneously and
|
|
||||||
// merge ranges into `merged`.
|
|
||||||
let mut merged: LiveRangeList = smallvec![];
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"merging: ranges_from = {:?} ranges_to = {:?}",
|
"merging: ranges_from = {:?} ranges_to = {:?}",
|
||||||
ranges_from,
|
ranges_from,
|
||||||
ranges_to
|
ranges_to
|
||||||
);
|
);
|
||||||
while idx_from < ranges_from.len() || idx_to < ranges_to.len() {
|
|
||||||
if idx_from < ranges_from.len() && idx_to < ranges_to.len() {
|
// Two non-empty lists of LiveRanges: concatenate and
|
||||||
if ranges_from[idx_from].range.from <= ranges_to[idx_to].range.from {
|
// sort. This is faster than a mergesort-like merge into a new
|
||||||
self.ranges[ranges_from[idx_from].index.index()].bundle = to;
|
// list, empirically.
|
||||||
merged.push(ranges_from[idx_from]);
|
let from_list = std::mem::replace(&mut self.bundles[from.index()].ranges, smallvec![]);
|
||||||
idx_from += 1;
|
for entry in &from_list {
|
||||||
} else {
|
|
||||||
merged.push(ranges_to[idx_to]);
|
|
||||||
idx_to += 1;
|
|
||||||
}
|
|
||||||
} else if idx_from < ranges_from.len() {
|
|
||||||
for entry in &ranges_from[idx_from..] {
|
|
||||||
self.ranges[entry.index.index()].bundle = to;
|
self.ranges[entry.index.index()].bundle = to;
|
||||||
}
|
}
|
||||||
merged.extend_from_slice(&ranges_from[idx_from..]);
|
self.bundles[to.index()]
|
||||||
break;
|
.ranges
|
||||||
} else {
|
.extend_from_slice(&from_list[..]);
|
||||||
assert!(idx_to < ranges_to.len());
|
self.bundles[to.index()]
|
||||||
merged.extend_from_slice(&ranges_to[idx_to..]);
|
.ranges
|
||||||
break;
|
.sort_unstable_by_key(|entry| entry.range.from);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
if self.annotations_enabled {
|
||||||
{
|
log::debug!("merging: merged = {:?}", self.bundles[to.index()].ranges);
|
||||||
log::debug!("merging: merged = {:?}", merged);
|
|
||||||
let mut last_range = None;
|
let mut last_range = None;
|
||||||
for entry in &merged {
|
for i in 0..self.bundles[to.index()].ranges.len() {
|
||||||
|
let entry = self.bundles[to.index()].ranges[i];
|
||||||
if last_range.is_some() {
|
if last_range.is_some() {
|
||||||
assert!(last_range.unwrap() < entry.range);
|
assert!(last_range.unwrap() < entry.range);
|
||||||
}
|
}
|
||||||
last_range = Some(entry.range);
|
last_range = Some(entry.range);
|
||||||
|
|
||||||
if self.ranges[entry.index.index()].bundle == from {
|
if self.ranges[entry.index.index()].bundle == from {
|
||||||
if self.annotations_enabled {
|
|
||||||
self.annotate(
|
self.annotate(
|
||||||
entry.range.from,
|
entry.range.from,
|
||||||
format!(
|
format!(
|
||||||
@@ -2172,7 +2181,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
" -> merged result for bundle{}: range{}",
|
" -> merged result for bundle{}: range{}",
|
||||||
@@ -2182,9 +2190,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bundles[to.index()].ranges = merged;
|
|
||||||
self.bundles[from.index()].ranges.clear();
|
|
||||||
|
|
||||||
if self.bundles[from.index()].spillset != self.bundles[to.index()].spillset {
|
if self.bundles[from.index()].spillset != self.bundles[to.index()].spillset {
|
||||||
let from_vregs = std::mem::replace(
|
let from_vregs = std::mem::replace(
|
||||||
&mut self.spillsets[self.bundles[from.index()].spillset.index()].vregs,
|
&mut self.spillsets[self.bundles[from.index()].spillset.index()].vregs,
|
||||||
@@ -2198,6 +2203,13 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.bundles[from.index()].cached_stack() {
|
||||||
|
self.bundles[to.index()].set_cached_stack();
|
||||||
|
}
|
||||||
|
if self.bundles[from.index()].cached_fixed() {
|
||||||
|
self.bundles[to.index()].set_cached_fixed();
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2239,6 +2251,28 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
self.ranges[entry.index.index()].bundle = bundle;
|
self.ranges[entry.index.index()].bundle = bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut fixed = false;
|
||||||
|
let mut stack = false;
|
||||||
|
for entry in &self.bundles[bundle.index()].ranges {
|
||||||
|
for u in &self.ranges[entry.index.index()].uses {
|
||||||
|
if let OperandPolicy::FixedReg(_) = u.operand.policy() {
|
||||||
|
fixed = true;
|
||||||
|
}
|
||||||
|
if let OperandPolicy::Stack = u.operand.policy() {
|
||||||
|
stack = true;
|
||||||
|
}
|
||||||
|
if fixed && stack {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fixed {
|
||||||
|
self.bundles[bundle.index()].set_cached_fixed();
|
||||||
|
}
|
||||||
|
if stack {
|
||||||
|
self.bundles[bundle.index()].set_cached_stack();
|
||||||
|
}
|
||||||
|
|
||||||
// Create a spillslot for this bundle.
|
// Create a spillslot for this bundle.
|
||||||
let ssidx = SpillSetIndex::new(self.spillsets.len());
|
let ssidx = SpillSetIndex::new(self.spillsets.len());
|
||||||
let reg = self.vreg_regs[vreg.index()];
|
let reg = self.vreg_regs[vreg.index()];
|
||||||
|
|||||||
Reference in New Issue
Block a user