1 use super::{
2     last_use, next_use, IntId, Intervals, Mention, MentionMap, OptimalSplitStrategy, RegUses,
3     Statistics, VirtualInterval,
4 };
5 use crate::{
6     data_structures::{InstPoint, Point, RegVecsAndBounds},
7     Function, InstIx, LinearScanOptions, RealReg, RealRegUniverse, Reg, RegAllocError, SpillSlot,
8     VirtualReg, NUM_REG_CLASSES,
9 };
10 
11 use log::{debug, info, log_enabled, trace, Level};
12 use rustc_hash::FxHashMap as HashMap;
13 use smallvec::SmallVec;
14 use std::collections::BinaryHeap;
15 use std::{cmp, cmp::Ordering, fmt};
16 
17 macro_rules! lsra_assert {
18     ($arg:expr) => {
19         #[cfg(debug_assertions)]
20         debug_assert!($arg);
21     };
22 
23     ($arg:expr, $text:expr) => {
24         #[cfg(debug_assertions)]
25         debug_assert!($arg, $text);
26     };
27 }
28 
29 #[derive(Clone, Copy, PartialEq)]
30 enum ActiveInt {
31     Virtual(IntId),
32     Fixed((RealReg, usize)),
33 }
34 
35 impl fmt::Debug for ActiveInt {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result36     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
37         match self {
38             ActiveInt::Virtual(id) => write!(fmt, "virtual({:?})", id),
39             ActiveInt::Fixed((rreg, _)) => write!(fmt, "real({:?})", rreg),
40         }
41     }
42 }
43 
44 struct ActivityTracker {
45     /// Intervals that are covering the current interval's start position.
46     /// TODO Invariant: they always have a register attached to them.
47     active: Vec<ActiveInt>,
48 
49     /// Intervals that are not covering but end after the current interval's start position.
50     /// None means that the interval may have fragments, but they all live after the current
51     /// position.
52     /// TODO Invariant: they're all fixed registers, so they must have a register attached to them.
53     inactive: Vec<(RealReg, usize)>,
54 }
55 
56 impl ActivityTracker {
new(intervals: &Intervals) -> Self57     fn new(intervals: &Intervals) -> Self {
58         let mut inactive = Vec::with_capacity(intervals.fixeds.len());
59         for fixed in &intervals.fixeds {
60             if !fixed.frags.is_empty() {
61                 inactive.push((fixed.reg, 0))
62             }
63         }
64 
65         Self {
66             active: Vec::new(),
67             inactive,
68         }
69     }
70 
set_active(&mut self, id: IntId)71     fn set_active(&mut self, id: IntId) {
72         self.active.push(ActiveInt::Virtual(id));
73     }
74 
update(&mut self, start: InstPoint, stats: &mut Option<Statistics>, intervals: &Intervals)75     fn update(&mut self, start: InstPoint, stats: &mut Option<Statistics>, intervals: &Intervals) {
76         // From active, only possible transitions are to active or expired.
77         // From inactive, only possible transitions are to inactive, active or expired.
78         // => active has an upper bound.
79         // => inactive only shrinks.
80         let mut to_delete: SmallVec<[usize; 16]> = SmallVec::new();
81         let mut new_inactive: SmallVec<[(RealReg, usize); 16]> = SmallVec::new();
82 
83         for (i, id) in self.active.iter_mut().enumerate() {
84             match id {
85                 ActiveInt::Virtual(int_id) => {
86                     let int = intervals.get(*int_id);
87 
88                     if int.location.spill().is_some() {
89                         // TODO these shouldn't appear here...
90                         to_delete.push(i);
91                         continue;
92                     }
93                     //debug_assert!(int.location.spill().is_none(), "active int must have a reg");
94 
95                     if int.end < start {
96                         // It's expired, forget about it.
97                         to_delete.push(i);
98                     } else {
99                         // Stays active.
100                         lsra_assert!(int.covers(start), "no active to inactive transition");
101                     }
102                 }
103 
104                 ActiveInt::Fixed((rreg, ref mut fix)) => {
105                     // Possible transitions: active => { active, inactive, expired }.
106                     let frags = &intervals.fixeds[rreg.get_index()].frags;
107 
108                     // Fast-forward to the first fragment that contains or is after start.
109                     while *fix < frags.len() && start > frags[*fix].last {
110                         *fix += 1;
111                     }
112 
113                     if *fix == frags.len() {
114                         // It expired, remove it from the active list.
115                         to_delete.push(i);
116                     } else if start < frags[*fix].first {
117                         // It is now inactive.
118                         lsra_assert!(!frags[*fix].contains(&start));
119                         new_inactive.push((*rreg, *fix));
120                         to_delete.push(i);
121                     } else {
122                         // Otherwise, it's still active.
123                         lsra_assert!(frags[*fix].contains(&start));
124                     }
125                 }
126             }
127         }
128 
129         for &i in to_delete.iter().rev() {
130             self.active.swap_remove(i);
131         }
132         to_delete.clear();
133 
134         for (i, (rreg, fix)) in self.inactive.iter_mut().enumerate() {
135             // Possible transitions: inactive => { active, inactive, expired }.
136             let frags = &intervals.fixeds[rreg.get_index()].frags;
137 
138             // Fast-forward to the first fragment that contains or is after start.
139             while *fix < frags.len() && start > frags[*fix].last {
140                 *fix += 1;
141             }
142 
143             if *fix == frags.len() {
144                 // It expired, remove it from the inactive list.
145                 to_delete.push(i);
146             } else if start >= frags[*fix].first {
147                 // It is now active.
148                 lsra_assert!(frags[*fix].contains(&start));
149                 self.active.push(ActiveInt::Fixed((*rreg, *fix)));
150                 to_delete.push(i);
151             } else {
152                 // Otherwise it remains inactive.
153                 lsra_assert!(!frags[*fix].contains(&start));
154             }
155         }
156 
157         for &i in to_delete.iter().rev() {
158             self.inactive.swap_remove(i);
159         }
160         self.inactive.extend(new_inactive.into_vec());
161 
162         trace!("active:");
163         for aid in &self.active {
164             match aid {
165                 ActiveInt::Virtual(id) => {
166                     trace!("  {}", intervals.get(*id));
167                 }
168                 ActiveInt::Fixed((real_reg, _frag)) => {
169                     trace!("  {}", intervals.fixeds[real_reg.get_index()]);
170                 }
171             }
172         }
173         trace!("inactive:");
174         for &(rreg, fix) in &self.inactive {
175             trace!(
176                 "  {:?} {:?}",
177                 rreg,
178                 intervals.fixeds[rreg.get_index()].frags[fix]
179             );
180         }
181         trace!("end update state");
182 
183         stats.as_mut().map(|stats| {
184             stats.peak_active = usize::max(stats.peak_active, self.active.len());
185             stats.peak_inactive = usize::max(stats.peak_inactive, self.inactive.len());
186         });
187     }
188 }
189 
run<F: Function>( opts: &LinearScanOptions, func: &F, reg_uses: &RegVecsAndBounds, reg_universe: &RealRegUniverse, scratches_by_rc: &Vec<Option<RealReg>>, intervals: Intervals, stats: Option<Statistics>, ) -> Result<(Intervals, u32), RegAllocError>190 pub(crate) fn run<F: Function>(
191     opts: &LinearScanOptions,
192     func: &F,
193     reg_uses: &RegVecsAndBounds,
194     reg_universe: &RealRegUniverse,
195     scratches_by_rc: &Vec<Option<RealReg>>,
196     intervals: Intervals,
197     stats: Option<Statistics>,
198 ) -> Result<(Intervals, u32), RegAllocError> {
199     let mut state = State::new(opts, func, &reg_uses, intervals, stats);
200     let mut reusable = ReusableState::new(reg_universe, &scratches_by_rc);
201 
202     #[cfg(debug_assertions)]
203     let mut prev_start = InstPoint::min_value();
204 
205     while let Some(id) = state.next_unhandled() {
206         info!("main loop: allocating {}", state.intervals.get(id));
207 
208         #[cfg(debug_assertions)]
209         {
210             let int = state.intervals.get(id);
211             debug_assert!(prev_start <= int.start, "main loop must make progress");
212             prev_start = int.start;
213         }
214 
215         if state.intervals.get(id).location.is_none() {
216             let int = state.intervals.get(id);
217 
218             state
219                 .activity
220                 .update(int.start, &mut state.stats, &state.intervals);
221 
222             let ok = try_allocate_reg(&mut reusable, id, &mut state);
223             if !ok {
224                 allocate_blocked_reg(&mut reusable, id, &mut state)?;
225             }
226 
227             if state.intervals.get(id).location.reg().is_some() {
228                 state.activity.set_active(id);
229             }
230 
231             // Reset reusable state.
232             reusable.computed_inactive = false;
233         }
234 
235         debug!("");
236     }
237 
238     if log_enabled!(Level::Debug) {
239         debug!("allocation results (in order):");
240         for int in state.intervals.virtuals.iter() {
241             debug!("{}", int);
242         }
243         debug!("");
244     }
245 
246     Ok((state.intervals, state.next_spill_slot.get()))
247 }
248 
249 /// A mapping from real reg to some T.
250 #[derive(Clone)]
251 struct RegisterMapping<T> {
252     offset: usize,
253     regs: Vec<(RealReg, T)>,
254     scratch: Option<RealReg>,
255     initial_value: T,
256     reg_class_index: usize,
257 }
258 
259 impl<T: Copy> RegisterMapping<T> {
with_default( reg_class_index: usize, reg_universe: &RealRegUniverse, scratch: Option<RealReg>, initial_value: T, ) -> Self260     fn with_default(
261         reg_class_index: usize,
262         reg_universe: &RealRegUniverse,
263         scratch: Option<RealReg>,
264         initial_value: T,
265     ) -> Self {
266         let mut regs = Vec::new();
267         let mut offset = 0;
268         // Collect all the registers for the current class.
269         if let Some(ref info) = reg_universe.allocable_by_class[reg_class_index] {
270             lsra_assert!(info.first <= info.last);
271             offset = info.first;
272             for reg in &reg_universe.regs[info.first..=info.last] {
273                 lsra_assert!(regs.len() == reg.0.get_index() - offset);
274                 regs.push((reg.0, initial_value));
275             }
276         };
277         Self {
278             offset,
279             regs,
280             scratch,
281             initial_value,
282             reg_class_index,
283         }
284     }
285 
clear(&mut self)286     fn clear(&mut self) {
287         for reg in self.regs.iter_mut() {
288             reg.1 = self.initial_value;
289         }
290     }
291 
iter<'a>(&'a self) -> RegisterMappingIter<T>292     fn iter<'a>(&'a self) -> RegisterMappingIter<T> {
293         RegisterMappingIter {
294             iter: self.regs.iter(),
295             scratch: self.scratch,
296         }
297     }
298 }
299 
300 struct RegisterMappingIter<'a, T: Copy> {
301     iter: std::slice::Iter<'a, (RealReg, T)>,
302     scratch: Option<RealReg>,
303 }
304 
305 impl<'a, T: Copy> std::iter::Iterator for RegisterMappingIter<'a, T> {
306     type Item = &'a (RealReg, T);
next(&mut self) -> Option<Self::Item>307     fn next(&mut self) -> Option<Self::Item> {
308         match self.iter.next() {
309             Some(pair) => {
310                 if Some(pair.0) == self.scratch {
311                     // Skip to the next one.
312                     self.iter.next()
313                 } else {
314                     Some(pair)
315                 }
316             }
317             None => None,
318         }
319     }
320 }
321 
322 impl<T> std::ops::Index<RealReg> for RegisterMapping<T> {
323     type Output = T;
index(&self, rreg: RealReg) -> &Self::Output324     fn index(&self, rreg: RealReg) -> &Self::Output {
325         lsra_assert!(
326             rreg.get_class() as usize == self.reg_class_index,
327             "trying to index a reg from the wrong class"
328         );
329         lsra_assert!(Some(rreg) != self.scratch, "trying to use the scratch");
330         &self.regs[rreg.get_index() - self.offset].1
331     }
332 }
333 
334 impl<T> std::ops::IndexMut<RealReg> for RegisterMapping<T> {
index_mut(&mut self, rreg: RealReg) -> &mut Self::Output335     fn index_mut(&mut self, rreg: RealReg) -> &mut Self::Output {
336         lsra_assert!(
337             rreg.get_class() as usize == self.reg_class_index,
338             "trying to index a reg from the wrong class"
339         );
340         lsra_assert!(Some(rreg) != self.scratch, "trying to use the scratch");
341         &mut self.regs[rreg.get_index() - self.offset].1
342     }
343 }
344 
345 // State management.
346 
347 /// Parts of state just reused for recycling memory.
348 struct ReusableState {
349     inactive_intersecting: Vec<(RealReg, InstPoint)>,
350     computed_inactive: bool,
351     reg_to_instpoint_1: Vec<RegisterMapping<InstPoint>>,
352     reg_to_instpoint_2: Vec<RegisterMapping<InstPoint>>,
353 }
354 
355 impl ReusableState {
new(reg_universe: &RealRegUniverse, scratches: &[Option<RealReg>]) -> Self356     fn new(reg_universe: &RealRegUniverse, scratches: &[Option<RealReg>]) -> Self {
357         let mut reg_to_instpoint_1 = Vec::with_capacity(NUM_REG_CLASSES);
358 
359         for i in 0..NUM_REG_CLASSES {
360             let scratch = scratches[i];
361             reg_to_instpoint_1.push(RegisterMapping::with_default(
362                 i,
363                 reg_universe,
364                 scratch,
365                 InstPoint::max_value(),
366             ));
367         }
368 
369         let reg_to_instpoint_2 = reg_to_instpoint_1.clone();
370 
371         Self {
372             inactive_intersecting: Vec::new(),
373             computed_inactive: false,
374             reg_to_instpoint_1,
375             reg_to_instpoint_2,
376         }
377     }
378 }
379 
380 /// A small pair containing the interval id and the instruction point of an interval that is still
381 /// to be allocated, to be stored in the unhandled list of intervals.
382 struct IntervalStart(IntId, InstPoint);
383 
384 impl cmp::PartialEq for IntervalStart {
385     #[inline(always)]
eq(&self, other: &Self) -> bool386     fn eq(&self, other: &Self) -> bool {
387         self.0 == other.0
388     }
389 }
390 impl cmp::Eq for IntervalStart {}
391 
392 impl cmp::PartialOrd for IntervalStart {
393     #[inline(always)]
partial_cmp(&self, other: &Self) -> Option<Ordering>394     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
395         // Note: we want a reverse ordering on start positions, so that we have a MinHeap and not a
396         // MaxHeap in UnhandledIntervals.
397         other.1.partial_cmp(&self.1)
398     }
399 }
400 
401 impl cmp::Ord for IntervalStart {
402     #[inline(always)]
cmp(&self, other: &Self) -> Ordering403     fn cmp(&self, other: &Self) -> Ordering {
404         self.partial_cmp(other).unwrap()
405     }
406 }
407 
408 struct UnhandledIntervals {
409     heap: BinaryHeap<IntervalStart>,
410 }
411 
412 impl UnhandledIntervals {
new() -> Self413     fn new() -> Self {
414         Self {
415             heap: BinaryHeap::with_capacity(16),
416         }
417     }
418 
419     /// Insert a virtual interval that's unallocated in the list of unhandled intervals.
420     ///
421     /// This relies on the fact that unhandled intervals's start positions can't change over time.
insert(&mut self, id: IntId, intervals: &Intervals)422     fn insert(&mut self, id: IntId, intervals: &Intervals) {
423         self.heap.push(IntervalStart(id, intervals.get(id).start))
424     }
425 
426     /// Get the new unhandled interval, in start order.
next_unhandled(&mut self, _intervals: &Intervals) -> Option<IntId>427     fn next_unhandled(&mut self, _intervals: &Intervals) -> Option<IntId> {
428         self.heap.pop().map(|entry| {
429             let ret = entry.0;
430             lsra_assert!(_intervals.get(ret).start == entry.1);
431             ret
432         })
433     }
434 }
435 
436 /// State structure, which can be cleared between different calls to register allocation.
437 /// TODO: split this into clearable fields and non-clearable fields.
438 struct State<'a, F: Function> {
439     func: &'a F,
440     reg_uses: &'a RegUses,
441     opts: &'a LinearScanOptions,
442 
443     intervals: Intervals,
444 
445     /// Intervals that are starting after the current interval's start position.
446     unhandled: UnhandledIntervals,
447 
448     /// Next available spill slot.
449     next_spill_slot: SpillSlot,
450 
451     /// Maps given virtual registers to the spill slots they should be assigned
452     /// to.
453     spill_map: HashMap<VirtualReg, SpillSlot>,
454 
455     activity: ActivityTracker,
456     stats: Option<Statistics>,
457 }
458 
459 impl<'a, F: Function> State<'a, F> {
new( opts: &'a LinearScanOptions, func: &'a F, reg_uses: &'a RegUses, intervals: Intervals, stats: Option<Statistics>, ) -> Self460     fn new(
461         opts: &'a LinearScanOptions,
462         func: &'a F,
463         reg_uses: &'a RegUses,
464         intervals: Intervals,
465         stats: Option<Statistics>,
466     ) -> Self {
467         let mut unhandled = UnhandledIntervals::new();
468         for int in intervals.virtuals.iter() {
469             unhandled.insert(int.id, &intervals);
470         }
471 
472         let activity = ActivityTracker::new(&intervals);
473 
474         Self {
475             func,
476             reg_uses,
477             opts,
478             intervals,
479             unhandled,
480             next_spill_slot: SpillSlot::new(0),
481             spill_map: HashMap::default(),
482             stats,
483             activity,
484         }
485     }
486 
next_unhandled(&mut self) -> Option<IntId>487     fn next_unhandled(&mut self) -> Option<IntId> {
488         self.unhandled.next_unhandled(&self.intervals)
489     }
insert_unhandled(&mut self, id: IntId)490     fn insert_unhandled(&mut self, id: IntId) {
491         self.unhandled.insert(id, &self.intervals);
492     }
493 
spill(&mut self, id: IntId)494     fn spill(&mut self, id: IntId) {
495         let int = self.intervals.get(id);
496         debug_assert!(int.location.spill().is_none(), "already spilled");
497         debug!("spilling {:?}", id);
498 
499         let vreg = int.vreg;
500         let spill_slot = if let Some(spill_slot) = self.spill_map.get(&vreg) {
501             *spill_slot
502         } else {
503             let size_slot = self.func.get_spillslot_size(vreg.get_class(), vreg);
504             let spill_slot = self.next_spill_slot.round_up(size_slot);
505             self.next_spill_slot = self.next_spill_slot.inc(1);
506             self.spill_map.insert(vreg, spill_slot);
507             spill_slot
508         };
509 
510         self.intervals.set_spill(id, spill_slot);
511     }
512 }
513 
514 #[inline(never)]
lazy_compute_inactive( intervals: &Intervals, activity: &ActivityTracker, cur_id: IntId, inactive_intersecting: &mut Vec<(RealReg, InstPoint)>, computed_inactive: &mut bool, )515 fn lazy_compute_inactive(
516     intervals: &Intervals,
517     activity: &ActivityTracker,
518     cur_id: IntId,
519     inactive_intersecting: &mut Vec<(RealReg, InstPoint)>,
520     computed_inactive: &mut bool,
521 ) {
522     if *computed_inactive {
523         return;
524     }
525     inactive_intersecting.clear();
526 
527     let int = intervals.get(cur_id);
528     let reg_class = int.vreg.get_class();
529 
530     for &(rreg, fix) in &activity.inactive {
531         if rreg.get_class() != reg_class {
532             continue;
533         }
534 
535         let frags = &intervals.fixeds[rreg.get_index()].frags;
536         let mut i = fix;
537         while let Some(ref frag) = frags.get(i) {
538             if frag.first > int.end {
539                 break;
540             }
541             if frag.first >= int.start {
542                 inactive_intersecting.push((rreg, frag.first));
543                 break;
544             }
545             i += 1;
546         }
547     }
548 
549     *computed_inactive = true;
550 }
551 
552 /// Transitions intervals from active/inactive into active/inactive/handled.
553 ///
554 /// An interval tree is stored in the state, containing all the active and
555 /// inactive intervals. The comparison key is the interval's start point.
556 ///
557 /// A state update consists in the following. We consider the next interval to
558 /// allocate, and in particular its start point S.
559 ///
560 /// 1. remove all the active/inactive intervals that have expired, i.e. their
561 ///    end point is before S.
562 /// 2. reconsider active/inactive intervals:
563 ///   - if they contain S, they become (or stay) active.
564 ///   - otherwise, they become (or stay) inactive.
565 ///
566 /// Item 1 is easy to implement, and fast enough.
567 ///
568 /// Item 2 is a bit trickier. While we could just call `Intervals::covers` for
569 /// each interval on S, this is quite expensive. In addition to this, it happens
570 /// that most intervals are inactive. This is explained by the fact that linear
571 /// scan can create large intervals, if a value is used much later after it's
572 /// been created, *according to the block ordering*.
573 ///
574 /// For each interval, we remember the last active fragment, or the first
575 /// inactive fragment that starts after S. This makes search really fast:
576 ///
577 /// - if the considered (active or inactive) interval start is before S, then we
578 /// should look more precisely if it's active or inactive. This might include
579 /// seeking to the next fragment that contains S.
580 /// - otherwise, if the considered interval start is *after* S, then it means
581 /// this interval, as well as all the remaining ones in the interval tree (since
582 /// they're sorted by starting position) are inactive, and we can escape the
583 /// loop eagerly.
584 ///
585 /// The escape for inactive intervals make this function overall cheap.
586 
587 /// Naive heuristic to select a register when we're not aware of any conflict.
588 /// Currently, it chooses the register with the furthest next use.
589 #[inline(never)]
select_naive_reg<F: Function>( reusable: &mut ReusableState, state: &mut State<F>, id: IntId, ) -> Option<(RealReg, InstPoint)>590 fn select_naive_reg<F: Function>(
591     reusable: &mut ReusableState,
592     state: &mut State<F>,
593     id: IntId,
594 ) -> Option<(RealReg, InstPoint)> {
595     let reg_class = state.intervals.get(id).vreg.get_class();
596     let free_until_pos = &mut reusable.reg_to_instpoint_1[reg_class as usize];
597     free_until_pos.clear();
598 
599     let mut num_free = usize::max(1, free_until_pos.regs.len()) - 1;
600 
601     // All registers currently in use are blocked.
602     for &aid in &state.activity.active {
603         let reg = match aid {
604             ActiveInt::Virtual(int_id) => {
605                 if let Some(reg) = state.intervals.get(int_id).location.reg() {
606                     reg
607                 } else {
608                     continue;
609                 }
610             }
611             ActiveInt::Fixed((real_reg, _)) => real_reg,
612         };
613 
614         if reg.get_class() == reg_class {
615             free_until_pos[reg] = InstPoint::min_value();
616             num_free -= 1;
617         }
618     }
619 
620     // Shortcut: if all the registers are taken, don't even bother.
621     if num_free == 0 {
622         lsra_assert!(!free_until_pos
623             .iter()
624             .any(|pair| pair.1 != InstPoint::min_value()));
625         return None;
626     }
627 
628     // All registers that would be used at the same time as the current interval
629     // are partially blocked, up to the point when they start being used.
630     lazy_compute_inactive(
631         &state.intervals,
632         &state.activity,
633         id,
634         &mut reusable.inactive_intersecting,
635         &mut reusable.computed_inactive,
636     );
637 
638     for &(reg, intersect_at) in reusable.inactive_intersecting.iter() {
639         if intersect_at < free_until_pos[reg] {
640             free_until_pos[reg] = intersect_at;
641         }
642     }
643 
644     // Find the register with the furthest next use, if there's any.
645     let mut best_reg = None;
646     let mut best_pos = InstPoint::min_value();
647     for &(reg, pos) in free_until_pos.iter() {
648         if pos > best_pos {
649             best_pos = pos;
650             best_reg = Some(reg);
651         }
652     }
653 
654     best_reg.and_then(|reg| Some((reg, best_pos)))
655 }
656 
657 #[inline(never)]
try_allocate_reg<F: Function>( reusable: &mut ReusableState, id: IntId, state: &mut State<F>, ) -> bool658 fn try_allocate_reg<F: Function>(
659     reusable: &mut ReusableState,
660     id: IntId,
661     state: &mut State<F>,
662 ) -> bool {
663     state
664         .stats
665         .as_mut()
666         .map(|stats| stats.num_try_allocate_reg += 1);
667 
668     let (best_reg, best_pos) = if let Some(solution) = select_naive_reg(reusable, state, id) {
669         solution
670     } else {
671         debug!("try_allocate_reg: all registers taken, need to spill.");
672         return false;
673     };
674     debug!(
675         "try_allocate_reg: best register {:?} has next use at {:?}",
676         best_reg, best_pos
677     );
678 
679     if best_pos <= state.intervals.get(id).end {
680         if !state.opts.partial_split || !try_split_regs(state, id, best_pos) {
681             return false;
682         }
683     }
684 
685     // At least a partial match: allocate.
686     debug!(
687         "{:?}: {:?} <- {:?}",
688         id,
689         state.intervals.get(id).vreg,
690         best_reg
691     );
692     state.intervals.set_reg(id, best_reg);
693 
694     state
695         .stats
696         .as_mut()
697         .map(|stats| stats.num_try_allocate_reg_success += 1);
698 
699     true
700 }
701 
702 #[inline(never)]
allocate_blocked_reg<F: Function>( reusable: &mut ReusableState, cur_id: IntId, state: &mut State<F>, ) -> Result<(), RegAllocError>703 fn allocate_blocked_reg<F: Function>(
704     reusable: &mut ReusableState,
705     cur_id: IntId,
706     state: &mut State<F>,
707 ) -> Result<(), RegAllocError> {
708     // If the current interval has no uses, spill it directly.
709     let first_use = match next_use(
710         &state.intervals.get(cur_id),
711         InstPoint::min_value(),
712         &state.reg_uses,
713     ) {
714         Some(u) => u,
715         None => {
716             state.spill(cur_id);
717             return Ok(());
718         }
719     };
720 
721     let (start_pos, reg_class) = {
722         let int = state.intervals.get(cur_id);
723         (int.start, int.vreg.get_class())
724     };
725 
726     // Note: in this function, "use" isn't just a use as in use-def; it really
727     // means a mention, so either a use or a definition.
728     //
729     // 1. Compute all the positions of next uses for registers of active intervals
730     // and inactive intervals that might intersect with the current one.
731     // 2. Then use this to select the interval with the further next use.
732     // 3. Spill either the current interval or active/inactive intervals with the
733     //    selected register.
734     // 4. Make sure that the current interval doesn't intersect with the fixed
735     //    interval for the selected register.
736 
737     // Step 1: compute all the next use positions.
738     let next_use_pos = &mut reusable.reg_to_instpoint_1[reg_class as usize];
739     next_use_pos.clear();
740 
741     let block_pos = &mut reusable.reg_to_instpoint_2[reg_class as usize];
742     block_pos.clear();
743 
744     trace!(
745         "allocate_blocked_reg: searching reg with next use after {:?}",
746         start_pos
747     );
748 
749     for &aid in &state.activity.active {
750         match aid {
751             ActiveInt::Virtual(int_id) => {
752                 let int = state.intervals.get(int_id);
753                 if int.vreg.get_class() != reg_class {
754                     continue;
755                 }
756                 if let Some(reg) = int.location.reg() {
757                     if next_use_pos[reg] != InstPoint::min_value() {
758                         if let Some(next_use) =
759                             next_use(&state.intervals.get(int_id), start_pos, &state.reg_uses)
760                         {
761                             next_use_pos[reg] = InstPoint::min(next_use_pos[reg], next_use);
762                         }
763                     }
764                 }
765             }
766 
767             ActiveInt::Fixed((reg, _frag)) => {
768                 if reg.get_class() == reg_class {
769                     block_pos[reg] = InstPoint::min_value();
770                     next_use_pos[reg] = InstPoint::min_value();
771                 }
772             }
773         }
774     }
775 
776     lazy_compute_inactive(
777         &state.intervals,
778         &state.activity,
779         cur_id,
780         &mut reusable.inactive_intersecting,
781         &mut reusable.computed_inactive,
782     );
783 
784     for &(reg, intersect_pos) in &reusable.inactive_intersecting {
785         debug_assert!(reg.get_class() == reg_class);
786         if block_pos[reg] == InstPoint::min_value() {
787             // This register is already blocked.
788             debug_assert!(next_use_pos[reg] == InstPoint::min_value());
789             continue;
790         }
791         block_pos[reg] = InstPoint::min(block_pos[reg], intersect_pos);
792         next_use_pos[reg] = InstPoint::min(next_use_pos[reg], intersect_pos);
793     }
794 
795     // Step 2: find the register with the furthest next use.
796     let best_reg = {
797         let mut best = None;
798         for (reg, pos) in next_use_pos.iter() {
799             trace!("allocate_blocked_reg: {:?} has next use at {:?}", reg, pos);
800             match best {
801                 None => best = Some((reg, pos)),
802                 Some((ref mut best_reg, ref mut best_pos)) => {
803                     if *best_pos < pos {
804                         *best_pos = pos;
805                         *best_reg = reg;
806                     }
807                 }
808             }
809         }
810         match best {
811             Some(best) => *best.0,
812             None => {
813                 return Err(RegAllocError::Other(format!(
814                     "the {:?} register class has no registers!",
815                     reg_class
816                 )));
817             }
818         }
819     };
820     debug!(
821         "selecting blocked register {:?} with furthest next use at {:?}",
822         best_reg, next_use_pos[best_reg]
823     );
824 
825     // Step 3: if the next use of the current interval is after the furthest use
826     // of the selected register, then we should spill the current interval.
827     // Otherwise, spill other intervals.
828     debug!(
829         "current first used at {:?}, next use of best reg at {:?}",
830         first_use, next_use_pos[best_reg]
831     );
832 
833     if first_use >= next_use_pos[best_reg] {
834         if first_use == start_pos {
835             return Err(RegAllocError::OutOfRegisters(reg_class));
836         }
837         debug!("spill current interval");
838         let new_int = split(state, cur_id, first_use);
839         state.insert_unhandled(new_int);
840         state.spill(cur_id);
841     } else {
842         debug!("taking over register, spilling intersecting intervals");
843 
844         // Spill intervals that currently block the selected register.
845         state.intervals.set_reg(cur_id, best_reg);
846 
847         // If there's an interference with a fixed interval, split at the
848         // intersection.
849         let int_end = state.intervals.get(cur_id).end;
850         if block_pos[best_reg] <= int_end {
851             debug!(
852                 "allocate_blocked_reg: fixed conflict! blocked at {:?}, while ending at {:?}",
853                 block_pos[best_reg], int_end
854             );
855 
856             if !state.opts.partial_split || !try_split_regs(state, cur_id, block_pos[best_reg]) {
857                 split_and_spill(state, cur_id, block_pos[best_reg]);
858             }
859         }
860 
861         for &aid in &state.activity.active {
862             match aid {
863                 ActiveInt::Virtual(int_id) => {
864                     let int = state.intervals.get(int_id);
865                     if int.vreg.get_class() != reg_class {
866                         continue;
867                     }
868                     if let Some(reg) = int.location.reg() {
869                         if reg == best_reg {
870                             // spill it!
871                             debug!("allocate_blocked_reg: split and spill active stolen reg");
872                             split_and_spill(state, int_id, start_pos);
873                             break;
874                         }
875                     }
876                 }
877 
878                 ActiveInt::Fixed((_reg, _fix)) => {
879                     lsra_assert!(
880                         _reg != best_reg
881                             || state.intervals.get(cur_id).end
882                                 < state.intervals.fixeds[_reg.get_index()].frags[_fix].first,
883                         "can't split fixed active interval"
884                     );
885                 }
886             }
887         }
888 
889         // Inactive virtual intervals would need to be split and spilled here too, but we can't
890         // have inactive virtual intervals.
891         #[cfg(debug_assertions)]
892         for &(reg, intersect_pos) in &reusable.inactive_intersecting {
893             debug_assert!(
894                 reg != best_reg || state.intervals.get(cur_id).end < intersect_pos,
895                 "can't split fixed inactive interval"
896             );
897         }
898     }
899 
900     Ok(())
901 }
902 
903 /// Finds an optimal split position, whenever we're given a range of possible
904 /// positions where to split.
find_optimal_split_pos<F: Function>( state: &State<F>, id: IntId, from: InstPoint, to: InstPoint, ) -> InstPoint905 fn find_optimal_split_pos<F: Function>(
906     state: &State<F>,
907     id: IntId,
908     from: InstPoint,
909     to: InstPoint,
910 ) -> InstPoint {
911     trace!("find_optimal_split_pos between {:?} and {:?}", from, to);
912 
913     debug_assert!(from <= to, "split between positions are inconsistent");
914     let int = state.intervals.get(id);
915     debug_assert!(from >= int.start, "split should happen after the start");
916     debug_assert!(to <= int.end, "split should happen before the end");
917 
918     if from == to {
919         return from;
920     }
921 
922     let candidate = match state.opts.split_strategy {
923         OptimalSplitStrategy::To => Some(to),
924         OptimalSplitStrategy::NextFrom => Some(next_pos(from)),
925         OptimalSplitStrategy::NextNextFrom => Some(next_pos(next_pos(from))),
926         OptimalSplitStrategy::From => {
927             // This is the general setting, so win some time and eagerly return here.
928             return from;
929         }
930         OptimalSplitStrategy::PrevTo => Some(prev_pos(to)),
931         OptimalSplitStrategy::PrevPrevTo => Some(prev_pos(prev_pos(to))),
932         OptimalSplitStrategy::Mid => Some(InstPoint::new_use(InstIx::new(
933             (from.iix().get() + to.iix().get()) / 2,
934         ))),
935     };
936 
937     if let Some(pos) = candidate {
938         if pos >= from && pos <= to && state.intervals.get(id).covers(pos) {
939             return pos;
940         }
941     }
942 
943     from
944 }
945 
prev_pos(mut pos: InstPoint) -> InstPoint946 fn prev_pos(mut pos: InstPoint) -> InstPoint {
947     match pos.pt() {
948         Point::Def => {
949             pos.set_pt(Point::Use);
950             pos
951         }
952         Point::Use => {
953             pos.set_iix(pos.iix().minus(1));
954             pos.set_pt(Point::Def);
955             pos
956         }
957         _ => unreachable!(),
958     }
959 }
960 
next_pos(mut pos: InstPoint) -> InstPoint961 fn next_pos(mut pos: InstPoint) -> InstPoint {
962     match pos.pt() {
963         Point::Use => pos.set_pt(Point::Def),
964         Point::Def => {
965             pos.set_pt(Point::Use);
966             pos.set_iix(pos.iix().plus(1));
967         }
968         _ => unreachable!(),
969     };
970     pos
971 }
972 
973 /// Splits the given interval between the last use before `split_pos` and
974 /// `split_pos`.
975 ///
976 /// In case of two-ways split (i.e. only place to split is precisely split_pos),
977 /// returns the live interval id for the middle child, to be added back to the
978 /// list of active/inactive intervals after iterating on these.
split_and_spill<F: Function>(state: &mut State<F>, id: IntId, split_pos: InstPoint)979 fn split_and_spill<F: Function>(state: &mut State<F>, id: IntId, split_pos: InstPoint) {
980     let child = match last_use(&state.intervals.get(id), split_pos, &state.reg_uses) {
981         Some(last_use) => {
982             debug!(
983                 "split_and_spill {:?}: spill between {:?} and {:?}",
984                 id, last_use, split_pos
985             );
986 
987             // Maintain ascending order between the min and max positions.
988             let min_pos = InstPoint::min(next_pos(last_use), split_pos);
989 
990             // Make sure that if the two positions are the same, we'll be splitting in
991             // a position that's in the current interval.
992             let optimal_pos = find_optimal_split_pos(state, id, min_pos, split_pos);
993 
994             let child = split(state, id, optimal_pos);
995             state.spill(child);
996             child
997         }
998 
999         None => {
1000             // The current interval has no uses before the split position, it can
1001             // safely be spilled.
1002             debug!(
1003                 "split_and_spill {:?}: spilling it since no uses before split position",
1004                 id
1005             );
1006             state.spill(id);
1007             id
1008         }
1009     };
1010 
1011     // Split until the next register use.
1012     match next_use(&state.intervals.get(child), split_pos, &state.reg_uses) {
1013         Some(next_use_pos) => {
1014             debug!(
1015                 "split spilled interval before next use @ {:?}",
1016                 next_use_pos
1017             );
1018             let child = split(state, child, next_use_pos);
1019             state.insert_unhandled(child);
1020         }
1021         None => {
1022             // Let it be spilled for the rest of its lifetime.
1023         }
1024     }
1025 
1026     // In both cases, the spilled child interval can remain on the stack.
1027     debug!("spilled split child {:?} silently expires", child);
1028 }
1029 
1030 /// Try to find a (use) position where to split the interval until the next point at which it
1031 /// becomes unavailable, and put it back into the queue of intervals to allocate later on.  Returns
1032 /// true if it succeeded in finding such a position, false otherwise.
try_split_regs<F: Function>( state: &mut State<F>, id: IntId, available_until: InstPoint, ) -> bool1033 fn try_split_regs<F: Function>(
1034     state: &mut State<F>,
1035     id: IntId,
1036     available_until: InstPoint,
1037 ) -> bool {
1038     state.stats.as_mut().map(|stats| stats.num_reg_splits += 1);
1039 
1040     // Find a position for the split: we'll iterate backwards from the point until the register is
1041     // available, down to the previous use of the current interval.
1042     let prev_use = match last_use(&state.intervals.get(id), available_until, &state.reg_uses) {
1043         Some(prev_use) => prev_use,
1044         None => state.intervals.get(id).start,
1045     };
1046 
1047     let split_pos = if state.opts.partial_split_near_end {
1048         // Split at the position closest to the available_until position.
1049         let pos = match available_until.pt() {
1050             Point::Use => prev_pos(prev_pos(available_until)),
1051             Point::Def => prev_pos(available_until),
1052             _ => unreachable!(),
1053         };
1054         if pos <= prev_use {
1055             return false;
1056         }
1057         pos
1058     } else {
1059         // Split at the position closest to the prev_use position. If it was a def, we can split
1060         // just thereafter, if it was at a use, go to the next use.
1061         let pos = match prev_use.pt() {
1062             Point::Use => next_pos(next_pos(prev_use)),
1063             Point::Def => next_pos(prev_use),
1064             _ => unreachable!(),
1065         };
1066         if pos >= available_until {
1067             return false;
1068         }
1069         pos
1070     };
1071 
1072     let child = split(state, id, split_pos);
1073     state.insert_unhandled(child);
1074 
1075     state
1076         .stats
1077         .as_mut()
1078         .map(|stats| stats.num_reg_splits_success += 1);
1079 
1080     true
1081 }
1082 
1083 /// Splits the interval at the given position.
1084 ///
1085 /// The split position must either be a Def of the current vreg, or it must be
1086 /// at a Use position (otherwise there's no place to put the moves created by
1087 /// the split).
1088 ///
1089 /// The id of the new interval is returned, while the parent interval is mutated
1090 /// in place. The child interval starts after (including) at_pos.
1091 #[inline(never)]
split<F: Function>(state: &mut State<F>, id: IntId, at_pos: InstPoint) -> IntId1092 fn split<F: Function>(state: &mut State<F>, id: IntId, at_pos: InstPoint) -> IntId {
1093     debug!("split {:?} at {:?}", id, at_pos);
1094     trace!("interval: {}", state.intervals.get(id));
1095 
1096     let int = state.intervals.get(id);
1097     debug_assert!(int.start <= at_pos, "must split after the start");
1098     debug_assert!(at_pos <= int.end, "must split before the end");
1099 
1100     // We're splitting in the middle of a fragment: [L, R].
1101     // Split it into two fragments: parent [L, pos[ + child [pos, R].
1102     debug_assert!(int.start < int.end, "trying to split unit fragment");
1103     debug_assert!(int.start <= at_pos, "no space to split fragment");
1104 
1105     let parent_start = int.start;
1106     let parent_end = prev_pos(at_pos);
1107     let child_start = at_pos;
1108     let child_end = int.end;
1109 
1110     trace!(
1111         "split fragment [{:?}; {:?}] into two parts: [{:?}; {:?}] to [{:?}; {:?}]",
1112         int.start,
1113         int.end,
1114         parent_start,
1115         parent_end,
1116         child_start,
1117         child_end
1118     );
1119 
1120     debug_assert!(parent_start <= parent_end);
1121     debug_assert!(parent_end <= child_start);
1122     debug_assert!(child_start <= child_end);
1123 
1124     let vreg = int.vreg;
1125     let ancestor = int.ancestor;
1126 
1127     let parent_mentions = state.intervals.get_mut(id).mentions_mut();
1128     let index = parent_mentions.binary_search_by(|mention| {
1129         // The comparator function returns the position of the argument compared to the target.
1130 
1131         // Search by index first.
1132         let iix = mention.0;
1133         if iix < at_pos.iix() {
1134             return Ordering::Less;
1135         }
1136         if iix > at_pos.iix() {
1137             return Ordering::Greater;
1138         }
1139 
1140         // The instruction index is the same. Consider the instruction side now, and compare it
1141         // with the set. For the purpose of LSRA, mod means use and def.
1142         let set = mention.1;
1143         if at_pos.pt() == Point::Use {
1144             if set.is_use_or_mod() {
1145                 Ordering::Equal
1146             } else {
1147                 // It has to be Mod or Def. We need to look more to the right of the seeked array.
1148                 // Thus indicate this mention is after the target.
1149                 Ordering::Greater
1150             }
1151         } else {
1152             debug_assert!(at_pos.pt() == Point::Def);
1153             if set.is_mod_or_def() {
1154                 Ordering::Equal
1155             } else {
1156                 // Look to the left.
1157                 Ordering::Less
1158             }
1159         }
1160     });
1161 
1162     let (index, may_need_fixup) = match index {
1163         Ok(index) => (index, true),
1164         Err(index) => (index, false),
1165     };
1166 
1167     // Emulate split_off for SmallVec here.
1168     let mut child_mentions = MentionMap::with_capacity(parent_mentions.len() - index);
1169     for mention in parent_mentions.iter().skip(index) {
1170         child_mentions.push(mention.clone());
1171     }
1172     parent_mentions.truncate(index);
1173 
1174     // In the situation where we split at the def point of an instruction, and the mention set
1175     // contains the use point, we need to refine the sets:
1176     // - the parent must still contain the use point (and the modified point if present)
1177     // - the child must only contain the def point (and the modified point if present).
1178     // Note that if we split at the use point of an instruction, and the mention set contains the
1179     // def point, it is fine: we're not splitting between the two of them.
1180     if may_need_fixup && at_pos.pt() == Point::Def && child_mentions.first().unwrap().1.is_use() {
1181         let first_child_mention = child_mentions.first_mut().unwrap();
1182         first_child_mention.1.remove_use();
1183 
1184         let last_parent_mention = parent_mentions.last_mut().unwrap();
1185         last_parent_mention.1.add_use();
1186 
1187         if first_child_mention.1.is_mod() {
1188             last_parent_mention.1.add_mod();
1189         }
1190     }
1191 
1192     let child_id = IntId(state.intervals.num_virtual_intervals());
1193     let mut child_int =
1194         VirtualInterval::new(child_id, vreg, child_start, child_end, child_mentions);
1195     child_int.parent = Some(id);
1196     child_int.ancestor = ancestor;
1197 
1198     state.intervals.push_interval(child_int);
1199 
1200     state.intervals.get_mut(id).end = parent_end;
1201     state.intervals.set_child(id, child_id);
1202 
1203     if log_enabled!(Level::Trace) {
1204         trace!("split results:");
1205         trace!("- {}", state.intervals.get(id));
1206         trace!("- {}", state.intervals.get(child_id));
1207     }
1208 
1209     child_id
1210 }
1211 
_build_mention_map(reg_uses: &RegUses) -> HashMap<Reg, MentionMap>1212 fn _build_mention_map(reg_uses: &RegUses) -> HashMap<Reg, MentionMap> {
1213     // Maps reg to its mentions.
1214     let mut reg_mentions: HashMap<Reg, MentionMap> = HashMap::default();
1215 
1216     // Collect all the mentions.
1217     for i in 0..reg_uses.num_insns() {
1218         let iix = InstIx::new(i as u32);
1219         let regsets = reg_uses.get_reg_sets_for_iix(iix);
1220         debug_assert!(regsets.is_sanitized());
1221 
1222         for reg in regsets.uses.iter() {
1223             let mentions = reg_mentions.entry(*reg).or_default();
1224             if mentions.is_empty() || mentions.last().unwrap().0 != iix {
1225                 mentions.push((iix, Mention::new()));
1226             }
1227             mentions.last_mut().unwrap().1.add_use();
1228         }
1229 
1230         for reg in regsets.mods.iter() {
1231             let mentions = reg_mentions.entry(*reg).or_default();
1232             if mentions.is_empty() || mentions.last().unwrap().0 != iix {
1233                 mentions.push((iix, Mention::new()));
1234             }
1235             mentions.last_mut().unwrap().1.add_mod();
1236         }
1237 
1238         for reg in regsets.defs.iter() {
1239             let mentions = reg_mentions.entry(*reg).or_default();
1240             if mentions.is_empty() || mentions.last().unwrap().0 != iix {
1241                 mentions.push((iix, Mention::new()));
1242             }
1243             mentions.last_mut().unwrap().1.add_def();
1244         }
1245     }
1246 
1247     reg_mentions
1248 }
1249