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