Skip to main content

rucc_regalloc/
assign.rs

1//! Which register each value lives in, and which values live on the stack instead.
2//!
3//! Design: `spec/10-backend.md` section 10.4.
4//!
5//! This is the `-O0` allocator's decision and nothing else. It is linear scan over the line
6//! [`crate::order`] lays the function out in: the values are taken in the order they are written,
7//! each is given a register that nothing else live at the same time is in, and when there is no
8//! such register one of the values in flight goes to the stack instead. There is no splitting and
9//! no coalescing, so a value gets one place for the whole of its range and keeps it. That produces
10//! mediocre code quickly, which is what `-O0` is for, and the allocator that produces good code
11//! slowly is a separate one, in M4.
12//!
13//! Which value is sent to the stack is the one whose range ends last, counting the value being
14//! placed among the candidates. A value wanted for a long time is the cheapest to spill per
15//! instruction it frees a register over, and it is the only heuristic here. What is picked is
16//! really a register and not a value, since two values that are never both wanted share one, and
17//! then every value in that register which is in this one's way goes.
18//!
19//! # Where the line is not the function
20//!
21//! The line is the order the blocks arrived in, and `crate::layout` puts them in a different one
22//! afterwards, so being between two blocks on the line says nothing about being between them in
23//! the code. A value live in one loop and live again in a later one is written down with
24//! everything in between inside the interval around it, and it is not live in any of it.
25//!
26//! Which is why what decides anything here is the area from `crate::live`, and the interval is
27//! only the sweep's bookkeeping: it says which values to compare and the areas say which of them
28//! actually collide. Three loops one after another in a function put a dozen values in flight at
29//! the same instant of the line and never at the same instant of the program, and asking the
30//! interval would spill the one this loop is walking for the sake of eleven values in the other
31//! two. tamnd/rucc#982.
32//!
33//! The same holds for a register an instruction insists on. A call destroys seven registers on
34//! x86-64, and a function whose blocks happen to arrive with a call written between the blocks of
35//! a loop would otherwise lose all seven for every value in that loop, for a call the loop never
36//! reaches, so that question is asked of the area and not of the interval either.
37//!
38//! Allowed is not the same as free, though, so the registers are offered in two passes. First the
39//! ones nothing insists on anywhere the range reaches, then the ones something insists on somewhere
40//! the value never goes. The second kind costs: the instruction that insists has to be handed the
41//! register in the end, and what hands it over is a move. A function that gives a value back has an
42//! operand fixed to `rax` at the end of it, and putting the busiest value in the function in `rax`
43//! because no path reaches the return with it live buys one register and pays a move at every
44//! return. Ordering the two passes is what keeps the register and drops the moves.
45//!
46//! The hint below is asked the first question rather than the second for the same reason. A value
47//! taking the register its own operand asked for saves a move, and taking one somebody else's
48//! operand asked for somewhere it never goes costs one, so a hint is worth following when the
49//! register is clear and not worth following when it is merely allowed.
50//!
51//! # What it does with a register an instruction insists on
52//!
53//! Two things. It stays out of that register for everybody else, and it tries that register first
54//! for the value the operand names. A division wants its dividend in `rax`, so `rax` is
55//! unavailable to every other value that is live where the division reads, and it is the first
56//! register offered to the dividend itself. When the dividend gets it there is no move on the way
57//! in, and when it does not the rewrite writes one and nothing else changes.
58//!
59//! That second half is the hint, and without it the register an instruction insists on is the one
60//! register the value in it can never have, since the value's own operand is what makes the
61//! register look busy. The effect is largest on returns, because a function that gives a value
62//! back has an operand fixed to `rax` at the end of it and most functions give a value back.
63//!
64//! What makes the hint safe is asking about the register at each of the instruction's two points
65//! rather than across the whole of it. An instruction reads at the first and writes at the second,
66//! so a register it insists on is one value's at the first, another value's at the second, and
67//! nobody else's at either. A division reads its dividend from `rax` and writes its quotient to
68//! `rax`, and those are different values that can both live there. A value passed to a call in
69//! `rdi` and wanted again afterwards cannot, because nothing writes `rdi` at the second point and
70//! a register the call does not write is a register the call is assumed to destroy.
71//!
72//! An operand that has to be in memory is the other way round. The value it names goes on the
73//! stack whatever else is true of it, because that is the only place the instruction could read it
74//! from.
75//!
76//! # What it does with a two address instruction
77//!
78//! An `add` on x86-64 writes one of the registers it reads, which the operand says as a reuse of
79//! another operand. The rewrite can always make that true by copying the source into the
80//! destination first, but only if the destination is a register the instruction does not otherwise
81//! read, so a value written by a reuse is treated here as live from where the instruction reads
82//! rather than from where it writes. Then the copy is always safe.
83//!
84//! The copy is also usually unnecessary, and the one place this looks past the interval it is
85//! placing is to see that: if the value being reused is read here for the last time and the value
86//! being written starts here, the second may have the first's register, and the instruction is
87//! already two address without anything being moved anywhere. That is the whole of the coalescing
88//! this allocator does, and it is worth the dozen lines, because otherwise every piece of
89//! arithmetic in the output carries a move in front of it.
90//!
91//! Both halves of that are needed. The second is the one a loop breaks: an instruction at the
92//! bottom of a loop can write a value the top of the loop reads on the next turn, and such a value
93//! is live on the way into the instruction that writes it as well as after. It is then wanted at
94//! the same time as the value it reuses, whatever is true of the reuse, and giving it the same
95//! register makes an addition read the answer to the last one instead of its own operand.
96//!
97//! # What it does not do
98//!
99//! It does not touch the function. What comes out is a table saying where each value went, and the
100//! pass that rewrites the operands and writes the moves reads it. Keeping the decision and the
101//! rewrite apart is what lets the decision be checked by looking at it, and it is the shape
102//! `spec/10-backend.md` section 10.4 asks for: an allocator is a function from a program to an
103//! assignment and the moves that make it true.
104
105use std::cmp::Reverse;
106
107use rucc_mir::{Constraint, Flags, Func, Inst, Operand, Reg, Role};
108use rucc_target::{PhysReg, RegClass};
109
110use crate::live::{Area, Live, Range};
111use crate::order::{Order, Point};
112
113/// Where a value lives.
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub enum Place {
116    /// In a register, for the whole of its range.
117    Reg(PhysReg),
118    /// In a slot of the frame, which is what a value the allocator ran out of registers for gets,
119    /// and what a value an instruction can only read from memory gets.
120    Slot(u32),
121}
122
123/// What the allocator is allowed to use.
124///
125/// The order is the calling convention's, because which register to hand out first follows from
126/// which ones a call destroys, and `rucc-target` is where a convention says so. The scratch
127/// registers are held back out of the order and are what a spilled value is read into at each
128/// instruction that wants it, so a class needs as many of them as one of its instructions has
129/// register operands. Nothing here uses them, since a spilled value is only read once the rewrite
130/// is writing the instruction that reads it, but they are held back here because this is what
131/// decides what everything else may have.
132#[derive(Debug, Clone, Default)]
133pub struct Env {
134    classes: Vec<Class>,
135}
136
137/// What one class of registers offers.
138#[derive(Debug, Clone, Default)]
139struct Class {
140    order: Vec<PhysReg>,
141    scratch: Vec<PhysReg>,
142}
143
144impl Env {
145    /// An environment offering nothing, which is what a target that has said nothing offers.
146    #[must_use]
147    pub fn new() -> Self {
148        Self::default()
149    }
150
151    /// The same environment, with that class described.
152    #[must_use]
153    pub fn with(mut self, class: RegClass, order: &[PhysReg], scratch: &[PhysReg]) -> Self {
154        let index = usize::from(class.number());
155        if self.classes.len() <= index {
156            self.classes.resize(index + 1, Class::default());
157        }
158        self.classes[index] = Class { order: order.to_vec(), scratch: scratch.to_vec() };
159        self
160    }
161
162    /// The registers it may hand out in a class, in the order it prefers them.
163    #[must_use]
164    pub fn order(&self, class: RegClass) -> &[PhysReg] {
165        self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.order)
166    }
167
168    /// The registers it may hand out, by class number, empty for a class it says nothing about.
169    pub(crate) fn offered(&self) -> impl Iterator<Item = &[PhysReg]> + '_ {
170        self.classes.iter().map(|class| class.order.as_slice())
171    }
172
173    /// The registers held back in a class for reading a spilled value into.
174    #[must_use]
175    pub fn scratch(&self, class: RegClass) -> &[PhysReg] {
176        self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.scratch)
177    }
178}
179
180/// Where every value in a function went.
181#[derive(Debug, Clone)]
182pub struct Assignment {
183    places: Vec<Option<Place>>,
184    slots: Vec<RegClass>,
185    commuted: Vec<Inst>,
186}
187
188impl Assignment {
189    /// Records that the sources of `inst` are to be swapped, for an answer written over the second.
190    pub(crate) fn commute(&mut self, inst: Inst) {
191        self.commuted.push(inst);
192    }
193
194    /// An assignment that says nothing yet about a function with that many values.
195    ///
196    /// This and [`Assignment::put`] and [`Assignment::take_slot`] are how an allocator says what
197    /// it decided. There will be a second one in M4 and it will not reach its answer this way, so
198    /// what an assignment is has to be separable from how this file arrives at one, and the
199    /// checker in [`crate::check`] reads an assignment without caring which allocator wrote it.
200    #[must_use]
201    pub fn empty(vregs: usize) -> Self {
202        Self { places: vec![None; vregs], slots: Vec::new(), commuted: Vec::new() }
203    }
204
205    /// The two address instructions whose answer went into the register of their second source.
206    ///
207    /// Each has to have its two sources swapped before anything reads the assignment against the
208    /// function, which [`crate::run`] does. After that the answer reuses what is then the first
209    /// source, as every two address instruction does. tamnd/rucc#1895.
210    #[must_use]
211    pub fn commuted(&self) -> &[Inst] {
212        &self.commuted
213    }
214
215    /// Records where a value went.
216    ///
217    /// # Panics
218    ///
219    /// Panics on a physical register, which is somewhere already, and on a virtual one the
220    /// function never handed out.
221    pub fn put(&mut self, reg: Reg, place: Place) {
222        self.places[index(reg)] = Some(place);
223    }
224
225    /// Takes a slot of the frame, of that class, and gives back which one it is.
226    ///
227    /// # Panics
228    ///
229    /// Panics past four billion slots, which is a frame no machine has room for.
230    pub fn take_slot(&mut self, class: RegClass) -> u32 {
231        let slot = u32::try_from(self.slots.len()).expect("too many spilled values");
232        self.slots.push(class);
233        slot
234    }
235
236    /// Where a value lives, or `None` for a virtual register this function never mentions and for
237    /// a physical one, which is already where it is.
238    #[must_use]
239    pub fn place(&self, reg: Reg) -> Option<Place> {
240        self.places.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
241    }
242
243    /// The class of each slot of the frame, which is what says how wide it has to be.
244    #[must_use]
245    pub fn slots(&self) -> &[RegClass] {
246        &self.slots
247    }
248
249    /// Every value that went somewhere, and where it went.
250    ///
251    /// The assignment read the other way round, which is what a caller wants when the question is
252    /// about the places rather than about the values. The stack slot allocator asks it that way,
253    /// since what it needs is which value is in each slot and the assignment is stored by value.
254    pub fn placed(&self) -> impl Iterator<Item = (Reg, Place)> + '_ {
255        self.places.iter().enumerate().filter_map(|(number, place)| {
256            let number = u32::try_from(number).ok()?;
257            Some((Reg::virtual_reg(number), (*place)?))
258        })
259    }
260
261    /// How many values went to the stack.
262    #[must_use]
263    pub fn spilled(&self) -> usize {
264        self.slots.len()
265    }
266
267    /// Puts a value on the stack, in a slot of its own.
268    pub(crate) fn spill(&mut self, reg: Reg, class: RegClass) {
269        let slot = self.take_slot(class);
270        self.put(reg, Place::Slot(slot));
271    }
272}
273
274/// One value waiting for a place.
275#[derive(Debug, Clone, Copy)]
276struct Interval<'a> {
277    reg: Reg,
278    class: RegClass,
279    /// The interval around the area, which is what the sweep below reads and what says which value
280    /// is wanted for longest when one of them has to go.
281    range: Range,
282    /// Everywhere the value is really live, which is what says whether two of them fit in one
283    /// register.
284    area: Area<'a>,
285}
286
287/// One value that has a register, for as long as it still wants it.
288#[derive(Debug, Clone, Copy)]
289struct Held<'a> {
290    reg: Reg,
291    class: RegClass,
292    range: Range,
293    area: Area<'a>,
294    at: PhysReg,
295    /// How many values were given a register before this one, which is the order the values in
296    /// flight are looked at in when one register has to be taken back.
297    since: usize,
298}
299
300/// The values that have a register, kept by the register each is in.
301///
302/// Nearly every question asked of them is about one register: whether it is free for an interval,
303/// or whether a value is still in it. They used to be one list walked from the start for every
304/// register tried, and on a function with a thousand values in flight that walk was most of the
305/// time the allocator took. Keeping them by register means asking about one reads only the values
306/// that are in it. Registers are numbered within their class, so two classes can share a list and
307/// the class is still checked.
308#[derive(Default)]
309struct Active<'a> {
310    by: Vec<Vec<Held<'a>>>,
311    /// For each register, a point no value in it ends before. Values are let go of at the start of
312    /// every interval, and most of those times nothing in most registers has ended, so a register
313    /// whose values all end at or after the point is not walked at all.
314    soonest: Vec<Point>,
315    /// How many values have been given a register so far.
316    count: usize,
317    /// The pieces of the values in each register, by class and then by register number, which is
318    /// what [`available`] asks about.
319    pieces: Vec<Vec<Pieces>>,
320    /// The list [`spill_one`] weighs the registers in, kept so a spill does not build a new one.
321    costs: Vec<(usize, PhysReg, usize, Point)>,
322}
323
324impl<'a> Active<'a> {
325    /// The values in one register, in the order they were given it.
326    fn at(&self, at: PhysReg) -> &[Held<'a>] {
327        self.by.get(usize::from(at.number())).map_or(&[], Vec::as_slice)
328    }
329
330    fn push(&mut self, reg: Reg, class: RegClass, range: Range, area: Area<'a>, at: PhysReg) {
331        let slot = usize::from(at.number());
332        if self.by.len() <= slot {
333            self.by.resize_with(slot + 1, Vec::new);
334            self.soonest.resize(slot + 1, Point::MAX);
335        }
336        self.by[slot].push(Held { reg, class, range, area, at, since: self.count });
337        self.soonest[slot] = self.soonest[slot].min(range.end);
338        self.count += 1;
339        let held = &self.by[slot];
340        let pieces = pieces_mut(&mut self.pieces, class, slot);
341        if pieces.kept {
342            pieces.drop_before(range.start);
343            for piece in area.pieces() {
344                pieces.insert(piece, reg);
345            }
346        } else if held.len() > FEW {
347            // Enough values to be worth a list, which starts with what is already there.
348            pieces.kept = true;
349            for held in held.iter().filter(|held| held.class == class) {
350                for piece in held.area.pieces() {
351                    pieces.insert(piece, held.reg);
352                }
353            }
354        }
355    }
356
357    /// Whether a value of the class in `at` other than `except` is live anywhere the area is.
358    fn taken(&self, class: RegClass, at: PhysReg, area: Area<'_>, except: Option<Reg>) -> bool {
359        let held = self.at(at);
360        if held.len() > FEW {
361            if let Some(answer) = self.listed(class, at, area, except) {
362                return answer;
363            }
364        }
365        held.iter()
366            .any(|held| held.class == class && Some(held.reg) != except && held.area.overlaps(area))
367    }
368
369    /// What the list of `at`'s pieces says, or nothing when it is not kept or not in order. Out of
370    /// line so that the walk above, which is all most registers ever need, stays small enough to
371    /// be put inline where it is asked.
372    #[inline(never)]
373    fn listed(
374        &self,
375        class: RegClass,
376        at: PhysReg,
377        area: Area<'_>,
378        except: Option<Reg>,
379    ) -> Option<bool> {
380        let by = self.pieces.get(usize::from(class.number()))?;
381        let pieces = by.get(usize::from(at.number()))?;
382        (pieces.kept && !pieces.broken).then(|| pieces.touch(area, except))
383    }
384
385    /// The values of the class in register number `slot` that touch the area, from its list of
386    /// pieces, or nothing when the list is not kept or not in order.
387    #[inline(never)]
388    fn owners(&self, class: RegClass, slot: usize, area: Area<'_>) -> Option<Vec<Reg>> {
389        let pieces = self.pieces.get(usize::from(class.number()))?.get(slot)?;
390        if pieces.kept { pieces.owners(area) } else { None }
391    }
392
393    /// Takes the values of the class in `at` whose areas `goes` says to, and hands each to `gone`.
394    fn evict(
395        &mut self,
396        class: RegClass,
397        at: PhysReg,
398        goes: impl Fn(&Held<'a>) -> bool,
399        mut gone: impl FnMut(&Held<'a>),
400    ) {
401        let slot = usize::from(at.number());
402        let mut taken = Vec::new();
403        self.by[slot].retain(|held| {
404            let out = held.class == class && goes(held);
405            if out {
406                gone(held);
407                taken.push((held.reg, held.area));
408            }
409            !out
410        });
411        let pieces = pieces_mut(&mut self.pieces, class, slot);
412        if pieces.kept {
413            for (reg, area) in taken {
414                for piece in area.pieces() {
415                    pieces.remove(piece, reg);
416                }
417            }
418        }
419    }
420
421    /// Lets go of every value whose interval ends before a point.
422    ///
423    /// Taking a value out of a register anywhere else leaves that register's soonest end where it
424    /// was, which is still a point nothing in it ends before, so only this and [`Active::push`]
425    /// have to keep it.
426    fn expire(&mut self, point: Point) {
427        for (held, soonest) in self.by.iter_mut().zip(&mut self.soonest) {
428            if *soonest >= point {
429                continue;
430            }
431            held.retain(|held| held.range.end >= point);
432            *soonest = held.iter().map(|held| held.range.end).min().unwrap_or(Point::MAX);
433        }
434    }
435}
436
437/// How many values a register can hold before its pieces are kept in a list. A register with no
438/// more than this in it, which is most of them without optimization, is quicker to ask about by
439/// walking its values, and keeping a list for every one of those cost more than it saved.
440pub(crate) const FEW: usize = 4;
441
442/// The list for one class and register number, made when it is first asked for.
443fn pieces_mut(pieces: &mut Vec<Vec<Pieces>>, class: RegClass, slot: usize) -> &mut Pieces {
444    let class = usize::from(class.number());
445    if pieces.len() <= class {
446        pieces.resize_with(class + 1, Vec::new);
447    }
448    let by = &mut pieces[class];
449    if by.len() <= slot {
450        by.resize_with(slot + 1, Pieces::default);
451    }
452    &mut by[slot]
453}
454
455/// The pieces of every value of one class in one register, sorted by where they start.
456///
457/// Asking whether a register is free for a value used to compare the value with every other value
458/// in the register, a walk over both lists of pieces for each one, and with a few dozen values
459/// in each register that was a large part of an optimized build of a large file. Two values in
460/// one register are never live at once, bar the one point a value written over the one it reuses
461/// shares with it, so in start order the pieces end in order too. Then the only piece that can
462/// touch one of the value's is the last one that starts before that piece ends, and asking is a
463/// search for each piece of the value rather than a walk over everything in the register.
464///
465/// Whether the ends really are in order is checked as each piece goes in, and a register where
466/// they are not is answered by the walk over its values instead, so the answer is the same either
467/// way.
468#[derive(Default)]
469pub(crate) struct Pieces {
470    /// Start, end and whose, sorted by start and then by end.
471    list: Vec<(Point, Point, Reg)>,
472    /// Whether a piece went in that ends before one in front of it.
473    broken: bool,
474    /// Whether the list is kept at all, which it is from the first time the register holds more
475    /// than [`FEW`] values.
476    pub(crate) kept: bool,
477}
478
479impl Pieces {
480    #[inline(never)]
481    pub(crate) fn insert(&mut self, piece: Range, reg: Reg) {
482        let key = (piece.start, piece.end);
483        let at = self.list.partition_point(|&(start, end, _)| (start, end) <= key);
484        let after = at == 0 || self.list[at - 1].1 <= piece.end;
485        let before = self.list.get(at).is_none_or(|next| piece.end <= next.1);
486        if !(after && before) {
487            self.broken = true;
488        }
489        self.list.insert(at, (piece.start, piece.end, reg));
490    }
491
492    pub(crate) fn remove(&mut self, piece: Range, reg: Reg) {
493        let from = self.list.partition_point(|&(start, _, _)| start < piece.start);
494        let found = self.list[from..]
495            .iter()
496            .take_while(|&&(start, _, _)| start == piece.start)
497            .position(|&(_, end, owner)| end == piece.end && owner == reg);
498        if let Some(offset) = found {
499            self.list.remove(from + offset);
500        }
501    }
502
503    /// Lets go of the pieces that end before a point, which no value starting there can touch.
504    /// They are the ones at the front while the ends are in order.
505    fn drop_before(&mut self, point: Point) {
506        if !self.broken {
507            let gone = self.list.partition_point(|&(_, end, _)| end < point);
508            self.list.drain(..gone);
509        }
510    }
511
512    /// Whether a piece of a value other than `except` touches the area.
513    fn touch(&self, area: Area<'_>, except: Option<Reg>) -> bool {
514        area.pieces().any(|piece| {
515            let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
516            self.list[..below]
517                .iter()
518                .rev()
519                .find(|&&(_, _, owner)| Some(owner) != except)
520                .is_some_and(|&(_, end, _)| end >= piece.start)
521        })
522    }
523
524    /// Every value with a piece that touches the area, each once and in order, or `None` for a
525    /// list whose ends are out of order. With the ends in order the pieces that touch one of the
526    /// area's are the last few that start before it ends, back to the first that ends before it
527    /// starts.
528    pub(crate) fn owners(&self, area: Area<'_>) -> Option<Vec<Reg>> {
529        if self.broken {
530            return None;
531        }
532        let mut owners = Vec::new();
533        for piece in area.pieces() {
534            let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
535            let touching =
536                self.list[..below].iter().rev().take_while(|&&(_, end, _)| end >= piece.start);
537            owners.extend(touching.map(|&(_, _, owner)| owner));
538        }
539        owners.sort_unstable();
540        owners.dedup();
541        Some(owners)
542    }
543}
544
545/// A register an instruction insists on, and where it insists on it.
546#[derive(Debug, Clone, Copy)]
547struct Blocked {
548    class: RegClass,
549    at: PhysReg,
550    /// One of the instruction's two points. Every register an instruction insists on has an entry
551    /// at each of them, because a register held at one of the two is a register nothing else may
552    /// be in across the instruction.
553    point: Point,
554    /// The one value that may be in it there, which is the value of an operand the instruction
555    /// reads at that point or writes at it. `None` means nothing may: an operand naming a physical
556    /// register outright claims it against everything, and a point no operand covers is a point
557    /// the instruction has the register to itself at.
558    by: Option<Reg>,
559    /// The byte the instruction writes the register from, when it leaves the bottom of it alone,
560    /// which is what a call does to a register AArch64 keeps the low half of. A value that fits
561    /// below it is not in the way. See [`Constraint::Above`].
562    above: Option<u8>,
563}
564
565impl Blocked {
566    /// Whether this is in the way of a value of that width, which it is unless it writes only
567    /// above everything the value takes.
568    fn reaches(&self, width: Option<u8>) -> bool {
569        match (self.above, width) {
570            (Some(above), Some(width)) => width > above,
571            _ => true,
572        }
573    }
574}
575
576/// A value written into the register another operand of the same instruction was read from.
577#[derive(Debug, Clone, Copy)]
578pub(crate) struct Reuse {
579    /// The value being read, which is the one whose register would do.
580    pub(crate) source: Reg,
581    /// The other value the instruction reads, when the instruction reads the two either way round
582    /// and so could write its answer over this one instead.
583    pub(crate) second: Option<Reg>,
584    /// Where the instruction reads it.
585    pub(crate) at: Point,
586    /// The instruction, which is swapped round if the answer takes the second value's register.
587    pub(crate) inst: Inst,
588}
589
590/// Decides where every value in a function lives.
591///
592/// # Panics
593///
594/// Panics if a class has no registers to hand out and something in the function is in that class,
595/// since that is a target description that does not describe the target the function is for.
596#[must_use]
597pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
598    let blocked = blocked(func, order);
599    let forced = forced(func);
600    let reuses = reuses(func, order);
601    let hints = hints(func);
602    let passed = passed(func);
603
604    let mut intervals = Vec::with_capacity(func.vregs());
605    for (number, reuse) in reuses.iter().enumerate() {
606        let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
607        let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
608            continue;
609        };
610        if let Some(reuse) = reuse {
611            area = area.with(reuse.at);
612        }
613        intervals.push(Interval { reg, class, range: area.hull(), area });
614    }
615    intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
616
617    let mut assignment = Assignment::empty(func.vregs());
618    let mut active = Active::default();
619    for interval in intervals {
620        active.expire(interval.range.start);
621        if forced.contains(&interval.reg) {
622            assignment.spill(interval.reg, interval.class);
623            continue;
624        }
625        // A class with no order is one the target says nothing allocates from, which on x86-64 is
626        // the x87 stack. A value of such a class is a mistake at the point it was made rather than
627        // a value with nowhere to go: what the target means is that the value lives in memory and
628        // that whatever operates on it takes an address. See `ClassInfo::allocatable`.
629        assert!(
630            !env.order(interval.class).is_empty(),
631            "a value in class {}, which the target hands out no registers from",
632            interval.class.number()
633        );
634        let reuse = reuses[index(interval.reg)];
635        let coalesced = |source| coalesce(&assignment, &active, &blocked, live, interval, source);
636        let first = reuse.and_then(|reuse| coalesced(reuse.source));
637        let second = reuse.and_then(|reuse| reuse.second).and_then(coalesced);
638        // An instruction that reads its sources either way round can write over the second one
639        // instead, which is what it needs when the first is read again later and the second is
640        // not. When both would do, the first is kept unless only the second is where something
641        // wants the answer, which saves the move in front of that reader.
642        //
643        // A block the answer is passed to wants it where that block's parameter already is. That
644        // has to count as much as an instruction asking for a register. A sum a loop carries is
645        // passed back to the parameter it was read from, and taking the register of the other
646        // source because the sum is also printed at the end moves the copy onto the back edge,
647        // where it runs every turn instead of once.
648        let hinted_at = |at: Option<PhysReg>| {
649            at.is_some_and(|at| {
650                hints[index(interval.reg)].contains(&at)
651                    || passed[index(interval.reg)]
652                        .iter()
653                        .any(|&param| assignment.place(param) == Some(Place::Reg(at)))
654            })
655        };
656        let commute =
657            second.is_some() && (first.is_none() || hinted_at(second) && !hinted_at(first));
658        let two_address = if commute { second } else { first };
659        if let (true, Some(reuse)) = (commute, reuse) {
660            assignment.commuted.push(reuse.inst);
661        }
662        // The reuse comes first, because a two address instruction that has to copy its left
663        // operand in pays for the copy whatever the hint says, and taking the hint here would buy
664        // one move at the cost of another.
665        let hinted = hints[index(interval.reg)].iter().copied().find(|&at| {
666            env.order(interval.class).contains(&at)
667                && available(&active, &blocked, interval, at, None, Want::Clear)
668        });
669        // A register nobody else wants anywhere near this value first, and one somebody wants
670        // somewhere the value never goes only when there is no other. Both are correct and the
671        // second is the worse buy, since the instruction that wants it has to be handed it and
672        // whatever this value is doing there has to move out of the way first.
673        let scan = |want| {
674            env.order(interval.class)
675                .iter()
676                .copied()
677                .find(|&at| available(&active, &blocked, interval, at, None, want))
678        };
679        let chosen =
680            two_address.or(hinted).or_else(|| scan(Want::Clear)).or_else(|| scan(Want::Allowed));
681        match chosen {
682            Some(at) => {
683                assignment.places[index(interval.reg)] = Some(Place::Reg(at));
684                active.push(interval.reg, interval.class, interval.range, interval.area, at);
685            }
686            None => spill_one(&mut assignment, &mut active, &blocked, interval),
687        }
688    }
689    assignment
690}
691
692/// How much a register suits an interval.
693#[derive(Debug, Clone, Copy, PartialEq, Eq)]
694pub(crate) enum Want {
695    /// No other value is handed it anywhere the range reaches, and nothing writes it where the
696    /// value is live, so taking it costs nobody anything.
697    ///
698    /// A register an instruction only destroys, which is what a call does to seven of them, is
699    /// clear for a value that is dead there. There is no value of the instruction's own to move
700    /// in, so a loop counter that is passed to a call on the way out may stay in a register the
701    /// call destroys. Counting the clobber over the whole range sent such a value to a callee
702    /// saved register, which is a push and a pop for nothing. tamnd/rucc#2202.
703    Clear,
704    /// Something insists on it somewhere the range reaches and nowhere the value is live, so taking
705    /// it is allowed and may still cost: the instruction that insists wants the register for a
706    /// value of its own, and that value now has to be moved into it.
707    Allowed,
708}
709
710/// Every register every instruction in the function insists on, arranged to be asked about.
711///
712/// Built once and never changed afterwards, and there is only one question ever asked of it: of the
713/// constraints naming one register of one class, is there one at a point some interval covers. So
714/// the entries are ordered by the register they name and then by the point, and the question is a
715/// binary search for the start of the interval followed by a walk that stops at its end.
716///
717/// It used to be a flat list walked from one end for every candidate register of every interval,
718/// which is quadratic in the size of a function and is most of the compile on a large one. See
719/// tamnd/rucc#1003 for the profile that found it.
720///
721/// The search is over the points alone and only among the one register's entries. A search over
722/// the whole list compares three fields of an entry several times its size at every step, and on a
723/// large function that is most of what asking costs, since every candidate register of every
724/// interval asks.
725pub(crate) struct Blocks {
726    /// The constraints, sorted by class, then by register, then by point.
727    all: Vec<Blocked>,
728    /// The point of each constraint, in the same order, which is what the search reads.
729    points: Vec<Point>,
730    /// Where each register's constraints start and end in the list, by class times `stride` plus
731    /// the register's number.
732    spans: Vec<(usize, usize)>,
733    /// One more than the highest register number anything insists on.
734    stride: usize,
735    /// How many bytes of its register each virtual register's value takes, by number, which is
736    /// what [`Blocked::reaches`] asks.
737    widths: Vec<Option<u8>>,
738}
739
740impl Blocks {
741    /// Whether an instruction insists on `at` where a value over `area` would be in its way: at any
742    /// point the value's range reaches when the register is wanted clear and the instruction wants
743    /// it for a value of its own, and otherwise only at a point the value is live at. The value's
744    /// own operands never count.
745    pub(crate) fn insists(
746        &self,
747        reg: Reg,
748        class: RegClass,
749        area: Area<'_>,
750        range: Range,
751        at: PhysReg,
752        want: Want,
753    ) -> bool {
754        self.over(class, at, range).any(|one| {
755            one.by != Some(reg)
756                && one.reaches(self.width(reg))
757                && ((want == Want::Clear && one.by.is_some()) || area.covers(one.point))
758        })
759    }
760
761    /// How many bytes of its register a value takes, or `None` for all of it.
762    fn width(&self, reg: Reg) -> Option<u8> {
763        let number = usize::try_from(reg.number()?).ok()?;
764        self.widths.get(number).copied().flatten()
765    }
766
767    /// Every register an instruction takes for itself where no value may be in it, with the class
768    /// and the point, sorted by class, then by register, then by point.
769    ///
770    /// Not one it writes only the top of, since a value narrow enough may still be in that.
771    pub(crate) fn taken(&self) -> impl Iterator<Item = (RegClass, PhysReg, Point)> + '_ {
772        self.all
773            .iter()
774            .filter(|one| one.by.is_none() && one.above.is_none())
775            .map(|one| (one.class, one.at, one.point))
776    }
777
778    /// The constraints on one register of one class at the points an interval covers.
779    ///
780    /// Both ends of the walk come from the ordering rather than from a test, so what comes back is
781    /// exactly what the old `covers` call used to keep and in the same order.
782    #[inline]
783    fn over(
784        &self,
785        class: RegClass,
786        at: PhysReg,
787        range: Range,
788    ) -> impl Iterator<Item = &Blocked> + '_ {
789        let (low, high) = if usize::from(at.number()) < self.stride {
790            let key = usize::from(class.number()) * self.stride + usize::from(at.number());
791            self.spans.get(key).copied().unwrap_or((0, 0))
792        } else {
793            (0, 0)
794        };
795        let first = low + self.points[low..high].partition_point(|&point| point < range.start);
796        self.all[first..high].iter().take_while(move |one| one.point <= range.end)
797    }
798}
799
800/// Whether a register is one this interval could have.
801///
802/// The exception is the value a reuse is coalescing with, which holds the register right up to the
803/// point the new value takes it over and is the one thing that may overlap.
804///
805/// The sweep only keeps a value in `active` while the interval around it reaches this one, so the
806/// areas still have to be compared: two values whose intervals cross can have holes that let them
807/// share a register anyway, which on a function with several loops in it is most of them.
808fn available(
809    active: &Active<'_>,
810    blocked: &Blocks,
811    interval: Interval<'_>,
812    at: PhysReg,
813    except: Option<Reg>,
814    want: Want,
815) -> bool {
816    let taken = active.taken(interval.class, at, interval.area, except);
817    let width = blocked.width(interval.reg);
818    let insisted = blocked.over(interval.class, at, interval.range).any(|one| {
819        one.by != Some(interval.reg)
820            && one.reaches(width)
821            && ((want == Want::Clear && one.by.is_some()) || interval.area.covers(one.point))
822    });
823    !taken && !insisted
824}
825
826/// The register the value being reused is in, when the value being written is never live at the
827/// same time as it and the register is otherwise free.
828fn coalesce(
829    assignment: &Assignment,
830    active: &Active<'_>,
831    blocked: &Blocks,
832    live: &Live,
833    interval: Interval<'_>,
834    source: Reg,
835) -> Option<PhysReg> {
836    let Some(Place::Reg(at)) = assignment.place(source) else { return None };
837    active.at(at).iter().find(|held| held.reg == source)?;
838    // The two have to be apart everywhere, asked of the areas liveness worked out and without the
839    // point the reuse adds, since that point is the one they are allowed to share.
840    //
841    // That covers both ways it can go wrong. A value read again later needs its register after
842    // this instruction would have overwritten it. And a value being written that is live where the
843    // instruction reads already is what a loop carrying its own result round looks like: the
844    // instruction writes it at the bottom and the top of the loop reads what the last turn wrote.
845    // Either way the two are wanted at once, and no register holds both.
846    //
847    // It used to be asked of the end of the interval around the value being read, and that is not
848    // the same question. A block laid out after this instruction where the value is still live,
849    // such as the default arm of a `switch` that joins back in above it, stretches the interval
850    // past this point when nothing past it reads the value at all. The sum a loop carries round
851    // then went into a new register and was copied back at the bottom of every turn.
852    // tamnd/rucc#1965.
853    let free = available(active, blocked, interval, at, Some(source), Want::Allowed);
854    (apart(live, source, interval.reg) && free).then_some(at)
855}
856
857/// Whether two values are never live at the same time, going by what liveness worked out.
858pub(crate) fn apart(live: &Live, first: Reg, second: Reg) -> bool {
859    match (live.area(first), live.area(second)) {
860        (Some(first), Some(second)) => !first.overlaps(second),
861        _ => false,
862    }
863}
864
865/// Sends values to the stack to free a register: the ones wanted for longest, since a register
866/// held that long pays for itself over the most instructions.
867///
868/// What is chosen is a register rather than a value, because two values whose areas miss each
869/// other share one and taking it means every value in it this one is really on top of has to go.
870/// A register holding two of those costs twice as much to take as one holding a single value, so
871/// the cheap ones are looked at first and the reach only settles ties.
872fn spill_one<'a>(
873    assignment: &mut Assignment,
874    active: &mut Active<'a>,
875    blocked: &Blocks,
876    interval: Interval<'a>,
877) {
878    // What each register would cost: how many values would go, and the furthest any of them
879    // reaches. The list is one entry per register of the class, so walking it for each value in
880    // flight is the same shape as everything else here. The first number is when the earliest of
881    // them was given the register, and sorting by it puts the registers in the order the values
882    // were given them, which is what settles a tie.
883    let mut costs = std::mem::take(&mut active.costs);
884    costs.clear();
885    for (slot, values) in active.by.iter().enumerate() {
886        // A register with a list of its pieces says which values touch the area, which is quicker
887        // than asking each value in it when it holds many.
888        let owners = if values.len() > FEW {
889            active.owners(interval.class, slot, interval.area)
890        } else {
891            None
892        };
893        for held in values {
894            if held.class != interval.class {
895                continue;
896            }
897            let touches = match &owners {
898                Some(owners) => owners.binary_search(&held.reg).is_ok(),
899                None => held.area.overlaps(interval.area),
900            };
901            if !touches {
902                continue;
903            }
904            match costs.iter_mut().find(|(_, at, _, _)| *at == held.at) {
905                Some((first, _, count, reach)) => {
906                    *first = (*first).min(held.since);
907                    *count += 1;
908                    *reach = (*reach).max(held.range.end);
909                }
910                None => costs.push((held.since, held.at, 1, held.range.end)),
911            }
912        }
913    }
914    costs.sort_unstable_by_key(|&(first, _, _, _)| first);
915    // A register the instructions in the way insist on for themselves is no use, because taking it
916    // over would put this value in a register it may not have.
917    let none = Active::default();
918    let chosen = costs
919        .iter()
920        .filter(|&&(_, at, _, reach)| {
921            reach > interval.range.end
922                && available(&none, blocked, interval, at, None, Want::Allowed)
923        })
924        .min_by_key(|&&(_, _, count, reach)| (count, Reverse(reach)))
925        .map(|&(_, at, _, _)| at);
926    active.costs = costs;
927    match chosen {
928        Some(at) => {
929            active.evict(
930                interval.class,
931                at,
932                |held| held.area.overlaps(interval.area),
933                |held| assignment.spill(held.reg, held.class),
934            );
935            assignment.places[index(interval.reg)] = Some(Place::Reg(at));
936            active.push(interval.reg, interval.class, interval.range, interval.area, at);
937        }
938        None => assignment.spill(interval.reg, interval.class),
939    }
940}
941
942/// The registers the instructions insist on, and where.
943///
944/// A physical register an operand names outright counts the same way. Nothing before allocation
945/// writes one except an instruction that has to, and it has to for the length of that one
946/// instruction, which is the same statement a fixed constraint makes.
947pub(crate) fn blocked(func: &Func, order: &Order) -> Blocks {
948    let mut blocked = Vec::new();
949    let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
950    for block in func.blocks() {
951        for inst in func.insts(block) {
952            let operands = &func[func[inst].operands];
953            claimed.clear();
954            for operand in operands {
955                if let Some(at) = insisted(operand) {
956                    let key = (operand.class, at);
957                    if !claimed.contains(&key) {
958                        claimed.push(key);
959                    }
960                }
961            }
962            for &(class, at) in &claimed {
963                // Both points, whether or not an operand is at them. A register an instruction
964                // reads and does not write is still gone by the time the instruction is done as far
965                // as anything here knows, which is what stops the value a call is passed in `rdi`
966                // from staying in `rdi` over the call.
967                for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
968                {
969                    let mut named = false;
970                    for operand in operands {
971                        let mine = insisted(operand) == Some(at) && operand.class == class;
972                        if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
973                            continue;
974                        }
975                        named = true;
976                        let by = operand.reg.is_virtual().then_some(operand.reg);
977                        let above = match operand.constraint {
978                            Constraint::Above(above) => Some(above),
979                            _ => None,
980                        };
981                        blocked.push(Blocked { class, at, point, by, above });
982                    }
983                    // A register no operand names where the operands are read is one the
984                    // instruction writes and does not read, which is what a clobber is, and the
985                    // seven registers a call destroys are the whole of why that case is worth
986                    // separating. Such a register is free right up to the point it is written, so a
987                    // value whose last read is this instruction may sit in one: it is read before
988                    // the instruction writes anything, the way any other operand is. Blocking it
989                    // where the operands are read as well would take every caller saved register
990                    // away from the value a call is passed, which is a value that dies at the call
991                    // and pays for a callee saved register it holds for two instructions. Anything
992                    // living past the instruction is still refused, by the block below.
993                    //
994                    // This is where a target's early definitions are paid for. An instruction that
995                    // fills a register before it has finished reading has to say so, because that
996                    // is the one thing a plain definition here no longer covers: a division on
997                    // x86-64 is a sign extension and then the division itself, so `rdx` is gone
998                    // before the divisor is read, and a divisor that went there would be read as
999                    // the dividend's own sign bits. `rucc_target::x86_64` writes both of them down
1000                    // as early definitions for exactly that reason.
1001                    if !named && role == Role::Def {
1002                        blocked.push(Blocked { class, at, point, by: None, above: None });
1003                    }
1004                }
1005            }
1006        }
1007    }
1008    // Program order already has the points ascending, but the registers one instruction claims are
1009    // walked outside the two points rather than inside them, so the list arrives in order by
1010    // instruction and not by register. A sort by the key the lookup searches on is what makes it
1011    // searchable, and it is stable so two constraints on one register at one point keep the order
1012    // the instruction wrote them in.
1013    blocked.sort_by_key(|one: &Blocked| (one.class, one.at, one.point));
1014    let widths = (0..func.vregs())
1015        .map(|number| func.width(Reg::virtual_reg(u32::try_from(number).ok()?)))
1016        .collect();
1017    let points = blocked.iter().map(|one| one.point).collect();
1018    let stride = blocked.iter().map(|one| usize::from(one.at.number()) + 1).max().unwrap_or(0);
1019    let classes = blocked.last().map_or(0, |one| usize::from(one.class.number()) + 1);
1020    let mut spans = vec![(0, 0); classes * stride];
1021    for (index, one) in blocked.iter().enumerate() {
1022        let key = usize::from(one.class.number()) * stride + usize::from(one.at.number());
1023        let span = &mut spans[key];
1024        if span.1 == 0 {
1025            span.0 = index;
1026        }
1027        span.1 = index + 1;
1028    }
1029    Blocks { all: blocked, points, spans, stride, widths }
1030}
1031
1032/// The register an operand has to be in, which is the one a constraint asks for or the one the
1033/// operand names outright.
1034fn insisted(operand: &Operand) -> Option<PhysReg> {
1035    match operand.constraint {
1036        Constraint::Fixed(at) => Some(at),
1037        _ => operand.reg.phys(),
1038    }
1039}
1040
1041/// The registers each value would rather be in, which are the ones the operands naming it insist on.
1042///
1043/// In the order the function writes them down, so the definition comes first where there is one,
1044/// since a value written into a fixed register and then moved somewhere else pays for the move at
1045/// the top of its life rather than at the bottom. The ones after it are worth keeping for the same
1046/// reason the first one is, and the value a call is passed is where that shows: its definition may
1047/// insist on the register a parameter arrived in, which the call it is handed to has usually taken
1048/// back for an argument of its own by then, and behind that is the register the convention passes
1049/// it in, which is free and is exactly where the value wants to end up.
1050pub(crate) fn hints(func: &Func) -> Vec<Vec<PhysReg>> {
1051    let mut hints = vec![Vec::new(); func.vregs()];
1052    for block in func.blocks() {
1053        for inst in func.insts(block) {
1054            for operand in &func[func[inst].operands] {
1055                let Constraint::Fixed(at) = operand.constraint else { continue };
1056                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1057                let Some(number) = number else { continue };
1058                let wanted: &mut Vec<PhysReg> = &mut hints[number];
1059                if func.class_of(operand.reg) == Some(operand.class) && !wanted.contains(&at) {
1060                    wanted.push(at);
1061                }
1062            }
1063        }
1064    }
1065    hints
1066}
1067
1068/// The block parameters each value is passed to, by the virtual register passed.
1069pub(crate) fn passed(func: &Func) -> Vec<Vec<Reg>> {
1070    let mut passed = vec![Vec::new(); func.vregs()];
1071    for block in func.blocks() {
1072        for call in &func[block].succs {
1073            for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
1074                let number = arg.number().and_then(|number| usize::try_from(number).ok());
1075                let Some(number) = number else { continue };
1076                let to: &mut Vec<Reg> = &mut passed[number];
1077                if !to.contains(&param.reg) {
1078                    to.push(param.reg);
1079                }
1080            }
1081        }
1082    }
1083    passed
1084}
1085
1086/// The values that have to be on the stack whatever else is true of them.
1087pub(crate) fn forced(func: &Func) -> Vec<Reg> {
1088    let mut forced = Vec::new();
1089    for block in func.blocks() {
1090        for inst in func.insts(block) {
1091            for operand in &func[func[inst].operands] {
1092                if operand.constraint == Constraint::Stack
1093                    && operand.reg.is_virtual()
1094                    && !forced.contains(&operand.reg)
1095                {
1096                    forced.push(operand.reg);
1097                }
1098            }
1099        }
1100    }
1101    forced
1102}
1103
1104/// The value each two address instruction reuses, by the virtual register it writes.
1105pub(crate) fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
1106    let mut reuses = vec![None; func.vregs()];
1107    for block in func.blocks() {
1108        for inst in func.insts(block) {
1109            let operands = &func[func[inst].operands];
1110            for operand in operands {
1111                let Constraint::Reuse(other) = operand.constraint else { continue };
1112                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1113                let Some(number) = number else { continue };
1114                let source = operands[usize::from(other)].reg;
1115                let second = if func[inst].flags.contains(Flags::COMMUTES) {
1116                    swappable(operands, usize::from(other))
1117                } else {
1118                    None
1119                };
1120                reuses[number] = Some(Reuse { source, second, at: order.early(inst), inst });
1121            }
1122        }
1123    }
1124    reuses
1125}
1126
1127/// The second source of an instruction that reads its two sources either way round, when the
1128/// answer could go over it instead of over the first.
1129///
1130/// Only the shape of a two address instruction with two sources, the answer and then the two, with
1131/// the answer reusing the first. The second has to be a value of the same class that asks for
1132/// nothing more than a register, since after the swap it is the one the answer reuses.
1133fn swappable(operands: &[Operand], other: usize) -> Option<Reg> {
1134    let [answer, first, second] = operands else { return None };
1135    let same = second.class == first.class && second.class == answer.class;
1136    let plain = second.role == Role::Use && second.constraint == Constraint::Reg;
1137    (other == 1 && same && plain && second.reg.is_virtual() && second.reg != first.reg)
1138        .then_some(second.reg)
1139}
1140
1141/// A virtual register's number as a table index.
1142fn index(reg: Reg) -> usize {
1143    usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148    use rucc_base::Interner;
1149    use rucc_mir::{BlockCall, Opcode, Operand, Param};
1150    use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, RSI, SYSV};
1151
1152    use super::*;
1153
1154    /// The x86-64 environment, with the last three of the allocation order held back as scratch.
1155    fn env() -> Env {
1156        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
1157        Env::new().with(GPR, order, scratch)
1158    }
1159
1160    /// An environment with that many general purpose registers, for putting a function under
1161    /// pressure without writing a hundred instructions.
1162    fn narrow(count: usize) -> Env {
1163        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
1164    }
1165
1166    /// What a place is called, which is what an assertion reads.
1167    fn named(place: Option<Place>) -> String {
1168        match place {
1169            Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
1170            Some(Place::Slot(slot)) => format!("slot {slot}"),
1171            None => "nowhere".to_string(),
1172        }
1173    }
1174
1175    /// Where every value in a function went.
1176    fn places(func: &Func, env: &Env) -> Vec<String> {
1177        let order = Order::of(func);
1178        let live = Live::of(func, &order);
1179        let assignment = assign(func, &order, &live, env);
1180        (0..func.vregs())
1181            .map(|number| {
1182                let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
1183                named(assignment.place(reg))
1184            })
1185            .collect()
1186    }
1187
1188    #[test]
1189    fn two_values_that_are_never_both_wanted_share_a_register() {
1190        let mut names = Interner::new();
1191        let mut func = Func::new(names.intern("f"));
1192        let opcode = Opcode::new(names.intern("x64.nop"));
1193        let block = func.create_block();
1194        let first = func.new_vreg(GPR);
1195        let second = func.new_vreg(GPR);
1196        func.build(block, opcode).def(first, GPR).finish();
1197        func.build(block, opcode).uses(first, GPR).finish();
1198        func.build(block, opcode).def(second, GPR).finish();
1199        func.build(block, opcode).uses(second, GPR).finish();
1200
1201        // The first register in the order, twice, because the first value is finished with before
1202        // the second one is written.
1203        assert_eq!(places(&func, &env()), ["rax", "rax"]);
1204    }
1205
1206    /// A value held over an instruction that writes the whole of the first register and the top
1207    /// of the second, which is a call on AArch64 and `v8` in small, with the value as wide as that.
1208    fn over_the_top(width: u32) -> Func {
1209        let mut names = Interner::new();
1210        let mut func = Func::new(names.intern("f"));
1211        let opcode = Opcode::new(names.intern("x64.nop"));
1212        let block = func.create_block();
1213        let held = func.new_vreg(GPR);
1214        func.set_width(held, width);
1215        func.build(block, opcode).def(held, GPR).finish();
1216        func.build(block, opcode)
1217            .operand(Operand::write(Reg::physical(RAX), GPR))
1218            .operand(Operand::write(Reg::physical(RCX), GPR).with(Constraint::Above(8)))
1219            .finish();
1220        func.build(block, opcode).uses(held, GPR).finish();
1221        func
1222    }
1223
1224    #[test]
1225    fn a_value_that_fits_under_what_an_instruction_writes_stays_in_the_register() {
1226        assert_eq!(places(&over_the_top(8), &narrow(2)), ["rcx"]);
1227        assert_eq!(places(&over_the_top(4), &narrow(2)), ["rcx"]);
1228    }
1229
1230    #[test]
1231    fn a_value_wider_than_that_or_of_no_known_width_does_not() {
1232        assert_eq!(places(&over_the_top(16), &narrow(2)), ["slot 0"]);
1233        assert_eq!(places(&over_the_top(0), &narrow(2)), ["slot 0"]);
1234    }
1235
1236    #[test]
1237    fn two_values_that_are_both_wanted_do_not() {
1238        let mut names = Interner::new();
1239        let mut func = Func::new(names.intern("f"));
1240        let opcode = Opcode::new(names.intern("x64.nop"));
1241        let block = func.create_block();
1242        let first = func.new_vreg(GPR);
1243        let second = func.new_vreg(GPR);
1244        func.build(block, opcode).def(first, GPR).finish();
1245        func.build(block, opcode).def(second, GPR).finish();
1246        func.build(block, opcode).uses(first, GPR).finish();
1247        func.build(block, opcode).uses(second, GPR).finish();
1248
1249        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1250    }
1251
1252    #[test]
1253    fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
1254        let mut names = Interner::new();
1255        let mut func = Func::new(names.intern("f"));
1256        let opcode = Opcode::new(names.intern("x64.nop"));
1257        let block = func.create_block();
1258        let wanted = func.new_vreg(GPR);
1259        let spare = func.new_vreg(GPR);
1260        // A division: a remainder somebody wants, and a quotient nobody does. Both are written by
1261        // the one instruction and the quotient is written before the operands have been read.
1262        func.build(block, opcode)
1263            .def(wanted, GPR)
1264            .operand(Operand::write_early(spare, GPR))
1265            .finish();
1266        func.build(block, opcode).uses(wanted, GPR).finish();
1267
1268        // Two registers, not one. A value nothing reads is still somewhere, and the instruction
1269        // that wrote it wrote the other one too, so the two cannot be the same place. Handing them
1270        // the same register loses the remainder, because the copy that takes the quotient out of
1271        // the register the machine insisted on goes on top of it. The quotient gets the first
1272        // register because it is written first, which is the whole of what early means.
1273        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1274    }
1275
1276    #[test]
1277    fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
1278        let mut names = Interner::new();
1279        let mut func = Func::new(names.intern("f"));
1280        let opcode = Opcode::new(names.intern("x64.nop"));
1281        let block = func.create_block();
1282        let long = func.new_vreg(GPR);
1283        let short = func.new_vreg(GPR);
1284        let third = func.new_vreg(GPR);
1285        func.build(block, opcode).def(long, GPR).finish();
1286        func.build(block, opcode).def(short, GPR).finish();
1287        func.build(block, opcode).def(third, GPR).finish();
1288        func.build(block, opcode).uses(short, GPR).finish();
1289        func.build(block, opcode).uses(third, GPR).finish();
1290        func.build(block, opcode).uses(long, GPR).finish();
1291
1292        // Two registers between three values. The one still wanted at the end of the function is
1293        // the one whose register is worth the most to everybody else, so it is the one that goes.
1294        assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
1295    }
1296
1297    #[test]
1298    fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
1299        let mut names = Interner::new();
1300        let mut func = Func::new(names.intern("f"));
1301        let opcode = Opcode::new(names.intern("x64.nop"));
1302        let block = func.create_block();
1303        let across = func.new_vreg(GPR);
1304        let dividend = func.new_vreg(GPR);
1305        let quotient = func.new_vreg(GPR);
1306        let remainder = func.new_vreg(GPR);
1307        func.build(block, opcode).def(across, GPR).finish();
1308        func.build(block, opcode).def(dividend, GPR).finish();
1309        func.build(block, opcode)
1310            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1311            .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1312            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1313            .finish();
1314        func.build(block, opcode).uses(across, GPR).finish();
1315
1316        // The value that has to be across the division is nowhere near `rax` or `rdx`, and each of
1317        // the three the division names is in the register the division asked for it in. The
1318        // dividend and the quotient share `rax` because the first is read where the second is
1319        // written, which is what a division does.
1320        assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
1321    }
1322
1323    /// A value read by an instruction that fills a register before it reads is kept out of that
1324    /// register, even though the read is the last thing the value is wanted for.
1325    ///
1326    /// The divisor of a division is the case. What the machine runs is `cltd` and then `idivl`, so
1327    /// `rdx` holds the top half of the dividend by the time the divisor is read, and a divisor
1328    /// sitting in `rdx` is read as the dividend's own sign bits. An early definition is how the
1329    /// target says a register goes before the operands are read, and this is where the allocator
1330    /// has to hear it, since a value dying at an instruction is otherwise free to sit in a
1331    /// register that instruction writes. tamnd/rucc#1232.
1332    #[test]
1333    fn a_value_that_dies_at_an_instruction_stays_out_of_what_it_fills_first() {
1334        let mut names = Interner::new();
1335        let mut func = Func::new(names.intern("f"));
1336        let opcode = Opcode::new(names.intern("x64.nop"));
1337        let block = func.create_block();
1338        let across = func.new_vreg(GPR);
1339        let dividend = func.new_vreg(GPR);
1340        let divisor = func.new_vreg(GPR);
1341        let remainder = func.new_vreg(GPR);
1342        func.build(block, opcode).def(across, GPR).finish();
1343        func.build(block, opcode).def(dividend, GPR).finish();
1344        func.build(block, opcode).def(divisor, GPR).finish();
1345        func.build(block, opcode)
1346            .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1347            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1348            .operand(Operand::read(divisor, GPR))
1349            .finish();
1350        func.build(block, opcode).uses(across, GPR).uses(remainder, GPR).finish();
1351
1352        // Four registers for four values, and the divisor takes the fourth. `rdx` is free
1353        // everywhere in this function except at the instruction that is about to fill it, which is
1354        // the one instruction the divisor is wanted at.
1355        assert_eq!(places(&func, &narrow(4)), ["rcx", "rax", "rsi", "rdx"]);
1356    }
1357
1358    #[test]
1359    fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
1360        let mut names = Interner::new();
1361        let mut func = Func::new(names.intern("f"));
1362        let opcode = Opcode::new(names.intern("x64.nop"));
1363        let block = func.create_block();
1364        let dividend = func.new_vreg(GPR);
1365        let quotient = func.new_vreg(GPR);
1366        func.build(block, opcode).def(dividend, GPR).finish();
1367        func.build(block, opcode)
1368            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1369            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1370            .finish();
1371        func.build(block, opcode).uses(dividend, GPR).finish();
1372
1373        // The hint is a preference and not a claim. The dividend would rather be in `rax` and
1374        // cannot be, because the division writes `rax` and the dividend is wanted afterwards, so
1375        // it takes the next register and the quotient keeps the one it was promised.
1376        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1377    }
1378
1379    #[test]
1380    fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
1381        let mut names = Interner::new();
1382        let mut func = Func::new(names.intern("f"));
1383        let opcode = Opcode::new(names.intern("x64.nop"));
1384        let block = func.create_block();
1385        let value = func.new_vreg(GPR);
1386        func.build(block, opcode).def(value, GPR).finish();
1387        func.build(block, opcode)
1388            .operand(Operand::read(value, GPR).with(Constraint::Stack))
1389            .finish();
1390
1391        assert_eq!(places(&func, &env()), ["slot 0"]);
1392    }
1393
1394    #[test]
1395    fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
1396        let mut names = Interner::new();
1397        let mut func = Func::new(names.intern("f"));
1398        let opcode = Opcode::new(names.intern("x64.nop"));
1399        let block = func.create_block();
1400        let left = func.new_vreg(GPR);
1401        let right = func.new_vreg(GPR);
1402        let sum = func.new_vreg(GPR);
1403        func.build(block, opcode).def(left, GPR).finish();
1404        func.build(block, opcode).def(right, GPR).finish();
1405        func.build(block, opcode)
1406            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1407            .uses(left, GPR)
1408            .uses(right, GPR)
1409            .finish();
1410        func.build(block, opcode).uses(right, GPR).finish();
1411
1412        // The addition reads the left value for the last time, so the answer goes where that was
1413        // and the instruction is two address without a move in front of it.
1414        assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1415    }
1416
1417    #[test]
1418    fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
1419        let mut names = Interner::new();
1420        let mut func = Func::new(names.intern("f"));
1421        let opcode = Opcode::new(names.intern("x64.nop"));
1422        let block = func.create_block();
1423        let left = func.new_vreg(GPR);
1424        let right = func.new_vreg(GPR);
1425        let sum = func.new_vreg(GPR);
1426        func.build(block, opcode).def(left, GPR).finish();
1427        func.build(block, opcode).def(right, GPR).finish();
1428        func.build(block, opcode)
1429            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1430            .uses(left, GPR)
1431            .uses(right, GPR)
1432            .finish();
1433        func.build(block, opcode).uses(left, GPR).finish();
1434
1435        // The left value is wanted afterwards, so the answer cannot have its register. It cannot
1436        // have the right one's either, because the rewrite is about to write a move into it before
1437        // the addition has read anything.
1438        assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
1439    }
1440
1441    #[test]
1442    fn an_answer_that_commutes_goes_over_the_source_that_is_finished_with() {
1443        let mut names = Interner::new();
1444        let mut func = Func::new(names.intern("f"));
1445        let opcode = Opcode::new(names.intern("x64.nop"));
1446        let block = func.create_block();
1447        let left = func.new_vreg(GPR);
1448        let right = func.new_vreg(GPR);
1449        let sum = func.new_vreg(GPR);
1450        func.build(block, opcode).def(left, GPR).finish();
1451        func.build(block, opcode).def(right, GPR).finish();
1452        let add = func
1453            .build(block, opcode)
1454            .flags(Flags::COMMUTES)
1455            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1456            .uses(left, GPR)
1457            .uses(right, GPR)
1458            .finish();
1459        func.build(block, opcode).uses(left, GPR).uses(sum, GPR).finish();
1460
1461        // The same shape as the one above where the answer got a register of its own, except that
1462        // the addition reads its sources either way round, so the answer goes where the right one
1463        // was and the instruction is marked to be swapped.
1464        assert_eq!(places(&func, &env()), ["rax", "rcx", "rcx"]);
1465        let order = Order::of(&func);
1466        let live = Live::of(&func, &order);
1467        let assignment = assign(&func, &order, &live, &env());
1468        assert_eq!(assignment.commuted(), [add]);
1469
1470        // Once swapped, the instruction is an ordinary reuse of its first source, the checker and
1471        // the trace agree with it, and nothing has to be moved in front of it. The rewrite has put
1472        // the registers in by then, so the right one is `rcx` and the left one `rax`.
1473        let allocation = crate::run(&mut func, &env(), "f", true);
1474        assert!(allocation.edits.is_empty());
1475        let operands = &func[func[add].operands];
1476        let (first, second) = (operands[1].reg.phys(), operands[2].reg.phys());
1477        assert_eq!((first, second), (Some(RCX), Some(RAX)));
1478    }
1479
1480    #[test]
1481    fn an_answer_that_commutes_takes_the_source_something_after_it_wants() {
1482        let mut names = Interner::new();
1483        let mut func = Func::new(names.intern("f"));
1484        let opcode = Opcode::new(names.intern("x64.nop"));
1485        let block = func.create_block();
1486        let left = func.new_vreg(GPR);
1487        let right = func.new_vreg(GPR);
1488        let sum = func.new_vreg(GPR);
1489        func.build(block, opcode).def(left, GPR).finish();
1490        func.build(block, opcode)
1491            .operand(Operand::write(right, GPR).with(Constraint::Fixed(RAX)))
1492            .finish();
1493        let add = func
1494            .build(block, opcode)
1495            .flags(Flags::COMMUTES)
1496            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1497            .uses(left, GPR)
1498            .uses(right, GPR)
1499            .finish();
1500        func.build(block, opcode)
1501            .operand(Operand::read(sum, GPR).with(Constraint::Fixed(RAX)))
1502            .finish();
1503
1504        // Both sources are finished with, so either register would do for the answer. The one
1505        // reading it wants it in `rax`, which is where the right one already is, so it goes there
1506        // and nothing is moved in front of that reader.
1507        let names = places(&func, &env());
1508        assert_eq!(names[2], "rax");
1509        assert_ne!(names[0], "rax");
1510        let allocation = crate::run(&mut func, &env(), "f", true);
1511        assert!(allocation.edits.is_empty());
1512        assert_eq!(func[func[add].operands][1].reg.phys(), Some(RAX));
1513    }
1514
1515    #[test]
1516    fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1517        let mut names = Interner::new();
1518        let mut func = Func::new(names.intern("f"));
1519        let opcode = Opcode::new(names.intern("x64.nop"));
1520        let entry = func.create_block();
1521        let head = func.create_block();
1522        let out = func.create_block();
1523        let seed = func.new_vreg(GPR);
1524        let total = func.new_vreg(GPR);
1525        let term = func.new_vreg(GPR);
1526        let next = func.new_vreg(GPR);
1527        func.build(entry, opcode).def(seed, GPR).finish();
1528        *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1529        func.params_mut(head).push(Param { reg: total, class: GPR });
1530        func.build(head, opcode).def(term, GPR).finish();
1531        let add = func
1532            .build(head, opcode)
1533            .flags(Flags::COMMUTES)
1534            .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1535            .uses(total, GPR)
1536            .uses(term, GPR)
1537            .finish();
1538        func.build(head, opcode)
1539            .operand(Operand::read(next, GPR).with(Constraint::Fixed(RSI)))
1540            .finish();
1541        *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1542
1543        // Both sources are finished with and the sum is wanted in `rsi` as well, but the loop
1544        // passes it back to `total`, so it goes where `total` is and the back edge has nothing to
1545        // copy.
1546        let order = Order::of(&func);
1547        let live = Live::of(&func, &order);
1548        let assignment = assign(&func, &order, &live, &env());
1549        assert_eq!(assignment.place(next), assignment.place(total));
1550        assert!(!assignment.commuted().contains(&add));
1551    }
1552
1553    #[test]
1554    fn an_answer_that_does_not_commute_leaves_its_sources_where_they_are() {
1555        let mut names = Interner::new();
1556        let mut func = Func::new(names.intern("f"));
1557        let opcode = Opcode::new(names.intern("x64.nop"));
1558        let block = func.create_block();
1559        let left = func.new_vreg(GPR);
1560        let right = func.new_vreg(GPR);
1561        let sum = func.new_vreg(GPR);
1562        func.build(block, opcode).def(left, GPR).finish();
1563        func.build(block, opcode).def(right, GPR).finish();
1564        func.build(block, opcode)
1565            .flags(Flags::COMMUTES)
1566            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1567            .uses(left, GPR)
1568            .uses(right, GPR)
1569            .finish();
1570        func.build(block, opcode).uses(right, GPR).finish();
1571
1572        // The left one is finished with, so the answer goes over it as it always did, and there is
1573        // nothing to swap.
1574        assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1575        let order = Order::of(&func);
1576        let live = Live::of(&func, &order);
1577        assert!(assign(&func, &order, &live, &env()).commuted().is_empty());
1578    }
1579
1580    #[test]
1581    fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
1582        let mut names = Interner::new();
1583        let mut func = Func::new(names.intern("f"));
1584        let opcode = Opcode::new(names.intern("x64.nop"));
1585        let head = func.create_block();
1586        let body = func.create_block();
1587        let carried = func.new_vreg(GPR);
1588        let inside = func.new_vreg(GPR);
1589        func.build(head, opcode).def(carried, GPR).finish();
1590        *func.succs_mut(head) = vec![BlockCall::to(body)];
1591        func.build(body, opcode).def(inside, GPR).finish();
1592        func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
1593        *func.succs_mut(body) = vec![BlockCall::to(body)];
1594
1595        // The value inside the loop cannot have the carried one's register, even though nothing
1596        // between the two definitions says so.
1597        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1598    }
1599
1600    #[test]
1601    fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
1602        let mut names = Interner::new();
1603        let mut func = Func::new(names.intern("f"));
1604        let opcode = Opcode::new(names.intern("x64.nop"));
1605        let head = func.create_block();
1606        let latch = func.create_block();
1607        let out = func.create_block();
1608        let source = func.new_vreg(GPR);
1609        let carried = func.new_vreg(GPR);
1610        func.build(head, opcode).def(source, GPR).finish();
1611        func.build(head, opcode).def(carried, GPR).finish();
1612        *func.succs_mut(head) = vec![BlockCall::to(latch)];
1613        // The bottom of the loop adds the source to the carried value and writes the answer back
1614        // over it, reusing the register the source is in. The next turn round redefines both.
1615        func.build(latch, opcode)
1616            .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
1617            .uses(source, GPR)
1618            .uses(carried, GPR)
1619            .finish();
1620        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1621        func.build(out, opcode).uses(carried, GPR).finish();
1622
1623        // The source is read here for the last time, which on its own is the shape the two address
1624        // shortcut is for, and taking it would be wrong. The carried value was written by the same
1625        // instruction on the last turn and is read by this one, so the two are both wanted where
1626        // the instruction reads and one register cannot hold both.
1627        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1628
1629        // And the checker has to agree, since it excused this pair on the same reasoning and so
1630        // would have let the answer through.
1631        let order = Order::of(&func);
1632        let live = Live::of(&func, &order);
1633        let assignment = assign(&func, &order, &live, &env());
1634        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1635    }
1636
1637    #[test]
1638    fn a_two_address_answer_with_a_hole_in_front_of_it_does_not_take_its_other_operand() {
1639        let mut names = Interner::new();
1640        let mut func = Func::new(names.intern("f"));
1641        let nop = Opcode::new(names.intern("x64.nop"));
1642        let add = Opcode::new(names.intern("x64.add"));
1643        let entry = func.create_block();
1644        let head = func.create_block();
1645        let arm = func.create_block();
1646        let latch = func.create_block();
1647        let out = func.create_block();
1648        let seed = func.new_vreg(GPR);
1649        let sum = func.new_vreg(GPR);
1650        let inside = func.new_vreg(GPR);
1651        let loaded = func.new_vreg(GPR);
1652        func.build(entry, nop).def(seed, GPR).finish();
1653        func.build(entry, nop).def(sum, GPR).finish();
1654        *func.succs_mut(entry) = vec![BlockCall::to(head)];
1655        func.build(head, nop).uses(sum, GPR).finish();
1656        *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
1657        func.build(arm, nop).def(inside, GPR).finish();
1658        func.build(arm, nop).uses(inside, GPR).finish();
1659        *func.succs_mut(arm) = vec![BlockCall::to(out)];
1660        func.build(latch, nop).def(loaded, GPR).finish();
1661        func.build(latch, add)
1662            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1663            .uses(seed, GPR)
1664            .uses(loaded, GPR)
1665            .finish();
1666        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1667
1668        // The answer is live in the entry and the head as well, and the arm between them is a hole
1669        // in it, so the piece the addition writes is not the first one. The value the addition reads
1670        // out of memory is still wanted where the addition reads, so it may not be in the register
1671        // the answer is about to be copied into, holes or no holes. tamnd/rucc#982.
1672        let places = places(&func, &env());
1673        assert_ne!(places[index(sum)], places[index(loaded)]);
1674
1675        let order = Order::of(&func);
1676        let live = Live::of(&func, &order);
1677        let assignment = assign(&func, &order, &live, &env());
1678        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1679    }
1680
1681    #[test]
1682    fn a_sum_a_loop_carries_round_keeps_its_register_past_an_arm_laid_out_after_it() {
1683        let mut names = Interner::new();
1684        let mut func = Func::new(names.intern("f"));
1685        let nop = Opcode::new(names.intern("x64.nop"));
1686        let add = Opcode::new(names.intern("x64.add"));
1687        let entry = func.create_block();
1688        let head = func.create_block();
1689        let join = func.create_block();
1690        let arm = func.create_block();
1691        let out = func.create_block();
1692        let seed = func.new_vreg(GPR);
1693        let term = func.new_vreg(GPR);
1694        let next = func.new_vreg(GPR);
1695        func.build(entry, nop).def(seed, GPR).finish();
1696        *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1697        let total = func.append_param(head, GPR);
1698        func.build(head, nop).def(term, GPR).finish();
1699        *func.succs_mut(head) = vec![BlockCall::to(join), BlockCall::to(arm)];
1700        func.build(join, add)
1701            .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1702            .uses(total, GPR)
1703            .uses(term, GPR)
1704            .finish();
1705        *func.succs_mut(join) =
1706            vec![BlockCall::with(head, vec![next]), BlockCall::with(out, vec![next])];
1707        // The default arm of a `switch`, laid out after the addition it joins back in above. The
1708        // sum is live in it and nothing in it or after it reads the sum again.
1709        func.build(arm, nop).def(term, GPR).finish();
1710        *func.succs_mut(arm) = vec![BlockCall::to(join)];
1711        let result = func.append_param(out, GPR);
1712        func.build(out, nop).uses(result, GPR).finish();
1713
1714        // The addition reads the sum for the last time, so the new sum goes where the old one was
1715        // and the edge back to the top of the loop has nothing to move. tamnd/rucc#1965.
1716        let places = places(&func, &env());
1717        assert_eq!(places[index(next)], places[index(total)]);
1718
1719        let order = Order::of(&func);
1720        let live = Live::of(&func, &order);
1721        let assignment = assign(&func, &order, &live, &env());
1722        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1723    }
1724
1725    /// Two blocks the entry chooses between, with the one the clobber is in written first. The two
1726    /// values written in the entry block are read in the other one, so their ranges cover the
1727    /// clobber whether or not either of them ever reaches it.
1728    fn arms(reaches: bool) -> Func {
1729        let mut names = Interner::new();
1730        let mut func = Func::new(names.intern("f"));
1731        let opcode = Opcode::new(names.intern("x64.nop"));
1732        let entry = func.create_block();
1733        let arm = func.create_block();
1734        let tail = func.create_block();
1735        let first = func.new_vreg(GPR);
1736        let second = func.new_vreg(GPR);
1737        func.build(entry, opcode).def(first, GPR).finish();
1738        func.build(entry, opcode).def(second, GPR).finish();
1739        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1740        // What a call looks like here: an instruction writing the registers the convention says it
1741        // destroys, named outright so that nothing else may be in them.
1742        func.build(arm, opcode).operand(Operand::write(Reg::physical(RAX), GPR)).finish();
1743        *func.succs_mut(arm) = if reaches { vec![BlockCall::to(tail)] } else { Vec::new() };
1744        func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1745        func
1746    }
1747
1748    #[test]
1749    fn a_register_a_clobber_takes_beats_the_stack_for_a_value_not_live_in_that_block() {
1750        let func = arms(false);
1751
1752        // Two registers between two values, and a clobber in the arm that takes the first of them.
1753        // The intervals around both values cover the clobber, since the arm is written between the
1754        // two blocks they are live in, and the arm is a hole in both of their areas. So a value has
1755        // `rax` rather than a stack slot: the arm is a block its own path never goes through.
1756        // tamnd/rucc#982. It is the first value since tamnd/rucc#2202, because a clobber where a
1757        // value is dead leaves the register clear for it.
1758        assert_eq!(places(&func, &narrow(2)), ["rax", "rcx"]);
1759
1760        let order = Order::of(&func);
1761        let live = Live::of(&func, &order);
1762        let assignment = assign(&func, &order, &live, &narrow(2));
1763        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1764    }
1765
1766    #[test]
1767    fn a_register_a_clobber_takes_is_not_free_to_a_value_that_is_live_there() {
1768        let func = arms(true);
1769
1770        // The same blocks with an edge from the arm to the tail, which is all it takes: both values
1771        // now arrive at the read either way, so the clobber is on a path they are live over and the
1772        // one register left has to do for both of them.
1773        assert_eq!(places(&func, &narrow(2)), ["rcx", "slot 0"]);
1774    }
1775
1776    /// A value and the instruction that destroys a register, written one after the other, with the
1777    /// value read by that instruction or by the one after it.
1778    fn dies_at_the_clobber(here: bool) -> Func {
1779        let mut names = Interner::new();
1780        let mut func = Func::new(names.intern("f"));
1781        let opcode = Opcode::new(names.intern("x64.nop"));
1782        let entry = func.create_block();
1783        let value = func.new_vreg(GPR);
1784        func.build(entry, opcode).def(value, GPR).finish();
1785        let call = func.build(entry, opcode).operand(Operand::write(Reg::physical(RAX), GPR));
1786        if here {
1787            call.uses(value, GPR).finish();
1788        } else {
1789            call.finish();
1790            func.build(entry, opcode).uses(value, GPR).finish();
1791        }
1792        func
1793    }
1794
1795    /// A value whose last read is the instruction that destroys a register may be in that register,
1796    /// because the instruction reads what it is handed before it writes anything.
1797    ///
1798    /// The call is what this is about, and the value a call is passed is the case: seven registers
1799    /// on this machine are destroyed by one, every argument dies at the call that reads it, and
1800    /// refusing all seven to those values left them taking a callee saved register for a life two
1801    /// instructions long and paying for it in the prologue and the epilogue. tamnd/rucc#1232.
1802    #[test]
1803    fn a_value_that_dies_where_a_register_is_destroyed_may_be_in_that_register() {
1804        let func = dies_at_the_clobber(true);
1805        assert_eq!(places(&func, &narrow(1)), ["rax"]);
1806
1807        let order = Order::of(&func);
1808        let live = Live::of(&func, &order);
1809        let assignment = assign(&func, &order, &live, &narrow(1));
1810        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1811    }
1812
1813    /// And one read later than that is one the instruction really does destroy, which is the same
1814    /// function with the read moved down by one instruction.
1815    #[test]
1816    fn a_value_read_after_the_instruction_that_destroys_a_register_is_not_in_it() {
1817        let func = dies_at_the_clobber(false);
1818        assert_eq!(places(&func, &narrow(1)), ["slot 0"]);
1819    }
1820
1821    #[test]
1822    fn a_hint_is_followed_when_the_register_is_clear_and_not_when_it_is_merely_allowed() {
1823        let mut names = Interner::new();
1824        let mut func = Func::new(names.intern("f"));
1825        let opcode = Opcode::new(names.intern("x64.nop"));
1826        let entry = func.create_block();
1827        let mid = func.create_block();
1828        let tail = func.create_block();
1829        let first = func.new_vreg(GPR);
1830        let second = func.new_vreg(GPR);
1831        func.build(entry, opcode).def(first, GPR).finish();
1832        func.build(entry, opcode).def(second, GPR).finish();
1833        *func.succs_mut(entry) = vec![BlockCall::to(mid), BlockCall::to(tail)];
1834        // Two arms, each ending in an instruction that wants its own value in `rax`, which is what
1835        // a return out of either side of a branch looks like.
1836        func.build(mid, opcode)
1837            .operand(Operand::read(second, GPR).with(Constraint::Fixed(RAX)))
1838            .finish();
1839        func.build(tail, opcode)
1840            .operand(Operand::read(first, GPR).with(Constraint::Fixed(RAX)))
1841            .finish();
1842
1843        // The first value is hinted at `rax` and does not get it, because the other arm wants `rax`
1844        // for the other value and the first value's range reaches that far. Following the hint here
1845        // would save a move in the tail and cost one in the middle, and the second value gets `rax`
1846        // with nothing moved anywhere instead.
1847        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1848    }
1849
1850    #[test]
1851    fn a_value_living_in_a_hole_of_another_gets_the_same_register() {
1852        let mut names = Interner::new();
1853        let mut func = Func::new(names.intern("f"));
1854        let opcode = Opcode::new(names.intern("x64.nop"));
1855        let entry = func.create_block();
1856        let arm = func.create_block();
1857        let tail = func.create_block();
1858        let across = func.new_vreg(GPR);
1859        let inside = func.new_vreg(GPR);
1860        func.build(entry, opcode).def(across, GPR).finish();
1861        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1862        func.build(arm, opcode).def(inside, GPR).finish();
1863        func.build(arm, opcode).uses(inside, GPR).finish();
1864        func.build(tail, opcode).uses(across, GPR).finish();
1865
1866        // One register between the two of them, and one register is enough. Nothing in the arm can
1867        // reach the read in the tail, so the value the arm makes is welcome to the register the
1868        // value crossing the function is in. The interval around that value covers the arm and the
1869        // value is nowhere near it, which is what used to send one of the two to the stack.
1870        // tamnd/rucc#982.
1871        assert_eq!(places(&func, &narrow(1)), ["rax", "rax"]);
1872
1873        let order = Order::of(&func);
1874        let live = Live::of(&func, &order);
1875        let assignment = assign(&func, &order, &live, &narrow(1));
1876        assert_eq!(assignment.spilled(), 0);
1877        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1878    }
1879
1880    /// The blocks of [`arms`] with no edge from the arm to the tail, where the arm wants `rax` for
1881    /// a value of its own rather than destroying it.
1882    fn handed_in_the_arm() -> Func {
1883        let mut names = Interner::new();
1884        let mut func = Func::new(names.intern("f"));
1885        let opcode = Opcode::new(names.intern("x64.nop"));
1886        let entry = func.create_block();
1887        let arm = func.create_block();
1888        let tail = func.create_block();
1889        let first = func.new_vreg(GPR);
1890        let second = func.new_vreg(GPR);
1891        let own = func.new_vreg(GPR);
1892        func.build(entry, opcode).def(first, GPR).finish();
1893        func.build(entry, opcode).def(second, GPR).finish();
1894        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1895        func.build(arm, opcode).def(own, GPR).finish();
1896        func.build(arm, opcode)
1897            .operand(Operand::read(own, GPR).with(Constraint::Fixed(RAX)))
1898            .finish();
1899        func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1900        func
1901    }
1902
1903    #[test]
1904    fn a_register_another_value_is_handed_is_the_last_one_offered_rather_than_the_first() {
1905        // With a register to spare the value takes the spare one. Being allowed a register some
1906        // instruction insists on is not the same as it being free: the instruction has to be handed
1907        // it in the end, and what hands it over is a move.
1908        let func = handed_in_the_arm();
1909        assert_eq!(places(&func, &narrow(3)), ["rcx", "rdx", "rax"]);
1910    }
1911
1912    #[test]
1913    fn a_register_a_clobber_takes_is_clear_to_a_value_dead_where_it_is_taken() {
1914        let func = arms(false);
1915
1916        // A clobber hands the register to nobody, so there is nothing to move in and nothing to
1917        // pay. The first value takes `rax` though the arm destroys it, since it is dead there, and
1918        // neither value needs a register past the third. tamnd/rucc#2202.
1919        assert_eq!(places(&func, &narrow(3)), ["rax", "rcx"]);
1920    }
1921
1922    #[test]
1923    fn a_frame_says_what_each_of_its_slots_is_for() {
1924        let mut names = Interner::new();
1925        let mut func = Func::new(names.intern("f"));
1926        let opcode = Opcode::new(names.intern("x64.nop"));
1927        let block = func.create_block();
1928        let first = func.new_vreg(GPR);
1929        let second = func.new_vreg(GPR);
1930        func.build(block, opcode).def(first, GPR).finish();
1931        func.build(block, opcode).def(second, GPR).finish();
1932        func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
1933
1934        let order = Order::of(&func);
1935        let live = Live::of(&func, &order);
1936        let assignment = assign(&func, &order, &live, &narrow(1));
1937        assert_eq!(assignment.spilled(), 1);
1938        assert_eq!(assignment.slots(), [GPR]);
1939        // A register that is already a register is where it is, and this has nothing to say about
1940        // it.
1941        assert_eq!(assignment.place(Reg::physical(RCX)), None);
1942        assert_eq!(env().scratch(GPR), [R13, R14, R15]);
1943    }
1944
1945    /// Pieces of a value, from pairs of points.
1946    fn ranges(pairs: &[(Point, Point)]) -> Vec<Range> {
1947        pairs.iter().map(|&(start, end)| Range { start, end }).collect()
1948    }
1949
1950    #[test]
1951    fn the_pieces_of_a_register_answer_what_a_walk_over_its_values_would() {
1952        // Three values that take turns in one register, the first with a hole the third sits in.
1953        let held = [
1954            (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1955            (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1956            (Reg::virtual_reg(2), ranges(&[(10, 19), (31, 40)])),
1957        ];
1958        let mut pieces = Pieces::default();
1959        for (reg, list) in &held {
1960            for &piece in list {
1961                pieces.insert(piece, *reg);
1962            }
1963        }
1964        assert!(!pieces.broken);
1965        let asked = [
1966            ranges(&[(41, 50)]),
1967            ranges(&[(40, 50)]),
1968            ranges(&[(9, 9)]),
1969            ranges(&[(3, 3), (41, 42)]),
1970            ranges(&[(50, 60)]),
1971            ranges(&[(15, 15)]),
1972        ];
1973        for list in &asked {
1974            let area = Area::of_pieces(list);
1975            for except in [None, Some(Reg::virtual_reg(0)), Some(Reg::virtual_reg(2))] {
1976                let walked = held.iter().any(|(reg, pieces)| {
1977                    Some(*reg) != except && Area::of_pieces(pieces).overlaps(area)
1978                });
1979                assert_eq!(pieces.touch(area, except), walked, "{list:?} except {except:?}");
1980            }
1981        }
1982    }
1983
1984    #[test]
1985    fn the_owners_of_the_pieces_an_area_touches_are_the_values_a_walk_would_find() {
1986        let held = [
1987            (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1988            (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1989            (Reg::virtual_reg(2), ranges(&[(10, 19), (30, 40)])),
1990        ];
1991        let mut pieces = Pieces::default();
1992        for (reg, list) in &held {
1993            for &piece in list {
1994                pieces.insert(piece, *reg);
1995            }
1996        }
1997        let asked = [
1998            ranges(&[(41, 50)]),
1999            ranges(&[(30, 30)]),
2000            ranges(&[(3, 12)]),
2001            ranges(&[(3, 3), (25, 42)]),
2002            ranges(&[(0, 50)]),
2003        ];
2004        for list in &asked {
2005            let area = Area::of_pieces(list);
2006            let walked: Vec<Reg> = held
2007                .iter()
2008                .filter(|(_, pieces)| Area::of_pieces(pieces).overlaps(area))
2009                .map(|&(reg, _)| reg)
2010                .collect();
2011            assert_eq!(pieces.owners(area), Some(walked), "{list:?}");
2012        }
2013        pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(3));
2014        assert_eq!(pieces.owners(Area::of_pieces(&asked[0])), None);
2015    }
2016
2017    #[test]
2018    fn pieces_that_end_out_of_order_are_marked() {
2019        let mut pieces = Pieces::default();
2020        pieces.insert(Range { start: 0, end: 10 }, Reg::virtual_reg(0));
2021        pieces.insert(Range { start: 12, end: 20 }, Reg::virtual_reg(1));
2022        assert!(!pieces.broken);
2023        // Inside the first, which two values in one register never are.
2024        pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(2));
2025        assert!(pieces.broken);
2026    }
2027
2028    #[test]
2029    fn a_value_taken_out_of_a_register_leaves_its_pieces_with_it() {
2030        let mut pieces = Pieces::default();
2031        let (first, second) = (Reg::virtual_reg(0), Reg::virtual_reg(1));
2032        pieces.insert(Range { start: 0, end: 10 }, first);
2033        pieces.insert(Range { start: 12, end: 20 }, second);
2034        let asked = ranges(&[(15, 16)]);
2035        assert!(pieces.touch(Area::of_pieces(&asked), None));
2036        pieces.remove(Range { start: 12, end: 20 }, second);
2037        assert!(!pieces.touch(Area::of_pieces(&asked), None));
2038        pieces.drop_before(11);
2039        assert!(pieces.list.is_empty());
2040    }
2041}