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 a fixed register turns into
59//!
60//! A move each way. The assignment deliberately gave the value some other register, so a division
61//! whose dividend has to be in `rax` gets a move into `rax` in front of it and a move out of `rax`
62//! behind it. That is the cost of the rule the assignment follows, and it is the rule that keeps
63//! the `-O0` allocator one pass.
64//!
65//! # What an edge turns into
66//!
67//! The moves that write the block's parameters, in an order they can be made in one at a time,
68//! which is what [`crate::moves`] is for. Where they go depends on the shape of the edge. A block
69//! with one successor puts them at its own end, in front of the branch it finishes with, and a
70//! block with several puts them at the start of the block the edge goes to, which is safe exactly
71//! because that block has no other predecessor. An edge that is critical has neither place to put
72//! them and has to have been split before allocation ran, which this checks rather than assumes.
73//!
74//! An edge is also the one place a value can be asked to go from one stack slot to another, which
75//! happens when a spilled value is passed to a parameter that was itself spilled. No machine here
76//! has that instruction, so the move goes through a register, and the register is a second scratch
77//! rather than the one the ordering may be holding a value in for the length of a cycle. Expanding
78//! it here rather than leaving it to the target is the same decision as everything else in this
79//! file: a move through a temporary is a fact about places, and which register is free to be the
80//! temporary is a fact only this crate has.
81
82use rucc_mir::{Block, Constraint, Func, Inst, Operand, Param, Reg};
83use rucc_target::{PhysReg, RegClass};
84
85use crate::assign::{Assignment, Env, Place};
86use crate::moves::{self, Move};
87
88/// One move the places did not already make true.
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub struct Edit {
91    /// Where in the function it goes.
92    pub at: At,
93    /// What it moves, and where to.
94    pub mov: Move<Place>,
95    /// The class both places are in, which is what says how wide the move is.
96    pub class: RegClass,
97}
98
99/// Where an edit goes.
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum At {
102    /// In front of an instruction, which is where a value it reads is put where it wants it.
103    Before(Inst),
104    /// Behind an instruction, which is where a value it wrote somewhere it insisted on is taken
105    /// away to where it lives.
106    After(Inst),
107    /// At the start of a block, in front of everything in it.
108    StartOf(Block),
109    /// At the end of a block, behind everything in it. Only ever a block with one edge out of
110    /// it, since a block with two puts an edge's moves at the start of the block it goes to.
111    EndOf(Block),
112}
113
114/// Rewrites a function to the places it was given, and says what moves are still wanted.
115///
116/// # Panics
117///
118/// Panics if the entry block has parameters, since there is no edge into it for their moves to go
119/// on and what arrives in a function is the ABI lowering's to say. Panics on a critical edge, on
120/// an edge carrying the wrong number of arguments, and if a class runs out of scratch registers
121/// for one instruction or has fewer than two on an edge that moves a spilled value into a spilled
122/// parameter, all of which are the caller handing it something it was told not to.
123#[must_use]
124pub fn rewrite(func: &mut Func, assignment: &Assignment, env: &Env) -> Vec<Edit> {
125    let blocks: Vec<Block> = func.blocks().collect();
126    assert!(
127        func.entry().is_none_or(|entry| func[entry].params.is_empty()),
128        "what arrives in a function is not a block parameter"
129    );
130
131    let mut edits = Vec::new();
132    for &block in &blocks {
133        let insts: Vec<Inst> = func.insts(block).collect();
134        for inst in insts {
135            instruction(func, assignment, env, inst, &mut edits);
136        }
137    }
138
139    let preds = preds(func, &blocks);
140    for &block in &blocks {
141        edges(func, assignment, env, block, &preds, &mut edits);
142    }
143    for &block in &blocks {
144        func.params_mut(block).clear();
145        for call in func.succs_mut(block) {
146            call.args.clear();
147        }
148    }
149    edits
150}
151
152/// Rewrites one instruction's operands, and says what has to happen either side of it.
153fn instruction(
154    func: &mut Func,
155    assignment: &Assignment,
156    env: &Env,
157    inst: Inst,
158    edits: &mut Vec<Edit>,
159) {
160    let list = func[inst].operands;
161    let mut operands: Vec<Operand> = func[list].to_vec();
162    let mut before: Vec<(Move<Place>, RegClass)> = Vec::new();
163    let mut after: Vec<(Move<Place>, RegClass)> = Vec::new();
164    let mut taken = Taken::new();
165
166    // Where the assignment put each operand's value, taken before anything is rewritten, since
167    // rewriting an operand is what loses that. The second pass below reads it.
168    let places: Vec<Place> =
169        operands.iter().map(|operand| place(assignment, operand.reg)).collect();
170
171    // A spilled operand that reuses another is left for the second pass, because where it goes
172    // depends on where the operand it reuses went and that is not known until every operand ahead
173    // of it has been placed.
174    let mut reusing: Vec<usize> = Vec::new();
175
176    for (index, operand) in operands.iter_mut().enumerate() {
177        let fixed = match operand.constraint {
178            Constraint::Fixed(at) => Some(at),
179            _ => None,
180        };
181        let at = match (place(assignment, operand.reg), fixed) {
182            (Place::Reg(at), None) => at,
183            (Place::Reg(at), Some(fixed)) => {
184                if at != fixed {
185                    let (there, here) = (Place::Reg(fixed), Place::Reg(at));
186                    push(&mut before, &mut after, operand, Move::new(there, here));
187                }
188                fixed
189            }
190            (Place::Slot(_), None) if matches!(operand.constraint, Constraint::Reuse(_)) => {
191                reusing.push(index);
192                continue;
193            }
194            (Place::Slot(slot), fixed) => {
195                // Which of the two jobs this register is for. An operand the instruction only
196                // writes wants one from the instruction onwards, and an operand it reads wants one
197                // from before the instruction until it reads it, so the same register does both
198                // and the two are counted apart.
199                let at = match fixed {
200                    Some(fixed) => fixed,
201                    None if operand.role.is_def() => taken.written_into(env, operand.class),
202                    None => taken.read_into(env, operand.class),
203                };
204                push(
205                    &mut before,
206                    &mut after,
207                    operand,
208                    Move::new(Place::Reg(at), Place::Slot(slot)),
209                );
210                at
211            }
212        };
213        operand.reg = Reg::physical(at);
214    }
215
216    for index in reusing {
217        let Constraint::Reuse(other) = operands[index].constraint else {
218            unreachable!("only an operand that reuses another was left for this pass")
219        };
220        let Place::Slot(slot) = places[index] else {
221            unreachable!("only a spilled operand was left for this pass")
222        };
223        // Where the operand it reuses was read into, if it was read into anywhere. A scratch
224        // register holds a copy of a value that lives on the stack, so writing over it destroys
225        // nothing and the instruction can have it. A register the assignment gave out is a
226        // different matter: the value in it may be wanted after the instruction, and the
227        // assignment only lets one be written over when it is not, which it says by giving the
228        // answer that register. So a fresh scratch register there, and the copy below fills it.
229        //
230        // Either way the instruction wants two of the class and no more. If the operand it reuses
231        // is on the stack then it is holding one of them already, and if it is not then it is not
232        // holding one at all.
233        //
234        // This one is asked for as a read even though the instruction writes it, because the copy
235        // that fills it goes in front of the instruction. It is live from there, which is the same
236        // span a value read in off the stack is live for, so it cannot share with one.
237        let other = usize::from(other);
238        let at = match places[other] {
239            Place::Slot(_) => phys(operands[other].reg),
240            Place::Reg(_) => taken.read_into(env, operands[index].class),
241        };
242        push(
243            &mut before,
244            &mut after,
245            &operands[index],
246            Move::new(Place::Reg(at), Place::Slot(slot)),
247        );
248        operands[index].reg = Reg::physical(at);
249    }
250
251    // A two address instruction writes one of the registers it reads, and the copy that makes that
252    // true goes after everything else in front of the instruction, since what it reads may be a
253    // value that was itself only just read in from the stack.
254    for index in 0..operands.len() {
255        let Constraint::Reuse(other) = operands[index].constraint else { continue };
256        let (to, from) = (operands[index], operands[usize::from(other)]);
257        if to.reg != from.reg {
258            let mov = Move::new(Place::Reg(phys(to.reg)), Place::Reg(phys(from.reg)));
259            before.push((mov, to.class));
260        }
261    }
262
263    func[list].copy_from_slice(&operands);
264    edits.extend(before.into_iter().map(|(mov, class)| Edit { at: At::Before(inst), mov, class }));
265    edits.extend(after.into_iter().map(|(mov, class)| Edit { at: At::After(inst), mov, class }));
266}
267
268/// How many scratch registers of each class one instruction has been handed, in each of the two
269/// jobs they do.
270///
271/// Counted per class rather than in one running number, because the classes hold their own back
272/// and an instruction reading a spilled value out of each of two files would otherwise skip the
273/// first register of the second file for no reason.
274///
275/// Counted per job as well, and that is the part that keeps two enough. A register a spilled value
276/// is read into is live from in front of the instruction until the instruction reads it. A
277/// register the instruction writes its answer into is live from the instruction until the store
278/// behind it. Those two spans do not meet, so one register does both jobs and the counting starts
279/// again rather than carrying on. What that rests on is the machine reading its operands before it
280/// writes its answer, which is true of every instruction the backends here emit and is the same
281/// thing that makes `addq %rax, %rax` mean what it looks like.
282///
283/// The alternative is holding a third register of each class back, and on this target there is no
284/// third to hold back. `r10` and `r11` are the two the SysV convention neither passes an argument
285/// in nor asks the callee to give back, and a scratch register has to be both, since the rewriter
286/// runs after the prologue has been decided and cannot ask for a register to be saved.
287#[derive(Debug, Default)]
288struct Taken {
289    /// How many of each class hold a value read in ahead of the instruction.
290    read: Vec<usize>,
291    /// How many of each class hold an answer the instruction writes.
292    written: Vec<usize>,
293}
294
295impl Taken {
296    /// Nothing handed out yet.
297    fn new() -> Self {
298        Self::default()
299    }
300
301    /// The next scratch register of a class for a value read in ahead of the instruction.
302    ///
303    /// # Panics
304    ///
305    /// Panics if the class has none left. See [`Self::take`].
306    fn read_into(&mut self, env: &Env, class: RegClass) -> PhysReg {
307        Self::take(&mut self.read, env, class)
308    }
309
310    /// The next scratch register of a class for an answer the instruction writes.
311    ///
312    /// # Panics
313    ///
314    /// Panics if the class has none left. See [`Self::take`].
315    fn written_into(&mut self, env: &Env, class: RegClass) -> PhysReg {
316        Self::take(&mut self.written, env, class)
317    }
318
319    /// The next scratch register of a class out of one of the two counts.
320    ///
321    /// # Panics
322    ///
323    /// Panics if the class has none left, which is an instruction wanting more registers for one
324    /// of the two jobs than the target held back. Two is enough for both, since an instruction
325    /// reads at most two values and writes at most one answer that is not one of them.
326    fn take(counts: &mut Vec<usize>, env: &Env, class: RegClass) -> PhysReg {
327        let index = usize::from(class.number());
328        if counts.len() <= index {
329            counts.resize(index + 1, 0);
330        }
331        let scratch = *env
332            .scratch(class)
333            .get(counts[index])
334            .expect("an instruction wanting more scratch registers than the class has");
335        counts[index] += 1;
336        scratch
337    }
338}
339
340/// Files a move in front of the instruction or behind it, and turns it round for a value the
341/// instruction writes, since that one travels the other way.
342fn push(
343    before: &mut Vec<(Move<Place>, RegClass)>,
344    after: &mut Vec<(Move<Place>, RegClass)>,
345    operand: &Operand,
346    mov: Move<Place>,
347) {
348    if operand.role.is_def() {
349        after.push((Move::new(mov.from, mov.to), operand.class));
350    } else {
351        before.push((mov, operand.class));
352    }
353}
354
355/// The moves the edges out of a block turn into.
356fn edges(
357    func: &mut Func,
358    assignment: &Assignment,
359    env: &Env,
360    block: Block,
361    preds: &[usize],
362    edits: &mut Vec<Edit>,
363) {
364    let succs = func[block].succs.clone();
365    let single = succs.len() == 1;
366    for call in &succs {
367        let params = func[call.block].params.clone();
368        assert_eq!(
369            params.len(),
370            call.args.len(),
371            "an edge carries what the block it goes to asks for"
372        );
373        if params.is_empty() {
374            continue;
375        }
376        assert!(
377            single || preds[call.block.index()] == 1,
378            "a critical edge has nowhere to put its moves and has to be split before allocation"
379        );
380        let at = if single { At::EndOf(block) } else { At::StartOf(call.block) };
381        edits.extend(edge(assignment, env, &params, &call.args, at));
382    }
383}
384
385/// The moves one edge turns into, in the order they can be made in.
386fn edge(assignment: &Assignment, env: &Env, params: &[Param], args: &[Reg], at: At) -> Vec<Edit> {
387    let mut classes: Vec<RegClass> = params.iter().map(|param| param.class).collect();
388    classes.sort_unstable();
389    classes.dedup();
390
391    let mut edits = Vec::new();
392    for class in classes {
393        // One class at a time, because a scratch register is per class and a value never crosses
394        // from one to another on an edge.
395        let parallel: Vec<Move<Place>> = params
396            .iter()
397            .zip(args)
398            .filter(|(param, _)| param.class == class)
399            .map(|(param, &arg)| Move::new(place(assignment, param.reg), place(assignment, arg)))
400            .collect();
401        let scratch = env.scratch(class);
402        let cycle = *scratch
403            .first()
404            .expect("a class whose values are passed on an edge and which has no scratch register");
405        for mov in moves::sequence(&parallel, Place::Reg(cycle)) {
406            match (mov.to, mov.from) {
407                // No machine here moves one piece of memory into another, so the value goes
408                // through a register, and it is a second scratch rather than the one the ordering
409                // above may be holding a value in for the length of a cycle.
410                (Place::Slot(_), Place::Slot(_)) => {
411                    let through = Place::Reg(*scratch.get(1).expect(
412                        "a class passing a spilled value to a spilled parameter and having only \
413                         one scratch register",
414                    ));
415                    edits.push(Edit { at, mov: Move::new(through, mov.from), class });
416                    edits.push(Edit { at, mov: Move::new(mov.to, through), class });
417                }
418                _ => edits.push(Edit { at, mov, class }),
419            }
420        }
421    }
422    edits
423}
424
425/// How many edges arrive in each block.
426fn preds(func: &Func, blocks: &[Block]) -> Vec<usize> {
427    let mut preds = vec![0; func.block_count()];
428    for &block in blocks {
429        for call in &func[block].succs {
430            preds[call.block.index()] += 1;
431        }
432    }
433    preds
434}
435
436/// Where a register is, whether the allocator put it there or it was already somewhere.
437fn place(assignment: &Assignment, reg: Reg) -> Place {
438    assignment.place(reg).unwrap_or_else(|| Place::Reg(phys(reg)))
439}
440
441/// The physical register a register is, once it has to be one.
442fn phys(reg: Reg) -> PhysReg {
443    reg.phys().expect("a register the assignment says nothing about and that is not a register")
444}
445
446#[cfg(test)]
447mod tests {
448    use rucc_base::Interner;
449    use rucc_mir::{BlockCall, Opcode};
450    use rucc_target::x86_64::{GPR, RAX, RDX, REGS, SYSV, XMM};
451
452    use super::*;
453    use crate::assign::assign;
454    use crate::live::Live;
455    use crate::order::Order;
456
457    /// The x86-64 environment, with the last three of the allocation order held back as scratch.
458    fn env() -> Env {
459        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
460        Env::new().with(GPR, order, scratch)
461    }
462
463    /// An environment with that many general purpose registers and one scratch after them.
464    fn narrow(count: usize) -> Env {
465        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 2])
466    }
467
468    /// What a place is called, which is what an assertion reads.
469    ///
470    /// The class comes in because a register is a number within its class and the two files here
471    /// number from zero, so nothing but the class tells `rcx` from `xmm1`.
472    fn named(class: RegClass, place: Place) -> String {
473        match place {
474            Place::Reg(reg) => REGS.name(class, reg).expect("a register").to_string(),
475            Place::Slot(slot) => format!("slot{slot}"),
476        }
477    }
478
479    /// Runs both halves and reports the edits as lines an assertion can read.
480    fn run(func: &mut Func, env: &Env) -> Vec<String> {
481        let order = Order::of(func);
482        let live = Live::of(func, &order);
483        let assignment = assign(func, &order, &live, env);
484        rewrite(func, &assignment, env)
485            .into_iter()
486            .map(|edit| {
487                let at = match edit.at {
488                    At::Before(inst) => format!("before {}", inst.index()),
489                    At::After(inst) => format!("after {}", inst.index()),
490                    At::StartOf(block) => format!("start of {}", block.index()),
491                    At::EndOf(block) => format!("end of {}", block.index()),
492                };
493                format!(
494                    "{at}: {} = {}",
495                    named(edit.class, edit.mov.to),
496                    named(edit.class, edit.mov.from)
497                )
498            })
499            .collect()
500    }
501
502    /// The registers an instruction's operands ended up naming.
503    fn operands(func: &Func, inst: Inst) -> Vec<String> {
504        func[func[inst].operands]
505            .iter()
506            .map(|operand| named(operand.class, Place::Reg(phys(operand.reg))))
507            .collect()
508    }
509
510    #[test]
511    fn every_operand_ends_up_naming_the_register_its_value_was_given() {
512        let mut names = Interner::new();
513        let mut func = Func::new(names.intern("f"));
514        let opcode = Opcode::new(names.intern("x64.nop"));
515        let block = func.create_block();
516        let first = func.new_vreg(GPR);
517        let second = func.new_vreg(GPR);
518        func.build(block, opcode).def(first, GPR).finish();
519        func.build(block, opcode).def(second, GPR).finish();
520        let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
521
522        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
523        assert_eq!(operands(&func, read), ["rax", "rcx"]);
524    }
525
526    #[test]
527    fn a_register_an_instruction_insists_on_costs_nothing_when_the_values_can_have_it() {
528        let mut names = Interner::new();
529        let mut func = Func::new(names.intern("f"));
530        let opcode = Opcode::new(names.intern("x64.nop"));
531        let block = func.create_block();
532        let dividend = func.new_vreg(GPR);
533        let quotient = func.new_vreg(GPR);
534        func.build(block, opcode).def(dividend, GPR).finish();
535        let divide = func
536            .build(block, opcode)
537            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
538            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
539            .finish();
540        func.build(block, opcode).uses(quotient, GPR).finish();
541
542        // Nothing either side of the division. The dividend is read out of `rax` for the last
543        // time and the quotient is written into it afterwards, so both of them live there and the
544        // moves that used to carry the value in and the answer out are not written.
545        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
546        assert_eq!(operands(&func, divide), ["rax", "rax"]);
547    }
548
549    #[test]
550    fn a_register_an_instruction_insists_on_is_moved_into_when_the_value_cannot_have_it() {
551        let mut names = Interner::new();
552        let mut func = Func::new(names.intern("f"));
553        let opcode = Opcode::new(names.intern("x64.nop"));
554        let block = func.create_block();
555        let dividend = func.new_vreg(GPR);
556        let quotient = func.new_vreg(GPR);
557        func.build(block, opcode).def(dividend, GPR).finish();
558        let divide = func
559            .build(block, opcode)
560            .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
561            .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
562            .finish();
563        func.build(block, opcode).uses(quotient, GPR).finish();
564        func.build(block, opcode).uses(dividend, GPR).finish();
565
566        // This time the dividend is wanted after the division, so it cannot be in the register the
567        // division writes and the value is moved in. The answer still comes out of `rax` without
568        // a move, which is the half of it the hint bought.
569        assert_eq!(run(&mut func, &env()), ["before 1: rax = rcx"]);
570        assert_eq!(operands(&func, divide), ["rax", "rax"]);
571    }
572
573    #[test]
574    fn a_two_address_instruction_that_did_not_get_its_register_copies_first() {
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 left = func.new_vreg(GPR);
580        let right = func.new_vreg(GPR);
581        let sum = func.new_vreg(GPR);
582        func.build(block, opcode).def(left, GPR).finish();
583        func.build(block, opcode).def(right, GPR).finish();
584        let add = func
585            .build(block, opcode)
586            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
587            .uses(left, GPR)
588            .uses(right, GPR)
589            .finish();
590        func.build(block, opcode).uses(left, GPR).finish();
591
592        // The left value is wanted afterwards, so the answer could not have its register and the
593        // copy in front of the addition is what makes the instruction two address.
594        assert_eq!(run(&mut func, &env()), ["before 2: rdx = rax"]);
595        assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
596    }
597
598    #[test]
599    fn a_two_address_instruction_that_did_get_its_register_copies_nothing() {
600        let mut names = Interner::new();
601        let mut func = Func::new(names.intern("f"));
602        let opcode = Opcode::new(names.intern("x64.nop"));
603        let block = func.create_block();
604        let left = func.new_vreg(GPR);
605        let right = func.new_vreg(GPR);
606        let sum = func.new_vreg(GPR);
607        func.build(block, opcode).def(left, GPR).finish();
608        func.build(block, opcode).def(right, GPR).finish();
609        let add = func
610            .build(block, opcode)
611            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
612            .uses(left, GPR)
613            .uses(right, GPR)
614            .finish();
615        func.build(block, opcode).uses(right, GPR).finish();
616
617        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
618        assert_eq!(operands(&func, add), ["rax", "rax", "rcx"]);
619    }
620
621    #[test]
622    fn a_spilled_value_is_read_into_a_scratch_register_at_each_instruction_that_wants_it() {
623        let mut names = Interner::new();
624        let mut func = Func::new(names.intern("f"));
625        let opcode = Opcode::new(names.intern("x64.nop"));
626        let block = func.create_block();
627        let first = func.new_vreg(GPR);
628        let second = func.new_vreg(GPR);
629        func.build(block, opcode).def(first, GPR).finish();
630        func.build(block, opcode).def(second, GPR).finish();
631        let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
632
633        // One register between two values, so one of them goes to the stack. It is written there
634        // where it is computed and read back where it is wanted, and both ends of that go through
635        // the scratch register that is held out of the allocation order for exactly this.
636        assert_eq!(run(&mut func, &narrow(1)), ["after 1: slot0 = rcx", "before 2: rcx = slot0"]);
637        assert_eq!(operands(&func, read), ["rax", "rcx"]);
638    }
639
640    /// A two address instruction with nothing in a register is two scratch registers and not three.
641    ///
642    /// The answer has no register of its own to be in, so what it is written into is whichever one
643    /// the operand it reuses was read into, and it is stored away from there afterwards. Handing it
644    /// a scratch register of its own would want a third, and a class holds two back, which is issue
645    /// #350: a program with enough live values around a call reached it and the compiler aborted.
646    #[test]
647    fn a_two_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
648        let mut names = Interner::new();
649        let mut func = Func::new(names.intern("f"));
650        let opcode = Opcode::new(names.intern("x64.nop"));
651        let block = func.create_block();
652        let keeper = func.new_vreg(GPR);
653        let left = func.new_vreg(GPR);
654        let right = func.new_vreg(GPR);
655        let sum = func.new_vreg(GPR);
656        func.build(block, opcode).def(keeper, GPR).finish();
657        func.build(block, opcode)
658            .operand(Operand::write(left, GPR).with(Constraint::Stack))
659            .finish();
660        func.build(block, opcode)
661            .operand(Operand::write(right, GPR).with(Constraint::Stack))
662            .finish();
663        let add = func
664            .build(block, opcode)
665            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
666            .uses(left, GPR)
667            .uses(right, GPR)
668            .finish();
669        func.build(block, opcode).uses(keeper, GPR).finish();
670        func.build(block, opcode).uses(sum, GPR).finish();
671
672        // Both operands are read in, the answer is written into the register the operand it
673        // reuses arrived in, and it is stored away from there. Two scratch registers, which is
674        // what the class holds back. Asking for one of its own would be a third and would abort.
675        assert_eq!(
676            run(&mut func, &narrow(1)),
677            [
678                "after 1: slot0 = rcx",
679                "after 2: slot1 = rcx",
680                "before 3: rcx = slot0",
681                "before 3: rdx = slot1",
682                "after 3: slot2 = rcx",
683                "before 5: rcx = slot2",
684            ]
685        );
686        assert_eq!(operands(&func, add), ["rcx", "rcx", "rdx"]);
687    }
688
689    /// A three address instruction with nothing in a register is two scratch registers, not three.
690    ///
691    /// The case #726 aborted on. `x64.lea_64` and the `x64.cmp_set_*` family read two values and
692    /// write a third that is neither of them, and when all three ends are on the stack there are
693    /// three operands wanting a register at one instruction. Counting them in one running number
694    /// asks for a third scratch register and the class holds two back.
695    ///
696    /// Two is enough because the answer's register is not wanted until the instruction writes it,
697    /// by which time the registers the operands were read into have been read. So the answer goes
698    /// back into the first of them and is stored away from there.
699    #[test]
700    fn a_three_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
701        let mut names = Interner::new();
702        let mut func = Func::new(names.intern("f"));
703        let opcode = Opcode::new(names.intern("x64.nop"));
704        let block = func.create_block();
705        let keeper = func.new_vreg(GPR);
706        let base = func.new_vreg(GPR);
707        let index = func.new_vreg(GPR);
708        let address = func.new_vreg(GPR);
709        func.build(block, opcode).def(keeper, GPR).finish();
710        func.build(block, opcode)
711            .operand(Operand::write(base, GPR).with(Constraint::Stack))
712            .finish();
713        func.build(block, opcode)
714            .operand(Operand::write(index, GPR).with(Constraint::Stack))
715            .finish();
716        let lea =
717            func.build(block, opcode).def(address, GPR).uses(base, GPR).uses(index, GPR).finish();
718        func.build(block, opcode).uses(keeper, GPR).finish();
719        func.build(block, opcode).uses(address, GPR).finish();
720
721        // Both operands are read in, the answer is written into the first of the two registers
722        // they arrived in, and it is stored away from there. Two, which is what the class holds.
723        assert_eq!(
724            run(&mut func, &narrow(1)),
725            [
726                "after 1: slot0 = rcx",
727                "after 2: slot1 = rcx",
728                "before 3: rcx = slot0",
729                "before 3: rdx = slot1",
730                "after 3: slot2 = rcx",
731                "before 5: rcx = slot2",
732            ]
733        );
734        assert_eq!(operands(&func, lea), ["rcx", "rcx", "rdx"]);
735    }
736
737    /// A spilled answer takes a scratch register where the operand it reuses is in a real one.
738    ///
739    /// The value in that register may be wanted after the instruction, and the assignment is the
740    /// only thing that knows whether it is. It says so by giving the answer that register, and here
741    /// it did not, so writing over it would destroy a value. The count still comes to two, because
742    /// an operand that is in a register is not holding a scratch register.
743    #[test]
744    fn a_spilled_answer_does_not_write_over_a_register_the_assignment_gave_to_something_else() {
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 block = func.create_block();
749        let left = func.new_vreg(GPR);
750        let right = func.new_vreg(GPR);
751        let sum = func.new_vreg(GPR);
752        func.build(block, opcode).def(left, GPR).finish();
753        func.build(block, opcode)
754            .operand(Operand::write(right, GPR).with(Constraint::Stack))
755            .finish();
756        let add = func
757            .build(block, opcode)
758            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
759            .uses(left, GPR)
760            .uses(right, GPR)
761            .finish();
762        func.build(block, opcode).uses(left, GPR).finish();
763        func.build(block, opcode).uses(sum, GPR).finish();
764
765        // The left value is in `rax` and is read again afterwards, so the answer is copied into a
766        // scratch register and written there instead.
767        assert_eq!(
768            run(&mut func, &narrow(1)),
769            [
770                "after 1: slot0 = rcx",
771                "before 2: rcx = slot0",
772                "before 2: rdx = rax",
773                "after 2: slot1 = rdx",
774                "before 4: rcx = slot1",
775            ]
776        );
777        assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
778    }
779
780    /// The count of scratch registers handed out is per class and not one number for all of them.
781    ///
782    /// An instruction reading a spilled value out of each of two files wants the first register of
783    /// each, since the files hold their own back and nothing on the instruction is in the other's.
784    #[test]
785    fn an_instruction_reading_out_of_two_files_takes_the_first_scratch_register_of_each() {
786        let mut names = Interner::new();
787        let mut func = Func::new(names.intern("f"));
788        let opcode = Opcode::new(names.intern("x64.nop"));
789        let block = func.create_block();
790        let integer = func.new_vreg(GPR);
791        let number = func.new_vreg(XMM);
792        let spare = func.new_vreg(GPR);
793        let other = func.new_vreg(XMM);
794        func.build(block, opcode).def(integer, GPR).finish();
795        func.build(block, opcode).def(number, XMM).finish();
796        func.build(block, opcode).def(spare, GPR).finish();
797        func.build(block, opcode).def(other, XMM).finish();
798        func.build(block, opcode).uses(integer, GPR).uses(number, XMM).finish();
799        let read = func.build(block, opcode).uses(spare, GPR).uses(other, XMM).finish();
800
801        // One register in each file, so the value of each that is wanted later goes to the stack
802        // and is read back at the instruction that wants it.
803        let env = Env::new().with(GPR, &SYSV.int_order[..1], &SYSV.int_order[1..3]).with(
804            XMM,
805            &SYSV.sse_order[..1],
806            &SYSV.sse_order[1..3],
807        );
808        assert_eq!(
809            run(&mut func, &env),
810            [
811                "after 2: slot0 = rcx",
812                "after 3: slot1 = xmm1",
813                "before 5: rcx = slot0",
814                "before 5: xmm1 = slot1",
815            ]
816        );
817        assert_eq!(operands(&func, read), ["rcx", "xmm1"]);
818    }
819
820    #[test]
821    fn an_edge_out_of_a_block_with_one_way_to_go_moves_at_the_end_of_it() {
822        let mut names = Interner::new();
823        let mut func = Func::new(names.intern("f"));
824        let opcode = Opcode::new(names.intern("x64.nop"));
825        let head = func.create_block();
826        let tail = func.create_block();
827        let held = func.new_vreg(GPR);
828        let carried = func.new_vreg(GPR);
829        func.build(head, opcode).def(held, GPR).finish();
830        func.build(head, opcode).def(carried, GPR).finish();
831        func.build(head, opcode).uses(held, GPR).finish();
832        let param = func.append_param(tail, GPR);
833        *func.succs_mut(head) = vec![BlockCall::with(tail, vec![carried])];
834        let read = func.build(tail, opcode).uses(param, GPR).finish();
835
836        // The value the edge carries is in the second register, because the first was busy where
837        // the value was written, and the parameter it arrives as is in the first, because by then
838        // it is not. So the edge is a move, and it goes at the end of the block it leaves.
839        assert_eq!(run(&mut func, &env()), ["end of 0: rax = rcx"]);
840        assert_eq!(operands(&func, read), ["rax"]);
841        // Nothing arrives in a block any more and no edge carries anything, which is where SSA
842        // form stops.
843        assert!(func[tail].params.is_empty());
844        assert!(func[head].succs[0].args.is_empty());
845    }
846
847    #[test]
848    fn an_edge_out_of_a_block_with_a_choice_moves_at_the_start_of_where_it_goes() {
849        let mut names = Interner::new();
850        let mut func = Func::new(names.intern("f"));
851        let opcode = Opcode::new(names.intern("x64.nop"));
852        let head = func.create_block();
853        let left = func.create_block();
854        let right = func.create_block();
855        let held = func.new_vreg(GPR);
856        let carried = func.new_vreg(GPR);
857        func.build(head, opcode).def(held, GPR).finish();
858        func.build(head, opcode).def(carried, GPR).finish();
859        func.build(head, opcode).uses(held, GPR).finish();
860        let taken = func.append_param(left, GPR);
861        *func.succs_mut(head) = vec![BlockCall::with(left, vec![carried]), BlockCall::to(right)];
862        func.build(left, opcode).uses(taken, GPR).finish();
863
864        // The move cannot go at the end of the block it leaves, because the other way out of that
865        // block does not want it. It goes at the start of the block it arrives in, which is safe
866        // because nothing else arrives there.
867        assert_eq!(run(&mut func, &env()), ["start of 1: rax = rcx"]);
868    }
869
870    #[test]
871    fn two_values_that_swap_on_an_edge_get_an_order_and_a_scratch_register() {
872        let mut names = Interner::new();
873        let mut func = Func::new(names.intern("f"));
874        let opcode = Opcode::new(names.intern("x64.nop"));
875        let head = func.create_block();
876        let body = func.create_block();
877        let first = func.new_vreg(GPR);
878        let second = func.new_vreg(GPR);
879        func.build(head, opcode).def(first, GPR).finish();
880        func.build(head, opcode).def(second, GPR).finish();
881        let left = func.append_param(body, GPR);
882        let right = func.append_param(body, GPR);
883        *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
884        func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
885        *func.succs_mut(body) = vec![BlockCall::with(body, vec![right, left])];
886
887        // The loop hands each value back the other way round, which is the case no order of two
888        // moves answers, so one of them goes through the scratch register. The edge into the loop
889        // moves nothing, because each value is already where the parameter it feeds lives.
890        assert_eq!(
891            run(&mut func, &env()),
892            ["end of 1: r13 = rcx", "end of 1: rcx = rax", "end of 1: rax = r13"]
893        );
894    }
895
896    #[test]
897    fn a_spilled_value_handed_to_a_spilled_parameter_goes_through_a_register() {
898        let mut names = Interner::new();
899        let mut func = Func::new(names.intern("f"));
900        let opcode = Opcode::new(names.intern("x64.nop"));
901        let head = func.create_block();
902        let body = func.create_block();
903        let first = func.new_vreg(GPR);
904        let second = func.new_vreg(GPR);
905        func.build(head, opcode).def(first, GPR).finish();
906        func.build(head, opcode).def(second, GPR).finish();
907        let left = func.append_param(body, GPR);
908        let right = func.append_param(body, GPR);
909        *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
910        func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
911
912        // One register between the values and the parameters, so a value on the stack is handed to
913        // a parameter on the stack, and no machine here has that instruction. It goes through the
914        // second scratch register rather than the first, which is the one the ordering above is
915        // entitled to be holding a value in.
916        assert_eq!(
917            run(&mut func, &narrow(1)),
918            [
919                "after 1: slot0 = rcx",
920                "before 2: rcx = slot1",
921                "end of 0: rdx = slot0",
922                "end of 0: slot1 = rdx",
923            ]
924        );
925    }
926
927    #[test]
928    #[should_panic(expected = "a critical edge has nowhere to put its moves")]
929    fn a_critical_edge_is_refused() {
930        let mut names = Interner::new();
931        let mut func = Func::new(names.intern("f"));
932        let opcode = Opcode::new(names.intern("x64.nop"));
933        let head = func.create_block();
934        let other = func.create_block();
935        let join = func.create_block();
936        let value = func.new_vreg(GPR);
937        func.build(head, opcode).def(value, GPR).finish();
938        let param = func.append_param(join, GPR);
939        *func.succs_mut(head) = vec![BlockCall::with(join, vec![value]), BlockCall::to(other)];
940        *func.succs_mut(other) = vec![BlockCall::with(join, vec![value])];
941        func.build(join, opcode).uses(param, GPR).finish();
942
943        let _ = run(&mut func, &env());
944    }
945
946    #[test]
947    #[should_panic(expected = "what arrives in a function is not a block parameter")]
948    fn a_parameter_on_the_entry_block_is_refused() {
949        let mut names = Interner::new();
950        let mut func = Func::new(names.intern("f"));
951        let block = func.create_block();
952        let param = func.append_param(block, GPR);
953        let opcode = Opcode::new(names.intern("x64.nop"));
954        func.build(block, opcode).uses(param, GPR).finish();
955
956        let _ = run(&mut func, &env());
957    }
958
959    #[test]
960    fn a_value_already_in_a_register_is_left_where_it_is() {
961        let mut names = Interner::new();
962        let mut func = Func::new(names.intern("f"));
963        let opcode = Opcode::new(names.intern("x64.nop"));
964        let block = func.create_block();
965        let inst = func.build(block, opcode).uses(Reg::physical(RDX), GPR).finish();
966
967        assert_eq!(run(&mut func, &env()), Vec::<String>::new());
968        assert_eq!(operands(&func, inst), ["rdx"]);
969    }
970}