regalloc2/ion/
liveranges.rs

1/*
2 * This file was initially derived from the files
3 * `js/src/jit/BacktrackingAllocator.h` and
4 * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was
5 * originally licensed under the Mozilla Public License 2.0. We
6 * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see
7 * https://github.com/bytecodealliance/regalloc2/issues/7).
8 *
9 * Since the initial port, the design has been substantially evolved
10 * and optimized.
11 */
12
13//! Live-range computation.
14
15use super::{
16    CodeRange, Env, LiveRangeFlag, LiveRangeIndex, LiveRangeKey, LiveRangeList, LiveRangeListEntry,
17    LiveRangeSet, PRegData, PRegIndex, RegClass, Use, VRegData, VRegIndex,
18};
19use crate::indexset::IndexSet;
20use crate::ion::data_structures::{
21    BlockparamIn, BlockparamOut, FixedRegFixupLevel, MultiFixedRegFixup,
22};
23use crate::{
24    Allocation, Block, Function, Inst, InstPosition, Operand, OperandConstraint, OperandKind,
25    OperandPos, PReg, ProgPoint, RegAllocError, VReg, VecExt,
26};
27use core::convert::TryFrom;
28use core::usize;
29use smallvec::{smallvec, SmallVec};
30
31/// A spill weight computed for a certain Use.
32#[derive(Clone, Copy, Debug)]
33pub struct SpillWeight(f32);
34
35#[inline(always)]
36pub fn spill_weight_from_constraint(
37    constraint: OperandConstraint,
38    loop_depth: usize,
39    is_def: bool,
40) -> SpillWeight {
41    // A bonus of 1000 for one loop level, 4000 for two loop levels,
42    // 16000 for three loop levels, etc. Avoids exponentiation.
43    let loop_depth = core::cmp::min(10, loop_depth);
44    let hot_bonus: f32 = (0..loop_depth).fold(1000.0, |a, _| a * 4.0);
45    let def_bonus: f32 = if is_def { 2000.0 } else { 0.0 };
46    let constraint_bonus: f32 = match constraint {
47        OperandConstraint::Any => 1000.0,
48        OperandConstraint::Reg | OperandConstraint::FixedReg(_) => 2000.0,
49        _ => 0.0,
50    };
51    SpillWeight(hot_bonus + def_bonus + constraint_bonus)
52}
53
54impl SpillWeight {
55    /// Convert a floating-point weight to a u16 that can be compactly
56    /// stored in a `Use`. We simply take the top 16 bits of the f32; this
57    /// is equivalent to the bfloat16 format
58    /// (https://en.wikipedia.org/wiki/Bfloat16_floating-point_format).
59    pub fn to_bits(self) -> u16 {
60        (self.0.to_bits() >> 15) as u16
61    }
62
63    /// Convert a value that was returned from
64    /// `SpillWeight::to_bits()` back into a `SpillWeight`. Note that
65    /// some precision may be lost when round-tripping from a spill
66    /// weight to packed bits and back.
67    pub fn from_bits(bits: u16) -> SpillWeight {
68        let x = f32::from_bits((bits as u32) << 15);
69        SpillWeight(x)
70    }
71
72    /// Get a zero spill weight.
73    pub fn zero() -> SpillWeight {
74        SpillWeight(0.0)
75    }
76
77    /// Convert to a raw floating-point value.
78    pub fn to_f32(self) -> f32 {
79        self.0
80    }
81
82    /// Create a `SpillWeight` from a raw floating-point value.
83    pub fn from_f32(x: f32) -> SpillWeight {
84        SpillWeight(x)
85    }
86
87    pub fn to_int(self) -> u32 {
88        self.0 as u32
89    }
90}
91
92impl core::ops::Add<SpillWeight> for SpillWeight {
93    type Output = SpillWeight;
94    fn add(self, other: SpillWeight) -> Self {
95        SpillWeight(self.0 + other.0)
96    }
97}
98
99fn slot_idx(i: usize) -> Result<u16, RegAllocError> {
100    u16::try_from(i).map_err(|_| RegAllocError::TooManyOperands)
101}
102
103impl<'a, F: Function> Env<'a, F> {
104    pub fn create_pregs_and_vregs(&mut self) {
105        // Create PRegs from the env.
106        self.pregs.resize(
107            PReg::NUM_INDEX,
108            PRegData {
109                allocations: LiveRangeSet::new(),
110                is_stack: false,
111            },
112        );
113        for &preg in &self.env.fixed_stack_slots {
114            self.pregs[preg.index()].is_stack = true;
115        }
116        for class in 0..self.preferred_victim_by_class.len() {
117            self.preferred_victim_by_class[class] = self.env.non_preferred_regs_by_class[class]
118                .last()
119                .or(self.env.preferred_regs_by_class[class].last())
120                .cloned()
121                .unwrap_or(PReg::invalid());
122        }
123        // Create VRegs from the vreg count.
124        for idx in 0..self.func.num_vregs() {
125            // We'll fill in the real details when we see the def.
126            self.ctx.vregs.add(
127                VReg::new(idx, RegClass::Int),
128                VRegData {
129                    ranges: LiveRangeList::new_in(self.ctx.bump()),
130                    blockparam: Block::invalid(),
131                    // We'll learn the RegClass as we scan the code.
132                    class: None,
133                },
134            );
135        }
136        // Create allocations too.
137        for inst in 0..self.func.num_insts() {
138            let start = self.output.allocs.len() as u32;
139            self.output.inst_alloc_offsets.push(start);
140            for _ in 0..self.func.inst_operands(Inst::new(inst)).len() {
141                self.output.allocs.push(Allocation::none());
142            }
143        }
144    }
145
146    /// Mark `range` as live for the given `vreg`.
147    ///
148    /// Returns the liverange that contains the given range.
149    pub fn add_liverange_to_vreg(
150        &mut self,
151        vreg: VRegIndex,
152        mut range: CodeRange,
153    ) -> LiveRangeIndex {
154        trace!("add_liverange_to_vreg: vreg {:?} range {:?}", vreg, range);
155
156        // Invariant: as we are building liveness information, we
157        // *always* process instructions bottom-to-top, and as a
158        // consequence, new liveranges are always created before any
159        // existing liveranges for a given vreg. We assert this here,
160        // then use it to avoid an O(n) merge step (which would lead
161        // to O(n^2) liveness construction cost overall).
162        //
163        // We store liveranges in reverse order in the `.ranges`
164        // array, then reverse them at the end of
165        // `compute_liveness()`.
166
167        if !self.vregs[vreg].ranges.is_empty() {
168            let last_range_index = self.vregs[vreg].ranges.last().unwrap().index;
169            let last_range = self.ranges[last_range_index].range;
170            if self.func.allow_multiple_vreg_defs() {
171                if last_range.contains(&range) {
172                    // Special case (may occur when multiple defs of pinned
173                    // physical regs occur): if this new range overlaps the
174                    // existing range, return it.
175                    return last_range_index;
176                }
177                // If this range's end falls in the middle of the last
178                // range, truncate it to be contiguous so we can merge
179                // below.
180                if range.to >= last_range.from && range.to <= last_range.to {
181                    range.to = last_range.from;
182                }
183            }
184            debug_assert!(
185                range.to <= last_range.from,
186                "range {:?}, last_range {:?}",
187                range,
188                last_range
189            );
190        }
191
192        if self.vregs[vreg].ranges.is_empty()
193            || range.to
194                < self.ranges[self.vregs[vreg].ranges.last().unwrap().index]
195                    .range
196                    .from
197        {
198            // Is not contiguous with previously-added (immediately
199            // following) range; create a new range.
200            let lr = self.ctx.ranges.add(range, self.ctx.bump());
201            self.ranges[lr].vreg = vreg;
202            self.vregs[vreg]
203                .ranges
204                .push(LiveRangeListEntry { range, index: lr });
205            lr
206        } else {
207            // Is contiguous with previously-added range; just extend
208            // its range and return it.
209            let lr = self.vregs[vreg].ranges.last().unwrap().index;
210            debug_assert!(range.to == self.ranges[lr].range.from);
211            self.ranges[lr].range.from = range.from;
212            lr
213        }
214    }
215
216    pub fn insert_use_into_liverange(&mut self, into: LiveRangeIndex, mut u: Use) {
217        let operand = u.operand;
218        let constraint = operand.constraint();
219        let block = self.cfginfo.insn_block[u.pos.inst().index()];
220        let loop_depth = self.cfginfo.approx_loop_depth[block.index()] as usize;
221        let weight = spill_weight_from_constraint(
222            constraint,
223            loop_depth,
224            operand.kind() != OperandKind::Use,
225        );
226        u.weight = weight.to_bits();
227
228        trace!(
229            "insert use {:?} into lr {:?} with weight {:?}",
230            u,
231            into,
232            weight,
233        );
234
235        // N.B.: we do *not* update `requirement` on the range,
236        // because those will be computed during the multi-fixed-reg
237        // fixup pass later (after all uses are inserted).
238
239        self.ranges[into].uses.push(u);
240
241        // Update stats.
242        let range_weight = self.ranges[into].uses_spill_weight() + weight;
243        self.ranges[into].set_uses_spill_weight(range_weight);
244        trace!(
245            "  -> now range has weight {:?}",
246            self.ranges[into].uses_spill_weight(),
247        );
248    }
249
250    pub fn find_vreg_liverange_for_pos(
251        &self,
252        vreg: VRegIndex,
253        pos: ProgPoint,
254    ) -> Option<LiveRangeIndex> {
255        for entry in &self.vregs[vreg].ranges {
256            if entry.range.contains_point(pos) {
257                return Some(entry.index);
258            }
259        }
260        None
261    }
262
263    pub fn add_liverange_to_preg(&mut self, range: CodeRange, reg: PReg) {
264        trace!("adding liverange to preg: {:?} to {}", range, reg);
265        let preg_idx = PRegIndex::new(reg.index());
266        let res = self.pregs[preg_idx.index()]
267            .allocations
268            .btree
269            .insert(LiveRangeKey::from_range(&range), LiveRangeIndex::invalid());
270        debug_assert!(res.is_none());
271    }
272
273    pub fn is_live_in(&mut self, block: Block, vreg: VRegIndex) -> bool {
274        self.liveins[block.index()].get(vreg.index())
275    }
276
277    pub fn compute_liveness(&mut self) -> Result<(), RegAllocError> {
278        // Create initial LiveIn and LiveOut bitsets.
279        for _ in 0..self.func.num_blocks() {
280            self.liveins.push(IndexSet::new());
281            self.liveouts.push(IndexSet::new());
282        }
283
284        // Run a worklist algorithm to precisely compute liveins and
285        // liveouts.
286        let mut workqueue = core::mem::take(&mut self.ctx.scratch_workqueue);
287        let mut workqueue_set = core::mem::take(&mut self.ctx.scratch_workqueue_set);
288        workqueue_set.clear();
289        // Initialize workqueue with postorder traversal.
290        for &block in &self.cfginfo.postorder[..] {
291            workqueue.push_back(block);
292            workqueue_set.insert(block);
293        }
294
295        while let Some(block) = workqueue.pop_front() {
296            workqueue_set.remove(&block);
297            let insns = self.func.block_insns(block);
298
299            trace!("computing liveins for block{}", block.index());
300
301            self.output.stats.livein_iterations += 1;
302
303            let mut live = self.liveouts[block.index()].clone();
304            trace!(" -> initial liveout set: {:?}", live);
305
306            // Include outgoing blockparams in the initial live set.
307            if self.func.is_branch(insns.last()) {
308                for i in 0..self.func.block_succs(block).len() {
309                    for &param in self.func.branch_blockparams(block, insns.last(), i) {
310                        live.set(param.vreg(), true);
311                        self.observe_vreg_class(param);
312                    }
313                }
314            }
315
316            for inst in insns.iter().rev() {
317                for pos in &[OperandPos::Late, OperandPos::Early] {
318                    for op in self.func.inst_operands(inst) {
319                        if op.as_fixed_nonallocatable().is_some() {
320                            continue;
321                        }
322                        if op.pos() == *pos {
323                            let was_live = live.get(op.vreg().vreg());
324                            trace!("op {:?} was_live = {}", op, was_live);
325                            match op.kind() {
326                                OperandKind::Use => {
327                                    live.set(op.vreg().vreg(), true);
328                                }
329                                OperandKind::Def => {
330                                    live.set(op.vreg().vreg(), false);
331                                }
332                            }
333                            self.observe_vreg_class(op.vreg());
334                        }
335                    }
336                }
337            }
338            for &blockparam in self.func.block_params(block) {
339                live.set(blockparam.vreg(), false);
340                self.observe_vreg_class(blockparam);
341            }
342
343            for &pred in self.func.block_preds(block) {
344                if self.ctx.liveouts[pred.index()].union_with(&live) {
345                    if !workqueue_set.contains(&pred) {
346                        workqueue_set.insert(pred);
347                        workqueue.push_back(pred);
348                    }
349                }
350            }
351
352            trace!("computed liveins at block{}: {:?}", block.index(), live);
353            self.liveins[block.index()] = live;
354        }
355
356        // Check that there are no liveins to the entry block.
357        if !self.liveins[self.func.entry_block().index()].is_empty() {
358            trace!(
359                "non-empty liveins to entry block: {:?}",
360                self.liveins[self.func.entry_block().index()]
361            );
362            return Err(RegAllocError::EntryLivein);
363        }
364
365        self.ctx.scratch_workqueue = workqueue;
366        self.ctx.scratch_workqueue_set = workqueue_set;
367
368        Ok(())
369    }
370
371    pub fn build_liveranges(&mut self) -> Result<(), RegAllocError> {
372        // Create Uses and Defs referring to VRegs, and place the Uses
373        // in LiveRanges.
374        //
375        // We already computed precise liveouts and liveins for every
376        // block above, so we don't need to run an iterative algorithm
377        // here; instead, every block's computation is purely local,
378        // from end to start.
379
380        // Track current LiveRange for each vreg.
381        //
382        // Invariant: a stale range may be present here; ranges are
383        // only valid if `live.get(vreg)` is true.
384        let mut vreg_ranges = core::mem::take(&mut self.ctx.scratch_vreg_ranges);
385        vreg_ranges.repopulate(self.func.num_vregs(), LiveRangeIndex::invalid());
386        let mut operand_rewrites = core::mem::take(&mut self.ctx.scratch_operand_rewrites);
387
388        for i in (0..self.func.num_blocks()).rev() {
389            let block = Block::new(i);
390            let insns = self.func.block_insns(block);
391
392            self.output.stats.livein_blocks += 1;
393
394            // Init our local live-in set.
395            let mut live = self.liveouts[block.index()].clone();
396
397            // If the last instruction is a branch (rather than
398            // return), create blockparam_out entries.
399            if self.func.is_branch(insns.last()) {
400                for (i, &succ) in self.func.block_succs(block).iter().enumerate() {
401                    let blockparams_in = self.func.block_params(succ);
402                    let blockparams_out = self.func.branch_blockparams(block, insns.last(), i);
403                    for (&blockparam_in, &blockparam_out) in
404                        blockparams_in.iter().zip(blockparams_out)
405                    {
406                        let blockparam_out = VRegIndex::new(blockparam_out.vreg());
407                        let blockparam_in = VRegIndex::new(blockparam_in.vreg());
408                        self.blockparam_outs.push(BlockparamOut {
409                            to_vreg: blockparam_in,
410                            to_block: succ,
411                            from_block: block,
412                            from_vreg: blockparam_out,
413                        });
414
415                        // Include outgoing blockparams in the initial live set.
416                        live.set(blockparam_out.index(), true);
417                    }
418                }
419            }
420
421            // Initially, registers are assumed live for the whole block.
422            for vreg in live.iter() {
423                let range = CodeRange {
424                    from: self.cfginfo.block_entry[block.index()],
425                    to: self.cfginfo.block_exit[block.index()].next(),
426                };
427                trace!(
428                    "vreg {:?} live at end of block --> create range {:?}",
429                    VRegIndex::new(vreg),
430                    range
431                );
432                let lr = self.add_liverange_to_vreg(VRegIndex::new(vreg), range);
433                vreg_ranges[vreg] = lr;
434            }
435
436            // Create vreg data for blockparams.
437            for &param in self.func.block_params(block) {
438                self.vregs[param].blockparam = block;
439            }
440
441            // For each instruction, in reverse order, process
442            // operands and clobbers.
443            for inst in insns.iter().rev() {
444                // Mark clobbers with CodeRanges on PRegs.
445                for clobber in self.func.inst_clobbers(inst) {
446                    // Clobber range is at After point only: an
447                    // instruction can still take an input in a reg
448                    // that it later clobbers. (In other words, the
449                    // clobber is like a normal def that never gets
450                    // used.)
451                    let range = CodeRange {
452                        from: ProgPoint::after(inst),
453                        to: ProgPoint::before(inst.next()),
454                    };
455                    self.add_liverange_to_preg(range, clobber);
456                }
457
458                // Does the instruction have any input-reusing
459                // outputs? This is important below to establish
460                // proper interference wrt other inputs. We note the
461                // *vreg* that is reused, not the index.
462                let mut reused_input = None;
463                for op in self.func.inst_operands(inst) {
464                    if let OperandConstraint::Reuse(i) = op.constraint() {
465                        debug_assert!(self.func.inst_operands(inst)[i]
466                            .as_fixed_nonallocatable()
467                            .is_none());
468                        reused_input = Some(self.func.inst_operands(inst)[i].vreg());
469                        break;
470                    }
471                }
472
473                // Preprocess defs and uses. Specifically, if there
474                // are any fixed-reg-constrained defs at Late position
475                // and fixed-reg-constrained uses at Early position
476                // with the same preg, we need to (i) add a fixup move
477                // for the use, (ii) rewrite the use to have an Any
478                // constraint, and (ii) move the def to Early position
479                // to reserve the register for the whole instruction.
480                //
481                // We don't touch any fixed-early-def or fixed-late-use
482                // constraints: the only situation where the same physical
483                // register can be used multiple times in the same
484                // instruction is with an early-use and a late-def. Anything
485                // else is a user error.
486                operand_rewrites.clear();
487                let mut late_def_fixed: SmallVec<[PReg; 8]> = smallvec![];
488                for &operand in self.func.inst_operands(inst) {
489                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
490                        match (operand.pos(), operand.kind()) {
491                            (OperandPos::Late, OperandKind::Def) => {
492                                late_def_fixed.push(preg);
493                            }
494                            _ => {}
495                        }
496                    }
497                }
498                for (i, &operand) in self.func.inst_operands(inst).iter().enumerate() {
499                    if operand.as_fixed_nonallocatable().is_some() {
500                        continue;
501                    }
502                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
503                        match (operand.pos(), operand.kind()) {
504                            (OperandPos::Early, OperandKind::Use)
505                                if live.get(operand.vreg().vreg()) =>
506                            {
507                                // If we have a use constraint at the
508                                // Early point for a fixed preg, and
509                                // this preg is also constrained with
510                                // a *separate* def at Late or is
511                                // clobbered, and *if* the vreg is
512                                // live downward, we have to use the
513                                // multi-fixed-reg mechanism for a
514                                // fixup and rewrite here without the
515                                // constraint. See #53.
516                                //
517                                // We adjust the def liverange and Use
518                                // to an "early" position to reserve
519                                // the register, it still must not be
520                                // used by some other vreg at the
521                                // use-site.
522                                //
523                                // Note that we handle multiple
524                                // conflicting constraints for the
525                                // same vreg in a separate pass (see
526                                // `fixup_multi_fixed_vregs` below).
527                                if late_def_fixed.contains(&preg)
528                                    || self.func.inst_clobbers(inst).contains(preg)
529                                {
530                                    trace!(
531                                        concat!(
532                                            "-> operand {:?} is fixed to preg {:?}, ",
533                                            "is downward live, and there is also a ",
534                                            "def or clobber at this preg"
535                                        ),
536                                        operand,
537                                        preg
538                                    );
539                                    let pos = ProgPoint::before(inst);
540                                    self.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
541                                        pos,
542                                        from_slot: slot_idx(i)?,
543                                        to_slot: slot_idx(i)?,
544                                        to_preg: PRegIndex::new(preg.index()),
545                                        vreg: VRegIndex::new(operand.vreg().vreg()),
546                                        level: FixedRegFixupLevel::Initial,
547                                    });
548
549                                    // We need to insert a reservation
550                                    // at the before-point to reserve
551                                    // the reg for the use too.
552                                    let range = CodeRange::singleton(pos);
553                                    self.add_liverange_to_preg(range, preg);
554
555                                    // Remove the fixed-preg
556                                    // constraint from the Use.
557                                    operand_rewrites.insert(
558                                        i,
559                                        Operand::new(
560                                            operand.vreg(),
561                                            OperandConstraint::Any,
562                                            operand.kind(),
563                                            operand.pos(),
564                                        ),
565                                    );
566                                }
567                            }
568                            _ => {}
569                        }
570                    }
571                }
572
573                // Process defs and uses.
574                for &cur_pos in &[InstPosition::After, InstPosition::Before] {
575                    for i in 0..self.func.inst_operands(inst).len() {
576                        // don't borrow `self`
577                        let operand = operand_rewrites
578                            .get(&i)
579                            .cloned()
580                            .unwrap_or(self.func.inst_operands(inst)[i]);
581                        let pos = match (operand.kind(), operand.pos()) {
582                            (OperandKind::Def, OperandPos::Early) => ProgPoint::before(inst),
583                            (OperandKind::Def, OperandPos::Late) => ProgPoint::after(inst),
584                            (OperandKind::Use, OperandPos::Late) => ProgPoint::after(inst),
585                            // If there are any reused inputs in this
586                            // instruction, and this is *not* the
587                            // reused vreg, force `pos` to
588                            // `After`. This ensures that we correctly
589                            // account for the interference between
590                            // the other inputs and the
591                            // input-that-is-reused/output.
592                            (OperandKind::Use, OperandPos::Early)
593                                if reused_input.is_some()
594                                    && reused_input.unwrap() != operand.vreg() =>
595                            {
596                                ProgPoint::after(inst)
597                            }
598                            (OperandKind::Use, OperandPos::Early) => ProgPoint::before(inst),
599                        };
600
601                        if pos.pos() != cur_pos {
602                            continue;
603                        }
604
605                        trace!(
606                            "processing inst{} operand at {:?}: {:?}",
607                            inst.index(),
608                            pos,
609                            operand
610                        );
611
612                        // If this is a "fixed non-allocatable
613                        // register" operand, set the alloc
614                        // immediately and then ignore the operand
615                        // hereafter.
616                        if let Some(preg) = operand.as_fixed_nonallocatable() {
617                            self.set_alloc(inst, i, Allocation::reg(preg));
618                            continue;
619                        }
620
621                        match operand.kind() {
622                            OperandKind::Def => {
623                                trace!("Def of {} at {:?}", operand.vreg(), pos);
624
625                                // Get or create the LiveRange.
626                                let mut lr = vreg_ranges[operand.vreg().vreg()];
627                                trace!(" -> has existing LR {:?}", lr);
628                                // If there was no liverange (dead def), create a trivial one.
629                                if !live.get(operand.vreg().vreg()) {
630                                    let from = pos;
631                                    // We want to we want to span
632                                    // until Before of the next
633                                    // inst. This ensures that early
634                                    // defs used for temps on an
635                                    // instruction are reserved across
636                                    // the whole instruction.
637                                    let to = ProgPoint::before(pos.inst().next());
638                                    lr = self.add_liverange_to_vreg(
639                                        VRegIndex::new(operand.vreg().vreg()),
640                                        CodeRange { from, to },
641                                    );
642                                    trace!(" -> invalid; created {:?}", lr);
643                                    vreg_ranges[operand.vreg().vreg()] = lr;
644                                    live.set(operand.vreg().vreg(), true);
645                                }
646                                // Create the use in the LiveRange.
647                                self.insert_use_into_liverange(
648                                    lr,
649                                    Use::new(operand, pos, slot_idx(i)?),
650                                );
651                                // If def (not mod), this reg is now dead,
652                                // scanning backward; make it so.
653                                if operand.kind() == OperandKind::Def {
654                                    // Trim the range for this vreg to start
655                                    // at `pos` if it previously ended at the
656                                    // start of this block (i.e. was not
657                                    // merged into some larger LiveRange due
658                                    // to out-of-order blocks).
659                                    if self.ranges[lr].range.from
660                                        == self.cfginfo.block_entry[block.index()]
661                                    {
662                                        trace!(" -> started at block start; trimming to {:?}", pos);
663                                        self.ranges[lr].range.from = pos;
664                                    }
665
666                                    self.ranges[lr].set_flag(LiveRangeFlag::StartsAtDef);
667
668                                    // Remove from live-set.
669                                    live.set(operand.vreg().vreg(), false);
670                                    vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
671                                }
672                            }
673                            OperandKind::Use => {
674                                // Create/extend the LiveRange if it
675                                // doesn't already exist, and add the use
676                                // to the range.
677                                let mut lr = vreg_ranges[operand.vreg().vreg()];
678                                if !live.get(operand.vreg().vreg()) {
679                                    let range = CodeRange {
680                                        from: self.cfginfo.block_entry[block.index()],
681                                        to: pos.next(),
682                                    };
683                                    lr = self.add_liverange_to_vreg(
684                                        VRegIndex::new(operand.vreg().vreg()),
685                                        range,
686                                    );
687                                    vreg_ranges[operand.vreg().vreg()] = lr;
688                                }
689                                debug_assert!(lr.is_valid());
690
691                                trace!("Use of {:?} at {:?} -> {:?}", operand, pos, lr,);
692
693                                self.insert_use_into_liverange(
694                                    lr,
695                                    Use::new(operand, pos, slot_idx(i)?),
696                                );
697
698                                // Add to live-set.
699                                live.set(operand.vreg().vreg(), true);
700                            }
701                        }
702                    }
703                }
704            }
705
706            // Block parameters define vregs at the very beginning of
707            // the block. Remove their live vregs from the live set
708            // here.
709            for vreg in self.func.block_params(block) {
710                if live.get(vreg.vreg()) {
711                    live.set(vreg.vreg(), false);
712                } else {
713                    // Create trivial liverange if blockparam is dead.
714                    let start = self.cfginfo.block_entry[block.index()];
715                    self.add_liverange_to_vreg(
716                        VRegIndex::new(vreg.vreg()),
717                        CodeRange {
718                            from: start,
719                            to: start.next(),
720                        },
721                    );
722                }
723                // add `blockparam_ins` entries.
724                let vreg_idx = VRegIndex::new(vreg.vreg());
725                for &pred in self.func.block_preds(block) {
726                    self.blockparam_ins.push(BlockparamIn {
727                        to_vreg: vreg_idx,
728                        to_block: block,
729                        from_block: pred,
730                    });
731                }
732            }
733        }
734
735        // Make ranges in each vreg and uses in each range appear in
736        // sorted order. We built them in reverse order above, so this
737        // is a simple reversal, *not* a full sort.
738        //
739        // The ordering invariant is always maintained for uses and
740        // always for ranges in bundles (which are initialized later),
741        // but not always for ranges in vregs; those are sorted only
742        // when needed, here and then again at the end of allocation
743        // when resolving moves.
744
745        for vreg in &mut self.ctx.vregs {
746            vreg.ranges.reverse();
747            let mut last = None;
748            for entry in &mut vreg.ranges {
749                // Ranges may have been truncated above at defs. We
750                // need to update with the final range here.
751                entry.range = self.ctx.ranges[entry.index].range;
752                // Assert in-order and non-overlapping.
753                debug_assert!(last.is_none() || last.unwrap() <= entry.range.from);
754                last = Some(entry.range.to);
755            }
756        }
757
758        for range in &mut self.ranges {
759            range.uses.reverse();
760            debug_assert!(range.uses.windows(2).all(|win| win[0].pos <= win[1].pos));
761        }
762
763        self.blockparam_ins.sort_unstable_by_key(|x| x.key());
764        self.blockparam_outs.sort_unstable_by_key(|x| x.key());
765
766        self.output.stats.initial_liverange_count = self.ranges.len();
767        self.output.stats.blockparam_ins_count = self.blockparam_ins.len();
768        self.output.stats.blockparam_outs_count = self.blockparam_outs.len();
769        self.ctx.scratch_vreg_ranges = vreg_ranges;
770        self.ctx.scratch_operand_rewrites = operand_rewrites;
771
772        Ok(())
773    }
774
775    pub fn fixup_multi_fixed_vregs(&mut self) {
776        // Do a fixed-reg cleanup pass: if there are any LiveRanges with
777        // multiple uses at the same ProgPoint and there is
778        // more than one FixedReg constraint at that ProgPoint, we
779        // need to record all but one of them in a special fixup list
780        // and handle them later; otherwise, bundle-splitting to
781        // create minimal bundles becomes much more complex (we would
782        // have to split the multiple uses at the same progpoint into
783        // different bundles, which breaks invariants related to
784        // disjoint ranges and bundles).
785        let mut extra_clobbers: SmallVec<[(PReg, ProgPoint); 8]> = smallvec![];
786        for vreg in 0..self.vregs.len() {
787            let vreg = VRegIndex::new(vreg);
788            for range_idx in 0..self.vregs[vreg].ranges.len() {
789                let entry = self.vregs[vreg].ranges[range_idx];
790                let range = entry.index;
791                trace!("multi-fixed-reg cleanup: vreg {:?} range {:?}", vreg, range,);
792
793                // Find groups of uses that occur in at the same program point.
794                for uses in self.ctx.ranges[range]
795                    .uses
796                    .chunk_by_mut(|a, b| a.pos == b.pos)
797                {
798                    if uses.len() < 2 {
799                        continue;
800                    }
801
802                    // Search for conflicting constraints in the uses.
803                    let mut requires_reg = false;
804                    let mut num_fixed_reg = 0;
805                    let mut num_fixed_stack = 0;
806                    let mut first_reg_slot = None;
807                    let mut first_stack_slot = None;
808                    let mut min_limit = usize::MAX;
809                    let mut max_fixed_reg = usize::MIN;
810                    for u in uses.iter() {
811                        match u.operand.constraint() {
812                            OperandConstraint::Any => {
813                                first_reg_slot.get_or_insert(u.slot);
814                                first_stack_slot.get_or_insert(u.slot);
815                            }
816                            OperandConstraint::Reg | OperandConstraint::Reuse(_) => {
817                                first_reg_slot.get_or_insert(u.slot);
818                                requires_reg = true;
819                            }
820                            OperandConstraint::Limit(max) => {
821                                first_reg_slot.get_or_insert(u.slot);
822                                min_limit = min_limit.min(max);
823                                requires_reg = true;
824                            }
825                            OperandConstraint::FixedReg(preg) => {
826                                max_fixed_reg = max_fixed_reg.max(preg.hw_enc());
827                                if self.ctx.pregs[preg.index()].is_stack {
828                                    num_fixed_stack += 1;
829                                    first_stack_slot.get_or_insert(u.slot);
830                                } else {
831                                    requires_reg = true;
832                                    num_fixed_reg += 1;
833                                    first_reg_slot.get_or_insert(u.slot);
834                                }
835                            }
836                            // Maybe this could be supported in this future...
837                            OperandConstraint::Stack => panic!(
838                                "multiple uses of vreg with a Stack constraint are not supported"
839                            ),
840                        }
841                    }
842
843                    // Fast path if there are no conflicts.
844                    if num_fixed_reg + num_fixed_stack <= 1
845                        && !(requires_reg && num_fixed_stack != 0)
846                        && max_fixed_reg < min_limit
847                    {
848                        continue;
849                    }
850
851                    // We pick one constraint (in order: FixedReg, Reg, FixedStack)
852                    // and then rewrite any incompatible constraints to Any.
853                    // This allows register allocation to succeed and we will
854                    // later insert moves to satisfy the rewritten constraints.
855                    let source_slot = if requires_reg {
856                        first_reg_slot.unwrap()
857                    } else {
858                        first_stack_slot.unwrap()
859                    };
860                    let mut first_preg = None;
861                    for u in uses.iter_mut() {
862                        if let OperandConstraint::FixedReg(preg) = u.operand.constraint() {
863                            let vreg_idx = VRegIndex::new(u.operand.vreg().vreg());
864                            let preg_idx = PRegIndex::new(preg.index());
865                            trace!(
866                                "at pos {:?}, vreg {:?} has fixed constraint to preg {:?}",
867                                u.pos,
868                                vreg_idx,
869                                preg_idx
870                            );
871
872                            // FixedStack is incompatible if there are any
873                            // Reg/FixedReg constraints. FixedReg is
874                            // incompatible if there already is a different
875                            // FixedReg constraint. If either condition is true,
876                            // we edit the constraint below; otherwise, we can
877                            // skip this edit.
878                            if !(requires_reg && self.ctx.pregs[preg.index()].is_stack)
879                                && *first_preg.get_or_insert(preg) == preg
880                                && preg.hw_enc() < min_limit
881                            {
882                                continue;
883                            }
884
885                            trace!(" -> duplicate; switching to constraint Any");
886                            self.ctx.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
887                                pos: u.pos,
888                                from_slot: source_slot,
889                                to_slot: u.slot,
890                                to_preg: preg_idx,
891                                vreg: vreg_idx,
892                                level: FixedRegFixupLevel::Secondary,
893                            });
894                            u.operand = Operand::new(
895                                u.operand.vreg(),
896                                OperandConstraint::Any,
897                                u.operand.kind(),
898                                u.operand.pos(),
899                            );
900                            trace!(" -> extra clobber {} at inst{}", preg, u.pos.inst().index());
901                            extra_clobbers.push((preg, u.pos));
902                        }
903                    }
904                }
905
906                for (clobber, pos) in extra_clobbers.drain(..) {
907                    let range = CodeRange {
908                        from: pos,
909                        to: pos.next(),
910                    };
911                    self.add_liverange_to_preg(range, clobber);
912                }
913            }
914        }
915    }
916}