1use super::{
16 AllocRegResult, Env, LiveRangeKey, LiveRangeSet, PReg, PRegIndex, RegTraversalIter,
17 SpillSetIndex, SpillSlotData, SpillSlotIndex, SpillSlotList,
18};
19use crate::{Allocation, Function, SpillSlot};
20use smallvec::smallvec;
21
22impl<'a, F: Function> Env<'a, F> {
23 pub fn try_allocating_regs_for_spilled_bundles(&mut self) {
24 trace!("allocating regs for spilled bundles");
25 for i in 0..self.spilled_bundles.len() {
26 let bundle = self.spilled_bundles[i]; if self.bundles[bundle.index()].ranges.is_empty() {
29 continue;
30 }
31
32 let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
33 let hint = self.spillsets[self.bundles[bundle.index()].spillset.index()].reg_hint;
34
35 self.bundles[bundle.index()]
38 .ranges
39 .sort_unstable_by_key(|entry| entry.range.from);
40
41 let mut success = false;
42 self.stats.spill_bundle_reg_probes += 1;
43 for preg in
44 RegTraversalIter::new(self.env, class, hint, PReg::invalid(), bundle.index(), None)
45 {
46 trace!("trying bundle {:?} to preg {:?}", bundle, preg);
47 let preg_idx = PRegIndex::new(preg.index());
48 if let AllocRegResult::Allocated(_) =
49 self.try_to_allocate_bundle_to_reg(bundle, preg_idx, None)
50 {
51 self.stats.spill_bundle_reg_success += 1;
52 success = true;
53 break;
54 }
55 }
56 if !success {
57 trace!(
58 "spilling bundle {:?}: marking spillset {:?} as required",
59 bundle,
60 self.bundles[bundle.index()].spillset
61 );
62 self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
63 }
64 }
65 }
66
67 pub fn spillslot_can_fit_spillset(
68 &mut self,
69 spillslot: SpillSlotIndex,
70 spillset: SpillSetIndex,
71 ) -> bool {
72 for &vreg in &self.spillsets[spillset.index()].vregs {
73 for entry in &self.vregs[vreg.index()].ranges {
74 if self.spillslots[spillslot.index()]
75 .ranges
76 .btree
77 .contains_key(&LiveRangeKey::from_range(&entry.range))
78 {
79 return false;
80 }
81 }
82 }
83 true
84 }
85
86 pub fn allocate_spillset_to_spillslot(
87 &mut self,
88 spillset: SpillSetIndex,
89 spillslot: SpillSlotIndex,
90 ) {
91 self.spillsets[spillset.index()].slot = spillslot;
92
93 for vreg in &self.spillsets[spillset.index()].vregs {
94 trace!(
95 "spillslot {:?} alloc'ed to spillset {:?}: vreg {:?}",
96 spillslot,
97 spillset,
98 vreg,
99 );
100 for entry in &self.vregs[vreg.index()].ranges {
101 trace!(
102 "spillslot {:?} getting range {:?} from LR {:?} from vreg {:?}",
103 spillslot,
104 entry.range,
105 entry.index,
106 vreg,
107 );
108 self.spillslots[spillslot.index()]
109 .ranges
110 .btree
111 .insert(LiveRangeKey::from_range(&entry.range), entry.index);
112 }
113 }
114 }
115
116 pub fn allocate_spillslots(&mut self) {
117 const MAX_ATTEMPTS: usize = 10;
118
119 for spillset in 0..self.spillsets.len() {
120 trace!("allocate spillslot: {}", spillset);
121 let spillset = SpillSetIndex::new(spillset);
122 if !self.spillsets[spillset.index()].required {
123 continue;
124 }
125 let size = self.spillsets[spillset.index()].size as usize;
127 if size >= self.slots_by_size.len() {
128 self.slots_by_size.resize(
129 size + 1,
130 SpillSlotList {
131 slots: smallvec![],
132 probe_start: 0,
133 },
134 );
135 }
136 let mut i = self.slots_by_size[size].probe_start;
138 let mut success = false;
139 for _attempt in 0..std::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
142 let spillslot = self.slots_by_size[size].slots[i];
150
151 if self.spillslot_can_fit_spillset(spillslot, spillset) {
152 self.allocate_spillset_to_spillslot(spillset, spillslot);
153 success = true;
154 self.slots_by_size[size].probe_start = i;
155 break;
156 }
157
158 i = self.slots_by_size[size].next_index(i);
159 }
160
161 if !success {
162 let spillslot = SpillSlotIndex::new(self.spillslots.len());
164 self.spillslots.push(SpillSlotData {
165 ranges: LiveRangeSet::new(),
166 alloc: Allocation::none(),
167 slots: size as u32,
168 });
169 self.slots_by_size[size].slots.push(spillslot);
170 self.slots_by_size[size].probe_start = self.slots_by_size[size].slots.len() - 1;
171
172 self.allocate_spillset_to_spillslot(spillset, spillslot);
173 }
174 }
175
176 for i in 0..self.spillslots.len() {
178 self.spillslots[i].alloc = self.allocate_spillslot(self.spillslots[i].slots);
179 }
180
181 trace!("spillslot allocator done");
182 }
183
184 pub fn allocate_spillslot(&mut self, size: u32) -> Allocation {
185 let mut offset = self.num_spillslots;
186 debug_assert!(size.is_power_of_two());
188 offset = (offset + size - 1) & !(size - 1);
189 let slot = if self.func.multi_spillslot_named_by_last_slot() {
190 offset + size - 1
191 } else {
192 offset
193 };
194 offset += size;
195 self.num_spillslots = offset;
196 Allocation::stack(SpillSlot::new(slot as usize))
197 }
198}