Coverage Report

Created: 2026-07-05 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/regalloc2/src/ion/reg_traversal.rs
Line
Count
Source
1
//! Iterate over available registers.
2
3
use crate::{MachineEnv, PReg, PRegSet, PRegSetIter, RegClass};
4
5
/// Keep track of where we are in the register traversal.
6
struct Cursor {
7
    first: PRegSetIter,
8
    second: PRegSetIter,
9
}
10
11
impl Cursor {
12
    #[inline]
13
27.5M
    fn new(registers: &PRegSet, class: RegClass, offset_hint: usize) -> Self {
14
27.5M
        let mut mask = PRegSet::empty();
15
27.5M
        mask.add_up_to(PReg::new(offset_hint % PReg::MAX, class));
16
27.5M
        let first = *registers & mask.invert();
17
27.5M
        let second = *registers & mask;
18
27.5M
        Self {
19
27.5M
            first: first.into_iter(),
20
27.5M
            second: second.into_iter(),
21
27.5M
        }
22
27.5M
    }
23
24
80.1M
    fn next(&mut self) -> Option<PReg> {
25
80.1M
        self.first.next().or_else(|| self.second.next())
26
80.1M
    }
27
}
28
29
/// This iterator represents a traversal through all allocatable registers of a
30
/// given class, in a certain order designed to minimize allocation contention.
31
///
32
/// The order in which we try registers is somewhat complex:
33
/// - First, if the register is fixed (i.e., pre-assigned), return that and stop
34
///   iteration.
35
/// - Then, if there is a hint, try that one.
36
/// - Next we try registers in a traversal order that is based on an "offset"
37
///   (usually the bundle index) spreading pressure evenly among registers to
38
///   reduce commitment-map contention.
39
/// - Within that scan, we try registers in two groups: first, preferred
40
///   registers; then, non-preferred registers. (In normal usage, these consist
41
///   of caller-save and callee-save registers respectively, to minimize
42
///   clobber-saves; but they need not.)
43
pub struct RegTraversalIter {
44
    is_fixed: bool,
45
    fixed: Option<PReg>,
46
    use_hint: bool,
47
    hint: Option<PReg>,
48
    preferred: Cursor,
49
    non_preferred: Cursor,
50
    limit: Option<usize>,
51
}
52
53
impl RegTraversalIter {
54
13.7M
    pub fn new(
55
13.7M
        env: &MachineEnv,
56
13.7M
        class: RegClass,
57
13.7M
        fixed: Option<PReg>,
58
13.7M
        hint: Option<PReg>,
59
13.7M
        offset: usize,
60
13.7M
        limit: Option<usize>,
61
13.7M
    ) -> Self {
62
13.7M
        debug_assert!(fixed != Some(PReg::invalid()));
63
13.7M
        debug_assert!(hint != Some(PReg::invalid()));
64
65
13.7M
        let class_index = class as u8 as usize;
66
13.7M
        let preferred = Cursor::new(&env.preferred_regs_by_class[class_index], class, offset);
67
13.7M
        let non_preferred =
68
13.7M
            Cursor::new(&env.non_preferred_regs_by_class[class_index], class, offset);
69
70
13.7M
        Self {
71
13.7M
            is_fixed: fixed.is_some(),
72
13.7M
            fixed,
73
13.7M
            use_hint: hint.is_some(),
74
13.7M
            hint,
75
13.7M
            preferred,
76
13.7M
            non_preferred,
77
13.7M
            limit,
78
13.7M
        }
79
13.7M
    }
80
}
81
82
impl core::iter::Iterator for RegTraversalIter {
83
    type Item = PReg;
84
85
73.4M
    fn next(&mut self) -> Option<PReg> {
86
73.4M
        if self.is_fixed {
87
1.10M
            return self.fixed.take();
88
72.3M
        }
89
90
72.3M
        if self.use_hint {
91
1.37M
            self.use_hint = false;
92
1.37M
            if self.hint.unwrap().hw_enc() < self.limit.unwrap_or(usize::MAX) {
93
1.37M
                return self.hint;
94
0
            }
95
70.9M
        }
96
97
71.5M
        while let Some(reg) = self.preferred.next() {
98
63.0M
            if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
99
628k
                continue; // Try again; we already tried the hint or we are outside of the register range limit.
100
62.4M
            }
101
62.4M
            return Some(reg);
102
        }
103
104
8.59M
        while let Some(reg) = self.non_preferred.next() {
105
7.76M
            if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
106
73.6k
                continue; // Try again; we already tried the hint or we are outside of the register range limit.
107
7.69M
            }
108
7.69M
            return Some(reg);
109
        }
110
111
830k
        None
112
73.4M
    }
113
}