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.
16//!
17//! # What it does with a register an instruction insists on
18//!
19//! Two things. It stays out of that register for everybody else, and it tries that register first
20//! for the value the operand names. A division wants its dividend in `rax`, so `rax` is
21//! unavailable to every other value that is live where the division reads, and it is the first
22//! register offered to the dividend itself. When the dividend gets it there is no move on the way
23//! in, and when it does not the rewrite writes one and nothing else changes.
24//!
25//! That second half is the hint, and without it the register an instruction insists on is the one
26//! register the value in it can never have, since the value's own operand is what makes the
27//! register look busy. The effect is largest on returns, because a function that gives a value
28//! back has an operand fixed to `rax` at the end of it and most functions give a value back.
29//!
30//! What makes the hint safe is asking about the register at each of the instruction's two points
31//! rather than across the whole of it. An instruction reads at the first and writes at the second,
32//! so a register it insists on is one value's at the first, another value's at the second, and
33//! nobody else's at either. A division reads its dividend from `rax` and writes its quotient to
34//! `rax`, and those are different values that can both live there. A value passed to a call in
35//! `rdi` and wanted again afterwards cannot, because nothing writes `rdi` at the second point and
36//! a register the call does not write is a register the call is assumed to destroy.
37//!
38//! An operand that has to be in memory is the other way round. The value it names goes on the
39//! stack whatever else is true of it, because that is the only place the instruction could read it
40//! from.
41//!
42//! # What it does with a two address instruction
43//!
44//! An `add` on x86-64 writes one of the registers it reads, which the operand says as a reuse of
45//! another operand. The rewrite can always make that true by copying the source into the
46//! destination first, but only if the destination is a register the instruction does not otherwise
47//! read, so a value written by a reuse is treated here as live from where the instruction reads
48//! rather than from where it writes. Then the copy is always safe.
49//!
50//! The copy is also usually unnecessary, and the one place this looks past the interval it is
51//! placing is to see that: if the value being reused is read here for the last time and the value
52//! being written starts here, the second may have the first's register, and the instruction is
53//! already two address without anything being moved anywhere. That is the whole of the coalescing
54//! this allocator does, and it is worth the dozen lines, because otherwise every piece of
55//! arithmetic in the output carries a move in front of it.
56//!
57//! Both halves of that are needed. The second is the one a loop breaks: an instruction at the
58//! bottom of a loop can write a value the top of the loop reads on the next turn, and such a value
59//! is live on the way into the instruction that writes it as well as after. It is then wanted at
60//! the same time as the value it reuses, whatever is true of the reuse, and giving it the same
61//! register makes an addition read the answer to the last one instead of its own operand.
62//!
63//! # What it does not do
64//!
65//! It does not touch the function. What comes out is a table saying where each value went, and the
66//! pass that rewrites the operands and writes the moves reads it. Keeping the decision and the
67//! rewrite apart is what lets the decision be checked by looking at it, and it is the shape
68//! `spec/10-backend.md` section 10.4 asks for: an allocator is a function from a program to an
69//! assignment and the moves that make it true.
70
71use rucc_mir::{Constraint, Func, Operand, Reg, Role};
72use rucc_target::{PhysReg, RegClass};
73
74use crate::live::{Live, Range};
75use crate::order::{Order, Point};
76
77/// Where a value lives.
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum Place {
80    /// In a register, for the whole of its range.
81    Reg(PhysReg),
82    /// In a slot of the frame, which is what a value the allocator ran out of registers for gets,
83    /// and what a value an instruction can only read from memory gets.
84    Slot(u32),
85}
86
87/// What the allocator is allowed to use.
88///
89/// The order is the calling convention's, because which register to hand out first follows from
90/// which ones a call destroys, and `rucc-target` is where a convention says so. The scratch
91/// registers are held back out of the order and are what a spilled value is read into at each
92/// instruction that wants it, so a class needs as many of them as one of its instructions has
93/// register operands. Nothing here uses them, since a spilled value is only read once the rewrite
94/// is writing the instruction that reads it, but they are held back here because this is what
95/// decides what everything else may have.
96#[derive(Debug, Clone, Default)]
97pub struct Env {
98    classes: Vec<Class>,
99}
100
101/// What one class of registers offers.
102#[derive(Debug, Clone, Default)]
103struct Class {
104    order: Vec<PhysReg>,
105    scratch: Vec<PhysReg>,
106}
107
108impl Env {
109    /// An environment offering nothing, which is what a target that has said nothing offers.
110    #[must_use]
111    pub fn new() -> Self {
112        Self::default()
113    }
114
115    /// The same environment, with that class described.
116    #[must_use]
117    pub fn with(mut self, class: RegClass, order: &[PhysReg], scratch: &[PhysReg]) -> Self {
118        let index = usize::from(class.number());
119        if self.classes.len() <= index {
120            self.classes.resize(index + 1, Class::default());
121        }
122        self.classes[index] = Class { order: order.to_vec(), scratch: scratch.to_vec() };
123        self
124    }
125
126    /// The registers it may hand out in a class, in the order it prefers them.
127    #[must_use]
128    pub fn order(&self, class: RegClass) -> &[PhysReg] {
129        self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.order)
130    }
131
132    /// The registers held back in a class for reading a spilled value into.
133    #[must_use]
134    pub fn scratch(&self, class: RegClass) -> &[PhysReg] {
135        self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.scratch)
136    }
137}
138
139/// Where every value in a function went.
140#[derive(Debug, Clone)]
141pub struct Assignment {
142    places: Vec<Option<Place>>,
143    slots: Vec<RegClass>,
144}
145
146impl Assignment {
147    /// An assignment that says nothing yet about a function with that many values.
148    ///
149    /// This and [`Assignment::put`] and [`Assignment::take_slot`] are how an allocator says what
150    /// it decided. There will be a second one in M4 and it will not reach its answer this way, so
151    /// what an assignment is has to be separable from how this file arrives at one, and the
152    /// checker in [`crate::check`] reads an assignment without caring which allocator wrote it.
153    #[must_use]
154    pub fn empty(vregs: usize) -> Self {
155        Self { places: vec![None; vregs], slots: Vec::new() }
156    }
157
158    /// Records where a value went.
159    ///
160    /// # Panics
161    ///
162    /// Panics on a physical register, which is somewhere already, and on a virtual one the
163    /// function never handed out.
164    pub fn put(&mut self, reg: Reg, place: Place) {
165        self.places[index(reg)] = Some(place);
166    }
167
168    /// Takes a slot of the frame, of that class, and gives back which one it is.
169    ///
170    /// # Panics
171    ///
172    /// Panics past four billion slots, which is a frame no machine has room for.
173    pub fn take_slot(&mut self, class: RegClass) -> u32 {
174        let slot = u32::try_from(self.slots.len()).expect("too many spilled values");
175        self.slots.push(class);
176        slot
177    }
178
179    /// Where a value lives, or `None` for a virtual register this function never mentions and for
180    /// a physical one, which is already where it is.
181    #[must_use]
182    pub fn place(&self, reg: Reg) -> Option<Place> {
183        self.places.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
184    }
185
186    /// The class of each slot of the frame, which is what says how wide it has to be.
187    #[must_use]
188    pub fn slots(&self) -> &[RegClass] {
189        &self.slots
190    }
191
192    /// How many values went to the stack.
193    #[must_use]
194    pub fn spilled(&self) -> usize {
195        self.slots.len()
196    }
197
198    /// Puts a value on the stack, in a slot of its own.
199    fn spill(&mut self, reg: Reg, class: RegClass) {
200        let slot = self.take_slot(class);
201        self.put(reg, Place::Slot(slot));
202    }
203}
204
205/// One value waiting for a place.
206#[derive(Debug, Clone, Copy)]
207struct Interval {
208    reg: Reg,
209    class: RegClass,
210    range: Range,
211}
212
213/// One value that has a register, for as long as it still wants it.
214#[derive(Debug, Clone, Copy)]
215struct Held {
216    reg: Reg,
217    class: RegClass,
218    range: Range,
219    at: PhysReg,
220}
221
222/// A register an instruction insists on, and where it insists on it.
223#[derive(Debug, Clone, Copy)]
224struct Blocked {
225    class: RegClass,
226    at: PhysReg,
227    /// One of the instruction's two points. Every register an instruction insists on has an entry
228    /// at each of them, because a register held at one of the two is a register nothing else may
229    /// be in across the instruction.
230    point: Point,
231    /// The one value that may be in it there, which is the value of an operand the instruction
232    /// reads at that point or writes at it. `None` means nothing may: an operand naming a physical
233    /// register outright claims it against everything, and a point no operand covers is a point
234    /// the instruction has the register to itself at.
235    by: Option<Reg>,
236}
237
238/// A value written into the register another operand of the same instruction was read from.
239#[derive(Debug, Clone, Copy)]
240struct Reuse {
241    /// The value being read, which is the one whose register would do.
242    source: Reg,
243    /// Where the instruction reads it.
244    at: Point,
245}
246
247/// Decides where every value in a function lives.
248///
249/// # Panics
250///
251/// Panics if a class has no registers to hand out and something in the function is in that class,
252/// since that is a target description that does not describe the target the function is for.
253#[must_use]
254pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
255    let blocked = blocked(func, order);
256    let forced = forced(func);
257    let reuses = reuses(func, order);
258    let hints = hints(func);
259
260    let mut intervals = Vec::with_capacity(func.vregs());
261    for (number, reuse) in reuses.iter().enumerate() {
262        let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
263        let (Some(mut range), Some(class)) = (live.range(reg), func.class_of(reg)) else {
264            continue;
265        };
266        if let Some(reuse) = reuse {
267            range.start = range.start.min(reuse.at);
268        }
269        intervals.push(Interval { reg, class, range });
270    }
271    intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
272
273    let mut assignment = Assignment::empty(func.vregs());
274    let mut active: Vec<Held> = Vec::new();
275    for interval in intervals {
276        active.retain(|held| held.range.end >= interval.range.start);
277        if forced.contains(&interval.reg) {
278            assignment.spill(interval.reg, interval.class);
279            continue;
280        }
281        // A class with no order is one the target says nothing allocates from, which on x86-64 is
282        // the x87 stack. A value of such a class is a mistake at the point it was made rather than
283        // a value with nowhere to go: what the target means is that the value lives in memory and
284        // that whatever operates on it takes an address. See `ClassInfo::allocatable`.
285        assert!(
286            !env.order(interval.class).is_empty(),
287            "a value in class {}, which the target hands out no registers from",
288            interval.class.number()
289        );
290        let two_address = reuses[index(interval.reg)]
291            .and_then(|reuse| coalesce(&assignment, &active, &blocked, interval, reuse));
292        // The reuse comes first, because a two address instruction that has to copy its left
293        // operand in pays for the copy whatever the hint says, and taking the hint here would buy
294        // one move at the cost of another.
295        let hinted = hints[index(interval.reg)].filter(|&at| {
296            env.order(interval.class).contains(&at)
297                && available(&active, &blocked, interval, at, None)
298        });
299        let chosen = two_address.or(hinted).or_else(|| {
300            env.order(interval.class)
301                .iter()
302                .copied()
303                .find(|&at| available(&active, &blocked, interval, at, None))
304        });
305        match chosen {
306            Some(at) => {
307                assignment.places[index(interval.reg)] = Some(Place::Reg(at));
308                let reg = interval.reg;
309                active.push(Held { reg, class: interval.class, range: interval.range, at });
310            }
311            None => spill_one(&mut assignment, &mut active, &blocked, interval),
312        }
313    }
314    assignment
315}
316
317/// Whether a register is one this interval could have.
318///
319/// The exception is the value a reuse is coalescing with, which holds the register right up to the
320/// point the new value takes it over and is the one thing that may overlap.
321fn available(
322    active: &[Held],
323    blocked: &[Blocked],
324    interval: Interval,
325    at: PhysReg,
326    except: Option<Reg>,
327) -> bool {
328    let taken = active
329        .iter()
330        .any(|held| held.at == at && held.class == interval.class && Some(held.reg) != except);
331    let insisted = blocked.iter().any(|one| {
332        one.at == at
333            && one.class == interval.class
334            && one.by != Some(interval.reg)
335            && interval.range.covers(one.point)
336    });
337    !taken && !insisted
338}
339
340/// The register the value being reused is in, when this instruction is the last thing that reads
341/// it, the value being written starts here, and the register is otherwise free.
342fn coalesce(
343    assignment: &Assignment,
344    active: &[Held],
345    blocked: &[Blocked],
346    interval: Interval,
347    reuse: Reuse,
348) -> Option<PhysReg> {
349    let Some(Place::Reg(at)) = assignment.place(reuse.source) else { return None };
350    let source = active.iter().find(|held| held.reg == reuse.source)?;
351    // A value read again later needs its register after this instruction would have overwritten
352    // it, so the two really do have to be different and the rewrite really does have to copy.
353    let dies = source.range.end == reuse.at;
354    // And the value being written has to begin here. The interval start was already pulled back to
355    // the reuse point above, so a start still earlier than that is a value that was live on the way
356    // into this instruction, which is what a loop carrying its own result round looks like: the
357    // instruction writes it at the bottom and the top of the loop reads what the last turn wrote.
358    // Such a value overlaps the one it reuses over the whole loop, so the two cannot be the same
359    // register no matter that the read here is the last one.
360    let begins = interval.range.start == reuse.at;
361    (dies && begins && available(active, blocked, interval, at, Some(reuse.source))).then_some(at)
362}
363
364/// Sends one value to the stack: the one wanted for longest, since its register pays for itself
365/// over the most instructions.
366fn spill_one(
367    assignment: &mut Assignment,
368    active: &mut Vec<Held>,
369    blocked: &[Blocked],
370    interval: Interval,
371) {
372    // A value whose register the instructions in the way insist on for themselves is no use as a
373    // victim, because taking it over would put this value in a register it may not have.
374    let victim = active
375        .iter()
376        .enumerate()
377        .filter(|(_, held)| held.class == interval.class)
378        .filter(|(_, held)| available(&[], blocked, interval, held.at, None))
379        .max_by_key(|(_, held)| held.range.end)
380        .map(|(at, held)| (at, held.at, held.range.end));
381    match victim {
382        Some((victim, at, end)) if end > interval.range.end => {
383            let held = active.remove(victim);
384            assignment.spill(held.reg, held.class);
385            assignment.places[index(interval.reg)] = Some(Place::Reg(at));
386            let reg = interval.reg;
387            active.push(Held { reg, class: interval.class, range: interval.range, at });
388        }
389        _ => assignment.spill(interval.reg, interval.class),
390    }
391}
392
393/// The registers the instructions insist on, and where.
394///
395/// A physical register an operand names outright counts the same way. Nothing before allocation
396/// writes one except an instruction that has to, and it has to for the length of that one
397/// instruction, which is the same statement a fixed constraint makes.
398fn blocked(func: &Func, order: &Order) -> Vec<Blocked> {
399    let mut blocked = Vec::new();
400    let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
401    for block in func.blocks() {
402        for inst in func.insts(block) {
403            let operands = &func[func[inst].operands];
404            claimed.clear();
405            for operand in operands {
406                if let Some(at) = insisted(operand) {
407                    let key = (operand.class, at);
408                    if !claimed.contains(&key) {
409                        claimed.push(key);
410                    }
411                }
412            }
413            for &(class, at) in &claimed {
414                // Both points, whether or not an operand is at them. A register an instruction
415                // reads and does not write is destroyed by the time the instruction is done as far
416                // as anything here knows, which is what stops the value a call is passed in `rdi`
417                // from staying in `rdi` over the call.
418                for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
419                {
420                    let mut named = false;
421                    for operand in operands {
422                        let mine = insisted(operand) == Some(at) && operand.class == class;
423                        if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
424                            continue;
425                        }
426                        named = true;
427                        let by = operand.reg.is_virtual().then_some(operand.reg);
428                        blocked.push(Blocked { class, at, point, by });
429                    }
430                    if !named {
431                        blocked.push(Blocked { class, at, point, by: None });
432                    }
433                }
434            }
435        }
436    }
437    blocked
438}
439
440/// The register an operand has to be in, which is the one a constraint asks for or the one the
441/// operand names outright.
442fn insisted(operand: &Operand) -> Option<PhysReg> {
443    match operand.constraint {
444        Constraint::Fixed(at) => Some(at),
445        _ => operand.reg.phys(),
446    }
447}
448
449/// The register each value would rather be in, which is the one an operand naming it insists on.
450///
451/// A value with two of them keeps the first the function writes down, which is the definition when
452/// there is one, since a value written into a fixed register and then moved somewhere else pays
453/// for the move at the top of its life rather than at the bottom. Two different fixed registers on
454/// one value is rare enough that the second is not worth carrying a list for.
455fn hints(func: &Func) -> Vec<Option<PhysReg>> {
456    let mut hints = vec![None; func.vregs()];
457    for block in func.blocks() {
458        for inst in func.insts(block) {
459            for operand in &func[func[inst].operands] {
460                let Constraint::Fixed(at) = operand.constraint else { continue };
461                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
462                let Some(number) = number else { continue };
463                if func.class_of(operand.reg) == Some(operand.class) && hints[number].is_none() {
464                    hints[number] = Some(at);
465                }
466            }
467        }
468    }
469    hints
470}
471
472/// The values that have to be on the stack whatever else is true of them.
473fn forced(func: &Func) -> Vec<Reg> {
474    let mut forced = Vec::new();
475    for block in func.blocks() {
476        for inst in func.insts(block) {
477            for operand in &func[func[inst].operands] {
478                if operand.constraint == Constraint::Stack
479                    && operand.reg.is_virtual()
480                    && !forced.contains(&operand.reg)
481                {
482                    forced.push(operand.reg);
483                }
484            }
485        }
486    }
487    forced
488}
489
490/// The value each two address instruction reuses, by the virtual register it writes.
491fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
492    let mut reuses = vec![None; func.vregs()];
493    for block in func.blocks() {
494        for inst in func.insts(block) {
495            let operands = &func[func[inst].operands];
496            for operand in operands {
497                let Constraint::Reuse(other) = operand.constraint else { continue };
498                let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
499                let Some(number) = number else { continue };
500                let source = operands[usize::from(other)].reg;
501                reuses[number] = Some(Reuse { source, at: order.early(inst) });
502            }
503        }
504    }
505    reuses
506}
507
508/// A virtual register's number as a table index.
509fn index(reg: Reg) -> usize {
510    usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
511}
512
513#[cfg(test)]
514mod tests {
515    use rucc_base::Interner;
516    use rucc_mir::{BlockCall, Opcode, Operand};
517    use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, SYSV};
518
519    use super::*;
520
521    /// The x86-64 environment, with the last three of the allocation order held back as scratch.
522    fn env() -> Env {
523        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
524        Env::new().with(GPR, order, scratch)
525    }
526
527    /// An environment with that many general purpose registers, for putting a function under
528    /// pressure without writing a hundred instructions.
529    fn narrow(count: usize) -> Env {
530        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
531    }
532
533    /// What a place is called, which is what an assertion reads.
534    fn named(place: Option<Place>) -> String {
535        match place {
536            Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
537            Some(Place::Slot(slot)) => format!("slot {slot}"),
538            None => "nowhere".to_string(),
539        }
540    }
541
542    /// Where every value in a function went.
543    fn places(func: &Func, env: &Env) -> Vec<String> {
544        let order = Order::of(func);
545        let live = Live::of(func, &order);
546        let assignment = assign(func, &order, &live, env);
547        (0..func.vregs())
548            .map(|number| {
549                let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
550                named(assignment.place(reg))
551            })
552            .collect()
553    }
554
555    #[test]
556    fn two_values_that_are_never_both_wanted_share_a_register() {
557        let mut names = Interner::new();
558        let mut func = Func::new(names.intern("f"));
559        let opcode = Opcode::new(names.intern("x64.nop"));
560        let block = func.create_block();
561        let first = func.new_vreg(GPR);
562        let second = func.new_vreg(GPR);
563        func.build(block, opcode).def(first, GPR).finish();
564        func.build(block, opcode).uses(first, GPR).finish();
565        func.build(block, opcode).def(second, GPR).finish();
566        func.build(block, opcode).uses(second, GPR).finish();
567
568        // The first register in the order, twice, because the first value is finished with before
569        // the second one is written.
570        assert_eq!(places(&func, &env()), ["rax", "rax"]);
571    }
572
573    #[test]
574    fn two_values_that_are_both_wanted_do_not() {
575        let mut names = Interner::new();
576        let mut func = Func::new(names.intern("f"));
577        let opcode = Opcode::new(names.intern("x64.nop"));
578        let block = func.create_block();
579        let first = func.new_vreg(GPR);
580        let second = func.new_vreg(GPR);
581        func.build(block, opcode).def(first, GPR).finish();
582        func.build(block, opcode).def(second, GPR).finish();
583        func.build(block, opcode).uses(first, GPR).finish();
584        func.build(block, opcode).uses(second, GPR).finish();
585
586        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
587    }
588
589    #[test]
590    fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
591        let mut names = Interner::new();
592        let mut func = Func::new(names.intern("f"));
593        let opcode = Opcode::new(names.intern("x64.nop"));
594        let block = func.create_block();
595        let wanted = func.new_vreg(GPR);
596        let spare = func.new_vreg(GPR);
597        // A division: a remainder somebody wants, and a quotient nobody does. Both are written by
598        // the one instruction and the quotient is written before the operands have been read.
599        func.build(block, opcode)
600            .def(wanted, GPR)
601            .operand(Operand::write_early(spare, GPR))
602            .finish();
603        func.build(block, opcode).uses(wanted, GPR).finish();
604
605        // Two registers, not one. A value nothing reads is still somewhere, and the instruction
606        // that wrote it wrote the other one too, so the two cannot be the same place. Handing them
607        // the same register loses the remainder, because the copy that takes the quotient out of
608        // the register the machine insisted on goes on top of it. The quotient gets the first
609        // register because it is written first, which is the whole of what early means.
610        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
611    }
612
613    #[test]
614    fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
615        let mut names = Interner::new();
616        let mut func = Func::new(names.intern("f"));
617        let opcode = Opcode::new(names.intern("x64.nop"));
618        let block = func.create_block();
619        let long = func.new_vreg(GPR);
620        let short = func.new_vreg(GPR);
621        let third = func.new_vreg(GPR);
622        func.build(block, opcode).def(long, GPR).finish();
623        func.build(block, opcode).def(short, GPR).finish();
624        func.build(block, opcode).def(third, GPR).finish();
625        func.build(block, opcode).uses(short, GPR).finish();
626        func.build(block, opcode).uses(third, GPR).finish();
627        func.build(block, opcode).uses(long, GPR).finish();
628
629        // Two registers between three values. The one still wanted at the end of the function is
630        // the one whose register is worth the most to everybody else, so it is the one that goes.
631        assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
632    }
633
634    #[test]
635    fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
636        let mut names = Interner::new();
637        let mut func = Func::new(names.intern("f"));
638        let opcode = Opcode::new(names.intern("x64.nop"));
639        let block = func.create_block();
640        let across = func.new_vreg(GPR);
641        let dividend = func.new_vreg(GPR);
642        let quotient = func.new_vreg(GPR);
643        let remainder = func.new_vreg(GPR);
644        func.build(block, opcode).def(across, GPR).finish();
645        func.build(block, opcode).def(dividend, GPR).finish();
646        func.build(block, opcode)
647            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
648            .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
649            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
650            .finish();
651        func.build(block, opcode).uses(across, GPR).finish();
652
653        // The value that has to be across the division is nowhere near `rax` or `rdx`, and each of
654        // the three the division names is in the register the division asked for it in. The
655        // dividend and the quotient share `rax` because the first is read where the second is
656        // written, which is what a division does.
657        assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
658    }
659
660    #[test]
661    fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
662        let mut names = Interner::new();
663        let mut func = Func::new(names.intern("f"));
664        let opcode = Opcode::new(names.intern("x64.nop"));
665        let block = func.create_block();
666        let dividend = func.new_vreg(GPR);
667        let quotient = func.new_vreg(GPR);
668        func.build(block, opcode).def(dividend, GPR).finish();
669        func.build(block, opcode)
670            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
671            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
672            .finish();
673        func.build(block, opcode).uses(dividend, GPR).finish();
674
675        // The hint is a preference and not a claim. The dividend would rather be in `rax` and
676        // cannot be, because the division writes `rax` and the dividend is wanted afterwards, so
677        // it takes the next register and the quotient keeps the one it was promised.
678        assert_eq!(places(&func, &env()), ["rcx", "rax"]);
679    }
680
681    #[test]
682    fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
683        let mut names = Interner::new();
684        let mut func = Func::new(names.intern("f"));
685        let opcode = Opcode::new(names.intern("x64.nop"));
686        let block = func.create_block();
687        let value = func.new_vreg(GPR);
688        func.build(block, opcode).def(value, GPR).finish();
689        func.build(block, opcode)
690            .operand(Operand::read(value, GPR).with(Constraint::Stack))
691            .finish();
692
693        assert_eq!(places(&func, &env()), ["slot 0"]);
694    }
695
696    #[test]
697    fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
698        let mut names = Interner::new();
699        let mut func = Func::new(names.intern("f"));
700        let opcode = Opcode::new(names.intern("x64.nop"));
701        let block = func.create_block();
702        let left = func.new_vreg(GPR);
703        let right = func.new_vreg(GPR);
704        let sum = func.new_vreg(GPR);
705        func.build(block, opcode).def(left, GPR).finish();
706        func.build(block, opcode).def(right, GPR).finish();
707        func.build(block, opcode)
708            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
709            .uses(left, GPR)
710            .uses(right, GPR)
711            .finish();
712        func.build(block, opcode).uses(right, GPR).finish();
713
714        // The addition reads the left value for the last time, so the answer goes where that was
715        // and the instruction is two address without a move in front of it.
716        assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
717    }
718
719    #[test]
720    fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
721        let mut names = Interner::new();
722        let mut func = Func::new(names.intern("f"));
723        let opcode = Opcode::new(names.intern("x64.nop"));
724        let block = func.create_block();
725        let left = func.new_vreg(GPR);
726        let right = func.new_vreg(GPR);
727        let sum = func.new_vreg(GPR);
728        func.build(block, opcode).def(left, GPR).finish();
729        func.build(block, opcode).def(right, GPR).finish();
730        func.build(block, opcode)
731            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
732            .uses(left, GPR)
733            .uses(right, GPR)
734            .finish();
735        func.build(block, opcode).uses(left, GPR).finish();
736
737        // The left value is wanted afterwards, so the answer cannot have its register. It cannot
738        // have the right one's either, because the rewrite is about to write a move into it before
739        // the addition has read anything.
740        assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
741    }
742
743    #[test]
744    fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
745        let mut names = Interner::new();
746        let mut func = Func::new(names.intern("f"));
747        let opcode = Opcode::new(names.intern("x64.nop"));
748        let head = func.create_block();
749        let body = func.create_block();
750        let carried = func.new_vreg(GPR);
751        let inside = func.new_vreg(GPR);
752        func.build(head, opcode).def(carried, GPR).finish();
753        *func.succs_mut(head) = vec![BlockCall::to(body)];
754        func.build(body, opcode).def(inside, GPR).finish();
755        func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
756        *func.succs_mut(body) = vec![BlockCall::to(body)];
757
758        // The value inside the loop cannot have the carried one's register, even though nothing
759        // between the two definitions says so.
760        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
761    }
762
763    #[test]
764    fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
765        let mut names = Interner::new();
766        let mut func = Func::new(names.intern("f"));
767        let opcode = Opcode::new(names.intern("x64.nop"));
768        let head = func.create_block();
769        let latch = func.create_block();
770        let out = func.create_block();
771        let source = func.new_vreg(GPR);
772        let carried = func.new_vreg(GPR);
773        func.build(head, opcode).def(source, GPR).finish();
774        func.build(head, opcode).def(carried, GPR).finish();
775        *func.succs_mut(head) = vec![BlockCall::to(latch)];
776        // The bottom of the loop adds the source to the carried value and writes the answer back
777        // over it, reusing the register the source is in. The next turn round redefines both.
778        func.build(latch, opcode)
779            .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
780            .uses(source, GPR)
781            .uses(carried, GPR)
782            .finish();
783        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
784        func.build(out, opcode).uses(carried, GPR).finish();
785
786        // The source is read here for the last time, which on its own is the shape the two address
787        // shortcut is for, and taking it would be wrong. The carried value was written by the same
788        // instruction on the last turn and is read by this one, so the two are both wanted where
789        // the instruction reads and one register cannot hold both.
790        assert_eq!(places(&func, &env()), ["rax", "rcx"]);
791
792        // And the checker has to agree, since it excused this pair on the same reasoning and so
793        // would have let the answer through.
794        let order = Order::of(&func);
795        let live = Live::of(&func, &order);
796        let assignment = assign(&func, &order, &live, &env());
797        assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
798    }
799
800    #[test]
801    fn a_frame_says_what_each_of_its_slots_is_for() {
802        let mut names = Interner::new();
803        let mut func = Func::new(names.intern("f"));
804        let opcode = Opcode::new(names.intern("x64.nop"));
805        let block = func.create_block();
806        let first = func.new_vreg(GPR);
807        let second = func.new_vreg(GPR);
808        func.build(block, opcode).def(first, GPR).finish();
809        func.build(block, opcode).def(second, GPR).finish();
810        func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
811
812        let order = Order::of(&func);
813        let live = Live::of(&func, &order);
814        let assignment = assign(&func, &order, &live, &narrow(1));
815        assert_eq!(assignment.spilled(), 1);
816        assert_eq!(assignment.slots(), [GPR]);
817        // A register that is already a register is where it is, and this has nothing to say about
818        // it.
819        assert_eq!(assignment.place(Reg::physical(RCX)), None);
820        assert_eq!(env().scratch(GPR), [R13, R14, R15]);
821    }
822}