Skip to content

Commit 9c81860

Browse files
committed
Store PRegSet in MachineEnv
Helps to make the `MachineEnv`s in Wasmtime `const`-allocatable.
1 parent 33c6242 commit 9c81860

8 files changed

Lines changed: 104 additions & 92 deletions

File tree

src/fastalloc/lru.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ pub struct LruNode {
2828
}
2929

3030
impl Lru {
31-
pub fn new(regclass: RegClass, regs: &[PReg]) -> Self {
31+
pub fn new(regclass: RegClass, regs: &PRegSet) -> Self {
32+
let regs = regs.into_iter().collect::<Vec<_>>();
3233
let mut data = vec![
3334
LruNode {
3435
prev: u8::MAX,
@@ -248,7 +249,7 @@ impl fmt::Debug for Lru {
248249
while node != self.head {
249250
if seen.contains(&node) {
250251
panic!(
251-
"The {:?} LRU is messed up:
252+
"The {:?} LRU is messed up:
252253
head: {:?}, {:?} -> p{node}, actual data: {:?}",
253254
self.regclass, self.head, data_str, self.data
254255
);
@@ -298,7 +299,7 @@ impl<T: PartialEq> PartialEq for PartedByRegClass<T> {
298299
pub type Lrus = PartedByRegClass<Lru>;
299300

300301
impl Lrus {
301-
pub fn new(int_regs: &[PReg], float_regs: &[PReg], vec_regs: &[PReg]) -> Self {
302+
pub fn new(int_regs: &PRegSet, float_regs: &PRegSet, vec_regs: &PRegSet) -> Self {
302303
Self {
303304
items: [
304305
Lru::new(RegClass::Int, int_regs),

src/fastalloc/mod.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -444,21 +444,9 @@ impl<'a, F: Function> Env<'a, F> {
444444
env.preferred_regs_by_class[RegClass::Float as usize].clone(),
445445
env.preferred_regs_by_class[RegClass::Vector as usize].clone(),
446446
];
447-
regs[0].extend(
448-
env.non_preferred_regs_by_class[RegClass::Int as usize]
449-
.iter()
450-
.cloned(),
451-
);
452-
regs[1].extend(
453-
env.non_preferred_regs_by_class[RegClass::Float as usize]
454-
.iter()
455-
.cloned(),
456-
);
457-
regs[2].extend(
458-
env.non_preferred_regs_by_class[RegClass::Vector as usize]
459-
.iter()
460-
.cloned(),
461-
);
447+
regs[0].union_from(env.non_preferred_regs_by_class[RegClass::Int as usize]);
448+
regs[1].union_from(env.non_preferred_regs_by_class[RegClass::Float as usize]);
449+
regs[2].union_from(env.non_preferred_regs_by_class[RegClass::Vector as usize]);
462450
let allocatable_regs = PRegSet::from(env);
463451
let num_available_pregs: PartedByRegClass<i16> = PartedByRegClass {
464452
items: [
@@ -508,9 +496,9 @@ impl<'a, F: Function> Env<'a, F> {
508496
],
509497
preferred_victim: PartedByRegClass {
510498
items: [
511-
regs[0].last().cloned().unwrap_or(PReg::invalid()),
512-
regs[1].last().cloned().unwrap_or(PReg::invalid()),
513-
regs[2].last().cloned().unwrap_or(PReg::invalid()),
499+
regs[0].max_preg().unwrap_or(PReg::invalid()),
500+
regs[1].max_preg().unwrap_or(PReg::invalid()),
501+
regs[2].max_preg().unwrap_or(PReg::invalid()),
514502
],
515503
},
516504
reused_input_to_reuse_op: vec![usize::MAX; max_operand_len as usize],

src/fastalloc/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ fn mach_env(no_of_regs: usize) -> MachineEnv {
146146
(0..no_of_regs)
147147
.map(|no| PReg::new(no, RegClass::Int))
148148
.collect(),
149-
vec![],
150-
vec![],
149+
PRegSet::empty(),
150+
PRegSet::empty(),
151151
],
152-
non_preferred_regs_by_class: [vec![], vec![], vec![]],
152+
non_preferred_regs_by_class: [PRegSet::empty(); 3],
153153
scratch_by_class: [None, None, None],
154154
fixed_stack_slots: vec![],
155155
}

src/fuzzing/func.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -696,20 +696,20 @@ impl core::fmt::Debug for Func {
696696
}
697697

698698
pub fn machine_env() -> MachineEnv {
699-
fn regs(r: core::ops::Range<usize>, c: RegClass) -> Vec<PReg> {
699+
fn regs(r: core::ops::Range<usize>, c: RegClass) -> PRegSet {
700700
r.map(|i| PReg::new(i, c)).collect()
701701
}
702-
let preferred_regs_by_class: [Vec<PReg>; 3] = [
702+
let preferred_regs_by_class = [
703703
regs(0..24, RegClass::Int),
704704
regs(0..24, RegClass::Float),
705705
regs(0..24, RegClass::Vector),
706706
];
707-
let non_preferred_regs_by_class: [Vec<PReg>; 3] = [
707+
let non_preferred_regs_by_class = [
708708
regs(24..32, RegClass::Int),
709709
regs(24..32, RegClass::Float),
710710
regs(24..32, RegClass::Vector),
711711
];
712-
let scratch_by_class: [Option<PReg>; 3] = [None, None, None];
712+
let scratch_by_class = [None, None, None];
713713
let fixed_stack_slots = (32..63)
714714
.flat_map(|i| {
715715
[

src/ion/liveranges.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,8 @@ impl<'a, F: Function> Env<'a, F> {
115115
}
116116
for class in 0..self.preferred_victim_by_class.len() {
117117
self.preferred_victim_by_class[class] = self.env.non_preferred_regs_by_class[class]
118-
.last()
119-
.or(self.env.preferred_regs_by_class[class].last())
120-
.cloned()
118+
.max_preg()
119+
.or(self.env.preferred_regs_by_class[class].max_preg())
121120
.unwrap_or(PReg::invalid());
122121
}
123122
// Create VRegs from the vreg count.

src/ion/process.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,8 +1219,8 @@ impl<'a, F: Function> Env<'a, F> {
12191219
let mut fixed_assigned = 0;
12201220
let mut total_regs = 0;
12211221
for preg in self.env.preferred_regs_by_class[class as u8 as usize]
1222-
.iter()
1223-
.chain(self.env.non_preferred_regs_by_class[class as u8 as usize].iter())
1222+
.into_iter()
1223+
.chain(self.env.non_preferred_regs_by_class[class as u8 as usize])
12241224
{
12251225
trace!(" -> PR {:?}", preg);
12261226
let start = LiveRangeKey::from_range(&CodeRange {

src/ion/reg_traversal.rs

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,31 @@
11
//! Iterate over available registers.
22
3-
use crate::{MachineEnv, PReg, RegClass};
3+
use crate::{MachineEnv, PReg, PRegSet, PRegSetIter, RegClass};
44

55
/// Keep track of where we are in the register traversal.
6-
struct Cursor<'a> {
7-
registers: &'a [PReg],
8-
index: usize,
9-
offset: usize,
6+
struct Cursor {
7+
first: PRegSetIter,
8+
second: PRegSetIter,
109
}
1110

12-
impl<'a> Cursor<'a> {
11+
impl Cursor {
1312
#[inline]
14-
fn new(registers: &'a [PReg], offset_hint: usize) -> Self {
15-
let offset = if registers.len() > 0 {
16-
offset_hint % registers.len()
17-
} else {
18-
0
19-
};
20-
Self {
21-
registers,
22-
index: 0,
23-
offset,
24-
}
25-
}
26-
27-
/// Wrap around the end of the register list; [`Cursor::done`] guarantees we
28-
/// do not see the same register twice.
29-
#[inline]
30-
fn wrap(index: usize, end: usize) -> usize {
31-
if index >= end {
32-
index - end
33-
} else {
34-
index
35-
}
13+
fn new(registers: &PRegSet, offset_hint: usize) -> Self {
14+
let first = registers
15+
.into_iter()
16+
.skip(offset_hint)
17+
.collect::<PRegSet>()
18+
.into_iter();
19+
let second = registers
20+
.into_iter()
21+
.take(offset_hint)
22+
.collect::<PRegSet>()
23+
.into_iter();
24+
Self { first, second }
3625
}
3726

38-
/// Advance to the next register and return it.
39-
#[inline]
40-
fn advance(&mut self) -> PReg {
41-
let loc = Self::wrap(self.index + self.offset, self.registers.len());
42-
let reg = self.registers[loc];
43-
self.index += 1;
44-
reg
45-
}
46-
47-
/// Return `true` if we have seen all registers.
48-
#[inline]
49-
fn done(&self) -> bool {
50-
self.index >= self.registers.len()
27+
fn next(&mut self) -> Option<PReg> {
28+
self.first.next().or_else(|| self.second.next())
5129
}
5230
}
5331

@@ -65,19 +43,19 @@ impl<'a> Cursor<'a> {
6543
/// registers; then, non-preferred registers. (In normal usage, these consist
6644
/// of caller-save and callee-save registers respectively, to minimize
6745
/// clobber-saves; but they need not.)
68-
pub struct RegTraversalIter<'a> {
46+
pub struct RegTraversalIter {
6947
is_fixed: bool,
7048
fixed: Option<PReg>,
7149
use_hint: bool,
7250
hint: Option<PReg>,
73-
preferred: Cursor<'a>,
74-
non_preferred: Cursor<'a>,
51+
preferred: Cursor,
52+
non_preferred: Cursor,
7553
limit: Option<usize>,
7654
}
7755

78-
impl<'a> RegTraversalIter<'a> {
56+
impl RegTraversalIter {
7957
pub fn new(
80-
env: &'a MachineEnv,
58+
env: &MachineEnv,
8159
class: RegClass,
8260
fixed: Option<PReg>,
8361
hint: Option<PReg>,
@@ -103,7 +81,7 @@ impl<'a> RegTraversalIter<'a> {
10381
}
10482
}
10583

106-
impl<'a> core::iter::Iterator for RegTraversalIter<'a> {
84+
impl core::iter::Iterator for RegTraversalIter {
10785
type Item = PReg;
10886

10987
fn next(&mut self) -> Option<PReg> {
@@ -118,16 +96,14 @@ impl<'a> core::iter::Iterator for RegTraversalIter<'a> {
11896
}
11997
}
12098

121-
while !self.preferred.done() {
122-
let reg = self.preferred.advance();
99+
while let Some(reg) = self.preferred.next() {
123100
if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
124101
continue; // Try again; we already tried the hint or we are outside of the register range limit.
125102
}
126103
return Some(reg);
127104
}
128105

129-
while !self.non_preferred.done() {
130-
let reg = self.non_preferred.advance();
106+
while let Some(reg) = self.non_preferred.next() {
131107
if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
132108
continue; // Try again; we already tried the hint or we are outside of the register range limit.
133109
}

src/lib.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,16 @@ impl PRegSet {
293293
pub fn is_empty(&self, regclass: RegClass) -> bool {
294294
self.bits[regclass as usize] == 0
295295
}
296+
297+
/// Returns the number of register in this set.
298+
pub fn len(&self) -> u32 {
299+
self.bits.iter().map(|s| s.count_ones()).sum()
300+
}
301+
302+
/// Returns the maximum register in this set, with the highest hw_enc value.
303+
pub fn max_preg(&self) -> Option<PReg> {
304+
self.into_iter().last()
305+
}
296306
}
297307

298308
impl core::ops::BitAnd<PRegSet> for PRegSet {
@@ -315,6 +325,14 @@ impl core::ops::BitOr<PRegSet> for PRegSet {
315325
}
316326
}
317327

328+
impl IntoIterator for &PRegSet {
329+
type Item = PReg;
330+
type IntoIter = PRegSetIter;
331+
fn into_iter(self) -> PRegSetIter {
332+
(*self).into_iter()
333+
}
334+
}
335+
318336
impl IntoIterator for PRegSet {
319337
type Item = PReg;
320338
type IntoIter = PRegSetIter;
@@ -352,15 +370,11 @@ impl From<&MachineEnv> for PRegSet {
352370
let mut res = Self::default();
353371

354372
for class in env.preferred_regs_by_class.iter() {
355-
for preg in class {
356-
res.add(*preg)
357-
}
373+
res.union_from(*class)
358374
}
359375

360376
for class in env.non_preferred_regs_by_class.iter() {
361-
for preg in class {
362-
res.add(*preg)
363-
}
377+
res.union_from(*class)
364378
}
365379

366380
res
@@ -1483,7 +1497,7 @@ pub struct MachineEnv {
14831497
///
14841498
/// If an explicit scratch register is provided in `scratch_by_class` then
14851499
/// it must not appear in this list.
1486-
pub preferred_regs_by_class: [Vec<PReg>; 3],
1500+
pub preferred_regs_by_class: [PRegSet; 3],
14871501

14881502
/// Non-preferred physical registers for each class. These are the
14891503
/// registers that will be allocated if a preferred register is
@@ -1492,7 +1506,7 @@ pub struct MachineEnv {
14921506
///
14931507
/// If an explicit scratch register is provided in `scratch_by_class` then
14941508
/// it must not appear in this list.
1495-
pub non_preferred_regs_by_class: [Vec<PReg>; 3],
1509+
pub non_preferred_regs_by_class: [PRegSet; 3],
14961510

14971511
/// Optional dedicated scratch register per class. This is needed to perform
14981512
/// moves between registers when cyclic move patterns occur. The
@@ -1774,3 +1788,37 @@ unsafe impl allocator_api2::alloc::Allocator for Bump {
17741788
self.0.deref().shrink(ptr, old_layout, new_layout)
17751789
}
17761790
}
1791+
1792+
#[cfg(test)]
1793+
mod tests {
1794+
use super::{PReg, PRegSet, RegClass::Int};
1795+
1796+
#[test]
1797+
fn preg_set_len() {
1798+
let mut set = PRegSet::empty();
1799+
assert_eq!(set.len(), 0);
1800+
1801+
set.add(PReg::new(3, Int));
1802+
assert_eq!(set.len(), 1);
1803+
set.add(PReg::new(3, Int));
1804+
assert_eq!(set.len(), 1);
1805+
1806+
set.add(PReg::new(4, Int));
1807+
assert_eq!(set.len(), 2);
1808+
}
1809+
1810+
#[test]
1811+
fn preg_set_max_preg() {
1812+
let mut set = PRegSet::empty();
1813+
assert_eq!(set.max_preg(), None);
1814+
1815+
set.add(PReg::new(3, Int));
1816+
assert_eq!(set.max_preg(), Some(PReg::new(3, Int)));
1817+
1818+
set.add(PReg::new(4, Int));
1819+
assert_eq!(set.max_preg(), Some(PReg::new(4, Int)));
1820+
1821+
set.add(PReg::new(2, Int));
1822+
assert_eq!(set.max_preg(), Some(PReg::new(4, Int)));
1823+
}
1824+
}

0 commit comments

Comments
 (0)