/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 | | } |