Skip to main content

rucc_regalloc/
rewrite.rs

1//! Making an assignment true in the function it was worked out for.
2//!
3//! Design: `spec/10-backend.md` section 10.4.
4//!
5//! [`crate::assign`] says where every value goes and touches nothing. This is the other half: every
6//! operand is rewritten to the place its value was given, and the moves that the places do not
7//! already say are collected. After it the function names no virtual register and no block asks
8//! for anything, which is the point at which machine IR stops being in SSA form and starts being
9//! something an encoder could read.
10//!
11//! # Why the moves are handed back rather than written
12//!
13//! A move is an instruction, and an instruction has an opcode, and an opcode belongs to a target.
14//! `spec/10-backend.md` section 10.8 says no pipeline crate holds target specific code, so this
15//! crate is not the one that can write `x64.mov`. What it hands back is an [`Edit`]: a move
16//! between two places, the class it is in, and where in the function it goes. `rucc-codegen` turns
17//! each one into whatever its target moves a register with, which for a value on the stack is a
18//! load or a store rather than a move at all.
19//!
20//! The edits at any one place are in the order they have to be made in. That matters in two
21//! places: a spilled operand is read into a scratch register before the instruction that wants it,
22//! and a two address instruction's copy has to come after that read, because what it is copying
23//! may be the thing that was just read in.
24//!
25//! # How many scratch registers one instruction wants
26//!
27//! Two of a class, and a target holds two of each back for exactly this. The instruction that asks
28//! for most reads two values and writes a third with nothing of the three in a register, and the
29//! arithmetic works out because the two reads are what use the two scratch registers and the answer
30//! is written back into one of them. Writing over it destroys nothing, since it holds a copy of a
31//! value whose home is a stack slot and the instruction has already read it, and the answer is
32//! stored away from it afterwards. Giving the answer a scratch register of its own would want a
33//! third, which a program with enough live values around a call reaches, and that was issue #350.
34//!
35//! Which register the answer goes back into depends on what wrote it. A two address instruction
36//! writes the register the operand it reuses was read into, because that is what two address means.
37//! A three address one, which is `lea` and the compare and set pairs, writes a register that is
38//! none of its operands, and there the answer takes the first scratch register of the class again:
39//! the reads are done by the time the write happens, so the two uses of that register do not meet.
40//! Counting the two jobs in one running number is what made a three address instruction with every
41//! end on the stack ask for a third register and abort, which was issue #726.
42//!
43//! It is only a scratch register the answer may have either way. Where the operand a two address
44//! instruction reuses is in a register the assignment gave out, the value in it may be wanted after
45//! the instruction, and the assignment only lets one be written over when it is not, which it says
46//! by giving the answer that register in the first place. So the answer takes a scratch register
47//! there and the two address copy fills it. That one is filled in front of the instruction rather
48//! than by it, so it cannot share with a read, and the count still comes to two, because an operand
49//! that is in a register is not holding a scratch register.
50//!
51//! Deciding either way needs to know where the operand it reuses went, so an operand that reuses
52//! another and has no register of its own is placed in a second pass over the operands.
53//!
54//! The count is per class. An instruction reading a spilled value out of each of two files wants
55//! the first register of each, since a class holds its own back and nothing on the instruction is
56//! in the other's.
57//!
58//! # What happens when two is not enough after all
59//!
60//! Two runs out on an instruction that reads three registers and writes none, because then there is
61//! no answer to fold back into a register an operand arrived in and the arithmetic above has nothing
62//! to work on. The instruction that does this on x86-64 is the indexed store, whose base, index and
63//! value are three registers it only reads, and at `-O0` all three of them can be stack slots. That
64//! is tamnd/rucc#913, and it stopped brotli and cmocka on the first file that held one.
65//!
66//! What answers it is borrowing: a register of the class the instruction has not named is
67//! taken, whatever is in it is put in a slot of the frame in front of the instruction, and it is
68//! brought back behind it. That asks nothing at all of the register, so it does not matter whether
69//! the value in it is wanted afterwards, whether the callee owes it back, or whether an argument
70//! travels in it, which are the three things that make a register held back hard to find. A third
71//! register held back would cost every function in the program one, and on x86-64 the only one
72//! available is `rax`, which is the return value, so the bill would be a move at every return. This
73//! costs two memory accesses at the one instruction that wanted it and a slot most functions never
74//! take.
75//!
76//! # What a fixed register turns into
77//!
78//! A move each way. The assignment deliberately gave the value some other register, so a division
79//! whose dividend has to be in `rax` gets a move into `rax` in front of it and a move out of `rax`
80//! behind it. That is the cost of the rule the assignment follows, and it is the rule that keeps
81//! the `-O0` allocator one pass.
82//!
83//! # What an edge turns into
84//!
85//! The moves that write the block's parameters, in an order they can be made in one at a time,
86//! which is what [`crate::moves`] is for. Where they go depends on the shape of the edge. A block
87//! with one successor puts them at its own end, in front of the branch it finishes with, and a
88//! block with several puts them at the start of the block the edge goes to, which is safe exactly
89//! because that block has no other predecessor. An edge that is critical has neither place to put
90//! them and has to have been split before allocation ran, which this checks rather than assumes.
91//!
92//! An edge is also the one place a value can be asked to go from one stack slot to another, which
93//! happens when a spilled value is passed to a parameter that was itself spilled. No machine here
94//! has that instruction, so the move goes through a register, and the register is a second scratch
95//! rather than the one the ordering may be holding a value in for the length of a cycle. Expanding
96//! it here rather than leaving it to the target is the same decision as everything else in this
97//! file: a move through a temporary is a fact about places, and which register is free to be the
98//! temporary is a fact only this crate has.
99
100use rucc_mir::{Block, Constraint, Func, Inst, Operand, Param, Reg, Role};
101use rucc_target::{PhysReg, RegClass};
102
103use crate::assign::{Assignment, Env, Place};
104use crate::moves::{self, Move};
105
106/// One move the places did not already make true.
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub struct Edit {
109    /// Where in the function it goes.
110    pub at: At,
111    /// What it moves, and where to.
112    pub mov: Move<Place>,
113    /// The class both places are in, which is what says how wide the move is.
114    pub class: RegClass,
115}
116
117/// Where an edit goes.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
119pub enum At {
120    /// In front of an instruction, which is where a value it reads is put where it wants it.
121    Before(Inst),
122    /// Behind an instruction, which is where a value it wrote somewhere it insisted on is taken
123    /// away to where it lives.
124    After(Inst),
125    /// At the start of a block, in front of everything in it.
126    StartOf(Block),
127    /// At the end of a block, behind everything in it. Only ever a block with one edge out of
128    /// it, since a block with two puts an edge's moves at the start of the block it goes to.
129    EndOf(Block),
130}
131
132/// Rewrites a function to the places it was given, and says what moves are still wanted.
133///
134/// # Panics
135///
136/// Panics if the entry block has parameters, since there is no edge into it for their moves to go
137/// on and what arrives in a function is the ABI lowering's to say. Panics on a critical edge, on
138/// an edge carrying the wrong number of arguments, and if a class has fewer than two registers on
139/// an edge that moves a spilled value into a spilled parameter, all of which are the caller handing
140/// it something it was told not to.
141///
142/// The assignment is taken by reference and may gain a slot, which is the one the register borrowed
143/// at an instruction with more spilled operands than the class holds registers back for waits in.
144/// The section above says what the borrowing is, and the slot is asked for here rather than planned
145/// before allocation because most functions never want one.
146#[must_use]
147pub fn rewrite(func: &mut Func, assignment: &mut Assignment, env: &Env) -> Vec<Edit> {
148    let blocks: Vec<Block> = func.blocks().collect();
149    assert!(
150        func.entry().is_none_or(|entry| func[entry].params.is_empty()),
151        "what arrives in a function is not a block parameter"
152    );
153
154    let mut edits = Vec::new();
155    let mut spare = Spare::default();
156    for &block in &blocks {
157        let insts: Vec<Inst> = func.insts(block).collect();
158        for inst in insts {
159            instruction(func, assignment, env, &mut spare, inst, &mut edits);
160        }
161    }
162
163    let preds = preds(func, &blocks);
164    for &block in &blocks {
165        edges(func, assignment, env, block, &preds, &mut edits);
166    }
167    for &block in &blocks {
168        func.params_mut(block).clear();
169        for call in func.succs_mut(block) {
170            call.args.clear();
171        }
172    }
173    edits
174}
175
176/// Rewrites one instruction's operands, and says what has to happen either side of it.
177fn instruction(
178    func: &mut Func,
179    assignment: &mut Assignment,
180    env: &Env,
181    spare: &mut Spare,
182    inst: Inst,
183    edits: &mut Vec<Edit>,
184) {
185    let list = func[inst].operands;
186    let mut operands: Vec<Operand> = func[list].to_vec();
187    let mut before = Moves::new();
188    let mut after = Moves::new();
189    let mut taken = Taken::new();
190
191    // Where the assignment put each operand's value, taken before anything is rewritten, since
192    // rewriting an operand is what loses that. The second pass below reads it.
193    let places: Vec<Place> =
194        operands.iter().map(|operand| place(assignment, operand.reg)).collect();
195
196    // A spilled operand that reuses another is left for the second pass, because where it goes
197    // depends on where the operand it reuses went and that is not known until every operand ahead
198    // of it has been placed.
199    let mut reusing: Vec<usize> = Vec::new();
200
201    // Every register the instruction has named for itself, which is one an operand's value is
202    // already in and one a fixed constraint asked for. Taken before anything is rewritten, for the
203    // same reason the places above are: rewriting is what turns an operand's register into a
204    // physical one and loses which of the two it was.
205    let mut claimed = Claimed::default();
206    for (operand, place) in operands.iter().zip(&places) {
207        if let Place::Reg(at) = *place {
208            claimed.named(operand, at);
209        }
210        if let Constraint::Fixed(at) = operand.constraint {
211            claimed.named(operand, at);
212        }
213    }
214    let mut scratch = Scratch::new(env, assignment, spare, claimed);
215
216    for (index, operand) in operands.iter_mut().enumerate() {
217        let fixed = match operand.constraint {
218            Constraint::Fixed(at) => Some(at),
219            _ => None,
220        };
221        let at = match (place(scratch.assignment, operand.reg), fixed) {
222            (Place::Reg(at), None) => at,
223            (Place::Reg(at), Some(fixed)) => {
224                if at != fixed {
225                    let (there, here) = (Place::Reg(fixed), Place::Reg(at));
226                    push(&mut before, &mut after, operand, Move::new(there, here));
227                }
228                fixed
229            }
230            (Place::Slot(_), None) if matches!(operand.constraint, Constraint::Reuse(_)) => {
231                reusing.push(index);
232                continue;
233            }
234            (Place::Slot(slot), fixed) => {
235                // Which of the two jobs this register is for. An operand the instruction only
236                // writes wants one from the instruction onwards, and an operand it reads wants one
237                // from before the instruction until it reads it, so the same register does both
238                // and the two are counted apart.
239                let at = match fixed {
240                    Some(fixed) => fixed,
241                    None if operand.role.is_def() => {
242                        taken.written_into(operand.class, &mut scratch)
243                    }
244                    None => taken.read_into(operand.class, &mut scratch),
245                };
246                push(
247                    &mut before,
248                    &mut after,
249                    operand,
250                    Move::new(Place::Reg(at), Place::Slot(slot)),
251                );
252                at
253            }
254        };
255        operand.reg = Reg::physical(at);
256    }
257
258    for index in reusing {
259        let Constraint::Reuse(other) = operands[index].constraint else {
260            unreachable!("only an operand that reuses another was left for this pass")
261        };
262        let Place::Slot(slot) = places[index] else {
263            unreachable!("only a spilled operand was left for this pass")
264        };
265        // Where the operand it reuses was read into, if it was read into anywhere. A scratch
266        // register holds a copy of a value that lives on the stack, so writing over it destroys
267        // nothing and the instruction can have it. A register the assignment gave out is a
268        // different matter: the value in it may be wanted after the instruction, and the
269        // assignment only lets one be written over when it is not, which it says by giving the
270        // answer that register. So a fresh scratch register there, and the copy below fills it.
271        //
272        // Either way this shape wants two of the class and no more. If the operand it reuses is on
273        // the stack then it is holding one of them already, and if it is not then it is not
274        // holding one at all.
275        //
276        // This one is asked for as a read even though the instruction writes it, because the copy
277        // that fills it goes in front of the instruction. It is live from there, which is the same
278        // span a value read in off the stack is live for, so it cannot share with one.
279        let other = usize::from(other);
280        let at = match places[other] {
281            Place::Slot(_) => phys(operands[other].reg),
282            Place::Reg(_) => taken.read_into(operands[index].class, &mut scratch),
283        };
284        push(
285            &mut before,
286            &mut after,
287            &operands[index],
288            Move::new(Place::Reg(at), Place::Slot(slot)),
289        );
290        operands[index].reg = Reg::physical(at);
291    }
292
293    // A two address instruction writes one of the registers it reads, and the copy that makes that
294    // true goes after everything else in front of the instruction, since what it reads may be a
295    // value that was itself only just read in from the stack.
296    for index in 0..operands.len() {
297        let Constraint::Reuse(other) = operands[index].constraint else { continue };
298        let (to, from) = (operands[index], operands[usize::from(other)]);
299        if to.reg != from.reg {
300            let mov = Move::new(Place::Reg(phys(to.reg)), Place::Reg(phys(from.reg)));
301            before.push((mov, to.class));
302        }
303    }
304
305    // A borrowed register is put away in front of everything else and brought back behind
306    // everything else, since what happens in between is the instruction using it and the moves
307    // that carry its operands in and out. Nothing borrowed at one instruction is still borrowed at
308    // the next, which is what lets the slot be shared.
309    let (saves, restores) = scratch.finish();
310
311    func[list].copy_from_slice(&operands);
312    edits.extend(saves.into_iter().map(|(mov, class)| Edit { at: At::Before(inst), mov, class }));
313    edits.extend(before.into_iter().map(|(mov, class)| Edit { at: At::Before(inst), mov, class }));
314    edits.extend(after.into_iter().map(|(mov, class)| Edit { at: At::After(inst), mov, class }));
315    edits.extend(restores.into_iter().map(|(mov, class)| Edit { at: At::After(inst), mov, class }));
316}
317
318/// How many scratch registers of each class one instruction has been handed, in each of the two
319/// jobs they do.
320///
321/// Counted per class rather than in one running number, because the classes hold their own back
322/// and an instruction reading a spilled value out of each of two files would otherwise skip the
323/// first register of the second file for no reason.
324///
325/// Counted per job as well, and that is the part that keeps the count down. A register a spilled
326/// value is read into is live from in front of the instruction until the instruction reads it. A
327/// register the instruction writes its answer into is live from the instruction until the store
328/// behind it. Those two spans do not meet, so one register does both jobs and the counting starts
329/// again rather than carrying on. What that rests on is the machine reading its operands before it
330/// writes its answer, which is true of every instruction the backends here emit and is the same
331/// thing that makes `addq %rax, %rax` mean what it looks like.
332///
333/// Where the count runs out is an instruction that reads three registers and writes none, because
334/// then there is no answer to fold back into a register an operand arrived in and the trick above
335/// has nothing to work on. On x86-64 that instruction is the indexed store, whose base, index and
336/// value are three registers it only reads, and at `-O0` all three of them can be stack slots. That
337/// is tamnd/rucc#913, and what answers it is [`Scratch::borrow`] rather than a third register held
338/// back, since holding a third back costs every function a register and this costs only the
339/// instruction that wanted one.
340#[derive(Debug, Default)]
341struct Taken {
342    /// How many of each class hold a value read in ahead of the instruction.
343    read: Vec<usize>,
344    /// How many of each class hold an answer the instruction writes.
345    written: Vec<usize>,
346}
347
348impl Taken {
349    /// Nothing handed out yet.
350    fn new() -> Self {
351        Self::default()
352    }
353
354    /// A register of a class for a value read in ahead of the instruction.
355    fn read_into(&mut self, class: RegClass, scratch: &mut Scratch<'_>) -> PhysReg {
356        Self::take(&mut self.read, class, scratch, Role::Use)
357    }
358
359    /// A register of a class for an answer the instruction writes.
360    fn written_into(&mut self, class: RegClass, scratch: &mut Scratch<'_>) -> PhysReg {
361        Self::take(&mut self.written, class, scratch, Role::Def)
362    }
363
364    /// The next register of a class out of one of the two counts, passing over any the instruction
365    /// has already named itself for a value travelling the same way and borrowing one when the held
366    /// back ones run out.
367    ///
368    /// An operand with a fixed constraint names a register the instruction has to have its value
369    /// in, and the move that puts it there is in the same list as the move that would fill a
370    /// scratch register. So handing the same register out for both would lose one of the two
371    /// values, quietly and at run time. It is passed over instead.
372    ///
373    /// Which way the value travels is what decides whether there is a clash at all, and [`Claimed`]
374    /// says why. A register the instruction only writes is free to carry a value in, which is what a
375    /// call wants: a call names every caller saved register as one it writes, and those are the very
376    /// registers held back for scratch.
377    ///
378    /// A clash comes up on a machine where a register held back is one an instruction can also
379    /// insist on, and on x86-64 the way in is inline assembly naming `r10` or `r11`.
380    fn take(
381        counts: &mut Vec<usize>,
382        class: RegClass,
383        scratch: &mut Scratch<'_>,
384        role: Role,
385    ) -> PhysReg {
386        let index = usize::from(class.number());
387        if counts.len() <= index {
388            counts.resize(index + 1, 0);
389        }
390        let held: &[PhysReg] = scratch.env.scratch(class);
391        while held.get(counts[index]).is_some_and(|&reg| scratch.claimed.clashes(role, class, reg))
392        {
393            counts[index] += 1;
394        }
395        if let Some(&at) = held.get(counts[index]) {
396            counts[index] += 1;
397            return at;
398        }
399        scratch.borrow(class)
400    }
401}
402
403/// The registers the instruction has named for itself, which scratch has to work around.
404///
405/// A register is kept with the class it was named in, because a register number is only a number
406/// into one file and the same one means a different register in another: a call names sixteen vector
407/// registers numbered nought to fifteen and sixteen general purpose ones numbered the same, and
408/// reading the two lists as one leaves the general purpose file looking entirely spoken for.
409///
410/// Reading and writing are kept apart because they clash with different things. A register a value
411/// arrives in is one no move in front of the instruction may write, and a register an answer leaves
412/// in is one no move behind it may write. A call is the case that makes the difference matter: it
413/// names every caller saved register as one it writes, `r10` and `r11` among them, and an indirect
414/// call through a pointer on the stack has to read that pointer into one of exactly those two.
415#[derive(Debug, Default)]
416struct Claimed {
417    /// The registers a value arrives in, with the class each was named in.
418    reads: Vec<(RegClass, PhysReg)>,
419    /// The registers an answer leaves in, with the class each was named in.
420    writes: Vec<(RegClass, PhysReg)>,
421}
422
423impl Claimed {
424    /// Records a register an operand named, on the side its value travels.
425    fn named(&mut self, operand: &Operand, at: PhysReg) {
426        self.side_mut(operand.role).push((operand.class, at));
427    }
428
429    /// Records a register nothing may be handed for the rest of the instruction, which is one
430    /// [`Scratch::borrow`] has just taken.
431    fn taken(&mut self, class: RegClass, at: PhysReg) {
432        self.reads.push((class, at));
433        self.writes.push((class, at));
434    }
435
436    /// Whether handing that register out for a value travelling that way would lose a value.
437    fn clashes(&self, role: Role, class: RegClass, at: PhysReg) -> bool {
438        self.side(role).contains(&(class, at))
439    }
440
441    /// Whether the instruction names that register at all, which is what borrowing has to keep off:
442    /// what is borrowed is put back behind the instruction, over anything left there.
443    fn names(&self, class: RegClass, at: PhysReg) -> bool {
444        self.reads.contains(&(class, at)) || self.writes.contains(&(class, at))
445    }
446
447    /// The list for values travelling that way. The lists are one instruction's long, so a scan
448    /// beats a set.
449    fn side(&self, role: Role) -> &Vec<(RegClass, PhysReg)> {
450        if role.is_def() { &self.writes } else { &self.reads }
451    }
452
453    /// The same, to write to.
454    fn side_mut(&mut self, role: Role) -> &mut Vec<(RegClass, PhysReg)> {
455        if role.is_def() { &mut self.writes } else { &mut self.reads }
456    }
457}
458
459/// Moves waiting to be filed, each with the class of the value it moves.
460///
461/// The class travels with the move because an [`Edit`] carries one and the consumer needs it to pick
462/// the instruction that does the move, and by the time a move is filed the operand it came from is
463/// out of reach.
464type Moves = Vec<(Move<Place>, RegClass)>;
465
466/// The frame slots a borrowed register's value waits in, one list per class.
467///
468/// They belong to the function rather than to an instruction, because a borrowed register is given
469/// back before the next instruction starts and the slot is dead in between, so one slot serves
470/// every instruction in the function that borrows. Most functions never take one at all.
471type Spare = Vec<Vec<u32>>;
472
473/// What it takes to hand a register to one instruction.
474///
475/// It is a struct rather than four arguments because [`Scratch::borrow`] writes to all of them at
476/// once: it reads the environment, takes a slot off the assignment, remembers the register so a
477/// second borrow at the same instruction does not land on it, and files the two moves that make it
478/// safe.
479struct Scratch<'a> {
480    env: &'a Env,
481    /// Where every value went, and where a slot for a borrowed register comes from.
482    assignment: &'a mut Assignment,
483    /// The function's slots for borrowed registers, reused at every instruction.
484    spare: &'a mut Spare,
485    /// Every register the instruction has named, and then every one borrowed here as it is borrowed.
486    claimed: Claimed,
487    /// How many of each class have been borrowed at this instruction, which says which slot the
488    /// next one uses.
489    borrowed: Vec<usize>,
490    /// The moves that put a borrowed register's value away, which go in front of everything else.
491    saves: Moves,
492    /// The moves that bring it back, which go behind everything else.
493    restores: Moves,
494}
495
496impl<'a> Scratch<'a> {
497    /// Nothing borrowed yet at an instruction claiming those registers.
498    fn new(
499        env: &'a Env,
500        assignment: &'a mut Assignment,
501        spare: &'a mut Spare,
502        claimed: Claimed,
503    ) -> Self {
504        Self {
505            env,
506            assignment,
507            spare,
508            claimed,
509            borrowed: Vec::new(),
510            saves: Vec::new(),
511            restores: Vec::new(),
512        }
513    }
514
515    /// A register of the class the instruction is not using, with whatever is in it put away in
516    /// front of the instruction and brought back behind it.
517    ///
518    /// This is what a class runs out to, and it works on any machine because it asks nothing at all
519    /// of the register it takes. Whatever was in it is somewhere else for the length of one
520    /// instruction, so it does not matter whether that value is wanted afterwards, whether the
521    /// callee owes the register back, or whether an argument travels in it, which are the three
522    /// things that make a register held back hard to find. What it costs is two memory accesses at
523    /// the one instruction that wanted it and one slot of the frame, against a register taken off
524    /// every function in the program, and `rucc_codegen::pipeline` says why that trade goes this
525    /// way round on x86-64.
526    ///
527    /// The register is any of the class the instruction has not claimed for itself. A register the
528    /// allocator gave a value that is live right across the instruction is as good as an idle one,
529    /// which is the whole point of putting the contents away first.
530    ///
531    /// # Panics
532    ///
533    /// Panics if the class has no register the instruction has not already claimed, which is an
534    /// instruction naming every register of a file at once.
535    fn borrow(&mut self, class: RegClass) -> PhysReg {
536        let index = usize::from(class.number());
537        let at = *self
538            .env
539            .order(class)
540            .iter()
541            .find(|&&reg| !self.claimed.names(class, reg))
542            .expect("an instruction naming every register of its class at once");
543
544        if self.borrowed.len() <= index {
545            self.borrowed.resize(index + 1, 0);
546        }
547        if self.spare.len() <= index {
548            self.spare.resize(index + 1, Vec::new());
549        }
550        let nth = self.borrowed[index];
551        if self.spare[index].len() <= nth {
552            let slot = self.assignment.take_slot(class);
553            self.spare[index].push(slot);
554        }
555        let slot = self.spare[index][nth];
556
557        self.borrowed[index] = nth + 1;
558        self.claimed.taken(class, at);
559        self.saves.push((Move::new(Place::Slot(slot), Place::Reg(at)), class));
560        self.restores.push((Move::new(Place::Reg(at), Place::Slot(slot)), class));
561        at
562    }
563
564    /// The moves either side of the instruction, once every register has been handed out.
565    fn finish(self) -> (Moves, Moves) {
566        (self.saves, self.restores)
567    }
568}
569
570/// Files a move in front of the instruction or behind it, and turns it round for a value the
571/// instruction writes, since that one travels the other way.
572fn push(before: &mut Moves, after: &mut Moves, operand: &Operand, mov: Move<Place>) {
573    if operand.role.is_def() {
574        after.push((Move::new(mov.from, mov.to), operand.class));
575    } else {
576        before.push((mov, operand.class));
577    }
578}
579
580/// The moves the edges out of a block turn into.
581fn edges(
582    func: &mut Func,
583    assignment: &Assignment,
584    env: &Env,
585    block: Block,
586    preds: &[usize],
587    edits: &mut Vec<Edit>,
588) {
589    let succs = func[block].succs.clone();
590    let single = succs.len() == 1;
591    for call in &succs {
592        let params = func[call.block].params.clone();
593        assert_eq!(
594            params.len(),
595            call.args.len(),
596            "an edge carries what the block it goes to asks for"
597        );
598        if params.is_empty() {
599            continue;
600        }
601        assert!(
602            single || preds[call.block.index()] == 1,
603            "a critical edge has nowhere to put its moves and has to be split before allocation"
604        );
605        let at = if single { At::EndOf(block) } else { At::StartOf(call.block) };
606        edits.extend(edge(assignment, env, &params, &call.args, at));
607    }
608}
609
610/// The moves one edge turns into, in the order they can be made in.
611fn edge(assignment: &Assignment, env: &Env, params: &[Param], args: &[Reg], at: At) -> Vec<Edit> {
612    let mut classes: Vec<RegClass> = params.iter().map(|param| param.class).collect();
613    classes.sort_unstable();
614    classes.dedup();
615
616    let mut edits = Vec::new();
617    for class in classes {
618        // One class at a time, because a scratch register is per class and a value never crosses
619        // from one to another on an edge.
620        let parallel: Vec<Move<Place>> = params
621            .iter()
622            .zip(args)
623            .filter(|(param, _)| param.class == class)
624            .map(|(param, &arg)| Move::new(place(assignment, param.reg), place(assignment, arg)))
625            .collect();
626        let scratch = env.scratch(class);
627        let cycle = *scratch
628            .first()
629            .expect("a class whose values are passed on an edge and which has no scratch register");
630        for mov in moves::sequence(&parallel, Place::Reg(cycle)) {
631            match (mov.to, mov.from) {
632                // No machine here moves one piece of memory into another, so the value goes
633                // through a register, and it is a second scratch rather than the one the ordering
634                // above may be holding a value in for the length of a cycle.
635                (Place::Slot(_), Place::Slot(_)) => {
636                    let through = Place::Reg(*scratch.get(1).expect(
637                        "a class passing a spilled value to a spilled parameter and having only \
638                         one scratch register",
639                    ));
640                    edits.push(Edit { at, mov: Move::new(through, mov.from), class });
641                    edits.push(Edit { at, mov: Move::new(mov.to, through), class });
642                }
643                _ => edits.push(Edit { at, mov, class }),
644            }
645        }
646    }
647    edits
648}
649
650/// How many edges arrive in each block.
651fn preds(func: &Func, blocks: &[Block]) -> Vec<usize> {
652    let mut preds = vec![0; func.block_count()];
653    for &block in blocks {
654        for call in &func[block].succs {
655            preds[call.block.index()] += 1;
656        }
657    }
658    preds
659}
660
661/// Where a register is, whether the allocator put it there or it was already somewhere.
662fn place(assignment: &Assignment, reg: Reg) -> Place {
663    assignment.place(reg).unwrap_or_else(|| Place::Reg(phys(reg)))
664}
665
666/// The physical register a register is, once it has to be one.
667fn phys(reg: Reg) -> PhysReg {
668    reg.phys().expect("a register the assignment says nothing about and that is not a register")
669}
670
671#[cfg(test)]
672mod tests {
673    use rucc_base::Interner;
674    use rucc_mir::{BlockCall, Opcode};
675    use rucc_target::x86_64::{GPR, RAX, RCX, RDX, REGS, RSI, SYSV, XMM};
676
677    use super::*;
678    use crate::assign::assign;
679    use crate::live::Live;
680    use crate::order::Order;
681
682    /// The x86-64 environment, with the last three of the allocation order held back as scratch.
683    fn env() -> Env {
684        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
685        Env::new().with(GPR, order, scratch)
686    }
687
688    /// An environment with that many general purpose registers and two scratch after them.
689    fn narrow(count: usize) -> Env {
690        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 2])
691    }
692
693    /// What a place is called, which is what an assertion reads.
694    ///
695    /// The class comes in because a register is a number within its class and the two files here
696    /// number from zero, so nothing but the class tells `rcx` from `xmm1`.
697    fn named(class: RegClass, place: Place) -> String {
698        match place {
699            Place::Reg(reg) => REGS.name(class, reg).expect("a register").to_string(),
700            Place::Slot(slot) => format!("slot{slot}"),
701        }
702    }
703
704    /// Runs both halves and reports the edits as lines an assertion can read.
705    fn run(func: &mut Func, env: &Env) -> Vec<String> {
706        let order = Order::of(func);
707        let live = Live::of(func, &order);
708        let mut assignment = assign(func, &order, &live, env);
709        rewrite(func, &mut assignment, env)
710            .into_iter()
711            .map(|edit| {
712                let at = match edit.at {
713                    At::Before(inst) => format!("before {}", inst.index()),
714                    At::After(inst) => format!("after {}", inst.index()),
715                    At::StartOf(block) => format!("start of {}", block.index()),
716                    At::EndOf(block) => format!("end of {}", block.index()),
717                };
718                format!(
719                    "{at}: {} = {}",
720                    named(edit.class, edit.mov.to),
721                    named(edit.class, edit.mov.from)
722                )
723            })
724            .collect()
725    }
726
727    /// The registers an instruction's operands ended up naming.
728    fn operands(func: &Func, inst: Inst) -> Vec<String> {
729        func[func[inst].operands]
730            .iter()
731            .map(|operand| named(operand.class, Place::Reg(phys(operand.reg))))
732            .collect()
733    }
734
735    #[test]
736    fn every_operand_ends_up_naming_the_register_its_value_was_given() {
737        let mut names = Interner::new();
738        let mut func = Func::new(names.intern("f"));
739        let opcode = Opcode::new(names.intern("x64.nop"));
740        let block = func.create_block();
741        let first = func.new_vreg(GPR);
742        let second = func.new_vreg(GPR);
743        func.build(block, opcode).def(first, GPR).finish();
744        func.build(block, opcode).def(second, GPR).finish();
745        let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
746
747        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
748        assert_eq!(operands(&func, read), ["rax", "rcx"]);
749    }
750
751    #[test]
752    fn a_register_an_instruction_insists_on_costs_nothing_when_the_values_can_have_it() {
753        let mut names = Interner::new();
754        let mut func = Func::new(names.intern("f"));
755        let opcode = Opcode::new(names.intern("x64.nop"));
756        let block = func.create_block();
757        let dividend = func.new_vreg(GPR);
758        let quotient = func.new_vreg(GPR);
759        func.build(block, opcode).def(dividend, GPR).finish();
760        let divide = func
761            .build(block, opcode)
762            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
763            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
764            .finish();
765        func.build(block, opcode).uses(quotient, GPR).finish();
766
767        // Nothing either side of the division. The dividend is read out of `rax` for the last
768        // time and the quotient is written into it afterwards, so both of them live there and the
769        // moves that used to carry the value in and the answer out are not written.
770        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
771        assert_eq!(operands(&func, divide), ["rax", "rax"]);
772    }
773
774    #[test]
775    fn a_register_an_instruction_insists_on_is_moved_into_when_the_value_cannot_have_it() {
776        let mut names = Interner::new();
777        let mut func = Func::new(names.intern("f"));
778        let opcode = Opcode::new(names.intern("x64.nop"));
779        let block = func.create_block();
780        let dividend = func.new_vreg(GPR);
781        let quotient = func.new_vreg(GPR);
782        func.build(block, opcode).def(dividend, GPR).finish();
783        let divide = func
784            .build(block, opcode)
785            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
786            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
787            .finish();
788        func.build(block, opcode).uses(quotient, GPR).finish();
789        func.build(block, opcode).uses(dividend, GPR).finish();
790
791        // This time the dividend is wanted after the division, so it cannot be in the register the
792        // division writes and the value is moved in. The answer still comes out of `rax` without
793        // a move, which is the half of it the hint bought.
794        assert_eq!(run(&mut func, &env()), ["before 1: rax = rcx"]);
795        assert_eq!(operands(&func, divide), ["rax", "rax"]);
796    }
797
798    #[test]
799    fn a_two_address_instruction_that_did_not_get_its_register_copies_first() {
800        let mut names = Interner::new();
801        let mut func = Func::new(names.intern("f"));
802        let opcode = Opcode::new(names.intern("x64.nop"));
803        let block = func.create_block();
804        let left = func.new_vreg(GPR);
805        let right = func.new_vreg(GPR);
806        let sum = func.new_vreg(GPR);
807        func.build(block, opcode).def(left, GPR).finish();
808        func.build(block, opcode).def(right, GPR).finish();
809        let add = func
810            .build(block, opcode)
811            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
812            .uses(left, GPR)
813            .uses(right, GPR)
814            .finish();
815        func.build(block, opcode).uses(left, GPR).finish();
816
817        // The left value is wanted afterwards, so the answer could not have its register and the
818        // copy in front of the addition is what makes the instruction two address.
819        assert_eq!(run(&mut func, &env()), ["before 2: rdx = rax"]);
820        assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
821    }
822
823    #[test]
824    fn a_two_address_instruction_that_did_get_its_register_copies_nothing() {
825        let mut names = Interner::new();
826        let mut func = Func::new(names.intern("f"));
827        let opcode = Opcode::new(names.intern("x64.nop"));
828        let block = func.create_block();
829        let left = func.new_vreg(GPR);
830        let right = func.new_vreg(GPR);
831        let sum = func.new_vreg(GPR);
832        func.build(block, opcode).def(left, GPR).finish();
833        func.build(block, opcode).def(right, GPR).finish();
834        let add = func
835            .build(block, opcode)
836            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
837            .uses(left, GPR)
838            .uses(right, GPR)
839            .finish();
840        func.build(block, opcode).uses(right, GPR).finish();
841
842        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
843        assert_eq!(operands(&func, add), ["rax", "rax", "rcx"]);
844    }
845
846    #[test]
847    fn a_spilled_value_is_read_into_a_scratch_register_at_each_instruction_that_wants_it() {
848        let mut names = Interner::new();
849        let mut func = Func::new(names.intern("f"));
850        let opcode = Opcode::new(names.intern("x64.nop"));
851        let block = func.create_block();
852        let first = func.new_vreg(GPR);
853        let second = func.new_vreg(GPR);
854        func.build(block, opcode).def(first, GPR).finish();
855        func.build(block, opcode).def(second, GPR).finish();
856        let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
857
858        // One register between two values, so one of them goes to the stack. It is written there
859        // where it is computed and read back where it is wanted, and both ends of that go through
860        // the scratch register that is held out of the allocation order for exactly this.
861        assert_eq!(run(&mut func, &narrow(1)), ["after 1: slot0 = rcx", "before 2: rcx = slot0"]);
862        assert_eq!(operands(&func, read), ["rax", "rcx"]);
863    }
864
865    /// A two address instruction with nothing in a register is two scratch registers and not three.
866    ///
867    /// The answer has no register of its own to be in, so what it is written into is whichever one
868    /// the operand it reuses was read into, and it is stored away from there afterwards. Handing it
869    /// a scratch register of its own would want a third, and a class holds two back, which is issue
870    /// #350: a program with enough live values around a call reached it and the compiler aborted.
871    #[test]
872    fn a_two_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
873        let mut names = Interner::new();
874        let mut func = Func::new(names.intern("f"));
875        let opcode = Opcode::new(names.intern("x64.nop"));
876        let block = func.create_block();
877        let keeper = func.new_vreg(GPR);
878        let left = func.new_vreg(GPR);
879        let right = func.new_vreg(GPR);
880        let sum = func.new_vreg(GPR);
881        func.build(block, opcode).def(keeper, GPR).finish();
882        func.build(block, opcode)
883            .operand(Operand::write(left, GPR).with(Constraint::Stack))
884            .finish();
885        func.build(block, opcode)
886            .operand(Operand::write(right, GPR).with(Constraint::Stack))
887            .finish();
888        let add = func
889            .build(block, opcode)
890            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
891            .uses(left, GPR)
892            .uses(right, GPR)
893            .finish();
894        func.build(block, opcode).uses(keeper, GPR).finish();
895        func.build(block, opcode).uses(sum, GPR).finish();
896
897        // Both operands are read in, the answer is written into the register the operand it
898        // reuses arrived in, and it is stored away from there. Two scratch registers, which is
899        // what the class holds back. Asking for one of its own would be a third and would abort.
900        assert_eq!(
901            run(&mut func, &narrow(1)),
902            [
903                "after 1: slot0 = rcx",
904                "after 2: slot1 = rcx",
905                "before 3: rcx = slot0",
906                "before 3: rdx = slot1",
907                "after 3: slot2 = rcx",
908                "before 5: rcx = slot2",
909            ]
910        );
911        assert_eq!(operands(&func, add), ["rcx", "rcx", "rdx"]);
912    }
913
914    /// A three address instruction with nothing in a register is two scratch registers, not three.
915    ///
916    /// The case #726 aborted on. `x64.lea_64` and the `x64.cmp_set_*` family read two values and
917    /// write a third that is neither of them, and when all three ends are on the stack there are
918    /// three operands wanting a register at one instruction. Counting them in one running number
919    /// asks for a third scratch register and the class holds two back.
920    ///
921    /// Two is enough because the answer's register is not wanted until the instruction writes it,
922    /// by which time the registers the operands were read into have been read. So the answer goes
923    /// back into the first of them and is stored away from there.
924    #[test]
925    fn a_three_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
926        let mut names = Interner::new();
927        let mut func = Func::new(names.intern("f"));
928        let opcode = Opcode::new(names.intern("x64.nop"));
929        let block = func.create_block();
930        let keeper = func.new_vreg(GPR);
931        let base = func.new_vreg(GPR);
932        let index = func.new_vreg(GPR);
933        let address = func.new_vreg(GPR);
934        func.build(block, opcode).def(keeper, GPR).finish();
935        func.build(block, opcode)
936            .operand(Operand::write(base, GPR).with(Constraint::Stack))
937            .finish();
938        func.build(block, opcode)
939            .operand(Operand::write(index, GPR).with(Constraint::Stack))
940            .finish();
941        let lea =
942            func.build(block, opcode).def(address, GPR).uses(base, GPR).uses(index, GPR).finish();
943        func.build(block, opcode).uses(keeper, GPR).finish();
944        func.build(block, opcode).uses(address, GPR).finish();
945
946        // Both operands are read in, the answer is written into the first of the two registers
947        // they arrived in, and it is stored away from there. Two, which is what the class holds.
948        assert_eq!(
949            run(&mut func, &narrow(1)),
950            [
951                "after 1: slot0 = rcx",
952                "after 2: slot1 = rcx",
953                "before 3: rcx = slot0",
954                "before 3: rdx = slot1",
955                "after 3: slot2 = rcx",
956                "before 5: rcx = slot2",
957            ]
958        );
959        assert_eq!(operands(&func, lea), ["rcx", "rcx", "rdx"]);
960    }
961
962    /// A spilled answer takes a scratch register where the operand it reuses is in a real one.
963    ///
964    /// The value in that register may be wanted after the instruction, and the assignment is the
965    /// only thing that knows whether it is. It says so by giving the answer that register, and here
966    /// it did not, so writing over it would destroy a value. The count still comes to two, because
967    /// an operand that is in a register is not holding a scratch register.
968    #[test]
969    fn a_spilled_answer_does_not_write_over_a_register_the_assignment_gave_to_something_else() {
970        let mut names = Interner::new();
971        let mut func = Func::new(names.intern("f"));
972        let opcode = Opcode::new(names.intern("x64.nop"));
973        let block = func.create_block();
974        let left = func.new_vreg(GPR);
975        let right = func.new_vreg(GPR);
976        let sum = func.new_vreg(GPR);
977        func.build(block, opcode).def(left, GPR).finish();
978        func.build(block, opcode)
979            .operand(Operand::write(right, GPR).with(Constraint::Stack))
980            .finish();
981        let add = func
982            .build(block, opcode)
983            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
984            .uses(left, GPR)
985            .uses(right, GPR)
986            .finish();
987        func.build(block, opcode).uses(left, GPR).finish();
988        func.build(block, opcode).uses(sum, GPR).finish();
989
990        // The left value is in `rax` and is read again afterwards, so the answer is copied into a
991        // scratch register and written there instead.
992        assert_eq!(
993            run(&mut func, &narrow(1)),
994            [
995                "after 1: slot0 = rcx",
996                "before 2: rcx = slot0",
997                "before 2: rdx = rax",
998                "after 2: slot1 = rdx",
999                "before 4: rcx = slot1",
1000            ]
1001        );
1002        assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
1003    }
1004
1005    /// The count of scratch registers handed out is per class and not one number for all of them.
1006    ///
1007    /// An instruction reading a spilled value out of each of two files wants the first register of
1008    /// each, since the files hold their own back and nothing on the instruction is in the other's.
1009    #[test]
1010    fn an_instruction_reading_out_of_two_files_takes_the_first_scratch_register_of_each() {
1011        let mut names = Interner::new();
1012        let mut func = Func::new(names.intern("f"));
1013        let opcode = Opcode::new(names.intern("x64.nop"));
1014        let block = func.create_block();
1015        let integer = func.new_vreg(GPR);
1016        let number = func.new_vreg(XMM);
1017        let spare = func.new_vreg(GPR);
1018        let other = func.new_vreg(XMM);
1019        func.build(block, opcode).def(integer, GPR).finish();
1020        func.build(block, opcode).def(number, XMM).finish();
1021        func.build(block, opcode).def(spare, GPR).finish();
1022        func.build(block, opcode).def(other, XMM).finish();
1023        func.build(block, opcode).uses(integer, GPR).uses(number, XMM).finish();
1024        let read = func.build(block, opcode).uses(spare, GPR).uses(other, XMM).finish();
1025
1026        // One register in each file, so the value of each that is wanted later goes to the stack
1027        // and is read back at the instruction that wants it.
1028        let env = Env::new().with(GPR, &SYSV.int_order[..1], &SYSV.int_order[1..3]).with(
1029            XMM,
1030            &SYSV.sse_order[..1],
1031            &SYSV.sse_order[1..3],
1032        );
1033        assert_eq!(
1034            run(&mut func, &env),
1035            [
1036                "after 2: slot0 = rcx",
1037                "after 3: slot1 = xmm1",
1038                "before 5: rcx = slot0",
1039                "before 5: xmm1 = slot1",
1040            ]
1041        );
1042        assert_eq!(operands(&func, read), ["rcx", "xmm1"]);
1043    }
1044
1045    #[test]
1046    fn an_edge_out_of_a_block_with_one_way_to_go_moves_at_the_end_of_it() {
1047        let mut names = Interner::new();
1048        let mut func = Func::new(names.intern("f"));
1049        let opcode = Opcode::new(names.intern("x64.nop"));
1050        let head = func.create_block();
1051        let tail = func.create_block();
1052        let held = func.new_vreg(GPR);
1053        let carried = func.new_vreg(GPR);
1054        func.build(head, opcode).def(held, GPR).finish();
1055        func.build(head, opcode).def(carried, GPR).finish();
1056        func.build(head, opcode).uses(held, GPR).finish();
1057        let param = func.append_param(tail, GPR);
1058        *func.succs_mut(head) = vec![BlockCall::with(tail, vec![carried])];
1059        let read = func.build(tail, opcode).uses(param, GPR).finish();
1060
1061        // The value the edge carries is in the second register, because the first was busy where
1062        // the value was written, and the parameter it arrives as is in the first, because by then
1063        // it is not. So the edge is a move, and it goes at the end of the block it leaves.
1064        assert_eq!(run(&mut func, &env()), ["end of 0: rax = rcx"]);
1065        assert_eq!(operands(&func, read), ["rax"]);
1066        // Nothing arrives in a block any more and no edge carries anything, which is where SSA
1067        // form stops.
1068        assert!(func[tail].params.is_empty());
1069        assert!(func[head].succs[0].args.is_empty());
1070    }
1071
1072    #[test]
1073    fn an_edge_out_of_a_block_with_a_choice_moves_at_the_start_of_where_it_goes() {
1074        let mut names = Interner::new();
1075        let mut func = Func::new(names.intern("f"));
1076        let opcode = Opcode::new(names.intern("x64.nop"));
1077        let head = func.create_block();
1078        let left = func.create_block();
1079        let right = func.create_block();
1080        let held = func.new_vreg(GPR);
1081        let carried = func.new_vreg(GPR);
1082        func.build(head, opcode).def(held, GPR).finish();
1083        func.build(head, opcode).def(carried, GPR).finish();
1084        func.build(head, opcode).uses(held, GPR).finish();
1085        let taken = func.append_param(left, GPR);
1086        *func.succs_mut(head) = vec![BlockCall::with(left, vec![carried]), BlockCall::to(right)];
1087        func.build(left, opcode).uses(taken, GPR).finish();
1088
1089        // The move cannot go at the end of the block it leaves, because the other way out of that
1090        // block does not want it. It goes at the start of the block it arrives in, which is safe
1091        // because nothing else arrives there.
1092        assert_eq!(run(&mut func, &env()), ["start of 1: rax = rcx"]);
1093    }
1094
1095    #[test]
1096    fn two_values_that_swap_on_an_edge_get_an_order_and_a_scratch_register() {
1097        let mut names = Interner::new();
1098        let mut func = Func::new(names.intern("f"));
1099        let opcode = Opcode::new(names.intern("x64.nop"));
1100        let head = func.create_block();
1101        let body = func.create_block();
1102        let first = func.new_vreg(GPR);
1103        let second = func.new_vreg(GPR);
1104        func.build(head, opcode).def(first, GPR).finish();
1105        func.build(head, opcode).def(second, GPR).finish();
1106        let left = func.append_param(body, GPR);
1107        let right = func.append_param(body, GPR);
1108        *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
1109        func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
1110        *func.succs_mut(body) = vec![BlockCall::with(body, vec![right, left])];
1111
1112        // The loop hands each value back the other way round, which is the case no order of two
1113        // moves answers, so one of them goes through the scratch register. The edge into the loop
1114        // moves nothing, because each value is already where the parameter it feeds lives.
1115        assert_eq!(
1116            run(&mut func, &env()),
1117            ["end of 1: r13 = rcx", "end of 1: rcx = rax", "end of 1: rax = r13"]
1118        );
1119    }
1120
1121    #[test]
1122    fn a_spilled_value_handed_to_a_spilled_parameter_goes_through_a_register() {
1123        let mut names = Interner::new();
1124        let mut func = Func::new(names.intern("f"));
1125        let opcode = Opcode::new(names.intern("x64.nop"));
1126        let head = func.create_block();
1127        let body = func.create_block();
1128        let first = func.new_vreg(GPR);
1129        let second = func.new_vreg(GPR);
1130        func.build(head, opcode).def(first, GPR).finish();
1131        func.build(head, opcode).def(second, GPR).finish();
1132        let left = func.append_param(body, GPR);
1133        let right = func.append_param(body, GPR);
1134        *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
1135        func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
1136
1137        // One register between the values and the parameters, so a value on the stack is handed to
1138        // a parameter on the stack, and no machine here has that instruction. It goes through the
1139        // second scratch register rather than the first, which is the one the ordering above is
1140        // entitled to be holding a value in.
1141        assert_eq!(
1142            run(&mut func, &narrow(1)),
1143            [
1144                "after 1: slot0 = rcx",
1145                "before 2: rcx = slot1",
1146                "end of 0: rdx = slot0",
1147                "end of 0: slot1 = rdx",
1148            ]
1149        );
1150    }
1151
1152    /// Three values read and none written wants a third register, which is tamnd/rucc#913.
1153    ///
1154    /// There is no answer here to fold back into the register an operand arrived in, so the trick
1155    /// that keeps a two address instruction down to two has nothing to work on and each of the
1156    /// three wants a register of its own. The instruction is the indexed store: `a[i] = v` reads a
1157    /// base, an index and a value, and at `-O0`, where nothing is coalesced, all three of them are
1158    /// stack slots. The rewriter aborted on it, which stopped brotli and cmocka on the first file
1159    /// that held one and sqlite3 on `fts5Init`.
1160    ///
1161    /// The third register is borrowed rather than held back, and the borrowing is what this is
1162    /// really about: it takes a register the allocator gave to a value that is live right across
1163    /// the instruction, which is safe because that value is put in a slot in front of the
1164    /// instruction and brought back behind it.
1165    #[test]
1166    fn an_instruction_reading_three_spilled_values_borrows_a_register_for_the_third() {
1167        let mut names = Interner::new();
1168        let mut func = Func::new(names.intern("f"));
1169        let opcode = Opcode::new(names.intern("x64.nop"));
1170        let block = func.create_block();
1171        let keeper = func.new_vreg(GPR);
1172        let base = func.new_vreg(GPR);
1173        let index = func.new_vreg(GPR);
1174        let value = func.new_vreg(GPR);
1175        func.build(block, opcode).def(keeper, GPR).finish();
1176        for reg in [base, index, value] {
1177            func.build(block, opcode)
1178                .operand(Operand::write(reg, GPR).with(Constraint::Stack))
1179                .finish();
1180        }
1181        let store =
1182            func.build(block, opcode).uses(base, GPR).uses(index, GPR).uses(value, GPR).finish();
1183        func.build(block, opcode).uses(keeper, GPR).finish();
1184
1185        assert_eq!(
1186            run(&mut func, &narrow(2)),
1187            [
1188                "after 1: slot0 = rdx",
1189                "after 2: slot1 = rdx",
1190                "after 3: slot2 = rdx",
1191                "before 4: slot3 = rax",
1192                "before 4: rdx = slot0",
1193                "before 4: rsi = slot1",
1194                "before 4: rax = slot2",
1195                "after 4: rax = slot3",
1196            ]
1197        );
1198        assert_eq!(operands(&func, store), ["rdx", "rsi", "rax"]);
1199    }
1200
1201    /// A register the instruction only writes still carries a value in.
1202    ///
1203    /// A call names every caller saved register as one it writes, and on x86-64 the two held back for
1204    /// scratch are both caller saved, so an indirect call through a pointer on the stack has nowhere
1205    /// to read the pointer into unless a register named only on the way out is still free on the way
1206    /// in. Reading them as spoken for stopped cmocka on its first file.
1207    #[test]
1208    fn a_register_the_instruction_only_writes_still_carries_a_value_in() {
1209        let mut names = Interner::new();
1210        let mut func = Func::new(names.intern("f"));
1211        let opcode = Opcode::new(names.intern("x64.nop"));
1212        let block = func.create_block();
1213        let target = func.new_vreg(GPR);
1214        func.build(block, opcode)
1215            .operand(Operand::write(target, GPR).with(Constraint::Stack))
1216            .finish();
1217        let call = func
1218            .build(block, opcode)
1219            .def(Reg::physical(RDX), GPR)
1220            .def(Reg::physical(RSI), GPR)
1221            .uses(target, GPR)
1222            .finish();
1223
1224        assert_eq!(run(&mut func, &narrow(2)), ["after 0: slot0 = rdx", "before 1: rdx = slot0"]);
1225        assert_eq!(operands(&func, call), ["rdx", "rsi", "rdx"]);
1226    }
1227
1228    /// A scratch register the instruction has already named for itself is passed over.
1229    ///
1230    /// The move that carries a value into a register a fixed constraint asks for and the move that
1231    /// fills a scratch register both go in front of the instruction, so handing the same register
1232    /// out twice would lose one of the two values without anything saying so. On x86-64 the way
1233    /// into this is inline assembly naming `r10` or `r11`, which are the two the file holds back.
1234    #[test]
1235    fn a_register_the_instruction_already_named_is_not_handed_out_as_scratch() {
1236        let mut names = Interner::new();
1237        let mut func = Func::new(names.intern("f"));
1238        let opcode = Opcode::new(names.intern("x64.nop"));
1239        let block = func.create_block();
1240        let wanted = func.new_vreg(GPR);
1241        let other = func.new_vreg(GPR);
1242        for reg in [wanted, other] {
1243            func.build(block, opcode)
1244                .operand(Operand::write(reg, GPR).with(Constraint::Stack))
1245                .finish();
1246        }
1247        let read = func
1248            .build(block, opcode)
1249            .operand(Operand::read(wanted, GPR).with(Constraint::Fixed(RCX)))
1250            .uses(other, GPR)
1251            .finish();
1252
1253        // `rcx` is both the first scratch register here and the one the instruction insists on, so
1254        // the value it did not ask for by name starts at the second one instead.
1255        assert_eq!(
1256            run(&mut func, &narrow(1)),
1257            [
1258                "after 0: slot0 = rcx",
1259                "after 1: slot1 = rcx",
1260                "before 2: rcx = slot0",
1261                "before 2: rdx = slot1"
1262            ]
1263        );
1264        assert_eq!(operands(&func, read), ["rcx", "rdx"]);
1265    }
1266
1267    #[test]
1268    #[should_panic(expected = "a critical edge has nowhere to put its moves")]
1269    fn a_critical_edge_is_refused() {
1270        let mut names = Interner::new();
1271        let mut func = Func::new(names.intern("f"));
1272        let opcode = Opcode::new(names.intern("x64.nop"));
1273        let head = func.create_block();
1274        let other = func.create_block();
1275        let join = func.create_block();
1276        let value = func.new_vreg(GPR);
1277        func.build(head, opcode).def(value, GPR).finish();
1278        let param = func.append_param(join, GPR);
1279        *func.succs_mut(head) = vec![BlockCall::with(join, vec![value]), BlockCall::to(other)];
1280        *func.succs_mut(other) = vec![BlockCall::with(join, vec![value])];
1281        func.build(join, opcode).uses(param, GPR).finish();
1282
1283        let _ = run(&mut func, &env());
1284    }
1285
1286    #[test]
1287    #[should_panic(expected = "what arrives in a function is not a block parameter")]
1288    fn a_parameter_on_the_entry_block_is_refused() {
1289        let mut names = Interner::new();
1290        let mut func = Func::new(names.intern("f"));
1291        let block = func.create_block();
1292        let param = func.append_param(block, GPR);
1293        let opcode = Opcode::new(names.intern("x64.nop"));
1294        func.build(block, opcode).uses(param, GPR).finish();
1295
1296        let _ = run(&mut func, &env());
1297    }
1298
1299    #[test]
1300    fn a_value_already_in_a_register_is_left_where_it_is() {
1301        let mut names = Interner::new();
1302        let mut func = Func::new(names.intern("f"));
1303        let opcode = Opcode::new(names.intern("x64.nop"));
1304        let block = func.create_block();
1305        let inst = func.build(block, opcode).uses(Reg::physical(RDX), GPR).finish();
1306
1307        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
1308        assert_eq!(operands(&func, inst), ["rdx"]);
1309    }
1310}