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 held back in a class for reading a spilled value into.
169    #[must_use]
170    pub fn scratch(&self, class: RegClass) -> &[PhysReg] {
171        self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.scratch)
172    }
173}
174
175/// Where every value in a function went.
176#[derive(Debug, Clone)]
177pub struct Assignment {
178    places: Vec<Option<Place>>,
179    slots: Vec<RegClass>,
180    commuted: Vec<Inst>,
181}
182
183impl Assignment {
184    /// An assignment that says nothing yet about a function with that many values.
185    ///
186    /// This and [`Assignment::put`] and [`Assignment::take_slot`] are how an allocator says what
187    /// it decided. There will be a second one in M4 and it will not reach its answer this way, so
188    /// what an assignment is has to be separable from how this file arrives at one, and the
189    /// checker in [`crate::check`] reads an assignment without caring which allocator wrote it.
190    #[must_use]
191    pub fn empty(vregs: usize) -> Self {
192        Self { places: vec![None; vregs], slots: Vec::new(), commuted: Vec::new() }
193    }
194
195    /// The two address instructions whose answer went into the register of their second source.
196    ///
197    /// Each has to have its two sources swapped before anything reads the assignment against the
198    /// function, which [`crate::run`] does. After that the answer reuses what is then the first
199    /// source, as every two address instruction does. tamnd/rucc#1895.
200    #[must_use]
201    pub fn commuted(&self) -> &[Inst] {
202        &self.commuted
203    }
204
205    /// Records where a value went.
206    ///
207    /// # Panics
208    ///
209    /// Panics on a physical register, which is somewhere already, and on a virtual one the
210    /// function never handed out.
211    pub fn put(&mut self, reg: Reg, place: Place) {
212        self.places[index(reg)] = Some(place);
213    }
214
215    /// Takes a slot of the frame, of that class, and gives back which one it is.
216    ///
217    /// # Panics
218    ///
219    /// Panics past four billion slots, which is a frame no machine has room for.
220    pub fn take_slot(&mut self, class: RegClass) -> u32 {
221        let slot = u32::try_from(self.slots.len()).expect("too many spilled values");
222        self.slots.push(class);
223        slot
224    }
225
226    /// Where a value lives, or `None` for a virtual register this function never mentions and for
227    /// a physical one, which is already where it is.
228    #[must_use]
229    pub fn place(&self, reg: Reg) -> Option<Place> {
230        self.places.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
231    }
232
233    /// The class of each slot of the frame, which is what says how wide it has to be.
234    #[must_use]
235    pub fn slots(&self) -> &[RegClass] {
236        &self.slots
237    }
238
239    /// Every value that went somewhere, and where it went.
240    ///
241    /// The assignment read the other way round, which is what a caller wants when the question is
242    /// about the places rather than about the values. The stack slot allocator asks it that way,
243    /// since what it needs is which value is in each slot and the assignment is stored by value.
244    pub fn placed(&self) -> impl Iterator<Item = (Reg, Place)> + '_ {
245        self.places.iter().enumerate().filter_map(|(number, place)| {
246            let number = u32::try_from(number).ok()?;
247            Some((Reg::virtual_reg(number), (*place)?))
248        })
249    }
250
251    /// How many values went to the stack.
252    #[must_use]
253    pub fn spilled(&self) -> usize {
254        self.slots.len()
255    }
256
257    /// Puts a value on the stack, in a slot of its own.
258    fn spill(&mut self, reg: Reg, class: RegClass) {
259        let slot = self.take_slot(class);
260        self.put(reg, Place::Slot(slot));
261    }
262}
263
264/// One value waiting for a place.
265#[derive(Debug, Clone, Copy)]
266struct Interval<'a> {
267    reg: Reg,
268    class: RegClass,
269    /// The interval around the area, which is what the sweep below reads and what says which value
270    /// is wanted for longest when one of them has to go.
271    range: Range,
272    /// Everywhere the value is really live, which is what says whether two of them fit in one
273    /// register.
274    area: Area<'a>,
275}
276
277/// One value that has a register, for as long as it still wants it.
278#[derive(Debug, Clone, Copy)]
279struct Held<'a> {
280    reg: Reg,
281    class: RegClass,
282    range: Range,
283    area: Area<'a>,
284    at: PhysReg,
285}
286
287/// A register an instruction insists on, and where it insists on it.
288#[derive(Debug, Clone, Copy)]
289struct Blocked {
290    class: RegClass,
291    at: PhysReg,
292    /// One of the instruction's two points. Every register an instruction insists on has an entry
293    /// at each of them, because a register held at one of the two is a register nothing else may
294    /// be in across the instruction.
295    point: Point,
296    /// The one value that may be in it there, which is the value of an operand the instruction
297    /// reads at that point or writes at it. `None` means nothing may: an operand naming a physical
298    /// register outright claims it against everything, and a point no operand covers is a point
299    /// the instruction has the register to itself at.
300    by: Option<Reg>,
301}
302
303/// A value written into the register another operand of the same instruction was read from.
304#[derive(Debug, Clone, Copy)]
305struct Reuse {
306    /// The value being read, which is the one whose register would do.
307    source: Reg,
308    /// The other value the instruction reads, when the instruction reads the two either way round
309    /// and so could write its answer over this one instead.
310    second: Option<Reg>,
311    /// Where the instruction reads it.
312    at: Point,
313    /// The instruction, which is swapped round if the answer takes the second value's register.
314    inst: Inst,
315}
316
317/// Decides where every value in a function lives.
318///
319/// # Panics
320///
321/// Panics if a class has no registers to hand out and something in the function is in that class,
322/// since that is a target description that does not describe the target the function is for.
323#[must_use]
324pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
325    let blocked = blocked(func, order);
326    let forced = forced(func);
327    let reuses = reuses(func, order);
328    let hints = hints(func);
329    let passed = passed(func);
330
331    let mut intervals = Vec::with_capacity(func.vregs());
332    for (number, reuse) in reuses.iter().enumerate() {
333        let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
334        let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
335            continue;
336        };
337        if let Some(reuse) = reuse {
338            area = area.with(reuse.at);
339        }
340        intervals.push(Interval { reg, class, range: area.hull(), area });
341    }
342    intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
343
344    let mut assignment = Assignment::empty(func.vregs());
345    let mut active: Vec<Held<'_>> = Vec::new();
346    for interval in intervals {
347        active.retain(|held| held.range.end >= interval.range.start);
348        if forced.contains(&interval.reg) {
349            assignment.spill(interval.reg, interval.class);
350            continue;
351        }
352        // A class with no order is one the target says nothing allocates from, which on x86-64 is
353        // the x87 stack. A value of such a class is a mistake at the point it was made rather than
354        // a value with nowhere to go: what the target means is that the value lives in memory and
355        // that whatever operates on it takes an address. See `ClassInfo::allocatable`.
356        assert!(
357            !env.order(interval.class).is_empty(),
358            "a value in class {}, which the target hands out no registers from",
359            interval.class.number()
360        );
361        let reuse = reuses[index(interval.reg)];
362        let coalesced = |source| coalesce(&assignment, &active, &blocked, live, interval, source);
363        let first = reuse.and_then(|reuse| coalesced(reuse.source));
364        let second = reuse.and_then(|reuse| reuse.second).and_then(coalesced);
365        // An instruction that reads its sources either way round can write over the second one
366        // instead, which is what it needs when the first is read again later and the second is
367        // not. When both would do, the first is kept unless only the second is where something
368        // wants the answer, which saves the move in front of that reader.
369        //
370        // A block the answer is passed to wants it where that block's parameter already is. That
371        // has to count as much as an instruction asking for a register. A sum a loop carries is
372        // passed back to the parameter it was read from, and taking the register of the other
373        // source because the sum is also printed at the end moves the copy onto the back edge,
374        // where it runs every turn instead of once.
375        let hinted_at = |at: Option<PhysReg>| {
376            at.is_some_and(|at| {
377                hints[index(interval.reg)].contains(&at)
378                    || passed[index(interval.reg)]
379                        .iter()
380                        .any(|&param| assignment.place(param) == Some(Place::Reg(at)))
381            })
382        };
383        let commute =
384            second.is_some() && (first.is_none() || hinted_at(second) && !hinted_at(first));
385        let two_address = if commute { second } else { first };
386        if let (true, Some(reuse)) = (commute, reuse) {
387            assignment.commuted.push(reuse.inst);
388        }
389        // The reuse comes first, because a two address instruction that has to copy its left
390        // operand in pays for the copy whatever the hint says, and taking the hint here would buy
391        // one move at the cost of another.
392        let hinted = hints[index(interval.reg)].iter().copied().find(|&at| {
393            env.order(interval.class).contains(&at)
394                && available(&active, &blocked, interval, at, None, Want::Clear)
395        });
396        // A register nobody else wants anywhere near this value first, and one somebody wants
397        // somewhere the value never goes only when there is no other. Both are correct and the
398        // second is the worse buy, since the instruction that wants it has to be handed it and
399        // whatever this value is doing there has to move out of the way first.
400        let scan = |want| {
401            env.order(interval.class)
402                .iter()
403                .copied()
404                .find(|&at| available(&active, &blocked, interval, at, None, want))
405        };
406        let chosen =
407            two_address.or(hinted).or_else(|| scan(Want::Clear)).or_else(|| scan(Want::Allowed));
408        match chosen {
409            Some(at) => {
410                assignment.places[index(interval.reg)] = Some(Place::Reg(at));
411                active.push(Held {
412                    reg: interval.reg,
413                    class: interval.class,
414                    range: interval.range,
415                    area: interval.area,
416                    at,
417                });
418            }
419            None => spill_one(&mut assignment, &mut active, &blocked, interval),
420        }
421    }
422    assignment
423}
424
425/// How much a register suits an interval.
426#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427enum Want {
428    /// Nothing insists on it anywhere the range reaches, so taking it costs nobody anything.
429    Clear,
430    /// Something insists on it somewhere the range reaches and nowhere the value is live, so taking
431    /// it is allowed and may still cost: the instruction that insists wants the register for a
432    /// value of its own, and that value now has to be moved into it.
433    Allowed,
434}
435
436/// Every register every instruction in the function insists on, arranged to be asked about.
437///
438/// Built once and never changed afterwards, and there is only one question ever asked of it: of the
439/// constraints naming one register of one class, is there one at a point some interval covers. So
440/// the entries are ordered by the register they name and then by the point, and the question is a
441/// binary search for the start of the interval followed by a walk that stops at its end.
442///
443/// It used to be a flat list walked from one end for every candidate register of every interval,
444/// which is quadratic in the size of a function and is most of the compile on a large one. See
445/// tamnd/rucc#1003 for the profile that found it.
446struct Blocks {
447    /// The constraints, sorted by class, then by register, then by point.
448    all: Vec<Blocked>,
449}
450
451impl Blocks {
452    /// The constraints on one register of one class at the points an interval covers.
453    ///
454    /// Both ends of the walk come from the ordering rather than from a test, so what comes back is
455    /// exactly what the old `covers` call used to keep and in the same order.
456    fn over(
457        &self,
458        class: RegClass,
459        at: PhysReg,
460        range: Range,
461    ) -> impl Iterator<Item = &Blocked> + '_ {
462        let first = self
463            .all
464            .partition_point(|one| (one.class, one.at, one.point) < (class, at, range.start));
465        self.all[first..]
466            .iter()
467            .take_while(move |one| one.class == class && one.at == at && one.point <= range.end)
468    }
469}
470
471/// Whether a register is one this interval could have.
472///
473/// The exception is the value a reuse is coalescing with, which holds the register right up to the
474/// point the new value takes it over and is the one thing that may overlap.
475///
476/// The sweep only keeps a value in `active` while the interval around it reaches this one, so the
477/// areas still have to be compared: two values whose intervals cross can have holes that let them
478/// share a register anyway, which on a function with several loops in it is most of them.
479fn available(
480    active: &[Held<'_>],
481    blocked: &Blocks,
482    interval: Interval<'_>,
483    at: PhysReg,
484    except: Option<Reg>,
485    want: Want,
486) -> bool {
487    let taken = active.iter().any(|held| {
488        held.at == at
489            && held.class == interval.class
490            && Some(held.reg) != except
491            && held.area.overlaps(interval.area)
492    });
493    let insisted = blocked.over(interval.class, at, interval.range).any(|one| {
494        one.by != Some(interval.reg) && (want == Want::Clear || interval.area.covers(one.point))
495    });
496    !taken && !insisted
497}
498
499/// The register the value being reused is in, when the value being written is never live at the
500/// same time as it and the register is otherwise free.
501fn coalesce(
502    assignment: &Assignment,
503    active: &[Held<'_>],
504    blocked: &Blocks,
505    live: &Live,
506    interval: Interval<'_>,
507    source: Reg,
508) -> Option<PhysReg> {
509    let Some(Place::Reg(at)) = assignment.place(source) else { return None };
510    active.iter().find(|held| held.reg == source)?;
511    // The two have to be apart everywhere, asked of the areas liveness worked out and without the
512    // point the reuse adds, since that point is the one they are allowed to share.
513    //
514    // That covers both ways it can go wrong. A value read again later needs its register after
515    // this instruction would have overwritten it. And a value being written that is live where the
516    // instruction reads already is what a loop carrying its own result round looks like: the
517    // instruction writes it at the bottom and the top of the loop reads what the last turn wrote.
518    // Either way the two are wanted at once, and no register holds both.
519    //
520    // It used to be asked of the end of the interval around the value being read, and that is not
521    // the same question. A block laid out after this instruction where the value is still live,
522    // such as the default arm of a `switch` that joins back in above it, stretches the interval
523    // past this point when nothing past it reads the value at all. The sum a loop carries round
524    // then went into a new register and was copied back at the bottom of every turn.
525    // tamnd/rucc#1965.
526    let free = available(active, blocked, interval, at, Some(source), Want::Allowed);
527    (apart(live, source, interval.reg) && free).then_some(at)
528}
529
530/// Whether two values are never live at the same time, going by what liveness worked out.
531pub(crate) fn apart(live: &Live, first: Reg, second: Reg) -> bool {
532    match (live.area(first), live.area(second)) {
533        (Some(first), Some(second)) => !first.overlaps(second),
534        _ => false,
535    }
536}
537
538/// Sends values to the stack to free a register: the ones wanted for longest, since a register
539/// held that long pays for itself over the most instructions.
540///
541/// What is chosen is a register rather than a value, because two values whose areas miss each
542/// other share one and taking it means every value in it this one is really on top of has to go.
543/// A register holding two of those costs twice as much to take as one holding a single value, so
544/// the cheap ones are looked at first and the reach only settles ties.
545fn spill_one<'a>(
546    assignment: &mut Assignment,
547    active: &mut Vec<Held<'a>>,
548    blocked: &Blocks,
549    interval: Interval<'a>,
550) {
551    // What each register would cost: how many values would go, and the furthest any of them
552    // reaches. The list is one entry per register of the class, so walking it for each value in
553    // flight is the same shape as everything else here.
554    let mut costs: Vec<(PhysReg, usize, Point)> = Vec::new();
555    for held in active.iter() {
556        if held.class != interval.class || !held.area.overlaps(interval.area) {
557            continue;
558        }
559        match costs.iter_mut().find(|(at, _, _)| *at == held.at) {
560            Some((_, count, reach)) => {
561                *count += 1;
562                *reach = (*reach).max(held.range.end);
563            }
564            None => costs.push((held.at, 1, held.range.end)),
565        }
566    }
567    // A register the instructions in the way insist on for themselves is no use, because taking it
568    // over would put this value in a register it may not have.
569    let chosen = costs
570        .iter()
571        .filter(|&&(at, _, reach)| {
572            reach > interval.range.end && available(&[], blocked, interval, at, None, Want::Allowed)
573        })
574        .min_by_key(|&&(_, count, reach)| (count, Reverse(reach)))
575        .map(|&(at, _, _)| at);
576    match chosen {
577        Some(at) => {
578            active.retain(|held| {
579                let goes = held.at == at
580                    && held.class == interval.class
581                    && held.area.overlaps(interval.area);
582                if goes {
583                    assignment.spill(held.reg, held.class);
584                }
585                !goes
586            });
587            assignment.places[index(interval.reg)] = Some(Place::Reg(at));
588            active.push(Held {
589                reg: interval.reg,
590                class: interval.class,
591                range: interval.range,
592                area: interval.area,
593                at,
594            });
595        }
596        None => assignment.spill(interval.reg, interval.class),
597    }
598}
599
600/// The registers the instructions insist on, and where.
601///
602/// A physical register an operand names outright counts the same way. Nothing before allocation
603/// writes one except an instruction that has to, and it has to for the length of that one
604/// instruction, which is the same statement a fixed constraint makes.
605fn blocked(func: &Func, order: &Order) -> Blocks {
606    let mut blocked = Vec::new();
607    let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
608    for block in func.blocks() {
609        for inst in func.insts(block) {
610            let operands = &func[func[inst].operands];
611            claimed.clear();
612            for operand in operands {
613                if let Some(at) = insisted(operand) {
614                    let key = (operand.class, at);
615                    if !claimed.contains(&key) {
616                        claimed.push(key);
617                    }
618                }
619            }
620            for &(class, at) in &claimed {
621                // Both points, whether or not an operand is at them. A register an instruction
622                // reads and does not write is still gone by the time the instruction is done as far
623                // as anything here knows, which is what stops the value a call is passed in `rdi`
624                // from staying in `rdi` over the call.
625                for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
626                {
627                    let mut named = false;
628                    for operand in operands {
629                        let mine = insisted(operand) == Some(at) && operand.class == class;
630                        if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
631                            continue;
632                        }
633                        named = true;
634                        let by = operand.reg.is_virtual().then_some(operand.reg);
635                        blocked.push(Blocked { class, at, point, by });
636                    }
637                    // A register no operand names where the operands are read is one the
638                    // instruction writes and does not read, which is what a clobber is, and the
639                    // seven registers a call destroys are the whole of why that case is worth
640                    // separating. Such a register is free right up to the point it is written, so a
641                    // value whose last read is this instruction may sit in one: it is read before
642                    // the instruction writes anything, the way any other operand is. Blocking it
643                    // where the operands are read as well would take every caller saved register
644                    // away from the value a call is passed, which is a value that dies at the call
645                    // and pays for a callee saved register it holds for two instructions. Anything
646                    // living past the instruction is still refused, by the block below.
647                    //
648                    // This is where a target's early definitions are paid for. An instruction that
649                    // fills a register before it has finished reading has to say so, because that
650                    // is the one thing a plain definition here no longer covers: a division on
651                    // x86-64 is a sign extension and then the division itself, so `rdx` is gone
652                    // before the divisor is read, and a divisor that went there would be read as
653                    // the dividend's own sign bits. `rucc_target::x86_64` writes both of them down
654                    // as early definitions for exactly that reason.
655                    if !named && role == Role::Def {
656                        blocked.push(Blocked { class, at, point, by: None });
657                    }
658                }
659            }
660        }
661    }
662    // Program order already has the points ascending, but the registers one instruction claims are
663    // walked outside the two points rather than inside them, so the list arrives in order by
664    // instruction and not by register. A sort by the key the lookup searches on is what makes it
665    // searchable, and it is stable so two constraints on one register at one point keep the order
666    // the instruction wrote them in.
667    blocked.sort_by_key(|one: &Blocked| (one.class, one.at, one.point));
668    Blocks { all: blocked }
669}
670
671/// The register an operand has to be in, which is the one a constraint asks for or the one the
672/// operand names outright.
673fn insisted(operand: &Operand) -> Option<PhysReg> {
674    match operand.constraint {
675        Constraint::Fixed(at) => Some(at),
676        _ => operand.reg.phys(),
677    }
678}
679
680/// The registers each value would rather be in, which are the ones the operands naming it insist on.
681///
682/// In the order the function writes them down, so the definition comes first where there is one,
683/// since a value written into a fixed register and then moved somewhere else pays for the move at
684/// the top of its life rather than at the bottom. The ones after it are worth keeping for the same
685/// reason the first one is, and the value a call is passed is where that shows: its definition may
686/// insist on the register a parameter arrived in, which the call it is handed to has usually taken
687/// back for an argument of its own by then, and behind that is the register the convention passes
688/// it in, which is free and is exactly where the value wants to end up.
689fn hints(func: &Func) -> Vec<Vec<PhysReg>> {
690    let mut hints = vec![Vec::new(); func.vregs()];
691    for block in func.blocks() {
692        for inst in func.insts(block) {
693            for operand in &func[func[inst].operands] {
694                let Constraint::Fixed(at) = operand.constraint else { continue };
695                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
696                let Some(number) = number else { continue };
697                let wanted: &mut Vec<PhysReg> = &mut hints[number];
698                if func.class_of(operand.reg) == Some(operand.class) && !wanted.contains(&at) {
699                    wanted.push(at);
700                }
701            }
702        }
703    }
704    hints
705}
706
707/// The block parameters each value is passed to, by the virtual register passed.
708fn passed(func: &Func) -> Vec<Vec<Reg>> {
709    let mut passed = vec![Vec::new(); func.vregs()];
710    for block in func.blocks() {
711        for call in &func[block].succs {
712            for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
713                let number = arg.number().and_then(|number| usize::try_from(number).ok());
714                let Some(number) = number else { continue };
715                let to: &mut Vec<Reg> = &mut passed[number];
716                if !to.contains(&param.reg) {
717                    to.push(param.reg);
718                }
719            }
720        }
721    }
722    passed
723}
724
725/// The values that have to be on the stack whatever else is true of them.
726fn forced(func: &Func) -> Vec<Reg> {
727    let mut forced = Vec::new();
728    for block in func.blocks() {
729        for inst in func.insts(block) {
730            for operand in &func[func[inst].operands] {
731                if operand.constraint == Constraint::Stack
732                    && operand.reg.is_virtual()
733                    && !forced.contains(&operand.reg)
734                {
735                    forced.push(operand.reg);
736                }
737            }
738        }
739    }
740    forced
741}
742
743/// The value each two address instruction reuses, by the virtual register it writes.
744fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
745    let mut reuses = vec![None; func.vregs()];
746    for block in func.blocks() {
747        for inst in func.insts(block) {
748            let operands = &func[func[inst].operands];
749            for operand in operands {
750                let Constraint::Reuse(other) = operand.constraint else { continue };
751                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
752                let Some(number) = number else { continue };
753                let source = operands[usize::from(other)].reg;
754                let second = if func[inst].flags.contains(Flags::COMMUTES) {
755                    swappable(operands, usize::from(other))
756                } else {
757                    None
758                };
759                reuses[number] = Some(Reuse { source, second, at: order.early(inst), inst });
760            }
761        }
762    }
763    reuses
764}
765
766/// The second source of an instruction that reads its two sources either way round, when the
767/// answer could go over it instead of over the first.
768///
769/// Only the shape of a two address instruction with two sources, the answer and then the two, with
770/// the answer reusing the first. The second has to be a value of the same class that asks for
771/// nothing more than a register, since after the swap it is the one the answer reuses.
772fn swappable(operands: &[Operand], other: usize) -> Option<Reg> {
773    let [answer, first, second] = operands else { return None };
774    let same = second.class == first.class && second.class == answer.class;
775    let plain = second.role == Role::Use && second.constraint == Constraint::Reg;
776    (other == 1 && same && plain && second.reg.is_virtual() && second.reg != first.reg)
777        .then_some(second.reg)
778}
779
780/// A virtual register's number as a table index.
781fn index(reg: Reg) -> usize {
782    usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
783}
784
785#[cfg(test)]
786mod tests {
787    use rucc_base::Interner;
788    use rucc_mir::{BlockCall, Opcode, Operand, Param};
789    use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, RSI, SYSV};
790
791    use super::*;
792
793    /// The x86-64 environment, with the last three of the allocation order held back as scratch.
794    fn env() -> Env {
795        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
796        Env::new().with(GPR, order, scratch)
797    }
798
799    /// An environment with that many general purpose registers, for putting a function under
800    /// pressure without writing a hundred instructions.
801    fn narrow(count: usize) -> Env {
802        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
803    }
804
805    /// What a place is called, which is what an assertion reads.
806    fn named(place: Option<Place>) -> String {
807        match place {
808            Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
809            Some(Place::Slot(slot)) => format!("slot {slot}"),
810            None => "nowhere".to_string(),
811        }
812    }
813
814    /// Where every value in a function went.
815    fn places(func: &Func, env: &Env) -> Vec<String> {
816        let order = Order::of(func);
817        let live = Live::of(func, &order);
818        let assignment = assign(func, &order, &live, env);
819        (0..func.vregs())
820            .map(|number| {
821                let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
822                named(assignment.place(reg))
823            })
824            .collect()
825    }
826
827    #[test]
828    fn two_values_that_are_never_both_wanted_share_a_register() {
829        let mut names = Interner::new();
830        let mut func = Func::new(names.intern("f"));
831        let opcode = Opcode::new(names.intern("x64.nop"));
832        let block = func.create_block();
833        let first = func.new_vreg(GPR);
834        let second = func.new_vreg(GPR);
835        func.build(block, opcode).def(first, GPR).finish();
836        func.build(block, opcode).uses(first, GPR).finish();
837        func.build(block, opcode).def(second, GPR).finish();
838        func.build(block, opcode).uses(second, GPR).finish();
839
840        // The first register in the order, twice, because the first value is finished with before
841        // the second one is written.
842        assert_eq!(places(&func, &env()), ["rax", "rax"]);
843    }
844
845    #[test]
846    fn two_values_that_are_both_wanted_do_not() {
847        let mut names = Interner::new();
848        let mut func = Func::new(names.intern("f"));
849        let opcode = Opcode::new(names.intern("x64.nop"));
850        let block = func.create_block();
851        let first = func.new_vreg(GPR);
852        let second = func.new_vreg(GPR);
853        func.build(block, opcode).def(first, GPR).finish();
854        func.build(block, opcode).def(second, GPR).finish();
855        func.build(block, opcode).uses(first, GPR).finish();
856        func.build(block, opcode).uses(second, GPR).finish();
857
858        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
859    }
860
861    #[test]
862    fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
863        let mut names = Interner::new();
864        let mut func = Func::new(names.intern("f"));
865        let opcode = Opcode::new(names.intern("x64.nop"));
866        let block = func.create_block();
867        let wanted = func.new_vreg(GPR);
868        let spare = func.new_vreg(GPR);
869        // A division: a remainder somebody wants, and a quotient nobody does. Both are written by
870        // the one instruction and the quotient is written before the operands have been read.
871        func.build(block, opcode)
872            .def(wanted, GPR)
873            .operand(Operand::write_early(spare, GPR))
874            .finish();
875        func.build(block, opcode).uses(wanted, GPR).finish();
876
877        // Two registers, not one. A value nothing reads is still somewhere, and the instruction
878        // that wrote it wrote the other one too, so the two cannot be the same place. Handing them
879        // the same register loses the remainder, because the copy that takes the quotient out of
880        // the register the machine insisted on goes on top of it. The quotient gets the first
881        // register because it is written first, which is the whole of what early means.
882        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
883    }
884
885    #[test]
886    fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
887        let mut names = Interner::new();
888        let mut func = Func::new(names.intern("f"));
889        let opcode = Opcode::new(names.intern("x64.nop"));
890        let block = func.create_block();
891        let long = func.new_vreg(GPR);
892        let short = func.new_vreg(GPR);
893        let third = func.new_vreg(GPR);
894        func.build(block, opcode).def(long, GPR).finish();
895        func.build(block, opcode).def(short, GPR).finish();
896        func.build(block, opcode).def(third, GPR).finish();
897        func.build(block, opcode).uses(short, GPR).finish();
898        func.build(block, opcode).uses(third, GPR).finish();
899        func.build(block, opcode).uses(long, GPR).finish();
900
901        // Two registers between three values. The one still wanted at the end of the function is
902        // the one whose register is worth the most to everybody else, so it is the one that goes.
903        assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
904    }
905
906    #[test]
907    fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
908        let mut names = Interner::new();
909        let mut func = Func::new(names.intern("f"));
910        let opcode = Opcode::new(names.intern("x64.nop"));
911        let block = func.create_block();
912        let across = func.new_vreg(GPR);
913        let dividend = func.new_vreg(GPR);
914        let quotient = func.new_vreg(GPR);
915        let remainder = func.new_vreg(GPR);
916        func.build(block, opcode).def(across, GPR).finish();
917        func.build(block, opcode).def(dividend, GPR).finish();
918        func.build(block, opcode)
919            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
920            .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
921            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
922            .finish();
923        func.build(block, opcode).uses(across, GPR).finish();
924
925        // The value that has to be across the division is nowhere near `rax` or `rdx`, and each of
926        // the three the division names is in the register the division asked for it in. The
927        // dividend and the quotient share `rax` because the first is read where the second is
928        // written, which is what a division does.
929        assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
930    }
931
932    /// A value read by an instruction that fills a register before it reads is kept out of that
933    /// register, even though the read is the last thing the value is wanted for.
934    ///
935    /// The divisor of a division is the case. What the machine runs is `cltd` and then `idivl`, so
936    /// `rdx` holds the top half of the dividend by the time the divisor is read, and a divisor
937    /// sitting in `rdx` is read as the dividend's own sign bits. An early definition is how the
938    /// target says a register goes before the operands are read, and this is where the allocator
939    /// has to hear it, since a value dying at an instruction is otherwise free to sit in a
940    /// register that instruction writes. tamnd/rucc#1232.
941    #[test]
942    fn a_value_that_dies_at_an_instruction_stays_out_of_what_it_fills_first() {
943        let mut names = Interner::new();
944        let mut func = Func::new(names.intern("f"));
945        let opcode = Opcode::new(names.intern("x64.nop"));
946        let block = func.create_block();
947        let across = func.new_vreg(GPR);
948        let dividend = func.new_vreg(GPR);
949        let divisor = func.new_vreg(GPR);
950        let remainder = func.new_vreg(GPR);
951        func.build(block, opcode).def(across, GPR).finish();
952        func.build(block, opcode).def(dividend, GPR).finish();
953        func.build(block, opcode).def(divisor, GPR).finish();
954        func.build(block, opcode)
955            .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
956            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
957            .operand(Operand::read(divisor, GPR))
958            .finish();
959        func.build(block, opcode).uses(across, GPR).uses(remainder, GPR).finish();
960
961        // Four registers for four values, and the divisor takes the fourth. `rdx` is free
962        // everywhere in this function except at the instruction that is about to fill it, which is
963        // the one instruction the divisor is wanted at.
964        assert_eq!(places(&func, &narrow(4)), ["rcx", "rax", "rsi", "rdx"]);
965    }
966
967    #[test]
968    fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
969        let mut names = Interner::new();
970        let mut func = Func::new(names.intern("f"));
971        let opcode = Opcode::new(names.intern("x64.nop"));
972        let block = func.create_block();
973        let dividend = func.new_vreg(GPR);
974        let quotient = func.new_vreg(GPR);
975        func.build(block, opcode).def(dividend, GPR).finish();
976        func.build(block, opcode)
977            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
978            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
979            .finish();
980        func.build(block, opcode).uses(dividend, GPR).finish();
981
982        // The hint is a preference and not a claim. The dividend would rather be in `rax` and
983        // cannot be, because the division writes `rax` and the dividend is wanted afterwards, so
984        // it takes the next register and the quotient keeps the one it was promised.
985        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
986    }
987
988    #[test]
989    fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
990        let mut names = Interner::new();
991        let mut func = Func::new(names.intern("f"));
992        let opcode = Opcode::new(names.intern("x64.nop"));
993        let block = func.create_block();
994        let value = func.new_vreg(GPR);
995        func.build(block, opcode).def(value, GPR).finish();
996        func.build(block, opcode)
997            .operand(Operand::read(value, GPR).with(Constraint::Stack))
998            .finish();
999
1000        assert_eq!(places(&func, &env()), ["slot 0"]);
1001    }
1002
1003    #[test]
1004    fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
1005        let mut names = Interner::new();
1006        let mut func = Func::new(names.intern("f"));
1007        let opcode = Opcode::new(names.intern("x64.nop"));
1008        let block = func.create_block();
1009        let left = func.new_vreg(GPR);
1010        let right = func.new_vreg(GPR);
1011        let sum = func.new_vreg(GPR);
1012        func.build(block, opcode).def(left, GPR).finish();
1013        func.build(block, opcode).def(right, GPR).finish();
1014        func.build(block, opcode)
1015            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1016            .uses(left, GPR)
1017            .uses(right, GPR)
1018            .finish();
1019        func.build(block, opcode).uses(right, GPR).finish();
1020
1021        // The addition reads the left value for the last time, so the answer goes where that was
1022        // and the instruction is two address without a move in front of it.
1023        assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1024    }
1025
1026    #[test]
1027    fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
1028        let mut names = Interner::new();
1029        let mut func = Func::new(names.intern("f"));
1030        let opcode = Opcode::new(names.intern("x64.nop"));
1031        let block = func.create_block();
1032        let left = func.new_vreg(GPR);
1033        let right = func.new_vreg(GPR);
1034        let sum = func.new_vreg(GPR);
1035        func.build(block, opcode).def(left, GPR).finish();
1036        func.build(block, opcode).def(right, GPR).finish();
1037        func.build(block, opcode)
1038            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1039            .uses(left, GPR)
1040            .uses(right, GPR)
1041            .finish();
1042        func.build(block, opcode).uses(left, GPR).finish();
1043
1044        // The left value is wanted afterwards, so the answer cannot have its register. It cannot
1045        // have the right one's either, because the rewrite is about to write a move into it before
1046        // the addition has read anything.
1047        assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
1048    }
1049
1050    #[test]
1051    fn an_answer_that_commutes_goes_over_the_source_that_is_finished_with() {
1052        let mut names = Interner::new();
1053        let mut func = Func::new(names.intern("f"));
1054        let opcode = Opcode::new(names.intern("x64.nop"));
1055        let block = func.create_block();
1056        let left = func.new_vreg(GPR);
1057        let right = func.new_vreg(GPR);
1058        let sum = func.new_vreg(GPR);
1059        func.build(block, opcode).def(left, GPR).finish();
1060        func.build(block, opcode).def(right, GPR).finish();
1061        let add = func
1062            .build(block, opcode)
1063            .flags(Flags::COMMUTES)
1064            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1065            .uses(left, GPR)
1066            .uses(right, GPR)
1067            .finish();
1068        func.build(block, opcode).uses(left, GPR).uses(sum, GPR).finish();
1069
1070        // The same shape as the one above where the answer got a register of its own, except that
1071        // the addition reads its sources either way round, so the answer goes where the right one
1072        // was and the instruction is marked to be swapped.
1073        assert_eq!(places(&func, &env()), ["rax", "rcx", "rcx"]);
1074        let order = Order::of(&func);
1075        let live = Live::of(&func, &order);
1076        let assignment = assign(&func, &order, &live, &env());
1077        assert_eq!(assignment.commuted(), [add]);
1078
1079        // Once swapped, the instruction is an ordinary reuse of its first source, the checker and
1080        // the trace agree with it, and nothing has to be moved in front of it. The rewrite has put
1081        // the registers in by then, so the right one is `rcx` and the left one `rax`.
1082        let allocation = crate::run(&mut func, &env(), "f", true);
1083        assert!(allocation.edits.is_empty());
1084        let operands = &func[func[add].operands];
1085        let (first, second) = (operands[1].reg.phys(), operands[2].reg.phys());
1086        assert_eq!((first, second), (Some(RCX), Some(RAX)));
1087    }
1088
1089    #[test]
1090    fn an_answer_that_commutes_takes_the_source_something_after_it_wants() {
1091        let mut names = Interner::new();
1092        let mut func = Func::new(names.intern("f"));
1093        let opcode = Opcode::new(names.intern("x64.nop"));
1094        let block = func.create_block();
1095        let left = func.new_vreg(GPR);
1096        let right = func.new_vreg(GPR);
1097        let sum = func.new_vreg(GPR);
1098        func.build(block, opcode).def(left, GPR).finish();
1099        func.build(block, opcode)
1100            .operand(Operand::write(right, GPR).with(Constraint::Fixed(RAX)))
1101            .finish();
1102        let add = func
1103            .build(block, opcode)
1104            .flags(Flags::COMMUTES)
1105            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1106            .uses(left, GPR)
1107            .uses(right, GPR)
1108            .finish();
1109        func.build(block, opcode)
1110            .operand(Operand::read(sum, GPR).with(Constraint::Fixed(RAX)))
1111            .finish();
1112
1113        // Both sources are finished with, so either register would do for the answer. The one
1114        // reading it wants it in `rax`, which is where the right one already is, so it goes there
1115        // and nothing is moved in front of that reader.
1116        let names = places(&func, &env());
1117        assert_eq!(names[2], "rax");
1118        assert_ne!(names[0], "rax");
1119        let allocation = crate::run(&mut func, &env(), "f", true);
1120        assert!(allocation.edits.is_empty());
1121        assert_eq!(func[func[add].operands][1].reg.phys(), Some(RAX));
1122    }
1123
1124    #[test]
1125    fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1126        let mut names = Interner::new();
1127        let mut func = Func::new(names.intern("f"));
1128        let opcode = Opcode::new(names.intern("x64.nop"));
1129        let entry = func.create_block();
1130        let head = func.create_block();
1131        let out = func.create_block();
1132        let seed = func.new_vreg(GPR);
1133        let total = func.new_vreg(GPR);
1134        let term = func.new_vreg(GPR);
1135        let next = func.new_vreg(GPR);
1136        func.build(entry, opcode).def(seed, GPR).finish();
1137        *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1138        func.params_mut(head).push(Param { reg: total, class: GPR });
1139        func.build(head, opcode).def(term, GPR).finish();
1140        let add = func
1141            .build(head, opcode)
1142            .flags(Flags::COMMUTES)
1143            .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1144            .uses(total, GPR)
1145            .uses(term, GPR)
1146            .finish();
1147        func.build(head, opcode)
1148            .operand(Operand::read(next, GPR).with(Constraint::Fixed(RSI)))
1149            .finish();
1150        *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1151
1152        // Both sources are finished with and the sum is wanted in `rsi` as well, but the loop
1153        // passes it back to `total`, so it goes where `total` is and the back edge has nothing to
1154        // copy.
1155        let order = Order::of(&func);
1156        let live = Live::of(&func, &order);
1157        let assignment = assign(&func, &order, &live, &env());
1158        assert_eq!(assignment.place(next), assignment.place(total));
1159        assert!(!assignment.commuted().contains(&add));
1160    }
1161
1162    #[test]
1163    fn an_answer_that_does_not_commute_leaves_its_sources_where_they_are() {
1164        let mut names = Interner::new();
1165        let mut func = Func::new(names.intern("f"));
1166        let opcode = Opcode::new(names.intern("x64.nop"));
1167        let block = func.create_block();
1168        let left = func.new_vreg(GPR);
1169        let right = func.new_vreg(GPR);
1170        let sum = func.new_vreg(GPR);
1171        func.build(block, opcode).def(left, GPR).finish();
1172        func.build(block, opcode).def(right, GPR).finish();
1173        func.build(block, opcode)
1174            .flags(Flags::COMMUTES)
1175            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1176            .uses(left, GPR)
1177            .uses(right, GPR)
1178            .finish();
1179        func.build(block, opcode).uses(right, GPR).finish();
1180
1181        // The left one is finished with, so the answer goes over it as it always did, and there is
1182        // nothing to swap.
1183        assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1184        let order = Order::of(&func);
1185        let live = Live::of(&func, &order);
1186        assert!(assign(&func, &order, &live, &env()).commuted().is_empty());
1187    }
1188
1189    #[test]
1190    fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
1191        let mut names = Interner::new();
1192        let mut func = Func::new(names.intern("f"));
1193        let opcode = Opcode::new(names.intern("x64.nop"));
1194        let head = func.create_block();
1195        let body = func.create_block();
1196        let carried = func.new_vreg(GPR);
1197        let inside = func.new_vreg(GPR);
1198        func.build(head, opcode).def(carried, GPR).finish();
1199        *func.succs_mut(head) = vec![BlockCall::to(body)];
1200        func.build(body, opcode).def(inside, GPR).finish();
1201        func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
1202        *func.succs_mut(body) = vec![BlockCall::to(body)];
1203
1204        // The value inside the loop cannot have the carried one's register, even though nothing
1205        // between the two definitions says so.
1206        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1207    }
1208
1209    #[test]
1210    fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
1211        let mut names = Interner::new();
1212        let mut func = Func::new(names.intern("f"));
1213        let opcode = Opcode::new(names.intern("x64.nop"));
1214        let head = func.create_block();
1215        let latch = func.create_block();
1216        let out = func.create_block();
1217        let source = func.new_vreg(GPR);
1218        let carried = func.new_vreg(GPR);
1219        func.build(head, opcode).def(source, GPR).finish();
1220        func.build(head, opcode).def(carried, GPR).finish();
1221        *func.succs_mut(head) = vec![BlockCall::to(latch)];
1222        // The bottom of the loop adds the source to the carried value and writes the answer back
1223        // over it, reusing the register the source is in. The next turn round redefines both.
1224        func.build(latch, opcode)
1225            .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
1226            .uses(source, GPR)
1227            .uses(carried, GPR)
1228            .finish();
1229        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1230        func.build(out, opcode).uses(carried, GPR).finish();
1231
1232        // The source is read here for the last time, which on its own is the shape the two address
1233        // shortcut is for, and taking it would be wrong. The carried value was written by the same
1234        // instruction on the last turn and is read by this one, so the two are both wanted where
1235        // the instruction reads and one register cannot hold both.
1236        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1237
1238        // And the checker has to agree, since it excused this pair on the same reasoning and so
1239        // would have let the answer through.
1240        let order = Order::of(&func);
1241        let live = Live::of(&func, &order);
1242        let assignment = assign(&func, &order, &live, &env());
1243        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1244    }
1245
1246    #[test]
1247    fn a_two_address_answer_with_a_hole_in_front_of_it_does_not_take_its_other_operand() {
1248        let mut names = Interner::new();
1249        let mut func = Func::new(names.intern("f"));
1250        let nop = Opcode::new(names.intern("x64.nop"));
1251        let add = Opcode::new(names.intern("x64.add"));
1252        let entry = func.create_block();
1253        let head = func.create_block();
1254        let arm = func.create_block();
1255        let latch = func.create_block();
1256        let out = func.create_block();
1257        let seed = func.new_vreg(GPR);
1258        let sum = func.new_vreg(GPR);
1259        let inside = func.new_vreg(GPR);
1260        let loaded = func.new_vreg(GPR);
1261        func.build(entry, nop).def(seed, GPR).finish();
1262        func.build(entry, nop).def(sum, GPR).finish();
1263        *func.succs_mut(entry) = vec![BlockCall::to(head)];
1264        func.build(head, nop).uses(sum, GPR).finish();
1265        *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
1266        func.build(arm, nop).def(inside, GPR).finish();
1267        func.build(arm, nop).uses(inside, GPR).finish();
1268        *func.succs_mut(arm) = vec![BlockCall::to(out)];
1269        func.build(latch, nop).def(loaded, GPR).finish();
1270        func.build(latch, add)
1271            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1272            .uses(seed, GPR)
1273            .uses(loaded, GPR)
1274            .finish();
1275        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1276
1277        // The answer is live in the entry and the head as well, and the arm between them is a hole
1278        // in it, so the piece the addition writes is not the first one. The value the addition reads
1279        // out of memory is still wanted where the addition reads, so it may not be in the register
1280        // the answer is about to be copied into, holes or no holes. tamnd/rucc#982.
1281        let places = places(&func, &env());
1282        assert_ne!(places[index(sum)], places[index(loaded)]);
1283
1284        let order = Order::of(&func);
1285        let live = Live::of(&func, &order);
1286        let assignment = assign(&func, &order, &live, &env());
1287        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1288    }
1289
1290    #[test]
1291    fn a_sum_a_loop_carries_round_keeps_its_register_past_an_arm_laid_out_after_it() {
1292        let mut names = Interner::new();
1293        let mut func = Func::new(names.intern("f"));
1294        let nop = Opcode::new(names.intern("x64.nop"));
1295        let add = Opcode::new(names.intern("x64.add"));
1296        let entry = func.create_block();
1297        let head = func.create_block();
1298        let join = func.create_block();
1299        let arm = func.create_block();
1300        let out = func.create_block();
1301        let seed = func.new_vreg(GPR);
1302        let term = func.new_vreg(GPR);
1303        let next = func.new_vreg(GPR);
1304        func.build(entry, nop).def(seed, GPR).finish();
1305        *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1306        let total = func.append_param(head, GPR);
1307        func.build(head, nop).def(term, GPR).finish();
1308        *func.succs_mut(head) = vec![BlockCall::to(join), BlockCall::to(arm)];
1309        func.build(join, add)
1310            .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1311            .uses(total, GPR)
1312            .uses(term, GPR)
1313            .finish();
1314        *func.succs_mut(join) =
1315            vec![BlockCall::with(head, vec![next]), BlockCall::with(out, vec![next])];
1316        // The default arm of a `switch`, laid out after the addition it joins back in above. The
1317        // sum is live in it and nothing in it or after it reads the sum again.
1318        func.build(arm, nop).def(term, GPR).finish();
1319        *func.succs_mut(arm) = vec![BlockCall::to(join)];
1320        let result = func.append_param(out, GPR);
1321        func.build(out, nop).uses(result, GPR).finish();
1322
1323        // The addition reads the sum for the last time, so the new sum goes where the old one was
1324        // and the edge back to the top of the loop has nothing to move. tamnd/rucc#1965.
1325        let places = places(&func, &env());
1326        assert_eq!(places[index(next)], places[index(total)]);
1327
1328        let order = Order::of(&func);
1329        let live = Live::of(&func, &order);
1330        let assignment = assign(&func, &order, &live, &env());
1331        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1332    }
1333
1334    /// Two blocks the entry chooses between, with the one the clobber is in written first. The two
1335    /// values written in the entry block are read in the other one, so their ranges cover the
1336    /// clobber whether or not either of them ever reaches it.
1337    fn arms(reaches: bool) -> Func {
1338        let mut names = Interner::new();
1339        let mut func = Func::new(names.intern("f"));
1340        let opcode = Opcode::new(names.intern("x64.nop"));
1341        let entry = func.create_block();
1342        let arm = func.create_block();
1343        let tail = func.create_block();
1344        let first = func.new_vreg(GPR);
1345        let second = func.new_vreg(GPR);
1346        func.build(entry, opcode).def(first, GPR).finish();
1347        func.build(entry, opcode).def(second, GPR).finish();
1348        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1349        // What a call looks like here: an instruction writing the registers the convention says it
1350        // destroys, named outright so that nothing else may be in them.
1351        func.build(arm, opcode).operand(Operand::write(Reg::physical(RAX), GPR)).finish();
1352        *func.succs_mut(arm) = if reaches { vec![BlockCall::to(tail)] } else { Vec::new() };
1353        func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1354        func
1355    }
1356
1357    #[test]
1358    fn a_register_a_clobber_takes_beats_the_stack_for_a_value_not_live_in_that_block() {
1359        let func = arms(false);
1360
1361        // Two registers between two values, and a clobber in the arm that takes the first of them.
1362        // The intervals around both values cover the clobber, since the arm is written between the
1363        // two blocks they are live in, and the arm is a hole in both of their areas. So the second
1364        // value has `rax` rather than a stack slot: the arm is a block its own path never goes
1365        // through. tamnd/rucc#982.
1366        assert_eq!(places(&func, &narrow(2)), ["rcx", "rax"]);
1367
1368        let order = Order::of(&func);
1369        let live = Live::of(&func, &order);
1370        let assignment = assign(&func, &order, &live, &narrow(2));
1371        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1372    }
1373
1374    #[test]
1375    fn a_register_a_clobber_takes_is_not_free_to_a_value_that_is_live_there() {
1376        let func = arms(true);
1377
1378        // The same blocks with an edge from the arm to the tail, which is all it takes: both values
1379        // now arrive at the read either way, so the clobber is on a path they are live over and the
1380        // one register left has to do for both of them.
1381        assert_eq!(places(&func, &narrow(2)), ["rcx", "slot 0"]);
1382    }
1383
1384    /// A value and the instruction that destroys a register, written one after the other, with the
1385    /// value read by that instruction or by the one after it.
1386    fn dies_at_the_clobber(here: bool) -> Func {
1387        let mut names = Interner::new();
1388        let mut func = Func::new(names.intern("f"));
1389        let opcode = Opcode::new(names.intern("x64.nop"));
1390        let entry = func.create_block();
1391        let value = func.new_vreg(GPR);
1392        func.build(entry, opcode).def(value, GPR).finish();
1393        let call = func.build(entry, opcode).operand(Operand::write(Reg::physical(RAX), GPR));
1394        if here {
1395            call.uses(value, GPR).finish();
1396        } else {
1397            call.finish();
1398            func.build(entry, opcode).uses(value, GPR).finish();
1399        }
1400        func
1401    }
1402
1403    /// A value whose last read is the instruction that destroys a register may be in that register,
1404    /// because the instruction reads what it is handed before it writes anything.
1405    ///
1406    /// The call is what this is about, and the value a call is passed is the case: seven registers
1407    /// on this machine are destroyed by one, every argument dies at the call that reads it, and
1408    /// refusing all seven to those values left them taking a callee saved register for a life two
1409    /// instructions long and paying for it in the prologue and the epilogue. tamnd/rucc#1232.
1410    #[test]
1411    fn a_value_that_dies_where_a_register_is_destroyed_may_be_in_that_register() {
1412        let func = dies_at_the_clobber(true);
1413        assert_eq!(places(&func, &narrow(1)), ["rax"]);
1414
1415        let order = Order::of(&func);
1416        let live = Live::of(&func, &order);
1417        let assignment = assign(&func, &order, &live, &narrow(1));
1418        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1419    }
1420
1421    /// And one read later than that is one the instruction really does destroy, which is the same
1422    /// function with the read moved down by one instruction.
1423    #[test]
1424    fn a_value_read_after_the_instruction_that_destroys_a_register_is_not_in_it() {
1425        let func = dies_at_the_clobber(false);
1426        assert_eq!(places(&func, &narrow(1)), ["slot 0"]);
1427    }
1428
1429    #[test]
1430    fn a_hint_is_followed_when_the_register_is_clear_and_not_when_it_is_merely_allowed() {
1431        let mut names = Interner::new();
1432        let mut func = Func::new(names.intern("f"));
1433        let opcode = Opcode::new(names.intern("x64.nop"));
1434        let entry = func.create_block();
1435        let mid = func.create_block();
1436        let tail = func.create_block();
1437        let first = func.new_vreg(GPR);
1438        let second = func.new_vreg(GPR);
1439        func.build(entry, opcode).def(first, GPR).finish();
1440        func.build(entry, opcode).def(second, GPR).finish();
1441        *func.succs_mut(entry) = vec![BlockCall::to(mid), BlockCall::to(tail)];
1442        // Two arms, each ending in an instruction that wants its own value in `rax`, which is what
1443        // a return out of either side of a branch looks like.
1444        func.build(mid, opcode)
1445            .operand(Operand::read(second, GPR).with(Constraint::Fixed(RAX)))
1446            .finish();
1447        func.build(tail, opcode)
1448            .operand(Operand::read(first, GPR).with(Constraint::Fixed(RAX)))
1449            .finish();
1450
1451        // The first value is hinted at `rax` and does not get it, because the other arm wants `rax`
1452        // for the other value and the first value's range reaches that far. Following the hint here
1453        // would save a move in the tail and cost one in the middle, and the second value gets `rax`
1454        // with nothing moved anywhere instead.
1455        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1456    }
1457
1458    #[test]
1459    fn a_value_living_in_a_hole_of_another_gets_the_same_register() {
1460        let mut names = Interner::new();
1461        let mut func = Func::new(names.intern("f"));
1462        let opcode = Opcode::new(names.intern("x64.nop"));
1463        let entry = func.create_block();
1464        let arm = func.create_block();
1465        let tail = func.create_block();
1466        let across = func.new_vreg(GPR);
1467        let inside = func.new_vreg(GPR);
1468        func.build(entry, opcode).def(across, GPR).finish();
1469        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1470        func.build(arm, opcode).def(inside, GPR).finish();
1471        func.build(arm, opcode).uses(inside, GPR).finish();
1472        func.build(tail, opcode).uses(across, GPR).finish();
1473
1474        // One register between the two of them, and one register is enough. Nothing in the arm can
1475        // reach the read in the tail, so the value the arm makes is welcome to the register the
1476        // value crossing the function is in. The interval around that value covers the arm and the
1477        // value is nowhere near it, which is what used to send one of the two to the stack.
1478        // tamnd/rucc#982.
1479        assert_eq!(places(&func, &narrow(1)), ["rax", "rax"]);
1480
1481        let order = Order::of(&func);
1482        let live = Live::of(&func, &order);
1483        let assignment = assign(&func, &order, &live, &narrow(1));
1484        assert_eq!(assignment.spilled(), 0);
1485        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1486    }
1487
1488    #[test]
1489    fn a_register_a_clobber_takes_is_the_last_one_offered_rather_than_the_first() {
1490        let func = arms(false);
1491
1492        // With a register to spare the value takes the spare one. Being allowed a register some
1493        // instruction insists on is not the same as it being free: the instruction has to be handed
1494        // it in the end, and what hands it over is a move.
1495        assert_eq!(places(&func, &narrow(3)), ["rcx", "rdx"]);
1496    }
1497
1498    #[test]
1499    fn a_frame_says_what_each_of_its_slots_is_for() {
1500        let mut names = Interner::new();
1501        let mut func = Func::new(names.intern("f"));
1502        let opcode = Opcode::new(names.intern("x64.nop"));
1503        let block = func.create_block();
1504        let first = func.new_vreg(GPR);
1505        let second = func.new_vreg(GPR);
1506        func.build(block, opcode).def(first, GPR).finish();
1507        func.build(block, opcode).def(second, GPR).finish();
1508        func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
1509
1510        let order = Order::of(&func);
1511        let live = Live::of(&func, &order);
1512        let assignment = assign(&func, &order, &live, &narrow(1));
1513        assert_eq!(assignment.spilled(), 1);
1514        assert_eq!(assignment.slots(), [GPR]);
1515        // A register that is already a register is where it is, and this has nothing to say about
1516        // it.
1517        assert_eq!(assignment.place(Reg::physical(RCX)), None);
1518        assert_eq!(env().scratch(GPR), [R13, R14, R15]);
1519    }
1520}