little tweak to avoid a div/mod on every iter of a PReg alloc loop
This commit is contained in:
@@ -23,15 +23,7 @@
|
|||||||
Performance and code-quality ideas:
|
Performance and code-quality ideas:
|
||||||
|
|
||||||
- Reduced spilling when spillslot is still "clean":
|
- Reduced spilling when spillslot is still "clean":
|
||||||
- When we allocate spillsets, use the whole bundle of a given
|
- Track 'dirty' status of reg and elide spill when not dirty.
|
||||||
spillset to check for fit. Add all bundles to spillset as we
|
|
||||||
split; then SpillSet::bundles always corresponds to original
|
|
||||||
merged bundle.
|
|
||||||
- Then a single bundle will never move between spillslots, so we
|
|
||||||
know that when we reload from the one single spillslot, it is
|
|
||||||
the last value that we spilled.
|
|
||||||
- So we can track 'dirty' status of reg and elide spill when not
|
|
||||||
dirty.
|
|
||||||
- This is slightly tricky: fixpoint problem, across edges.
|
- This is slightly tricky: fixpoint problem, across edges.
|
||||||
- We can simplify by assuming spillslot is dirty if value came
|
- We can simplify by assuming spillslot is dirty if value came
|
||||||
in on BB edge; only clean if we reload in same block we spill
|
in on BB edge; only clean if we reload in same block we spill
|
||||||
@@ -49,6 +41,11 @@
|
|||||||
- For a spillslot->spillslot move, push a fixed reg (say the
|
- For a spillslot->spillslot move, push a fixed reg (say the
|
||||||
first preferred one), reload into it, spill out of it, and then
|
first preferred one), reload into it, spill out of it, and then
|
||||||
pop old val
|
pop old val
|
||||||
|
|
||||||
|
- Avoid rebuilding MachineEnv on every function allocation in
|
||||||
|
regalloc.rs shim
|
||||||
|
|
||||||
|
- Profile allocations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#![allow(dead_code, unused_imports)]
|
#![allow(dead_code, unused_imports)]
|
||||||
@@ -137,7 +134,7 @@ struct LiveRangeListEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LiveRangeList = SmallVec<[LiveRangeListEntry; 4]>;
|
type LiveRangeList = SmallVec<[LiveRangeListEntry; 4]>;
|
||||||
type UseList = SmallVec<[Use; 4]>;
|
type UseList = SmallVec<[Use; 2]>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct LiveRange {
|
struct LiveRange {
|
||||||
@@ -689,7 +686,8 @@ struct RegTraversalIter<'a> {
|
|||||||
hint_idx: usize,
|
hint_idx: usize,
|
||||||
pref_idx: usize,
|
pref_idx: usize,
|
||||||
non_pref_idx: usize,
|
non_pref_idx: usize,
|
||||||
offset: usize,
|
offset_pref: usize,
|
||||||
|
offset_non_pref: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RegTraversalIter<'a> {
|
impl<'a> RegTraversalIter<'a> {
|
||||||
@@ -716,14 +714,26 @@ impl<'a> RegTraversalIter<'a> {
|
|||||||
hint2_reg = None;
|
hint2_reg = None;
|
||||||
}
|
}
|
||||||
let hints = [hint_reg, hint2_reg];
|
let hints = [hint_reg, hint2_reg];
|
||||||
|
let class = class as u8 as usize;
|
||||||
|
let offset_pref = if env.preferred_regs_by_class[class].len() > 0 {
|
||||||
|
offset % env.preferred_regs_by_class[class].len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let offset_non_pref = if env.non_preferred_regs_by_class[class].len() > 0 {
|
||||||
|
offset % env.non_preferred_regs_by_class[class].len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
env,
|
env,
|
||||||
class: class as u8 as usize,
|
class,
|
||||||
hints,
|
hints,
|
||||||
hint_idx: 0,
|
hint_idx: 0,
|
||||||
pref_idx: 0,
|
pref_idx: 0,
|
||||||
non_pref_idx: 0,
|
non_pref_idx: 0,
|
||||||
offset,
|
offset_pref,
|
||||||
|
offset_non_pref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -732,6 +742,13 @@ impl<'a> std::iter::Iterator for RegTraversalIter<'a> {
|
|||||||
type Item = PReg;
|
type Item = PReg;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<PReg> {
|
fn next(&mut self) -> Option<PReg> {
|
||||||
|
fn wrap(idx: usize, limit: usize) -> usize {
|
||||||
|
if idx >= limit {
|
||||||
|
idx - limit
|
||||||
|
} else {
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
}
|
||||||
if self.hint_idx < 2 && self.hints[self.hint_idx].is_some() {
|
if self.hint_idx < 2 && self.hints[self.hint_idx].is_some() {
|
||||||
let h = self.hints[self.hint_idx];
|
let h = self.hints[self.hint_idx];
|
||||||
self.hint_idx += 1;
|
self.hint_idx += 1;
|
||||||
@@ -739,7 +756,7 @@ impl<'a> std::iter::Iterator for RegTraversalIter<'a> {
|
|||||||
}
|
}
|
||||||
while self.pref_idx < self.env.preferred_regs_by_class[self.class].len() {
|
while self.pref_idx < self.env.preferred_regs_by_class[self.class].len() {
|
||||||
let arr = &self.env.preferred_regs_by_class[self.class][..];
|
let arr = &self.env.preferred_regs_by_class[self.class][..];
|
||||||
let r = arr[(self.pref_idx + self.offset) % arr.len()];
|
let r = arr[wrap(self.pref_idx + self.offset_pref, arr.len())];
|
||||||
self.pref_idx += 1;
|
self.pref_idx += 1;
|
||||||
if Some(r) == self.hints[0] || Some(r) == self.hints[1] {
|
if Some(r) == self.hints[0] || Some(r) == self.hints[1] {
|
||||||
continue;
|
continue;
|
||||||
@@ -748,7 +765,7 @@ impl<'a> std::iter::Iterator for RegTraversalIter<'a> {
|
|||||||
}
|
}
|
||||||
while self.non_pref_idx < self.env.non_preferred_regs_by_class[self.class].len() {
|
while self.non_pref_idx < self.env.non_preferred_regs_by_class[self.class].len() {
|
||||||
let arr = &self.env.non_preferred_regs_by_class[self.class][..];
|
let arr = &self.env.non_preferred_regs_by_class[self.class][..];
|
||||||
let r = arr[(self.non_pref_idx + self.offset) % arr.len()];
|
let r = arr[wrap(self.non_pref_idx + self.offset_non_pref, arr.len())];
|
||||||
self.non_pref_idx += 1;
|
self.non_pref_idx += 1;
|
||||||
if Some(r) == self.hints[0] || Some(r) == self.hints[1] {
|
if Some(r) == self.hints[0] || Some(r) == self.hints[1] {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user