1 use super::{FixedInterval, IntId, Intervals, Mention, MentionMap, VirtualInterval};
2 use crate::{
3     analysis_control_flow::{CFGInfo, InstIxToBlockIxMap},
4     analysis_data_flow::{
5         calc_def_and_use, calc_livein_and_liveout, get_sanitized_reg_uses_for_func, reg_ix_to_reg,
6         reg_to_reg_ix,
7     },
8     data_structures::{BlockIx, InstPoint, RangeFragIx, RangeFragKind, Reg, RegVecsAndBounds},
9     sparse_set::SparseSet,
10     union_find::UnionFind,
11     AnalysisError, Function, RealRegUniverse, RegClass, TypedIxVec,
12 };
13 use log::{debug, info, log_enabled, Level};
14 use smallvec::{smallvec, SmallVec};
15 use std::{fmt, mem};
16 
17 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
18 pub(crate) struct RangeFrag {
19     pub(crate) first: InstPoint,
20     pub(crate) last: InstPoint,
21     pub(crate) mentions: MentionMap,
22 }
23 
24 impl fmt::Debug for RangeFrag {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result25     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
26         write!(fmt, "[{:?}; {:?}]", self.first, self.last)
27     }
28 }
29 
30 impl RangeFrag {
new<F: Function>( func: &F, bix: BlockIx, first: InstPoint, last: InstPoint, mentions: MentionMap, ) -> (Self, RangeFragMetrics)31     fn new<F: Function>(
32         func: &F,
33         bix: BlockIx,
34         first: InstPoint,
35         last: InstPoint,
36         mentions: MentionMap,
37     ) -> (Self, RangeFragMetrics) {
38         debug_assert!(func.block_insns(bix).len() >= 1);
39         debug_assert!(func.block_insns(bix).contains(first.iix()));
40         debug_assert!(func.block_insns(bix).contains(last.iix()));
41         debug_assert!(first <= last);
42 
43         let first_in_block = InstPoint::new_use(func.block_insns(bix).first());
44         let last_in_block = InstPoint::new_def(func.block_insns(bix).last());
45         let kind = match (first == first_in_block, last == last_in_block) {
46             (false, false) => RangeFragKind::Local,
47             (false, true) => RangeFragKind::LiveOut,
48             (true, false) => RangeFragKind::LiveIn,
49             (true, true) => RangeFragKind::Thru,
50         };
51 
52         (
53             RangeFrag {
54                 first,
55                 last,
56                 mentions,
57             },
58             RangeFragMetrics { bix, kind },
59         )
60     }
61 
62     #[inline(always)]
63     #[cfg(debug_assertions)]
contains(&self, inst: &InstPoint) -> bool64     pub(crate) fn contains(&self, inst: &InstPoint) -> bool {
65         self.first <= *inst && *inst <= self.last
66     }
67 }
68 
69 struct RangeFragMetrics {
70     bix: BlockIx,
71     kind: RangeFragKind,
72 }
73 
74 pub(crate) struct AnalysisInfo {
75     /// The sanitized per-insn reg-use info.
76     pub(crate) reg_vecs_and_bounds: RegVecsAndBounds,
77     /// All the intervals, fixed or virtual.
78     pub(crate) intervals: Intervals,
79     /// Liveins per block.
80     pub(crate) liveins: TypedIxVec<BlockIx, SparseSet<Reg>>,
81     /// Liveouts per block.
82     pub(crate) liveouts: TypedIxVec<BlockIx, SparseSet<Reg>>,
83     /// Blocks's loop depths.
84     pub(crate) _loop_depth: TypedIxVec<BlockIx, u32>,
85     /// Maps InstIxs to BlockIxs.
86     pub(crate) _inst_to_block_map: InstIxToBlockIxMap,
87 }
88 
89 #[inline(never)]
run<F: Function>( func: &F, reg_universe: &RealRegUniverse, ) -> Result<AnalysisInfo, AnalysisError>90 pub(crate) fn run<F: Function>(
91     func: &F,
92     reg_universe: &RealRegUniverse,
93 ) -> Result<AnalysisInfo, AnalysisError> {
94     info!(
95         "run_analysis: begin: {} blocks, {} insns",
96         func.blocks().len(),
97         func.insns().len()
98     );
99 
100     // First do control flow analysis.  This is (relatively) simple.  Note that this can fail, for
101     // various reasons; we propagate the failure if so.  Also create the InstIx-to-BlockIx map;
102     // this isn't really control-flow analysis, but needs to be done at some point.
103 
104     info!("  run_analysis: begin control flow analysis");
105     let cfg_info = CFGInfo::create(func)?;
106     let inst_to_block_map = InstIxToBlockIxMap::new(func);
107     info!("  run_analysis: end control flow analysis");
108 
109     info!("  run_analysis: begin data flow analysis");
110 
111     // See `get_sanitized_reg_uses_for_func` for the meaning of "sanitized".
112     let reg_vecs_and_bounds = get_sanitized_reg_uses_for_func(func, reg_universe)
113         .map_err(|reg| AnalysisError::IllegalRealReg(reg))?;
114     assert!(reg_vecs_and_bounds.is_sanitized());
115 
116     // Calculate block-local def/use sets.
117     let (def_sets_per_block, use_sets_per_block) =
118         calc_def_and_use(func, &reg_vecs_and_bounds, &reg_universe);
119     debug_assert!(def_sets_per_block.len() == func.blocks().len() as u32);
120     debug_assert!(use_sets_per_block.len() == func.blocks().len() as u32);
121 
122     // Calculate live-in and live-out sets per block, using the traditional
123     // iterate-to-a-fixed-point scheme.
124     // `liveout_sets_per_block` is amended below for return blocks, hence `mut`.
125 
126     let (livein_sets_per_block, mut liveout_sets_per_block) = calc_livein_and_liveout(
127         func,
128         &def_sets_per_block,
129         &use_sets_per_block,
130         &cfg_info,
131         &reg_universe,
132     );
133     debug_assert!(livein_sets_per_block.len() == func.blocks().len() as u32);
134     debug_assert!(liveout_sets_per_block.len() == func.blocks().len() as u32);
135 
136     // Verify livein set of entry block against liveins specified by function (e.g., ABI params).
137     let func_liveins = SparseSet::from_vec(
138         func.func_liveins()
139             .to_vec()
140             .into_iter()
141             .map(|rreg| rreg.to_reg())
142             .collect(),
143     );
144     if !livein_sets_per_block[func.entry_block()].is_subset_of(&func_liveins) {
145         let mut regs = livein_sets_per_block[func.entry_block()].clone();
146         regs.remove(&func_liveins);
147         return Err(AnalysisError::EntryLiveinValues(regs.to_vec()));
148     }
149 
150     // Add function liveouts to every block ending in a return.
151     let func_liveouts = SparseSet::from_vec(
152         func.func_liveouts()
153             .to_vec()
154             .into_iter()
155             .map(|rreg| rreg.to_reg())
156             .collect(),
157     );
158     for block in func.blocks() {
159         let last_iix = func.block_insns(block).last();
160         if func.is_ret(last_iix) {
161             liveout_sets_per_block[block].union(&func_liveouts);
162         }
163     }
164 
165     info!("  run_analysis: end data flow analysis");
166 
167     info!("  run_analysis: begin liveness analysis");
168     let (frag_ixs_per_reg, mut frag_env, frag_metrics_env, vreg_classes) = get_range_frags(
169         func,
170         &reg_vecs_and_bounds,
171         &reg_universe,
172         &livein_sets_per_block,
173         &liveout_sets_per_block,
174     );
175 
176     let (mut fixed_intervals, virtual_intervals) = merge_range_frags(
177         &reg_universe,
178         &frag_ixs_per_reg,
179         &mut frag_env,
180         &frag_metrics_env,
181         &cfg_info,
182         &vreg_classes,
183     );
184     info!("  run_analysis: end liveness analysis");
185 
186     // Finalize interval construction by doing some last minute sort of the fixed intervals.
187     for fixed in fixed_intervals.iter_mut() {
188         fixed.frags.sort_unstable_by_key(|frag| frag.first);
189     }
190     let intervals = Intervals {
191         virtuals: virtual_intervals,
192         fixeds: fixed_intervals,
193     };
194 
195     info!("run_analysis: end");
196 
197     Ok(AnalysisInfo {
198         reg_vecs_and_bounds,
199         intervals,
200         liveins: livein_sets_per_block,
201         liveouts: liveout_sets_per_block,
202         _loop_depth: cfg_info.depth_map,
203         _inst_to_block_map: inst_to_block_map,
204     })
205 }
206 
207 /// Calculate all the RangeFrags for `bix`.  Add them to `out_frags` and
208 /// corresponding metrics data to `out_frag_metrics`.  Add to `out_map`, the
209 /// associated RangeFragIxs, segregated by Reg.  `bix`, `livein`, `liveout` and
210 /// `rvb` are expected to be valid in the context of the Func `f` (duh!).
211 #[inline(never)]
get_range_frags_for_block<F: Function>( func: &F, rvb: &RegVecsAndBounds, reg_universe: &RealRegUniverse, vreg_classes: &Vec<RegClass>, bix: BlockIx, livein: &SparseSet<Reg>, liveout: &SparseSet<Reg>, visited: &mut Vec<u32>, state: &mut Vec< Option<RangeFrag>>, out_map: &mut Vec<SmallVec<[RangeFragIx; 8]>>, out_frags: &mut Vec<RangeFrag>, out_frag_metrics: &mut Vec<RangeFragMetrics>, )212 fn get_range_frags_for_block<F: Function>(
213     func: &F,
214     rvb: &RegVecsAndBounds,
215     reg_universe: &RealRegUniverse,
216     vreg_classes: &Vec<RegClass>,
217     bix: BlockIx,
218     livein: &SparseSet<Reg>,
219     liveout: &SparseSet<Reg>,
220     // Temporary state reusable across function calls.
221     visited: &mut Vec<u32>,
222     state: &mut Vec</*rreg index, then vreg index, */ Option<RangeFrag>>,
223     // Effectively results.
224     out_map: &mut Vec<SmallVec<[RangeFragIx; 8]>>,
225     out_frags: &mut Vec<RangeFrag>,
226     out_frag_metrics: &mut Vec<RangeFragMetrics>,
227 ) {
228     let mut emit_range_frag =
229         |r: Reg, frag: RangeFrag, frag_metrics: RangeFragMetrics, num_real_regs: u32| {
230             let fix = RangeFragIx::new(out_frags.len() as u32);
231             out_frags.push(frag);
232             out_frag_metrics.push(frag_metrics);
233 
234             let out_map_index = reg_to_reg_ix(num_real_regs, r) as usize;
235             out_map[out_map_index].push(fix);
236         };
237 
238     // Some handy constants.
239     debug_assert!(func.block_insns(bix).len() >= 1);
240     let first_pt_in_block = InstPoint::new_use(func.block_insns(bix).first());
241     let last_pt_in_block = InstPoint::new_def(func.block_insns(bix).last());
242 
243     // Clear the running state.
244     visited.clear();
245 
246     let num_real_regs = reg_universe.regs.len() as u32;
247 
248     // First, set up `state` as if all of `livein` had been written just prior to the block.
249     for r in livein.iter() {
250         let r_state_ix = reg_to_reg_ix(num_real_regs, *r) as usize;
251         debug_assert!(state[r_state_ix].is_none());
252         state[r_state_ix] = Some(RangeFrag {
253             mentions: MentionMap::new(),
254             first: first_pt_in_block,
255             last: first_pt_in_block,
256         });
257         visited.push(r_state_ix as u32);
258     }
259 
260     // Now visit each instruction in turn, examining first the registers it reads, then those it
261     // modifies, and finally those it writes.
262     for iix in func.block_insns(bix) {
263         let bounds_for_iix = &rvb.bounds[iix];
264 
265         // Examine reads: they extend an existing RangeFrag to the U point of the reading
266         // insn.
267         for i in bounds_for_iix.uses_start as usize
268             ..bounds_for_iix.uses_start as usize + bounds_for_iix.uses_len as usize
269         {
270             let r = &rvb.vecs.uses[i];
271             let r_state_ix = reg_to_reg_ix(num_real_regs, *r) as usize;
272 
273             // There has to be an entry, otherwise we'd do a read of a register not listed in
274             // liveins.
275             let pf = match &mut state[r_state_ix] {
276                 None => panic!("get_range_frags_for_block: fail #1"),
277                 Some(ref mut pf) => pf,
278             };
279 
280             // This the first or subsequent read after a write.  Note that the "write" can be
281             // either a real write, or due to the fact that `r` is listed in `livein`.  We don't
282             // care here.
283             let new_last = InstPoint::new_use(iix);
284             debug_assert!(pf.last <= new_last);
285             pf.last = new_last;
286 
287             // This first loop iterates over all the uses for the first time, so there shouldn't be
288             // any duplicates.
289             debug_assert!(!pf.mentions.iter().any(|tuple| tuple.0 == iix));
290             let mut mention_set = Mention::new();
291             mention_set.add_use();
292             pf.mentions.push((iix, mention_set));
293         }
294 
295         // Examine modifies.  These are handled almost identically to
296         // reads, except that they extend an existing RangeFrag down to
297         // the D point of the modifying insn.
298         for i in bounds_for_iix.mods_start as usize
299             ..bounds_for_iix.mods_start as usize + bounds_for_iix.mods_len as usize
300         {
301             let r = &rvb.vecs.mods[i];
302             let r_state_ix = reg_to_reg_ix(num_real_regs, *r) as usize;
303 
304             // There has to be an entry here too.
305             let pf = match &mut state[r_state_ix] {
306                 None => panic!("get_range_frags_for_block: fail #2"),
307                 Some(ref mut pf) => pf,
308             };
309 
310             // This the first or subsequent modify after a write.
311             let new_last = InstPoint::new_def(iix);
312             debug_assert!(pf.last <= new_last);
313             pf.last = new_last;
314 
315             pf.mentions.push((iix, {
316                 let mut mention_set = Mention::new();
317                 mention_set.add_mod();
318                 mention_set
319             }));
320         }
321 
322         // Examine writes (but not writes implied by modifies).  The general idea is that a write
323         // causes us to terminate the existing RangeFrag, if any, add it to the results,
324         // and start a new frag.
325         for i in bounds_for_iix.defs_start as usize
326             ..bounds_for_iix.defs_start as usize + bounds_for_iix.defs_len as usize
327         {
328             let r = &rvb.vecs.defs[i];
329             let r_state_ix = reg_to_reg_ix(num_real_regs, *r) as usize;
330 
331             match &mut state[r_state_ix] {
332                 // First mention of a Reg we've never heard of before.
333                 // Start a new RangeFrag for it and keep going.
334                 None => {
335                     let new_pt = InstPoint::new_def(iix);
336                     let mut mention_set = Mention::new();
337                     mention_set.add_def();
338                     state[r_state_ix] = Some(RangeFrag {
339                         first: new_pt,
340                         last: new_pt,
341                         mentions: smallvec![(iix, mention_set)],
342                     })
343                 }
344 
345                 // There's already a RangeFrag for `r`.  This write will start a new one, so
346                 // flush the existing one and note this write.
347                 Some(RangeFrag {
348                     ref mut first,
349                     ref mut last,
350                     ref mut mentions,
351                 }) => {
352                     // Steal the mentions and replace the mutable ref by an empty vector for reuse.
353                     let stolen_mentions = mem::replace(mentions, MentionMap::new());
354 
355                     let (frag, frag_metrics) =
356                         RangeFrag::new(func, bix, *first, *last, stolen_mentions);
357                     emit_range_frag(*r, frag, frag_metrics, num_real_regs);
358 
359                     let mut mention_set = Mention::new();
360                     mention_set.add_def();
361                     mentions.push((iix, mention_set));
362 
363                     // Reuse the previous entry for this new definition of the same vreg.
364                     let new_pt = InstPoint::new_def(iix);
365                     *first = new_pt;
366                     *last = new_pt;
367                 }
368             }
369 
370             visited.push(r_state_ix as u32);
371         }
372     }
373 
374     // We are at the end of the block.  We still have to deal with live-out Regs.  We must also
375     // deal with RangeFrag in `state` that are for registers not listed as live-out.
376 
377     // Deal with live-out Regs.  Treat each one as if it is read just after the block.
378     for r in liveout.iter() {
379         // Remove the entry from `state` so that the following loop doesn't process it again.
380         let r_state_ix = reg_to_reg_ix(num_real_regs, *r) as usize;
381         let entry = mem::replace(&mut state[r_state_ix], None);
382         match entry {
383             None => panic!("get_range_frags_for_block: fail #3"),
384             Some(pf) => {
385                 let (frag, frag_metrics) =
386                     RangeFrag::new(func, bix, pf.first, last_pt_in_block, pf.mentions);
387                 emit_range_frag(*r, frag, frag_metrics, num_real_regs);
388             }
389         }
390     }
391 
392     // Finally, round up any remaining RangeFrag left in `state`.
393     for r_state_ix in visited {
394         if let Some(pf) = &mut state[*r_state_ix as usize] {
395             let r = reg_ix_to_reg(reg_universe, vreg_classes, *r_state_ix);
396             let (frag, frag_metrics) = RangeFrag::new(
397                 func,
398                 bix,
399                 pf.first,
400                 pf.last,
401                 mem::replace(&mut pf.mentions, MentionMap::new()),
402             );
403             emit_range_frag(r, frag, frag_metrics, num_real_regs);
404             state[*r_state_ix as usize] = None;
405         }
406     }
407 }
408 
409 #[inline(never)]
get_range_frags<F: Function>( func: &F, rvb: &RegVecsAndBounds, reg_universe: &RealRegUniverse, liveins: &TypedIxVec<BlockIx, SparseSet<Reg>>, liveouts: &TypedIxVec<BlockIx, SparseSet<Reg>>, ) -> ( Vec< SmallVec<[RangeFragIx; 8]>>, Vec<RangeFrag>, Vec<RangeFragMetrics>, Vec< RegClass>, )410 fn get_range_frags<F: Function>(
411     func: &F,
412     rvb: &RegVecsAndBounds,
413     reg_universe: &RealRegUniverse,
414     liveins: &TypedIxVec<BlockIx, SparseSet<Reg>>,
415     liveouts: &TypedIxVec<BlockIx, SparseSet<Reg>>,
416 ) -> (
417     Vec</*rreg index, then vreg index, */ SmallVec<[RangeFragIx; 8]>>,
418     Vec<RangeFrag>,
419     Vec<RangeFragMetrics>,
420     Vec</*vreg index,*/ RegClass>,
421 ) {
422     info!("    get_range_frags: begin");
423     debug_assert!(liveins.len() == func.blocks().len() as u32);
424     debug_assert!(liveouts.len() == func.blocks().len() as u32);
425     debug_assert!(rvb.is_sanitized());
426 
427     let mut vreg_classes = vec![RegClass::INVALID; func.get_num_vregs()];
428     for r in rvb
429         .vecs
430         .uses
431         .iter()
432         .chain(rvb.vecs.defs.iter())
433         .chain(rvb.vecs.mods.iter())
434     {
435         if r.is_real() {
436             continue;
437         }
438         let r_ix = r.get_index();
439         let vreg_classes_ptr = &mut vreg_classes[r_ix];
440         if *vreg_classes_ptr == RegClass::INVALID {
441             *vreg_classes_ptr = r.get_class();
442         } else {
443             debug_assert_eq!(*vreg_classes_ptr, r.get_class());
444         }
445     }
446 
447     let num_real_regs = reg_universe.regs.len();
448     let num_virtual_regs = vreg_classes.len();
449     let num_regs = num_real_regs + num_virtual_regs;
450 
451     // Reused by the function below.
452     let mut tmp_state = vec![None; num_regs];
453     let mut tmp_visited = Vec::with_capacity(32);
454 
455     let mut result_map = vec![SmallVec::new(); num_regs];
456     let mut result_frags = Vec::new();
457     let mut result_frag_metrics = Vec::new();
458     for bix in func.blocks() {
459         get_range_frags_for_block(
460             func,
461             &rvb,
462             reg_universe,
463             &vreg_classes,
464             bix,
465             &liveins[bix],
466             &liveouts[bix],
467             &mut tmp_visited,
468             &mut tmp_state,
469             &mut result_map,
470             &mut result_frags,
471             &mut result_frag_metrics,
472         );
473     }
474 
475     assert!(tmp_state.len() == num_regs);
476     assert!(result_map.len() == num_regs);
477     assert!(vreg_classes.len() == num_virtual_regs);
478     // This is pretty cheap (once per fn) and any failure will be catastrophic since it means we
479     // may have forgotten some live range fragments.  Hence `assert!` and not `debug_assert!`.
480     for state_elem in &tmp_state {
481         assert!(state_elem.is_none());
482     }
483 
484     if log_enabled!(Level::Debug) {
485         debug!("");
486         let mut n = 0;
487         for frag in result_frags.iter() {
488             debug!("{:<3?}   {:?}", RangeFragIx::new(n), frag);
489             n += 1;
490         }
491 
492         debug!("");
493         for (reg_ix, frag_ixs) in result_map.iter().enumerate() {
494             if frag_ixs.len() == 0 {
495                 continue;
496             }
497             let reg = reg_ix_to_reg(reg_universe, &vreg_classes, reg_ix as u32);
498             debug!(
499                 "frags for {}   {:?}",
500                 reg.show_with_rru(reg_universe),
501                 frag_ixs
502             );
503         }
504     }
505 
506     info!("    get_range_frags: end");
507     assert!(result_frags.len() == result_frag_metrics.len());
508 
509     (result_map, result_frags, result_frag_metrics, vreg_classes)
510 }
511 
512 #[inline(never)]
merge_range_frags( reg_universe: &RealRegUniverse, frag_ix_vec_per_reg: &[SmallVec<[RangeFragIx; 8]>], frag_env: &mut Vec<RangeFrag>, frag_metrics_env: &Vec<RangeFragMetrics>, cfg_info: &CFGInfo, vreg_classes: &Vec< RegClass>, ) -> (Vec<FixedInterval>, Vec<VirtualInterval>)513 fn merge_range_frags(
514     reg_universe: &RealRegUniverse,
515     frag_ix_vec_per_reg: &[SmallVec<[RangeFragIx; 8]>],
516     frag_env: &mut Vec<RangeFrag>,
517     frag_metrics_env: &Vec<RangeFragMetrics>,
518     cfg_info: &CFGInfo,
519     vreg_classes: &Vec</*vreg index,*/ RegClass>,
520 ) -> (Vec<FixedInterval>, Vec<VirtualInterval>) {
521     info!("    merge_range_frags: begin");
522     if log_enabled!(Level::Info) {
523         let mut stats_num_total_incoming_frags = 0;
524         for all_frag_ixs_for_reg in frag_ix_vec_per_reg.iter() {
525             stats_num_total_incoming_frags += all_frag_ixs_for_reg.len();
526         }
527         info!("      in: {} in frag_env", frag_env.len());
528         info!(
529             "      in: {} regs containing in total {} frags",
530             frag_ix_vec_per_reg.len(),
531             stats_num_total_incoming_frags
532         );
533     }
534 
535     debug_assert!(frag_env.len() == frag_metrics_env.len());
536 
537     // Prefill fixed intervals, one per real register.
538     let mut result_fixed = Vec::with_capacity(reg_universe.regs.len() as usize);
539     for rreg in reg_universe.regs.iter() {
540         result_fixed.push(FixedInterval {
541             reg: rreg.0,
542             frags: Vec::new(),
543         });
544     }
545 
546     let mut result_virtual = Vec::new();
547 
548     let mut triples = Vec::<(RangeFragIx, RangeFragKind, BlockIx)>::new();
549 
550     // BEGIN per_reg_loop
551     for (reg_ix, all_frag_ixs_for_reg) in frag_ix_vec_per_reg.iter().enumerate() {
552         let reg = reg_ix_to_reg(reg_universe, vreg_classes, reg_ix as u32);
553 
554         let num_reg_frags = all_frag_ixs_for_reg.len();
555 
556         // The reg might never have been mentioned at all, especially if it's a real reg.
557         if num_reg_frags == 0 {
558             continue;
559         }
560 
561         // Do some shortcutting.  First off, if there's only one frag for this reg, we can directly
562         // give it its own live range, and have done.
563         if num_reg_frags == 1 {
564             flush_interval(
565                 &mut result_fixed,
566                 &mut result_virtual,
567                 reg,
568                 all_frag_ixs_for_reg,
569                 frag_env,
570             );
571             continue;
572         }
573 
574         // BEGIN merge `all_frag_ixs_for_reg` entries as much as possible.
575         // but .. if we come across independents (RangeKind::Local), pull them out
576         // immediately.
577         triples.clear();
578 
579         // Create `triples`.  We will use it to guide the merging phase, but it is immutable there.
580         for fix in all_frag_ixs_for_reg {
581             let frag_metrics = &frag_metrics_env[fix.get() as usize];
582 
583             if frag_metrics.kind == RangeFragKind::Local {
584                 // This frag is Local (standalone).  Give it its own Range and move on.  This is an
585                 // optimisation, but it's also necessary: the main fragment-merging logic below
586                 // relies on the fact that the fragments it is presented with are all either
587                 // LiveIn, LiveOut or Thru.
588                 flush_interval(
589                     &mut result_fixed,
590                     &mut result_virtual,
591                     reg,
592                     &[*fix],
593                     frag_env,
594                 );
595                 continue;
596             }
597 
598             // This frag isn't Local (standalone) so we have to process it the slow way.
599             triples.push((*fix, frag_metrics.kind, frag_metrics.bix));
600         }
601 
602         let triples_len = triples.len();
603 
604         // This is the core of the merging algorithm.
605         //
606         // For each ix@(fix, kind, bix) in `triples` (order unimportant):
607         //
608         // (1) "Merge with blocks that are live 'downstream' from here":
609         //     if fix is live-out or live-through:
610         //        for b in succs[bix]
611         //           for each ix2@(fix2, kind2, bix2) in `triples`
612         //              if bix2 == b && kind2 is live-in or live-through:
613         //                  merge(ix, ix2)
614         //
615         // (2) "Merge with blocks that are live 'upstream' from here":
616         //     if fix is live-in or live-through:
617         //        for b in preds[bix]
618         //           for each ix2@(fix2, kind2, bix2) in `triples`
619         //              if bix2 == b && kind2 is live-out or live-through:
620         //                  merge(ix, ix2)
621         //
622         // `triples` remains unchanged.  The equivalence class info is accumulated
623         // in `eclasses_uf` instead.  `eclasses_uf` entries are indices into
624         // `triples`.
625         //
626         // Now, you might think it necessary to do both (1) and (2).  But no, they
627         // are mutually redundant, since if two blocks are connected by a live
628         // flow from one to the other, then they are also connected in the other
629         // direction.  Hence checking one of the directions is enough.
630         let mut eclasses_uf = UnionFind::<usize>::new(triples_len);
631 
632         // We have two schemes for group merging, one of which is N^2 in the
633         // length of triples, the other is N-log-N, but with higher constant
634         // factors.  Some experimentation with the bz2 test on a Cortex A57 puts
635         // the optimal crossover point between 200 and 300; it's not critical.
636         // Having this protects us against bad behaviour for huge inputs whilst
637         // still being fast for small inputs.
638         if triples_len <= 250 {
639             // The simple way, which is N^2 in the length of `triples`.
640             for (ix, (_fix, kind, bix)) in triples.iter().enumerate() {
641                 // Deal with liveness flows outbound from `fix`. Meaning, (1) above.
642                 if *kind == RangeFragKind::LiveOut || *kind == RangeFragKind::Thru {
643                     for b in cfg_info.succ_map[*bix].iter() {
644                         // Visit all entries in `triples` that are for `b`.
645                         for (ix2, (_fix2, kind2, bix2)) in triples.iter().enumerate() {
646                             if *bix2 != *b || *kind2 == RangeFragKind::LiveOut {
647                                 continue;
648                             }
649                             debug_assert!(
650                                 *kind2 == RangeFragKind::LiveIn || *kind2 == RangeFragKind::Thru
651                             );
652                             // Now we know that liveness for this reg "flows" from `triples[ix]` to
653                             // `triples[ix2]`.  So those two frags must be part of the same live
654                             // range.  Note this.
655                             if ix != ix2 {
656                                 eclasses_uf.union(ix, ix2); // Order of args irrelevant
657                             }
658                         }
659                     }
660                 }
661             } // outermost iteration over `triples`
662         } else {
663             // The more complex way, which is N-log-N in the length of `triples`.  This is the same
664             // as the simple way, except that the innermost loop, which is a linear search in
665             // `triples` to find entries for some block `b`, is replaced by a binary search.  This
666             // means that `triples` first needs to be sorted by block index.
667             triples.sort_unstable_by_key(|(_, _, bix)| *bix);
668 
669             for (ix, (_fix, kind, bix)) in triples.iter().enumerate() {
670                 // Deal with liveness flows outbound from `fix`.  Meaning, (1) above.
671                 if *kind == RangeFragKind::LiveOut || *kind == RangeFragKind::Thru {
672                     for b in cfg_info.succ_map[*bix].iter() {
673                         // Visit all entries in `triples` that are for `b`.  Binary search
674                         // `triples` to find the lowest-indexed entry for `b`.
675                         let mut ix_left = 0;
676                         let mut ix_right = triples_len;
677                         while ix_left < ix_right {
678                             let m = (ix_left + ix_right) >> 1;
679                             if triples[m].2 < *b {
680                                 ix_left = m + 1;
681                             } else {
682                                 ix_right = m;
683                             }
684                         }
685 
686                         // It might be that there is no block for `b` in the sequence.  That's
687                         // legit; it just means that block `bix` jumps to a successor where the
688                         // associated register isn't live-in/thru.  A failure to find `b` can be
689                         // indicated one of two ways:
690                         //
691                         // * ix_left == triples_len
692                         // * ix_left < triples_len and b < triples[ix_left].b
693                         //
694                         // In both cases I *think* the 'loop_over_entries_for_b below will not do
695                         // anything.  But this is all a bit hairy, so let's convert the second
696                         // variant into the first, so as to make it obvious that the loop won't do
697                         // anything.
698 
699                         // ix_left now holds the lowest index of any `triples` entry for block `b`.
700                         // Assert this.
701                         if ix_left < triples_len && *b < triples[ix_left].2 {
702                             ix_left = triples_len;
703                         }
704                         if ix_left < triples_len {
705                             assert!(ix_left == 0 || triples[ix_left - 1].2 < *b);
706                         }
707 
708                         // ix2 plays the same role as in the quadratic version.  ix_left and
709                         // ix_right are not used after this point.
710                         let mut ix2 = ix_left;
711                         loop {
712                             let (_fix2, kind2, bix2) = match triples.get(ix2) {
713                                 None => break,
714                                 Some(triple) => *triple,
715                             };
716                             if *b < bix2 {
717                                 // We've come to the end of the sequence of `b`-blocks.
718                                 break;
719                             }
720                             debug_assert!(*b == bix2);
721                             if kind2 == RangeFragKind::LiveOut {
722                                 ix2 += 1;
723                                 continue;
724                             }
725                             // Now we know that liveness for this reg "flows" from `triples[ix]` to
726                             // `triples[ix2]`.  So those two frags must be part of the same live
727                             // range.  Note this.
728                             eclasses_uf.union(ix, ix2);
729                             ix2 += 1;
730                         }
731 
732                         if ix2 + 1 < triples_len {
733                             debug_assert!(*b < triples[ix2 + 1].2);
734                         }
735                     }
736                 }
737             }
738         }
739 
740         // Now `eclasses_uf` contains the results of the merging-search.  Visit each of its
741         // equivalence classes in turn, and convert each into a virtual or real live range as
742         // appropriate.
743         let eclasses = eclasses_uf.get_equiv_classes();
744         for leader_triple_ix in eclasses.equiv_class_leaders_iter() {
745             // `leader_triple_ix` is an eclass leader.  Enumerate the whole eclass.
746             let mut frag_ixs = SmallVec::<[RangeFragIx; 4]>::new();
747             for triple_ix in eclasses.equiv_class_elems_iter(leader_triple_ix) {
748                 frag_ixs.push(triples[triple_ix].0 /*first field is frag ix*/);
749             }
750             flush_interval(
751                 &mut result_fixed,
752                 &mut result_virtual,
753                 reg,
754                 &frag_ixs,
755                 frag_env,
756             );
757         }
758         // END merge `all_frag_ixs_for_reg` entries as much as possible
759     } // END per reg loop
760 
761     info!("    merge_range_frags: end");
762 
763     (result_fixed, result_virtual)
764 }
765 
766 #[inline(never)]
flush_interval( result_real: &mut Vec<FixedInterval>, result_virtual: &mut Vec<VirtualInterval>, reg: Reg, frag_ixs: &[RangeFragIx], frags: &mut Vec<RangeFrag>, )767 fn flush_interval(
768     result_real: &mut Vec<FixedInterval>,
769     result_virtual: &mut Vec<VirtualInterval>,
770     reg: Reg,
771     frag_ixs: &[RangeFragIx],
772     frags: &mut Vec<RangeFrag>,
773 ) {
774     if reg.is_real() {
775         // Append all the RangeFrags to this fixed interval. They'll get sorted later.
776         result_real[reg.to_real_reg().get_index()]
777             .frags
778             .extend(frag_ixs.iter().map(|&i| {
779                 let frag = &mut frags[i.get() as usize];
780                 RangeFrag {
781                     first: frag.first,
782                     last: frag.last,
783                     mentions: mem::replace(&mut frag.mentions, MentionMap::new()),
784                 }
785             }));
786         return;
787     }
788 
789     debug_assert!(reg.is_virtual());
790 
791     let (start, end, mentions) = {
792         // Merge all the mentions together.
793         let capacity = frag_ixs
794             .iter()
795             .map(|fix| frags[fix.get() as usize].mentions.len())
796             .fold(0, |a, b| a + b);
797 
798         let mut start = InstPoint::max_value();
799         let mut end = InstPoint::min_value();
800 
801         // TODO rework this!
802         let mut mentions = MentionMap::with_capacity(capacity);
803         for frag in frag_ixs.iter().map(|fix| &frags[fix.get() as usize]) {
804             mentions.extend(frag.mentions.iter().cloned());
805             start = InstPoint::min(start, frag.first);
806             end = InstPoint::max(end, frag.last);
807         }
808         mentions.sort_unstable_by_key(|tuple| tuple.0);
809 
810         // Merge mention set that are at the same instruction.
811         let mut s = 0;
812         let mut e;
813         let mut to_remove = Vec::new();
814         while s < mentions.len() {
815             e = s;
816             while e + 1 < mentions.len() && mentions[s].0 == mentions[e + 1].0 {
817                 e += 1;
818             }
819             if s != e {
820                 let mut i = s + 1;
821                 while i <= e {
822                     if mentions[i].1.is_use() {
823                         mentions[s].1.add_use();
824                     }
825                     if mentions[i].1.is_mod() {
826                         mentions[s].1.add_mod();
827                     }
828                     if mentions[i].1.is_def() {
829                         mentions[s].1.add_def();
830                     }
831                     i += 1;
832                 }
833                 for i in s + 1..=e {
834                     to_remove.push(i);
835                 }
836             }
837             s = e + 1;
838         }
839 
840         for &i in to_remove.iter().rev() {
841             // TODO not efficient.
842             mentions.remove(i);
843         }
844 
845         (start, end, mentions)
846     };
847 
848     let id = IntId(result_virtual.len());
849     let mut int = VirtualInterval::new(id, reg.to_virtual_reg(), start, end, mentions);
850     int.ancestor = Some(id);
851 
852     result_virtual.push(int);
853 }
854