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