Skip to main content

rucc_regalloc/
backtrack.rs

1//! Which register each value lives in, decided in the order the values are hardest to place, and
2//! undone when a value that would cost more to lose finds its register taken.
3//!
4//! Design: `spec/optimizer/39-register-allocation.md` section 39.7, and tamnd/rucc#1177.
5//!
6//! [`crate::assign`] is the `-O0` answer. It walks the line once, and when it runs out of
7//! registers the value that goes to the stack is the one whose range ends last. That is a guess
8//! about cost made from a fact about length, and it is wrong exactly where it matters: a value read
9//! in every turn of a loop and wanted again after the loop ends last, so it is the one that goes,
10//! and every turn of the loop pays a load for it.
11//!
12//! This answers the same question with the cost in it. Every value gets a weight, which is how
13//! often it is read or written, each time counted by how often the block it happens in runs, over
14//! how much of the function it is live across. A value with a high weight is one that would cost
15//! a lot to keep in memory for little register in return, and that is the one to keep.
16//!
17//! # The order values are placed in
18//!
19//! Longest first. A long value meets more of the others than a short one does, so it has the
20//! fewest registers to choose from, and giving it first choice is what leaves the short ones
21//! something to fit into. That is the order LLVM's greedy allocator takes them in, for the same
22//! reason.
23//!
24//! # Backtracking
25//!
26//! Going longest first means a long cold value takes a register before a short hot one has been
27//! looked at. When the hot one comes and finds nothing free, it asks what it would cost to take a
28//! register back. For each register the answer is the values in it that are in the way, and the
29//! register can be taken when every one of them weighs less than the value asking. Of the
30//! registers that can, the one taken is the one whose heaviest value in the way is lightest. The
31//! values that lose it go back in the queue and look for another register, and a value that has
32//! lost one [`ROUNDS`] times goes to the stack instead of looking again.
33//!
34//! That rule is also why it stops. A value only ever takes a register from values lighter than
35//! itself, and each value is put back a bounded number of times.
36//!
37//! # What it keeps from the linear scan
38//!
39//! Everything that says what a register may hold. The registers an instruction insists on, the
40//! values an instruction can only read from memory, the two address instructions and the hints
41//! are all read the way [`crate::assign`] reads them, from the same functions, so the two
42//! allocators cannot disagree about what the machine allows. They only disagree about who gets
43//! the register, and [`crate::check`] asks the same questions of either answer.
44//!
45//! A two address instruction is coalesced from both ends here. The linear scan only ever meets the
46//! answer after its source, since the source is written first. Here either can be placed first, so
47//! a source looks at where the answer that reuses it went as well as the other way round. That
48//! goes for the second source of an instruction that reads its sources either way round too: it
49//! can follow an answer placed before it by having the sources swapped, when the first source is
50//! wanted after the instruction and so can never be where the answer goes. A loaded value added to
51//! a base the loop reads again is that case.
52//!
53//! # When it gives up
54//!
55//! Every question of whether two values are both wanted is counted, and a function that asks more
56//! than [`BUDGET`] of them is handed to the linear scan instead. The answer is worse and it comes
57//! out in time, which is what the section asks of a pathological function. It is a count of work
58//! rather than of values because a function with many short values that never meet is cheap
59//! however many there are.
60//!
61//! # What the spill phase adds
62//!
63//! It runs twice when [`crate::pressure`] finds a point with more values live than registers. Once
64//! as above, where a value goes to the stack only when the queue reaches it and it can take no
65//! register back, and once with the values [`crate::spill`] picked sent to the stack before the
66//! queue starts. The first is better where the pressure is brief and eviction settles it in a few
67//! moves. The second is better where it is long, since the values that go are picked by weight
68//! across every point that is over rather than by which one the queue met last. Neither wins
69//! everywhere, so both are costed.
70//!
71//! A value sent ahead still gets the offer described next, once every other value has a register.
72//! Before it did not, so where the second try won, a value the tuple deforming loop reads in every
73//! turn stayed on the stack while a register the `strlen` call destroys sat unused all through the
74//! function.
75//!
76//! # Putting a value away around a call
77//!
78//! A value wanted on the far side of a call cannot be in a register the call destroys, so it has
79//! the callee saved ones or the stack. Where the call is somewhere the loop only goes now and then,
80//! like the `strlen` a tuple deforming loop makes for a `cstring` column, every value the loop
81//! carries is wanted across it, the callee saved registers run out, and the rest are read from the
82//! stack in every turn while the registers the call destroys sit empty. tamnd/rucc#1177.
83//!
84//! So a value that would go to the stack is first offered a register whose only problem is the
85//! instructions that destroy it. It takes the one where that costs least, and the rewrite puts it
86//! away in a slot in front of each of those instructions and brings it back behind it. That is a
87//! store and a load for each, counted by how often its block runs, and it is only done when that is
88//! less than what the value would cost on the stack, which is a load or a store at every read and
89//! write. A value read in a hot loop around a cold call is the case it wins, and a value read once
90//! around a call in the same loop is the case it does not.
91//!
92//! It also gives up when it would lose. The linear scan runs as well, which is cheap next to this,
93//! and the answer kept is the one with the lower [`cost`]: the loads and stores of the values on
94//! the stack and the copies between the ends of each tie left apart, each counted by how often its
95//! block runs. Placing the long values first is right where registers are fought over in a loop,
96//! and it can be worse in a long straight run of arithmetic, where the order the linear scan walks
97//! in is also the order that lets each answer follow its source.
98
99use std::cmp::Reverse;
100use std::collections::BinaryHeap;
101
102use rucc_base::hash::{Map, Set};
103use rucc_mir::{Func, Inst, Reg};
104use rucc_target::{PhysReg, RegClass};
105
106use crate::assign::{self, Assignment, Blocks, Env, FEW, Pieces, Place, Reuse, Want};
107use crate::live::{Area, Live, Range};
108use crate::order::{Order, Point};
109use crate::pressure::Pressure;
110use crate::spill;
111
112/// How many questions of whether two values are both wanted a function may ask before it is handed
113/// to the linear scan.
114pub const BUDGET: u64 = 50_000_000;
115
116/// How many times a value may lose its register and look for another before it goes to the stack.
117pub const ROUNDS: u32 = 4;
118
119/// One value, as the queue sees it.
120#[derive(Debug, Clone, Copy)]
121struct Value<'a> {
122    reg: Reg,
123    class: RegClass,
124    area: Area<'a>,
125    range: Range,
126    weight: u128,
127    size: u32,
128}
129
130/// Where every value goes, in the order that places the hard ones first and takes a register back
131/// when a heavier value wants it.
132///
133/// A function that asks more than [`BUDGET`] questions gets the linear scan's answer instead, and
134/// so does one where the linear scan's answer has the lower [`cost`].
135#[must_use]
136pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
137    let linear = assign::assign(func, order, live, env);
138    let mut best = cost(func, order, &linear);
139    let mut kept = linear;
140    let pressure = Pressure::of(func, order, live, env);
141    let spilled = spill::choose(func, live, &pressure);
142    // With nothing sent ahead the second try would be the first one again.
143    let tries: &[&[Reg]] = if spilled.is_empty() { &[&[]] } else { &[&[], &spilled] };
144    for &early in tries {
145        let Some(ours) = placed(func, order, live, env, BUDGET, early) else { break };
146        let spent = cost(func, order, &ours);
147        if spent <= best {
148            best = spent;
149            kept = ours;
150        }
151    }
152    kept
153}
154
155/// What an assignment is expected to cost a function, in instructions each counted by how often
156/// its block runs.
157///
158/// A value on the stack costs a load or a store every time it is read or written. A two address
159/// instruction whose answer is not where its source is costs the copy between them, and so does a
160/// block parameter that is not where the value passed to it is. Moves the machine needs whatever
161/// the assignment, like those into the registers a call insists on, are left out, since they are
162/// the same for any answer.
163///
164/// # Panics
165///
166/// Panics on a function with more values than a register number can name, as
167/// [`Reg::virtual_reg`] does.
168#[must_use]
169pub fn cost(func: &Func, order: &Order, assignment: &Assignment) -> u128 {
170    let costs = costs(func);
171    let mut total = 0;
172    for (reg, place) in assignment.placed() {
173        if !matches!(place, Place::Reg(_)) {
174            total += costs[index(reg)];
175        }
176    }
177    let mut weights = Map::default();
178    for block in func.blocks() {
179        let weight = u128::from(func[block].weight.raw().max(1));
180        for inst in func.insts(block) {
181            weights.insert(inst, weight);
182        }
183        for call in &func[block].succs {
184            for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
185                if assignment.place(arg) != assignment.place(param.reg) {
186                    total += weight;
187                }
188            }
189        }
190    }
191    for save in assignment.saves() {
192        total += 2 * weights.get(&save.inst).copied().unwrap_or(1);
193    }
194    let commuted: Set<Inst> = assignment.commuted().iter().copied().collect();
195    for (number, reuse) in assign::reuses(func, order).iter().enumerate() {
196        let Some(reuse) = reuse else { continue };
197        let answer = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
198        let tied = if commuted.contains(&reuse.inst) { reuse.second } else { Some(reuse.source) };
199        let Some(at) = assignment.place(answer) else { continue };
200        if tied.and_then(|tied| assignment.place(tied)) != Some(at) {
201            total += weights.get(&reuse.inst).copied().unwrap_or(1);
202        }
203    }
204    total
205}
206
207/// The same, with the budget said, or `None` for a function that went over it.
208///
209/// # Panics
210///
211/// Panics on a value in a class the environment hands out no registers from, as the linear scan
212/// does.
213#[must_use]
214pub fn within(
215    func: &Func,
216    order: &Order,
217    live: &Live,
218    env: &Env,
219    budget: u64,
220) -> Option<Assignment> {
221    placed(func, order, live, env, budget, &[])
222}
223
224fn placed(
225    func: &Func,
226    order: &Order,
227    live: &Live,
228    env: &Env,
229    budget: u64,
230    early: &[Reg],
231) -> Option<Assignment> {
232    let blocked = assign::blocked(func, order);
233    let forced = assign::forced(func);
234    let reuses = assign::reuses(func, order);
235    let hints = assign::hints(func);
236    let passed = assign::passed(func);
237    let received = received(func);
238    let reused = reused(&reuses);
239    let seconds = seconds(&reuses);
240    let costs = costs(func);
241    let saveable = saveable(func, order);
242
243    let count = func.vregs();
244    let mut values: Vec<Option<Value<'_>>> = vec![None; count];
245    let mut queue = BinaryHeap::new();
246    for (number, reuse) in reuses.iter().enumerate() {
247        let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
248        let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
249            continue;
250        };
251        if let Some(reuse) = reuse {
252            area = area.with(reuse.at);
253        }
254        let size = size(area);
255        let weight = costs[number] * 1024 / u128::from(size + 8);
256        values[number] = Some(Value { reg, class, area, range: area.hull(), weight, size });
257        queue.push((size, Reverse(number)));
258    }
259
260    let mut state = State {
261        live,
262        blocked: &blocked,
263        reuses: &reuses,
264        values: &values,
265        held: Vec::new(),
266        pieces: Vec::new(),
267        at: vec![None; count],
268        commuted: vec![None; count],
269        saves: vec![Vec::new(); count],
270        work: 0,
271        budget,
272        asked: (None, Vec::new()),
273    };
274    let mut assignment = Assignment::empty(count);
275    let mut lost = vec![0u32; count];
276    let mut sent = Vec::new();
277    while let Some((_, Reverse(number))) = queue.pop() {
278        let Some(value) = values[number] else { continue };
279        if forced.contains(&value.reg) {
280            assignment.spill(value.reg, value.class);
281            continue;
282        }
283        if early.contains(&value.reg) {
284            sent.push(value);
285            continue;
286        }
287        assert!(
288            !env.order(value.class).is_empty(),
289            "a value in class {}, which the target hands out no registers from",
290            value.class.number()
291        );
292        // Allowed and not Clear, at each step that asks. A register something insists on only in a
293        // hole between this value's pieces costs it nothing, since the value is dead there and the
294        // instruction takes the register without a move. Clear is asked over the hull, and it
295        // turned a parameter read before an early return that calls away from the register it
296        // arrived in and into a saved one, which is a push, a move and a pop nobody needed.
297        // Only a register the class hands out. An instruction may insist on one of the scratch
298        // registers, which is what an i386 `"S"` operand does with `esi`, and that is a move in
299        // front of the instruction. Taking it as a hint put the whole value in the scratch, where
300        // the first reload of anything else wrote over it.
301        let order = env.order(value.class);
302        let handed = |list: &[PhysReg]| -> Vec<PhysReg> {
303            list.iter().copied().filter(|at| order.contains(at)).collect()
304        };
305        let chosen = state
306            .coalesced(value, &reused[number])
307            .or_else(|| state.hinted(value, &handed(&hints[number]), Want::Allowed))
308            .or_else(|| {
309                let partners = passed[number].iter().chain(&received[number]);
310                let partners: Vec<PhysReg> =
311                    partners.filter_map(|&other| state.reg_of(other)).collect();
312                state.hinted(value, &partners, Want::Allowed)
313            })
314            .or_else(|| state.swapped(value, &seconds[number]))
315            .or_else(|| {
316                let mut ties = reused[number].to_vec();
317                let source = reuses[number].and_then(|reuse| reuse.source.number());
318                ties.extend(source.and_then(|source| usize::try_from(source).ok()));
319                ties.retain(|&tie| state.at[tie].is_none() && values[tie].is_some());
320                let tied = ties.iter().flat_map(|&tie| handed(&hints[tie]));
321                let wanted: Vec<PhysReg> = tied.chain(order.iter().copied()).collect();
322                state.together(value, &ties, &wanted)
323            })
324            .or_else(|| state.hinted(value, env.order(value.class), Want::Allowed));
325        if state.work > state.budget {
326            return None;
327        }
328        if let Some(at) = chosen {
329            state.take(value, at);
330            continue;
331        }
332        let mut gone = Vec::new();
333        match state.cheapest(value, env.order(value.class)) {
334            Some(at) => {
335                for other in state.evict(value, at) {
336                    lost[other] += 1;
337                    let Some(evicted) = values[other] else { continue };
338                    if lost[other] > ROUNDS {
339                        gone.push(evicted);
340                    } else {
341                        queue.push((evicted.size, Reverse(other)));
342                    }
343                }
344                state.take(value, at);
345            }
346            None => gone.push(value),
347        }
348        // Last, so that a value put away around a call never takes the register the value that
349        // evicted it was given.
350        for last in gone {
351            let spilled = costs[index(last.reg)];
352            match state.saved(func, last, env.order(last.class), spilled, &saveable) {
353                Some((at, insts)) => {
354                    state.take(last, at);
355                    state.saves[index(last.reg)] = insts;
356                }
357                None => assignment.spill(last.reg, last.class),
358            }
359        }
360        if state.work > state.budget {
361            return None;
362        }
363    }
364    // A value sent ahead is one the stack was going to take anyway, but the stack is only the
365    // cheaper answer where the value is read more often than the calls it is wanted across are
366    // made. So once every other value has its register, each is offered one that only a call is in
367    // the way of, the most expensive to keep on the stack first, which is what a value that lost
368    // its register in the queue is offered too. Nothing is evicted for one here, since what is left
369    // is a register nothing else wanted.
370    sent.sort_by_key(|value| Reverse(costs[index(value.reg)]));
371    for value in sent {
372        let spilled = costs[index(value.reg)];
373        match state.saved(func, value, env.order(value.class), spilled, &saveable) {
374            Some((at, insts)) => {
375                state.take(value, at);
376                state.saves[index(value.reg)] = insts;
377            }
378            None => assignment.spill(value.reg, value.class),
379        }
380    }
381    if state.work > state.budget {
382        return None;
383    }
384    state.settle(&reused, &passed, &received);
385    if state.work > state.budget {
386        return None;
387    }
388    for (number, at) in state.at.iter().enumerate() {
389        let Some(at) = *at else { continue };
390        let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
391        assignment.put(reg, Place::Reg(at));
392        if let Some(value) = values[number] {
393            assignment.save(reg, value.class, &state.saves[number]);
394        }
395    }
396    for inst in state.commuted.iter().flatten() {
397        assignment.commute(*inst);
398    }
399    Some(assignment)
400}
401
402/// A value in a register, by number, with the stretch of the line it covers.
403type Held = (usize, Range);
404
405/// What the allocation knows while it runs.
406struct State<'a, 'v> {
407    live: &'a Live,
408    blocked: &'a Blocks,
409    reuses: &'a [Option<Reuse>],
410    values: &'v [Option<Value<'a>>],
411    /// Which values are in each register of each class, by number, each with the stretch of the
412    /// line it covers. Most values in a register are nowhere near the one being placed, and having
413    /// the stretch here tells so without reading the value itself from wherever it is in `values`.
414    held: Vec<((RegClass, PhysReg), Vec<Held>)>,
415    /// The pieces of the values in each register of `held`, at the same index, made the first time
416    /// a register with more than [`FEW`] values in it is asked about.
417    pieces: Vec<Pieces>,
418    /// Which register each value is in now, if one.
419    at: Vec<Option<PhysReg>>,
420    /// The instruction whose sources were swapped for the answer written by each value, if its
421    /// register is the second source's.
422    commuted: Vec<Option<Inst>>,
423    /// The instructions each value is put away around, which is nothing for a value in a register
424    /// nothing in its range destroys.
425    saves: Vec<Vec<Inst>>,
426    work: u64,
427    budget: u64,
428    /// What [`Blocks::insists`] said about each register for the value it was last asked about, by
429    /// the register's number, allowed and then clear. Placing one value asks about the same
430    /// registers more than once, for its hints, for its partners' registers and then for every
431    /// register in order, and the answer does not change in between.
432    asked: (Option<Reg>, Vec<[Option<bool>; 2]>),
433}
434
435impl<'a> State<'a, '_> {
436    fn reg_of(&self, reg: Reg) -> Option<PhysReg> {
437        self.at.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
438    }
439
440    fn slot(&mut self, class: RegClass, at: PhysReg) -> usize {
441        let found = self.held.iter().position(|(key, _)| *key == (class, at));
442        found.unwrap_or_else(|| {
443            self.held.push(((class, at), Vec::new()));
444            self.pieces.push(Pieces::default());
445            self.held.len() - 1
446        })
447    }
448
449    /// Takes values out of a register, and their pieces with them.
450    fn remove(&mut self, index: usize, gone: &[usize]) {
451        self.held[index].1.retain(|(other, _)| !gone.contains(other));
452        let pieces = &mut self.pieces[index];
453        if pieces.kept {
454            for value in gone.iter().filter_map(|&other| self.values[other]) {
455                for piece in value.area.pieces() {
456                    pieces.remove(piece, value.reg);
457                }
458            }
459        }
460    }
461
462    /// The values in `at` that are wanted while `value` is, leaving out the one a two address
463    /// instruction lets it share the register with.
464    fn clashes(&mut self, value: Value<'_>, at: PhysReg) -> Vec<usize> {
465        let Some(found) = self.held.iter().position(|(key, _)| *key == (value.class, at)) else {
466            return Vec::new();
467        };
468        let held = &self.held[found].1;
469        // Counted as a walk over every value in the register, so that the budget runs out at the
470        // same place whichever way the question is answered.
471        self.work += held.len() as u64;
472        if held.len() > FEW {
473            let pieces = &mut self.pieces[found];
474            if !pieces.kept {
475                pieces.kept = true;
476                for other in held.iter().filter_map(|&(other, _)| self.values[other]) {
477                    for piece in other.area.pieces() {
478                        pieces.insert(piece, other.reg);
479                    }
480                }
481            }
482            if let Some(owners) = pieces.owners(value.area) {
483                let clash = owners.into_iter().filter(|&other| !self.shares(value.reg, other));
484                return clash.map(index).collect();
485            }
486        }
487        let mut clashes = Vec::new();
488        for &(other, range) in held {
489            if !range.overlaps(value.range) {
490                continue;
491            }
492            let Some(held) = self.values[other] else { continue };
493            if !held.area.overlaps(value.area) {
494                continue;
495            }
496            if !self.shares(value.reg, held.reg) {
497                clashes.push(other);
498            }
499        }
500        clashes
501    }
502
503    /// Whether two values that are both wanted at one instruction may still be in one register,
504    /// which is when that instruction reads one for the last time and writes the other over it.
505    fn shares(&self, one: Reg, two: Reg) -> bool {
506        let reads = |answer: Reg, source: Reg| {
507            let Some(number) = answer.number().and_then(|n| usize::try_from(n).ok()) else {
508                return false;
509            };
510            let Some(reuse) = self.reuses[number] else { return false };
511            match self.commuted[number] {
512                Some(_) => reuse.second == Some(source),
513                None => reuse.source == source,
514            }
515        };
516        (reads(one, two) || reads(two, one)) && assign::apart(self.live, one, two)
517    }
518
519    fn free(&mut self, value: Value<'_>, at: PhysReg, want: Want) -> bool {
520        !self.insists(value, at, want) && self.clashes(value, at).is_empty()
521    }
522
523    /// Whether an instruction insists on `at` where `value` would be in its way, from what was
524    /// worked out the last time this was asked if it was asked about this value already. A
525    /// register clear for a value is allowed for it too, and one not allowed is not clear either.
526    fn insists(&mut self, value: Value<'_>, at: PhysReg, want: Want) -> bool {
527        let (asked, answers) = &mut self.asked;
528        if *asked != Some(value.reg) {
529            *asked = Some(value.reg);
530            answers.fill([None; 2]);
531        }
532        let number = usize::from(at.number());
533        if answers.len() <= number {
534            answers.resize(number + 1, [None; 2]);
535        }
536        let slot = usize::from(want == Want::Clear);
537        if let Some(answer) = answers[number][slot] {
538            return answer;
539        }
540        let answer =
541            self.blocked.insists(value.reg, value.class, value.area, value.range, at, want);
542        let known = &mut answers[number];
543        known[slot] = Some(answer);
544        match (want, answer) {
545            (Want::Clear, false) => known[0] = Some(false),
546            (Want::Allowed, true) => known[1] = Some(true),
547            _ => {}
548        }
549        answer
550    }
551
552    /// The first register of `wanted` that is free for `value`.
553    fn hinted(&mut self, value: Value<'_>, wanted: &[PhysReg], want: Want) -> Option<PhysReg> {
554        wanted.iter().copied().find(|&at| self.work <= self.budget && self.free(value, at, want))
555    }
556
557    /// The first register of `order` free for `value` and for each value in `ties`, which are the
558    /// values a two address instruction ties it to that have no register yet. Taking one of these
559    /// leaves the tied value a register to follow it into when its turn comes. The registers the
560    /// tied values are hinted to come first in `order`, so that a parameter's answer waits for it in
561    /// the register the parameter arrives in.
562    fn together(&mut self, value: Value<'_>, ties: &[usize], order: &[PhysReg]) -> Option<PhysReg> {
563        if ties.is_empty() {
564            return None;
565        }
566        for &at in order {
567            if self.work > self.budget {
568                return None;
569            }
570            if !self.free(value, at, Want::Clear) {
571                continue;
572            }
573            let values = self.values;
574            let mut tied = ties.iter().filter_map(|&tie| values[tie]);
575            if tied.all(|other| self.free(other, at, Want::Allowed)) {
576                return Some(at);
577            }
578        }
579        None
580    }
581
582    /// The register of a value a two address instruction ties this one to, if it can have it.
583    ///
584    /// Asked of the answer, it is the register of the source, or of the second source if the
585    /// instruction reads its sources either way round. Asked of a source, it is the register of an
586    /// answer that reuses it and was placed first.
587    fn coalesced(&mut self, value: Value<'_>, answers: &[usize]) -> Option<PhysReg> {
588        let number = index(value.reg);
589        if let Some(reuse) = self.reuses[number] {
590            if let Some(at) = self.reg_of(reuse.source) {
591                if self.free(value, at, Want::Allowed) {
592                    return Some(at);
593                }
594            }
595            if let Some(second) = reuse.second {
596                if let Some(at) = self.reg_of(second) {
597                    self.commuted[number] = Some(reuse.inst);
598                    if self.free(value, at, Want::Allowed) {
599                        return Some(at);
600                    }
601                    self.commuted[number] = None;
602                }
603            }
604        }
605        for &answer in answers {
606            let Some(at) = self.at[answer] else { continue };
607            if self.commuted[answer].is_none() && self.free(value, at, Want::Allowed) {
608                return Some(at);
609            }
610        }
611        None
612    }
613
614    /// The register of an answer placed first that could be written over this value with its
615    /// sources swapped, and cannot be written over its first source, because that one is still
616    /// wanted after it. Asked after the hints, because the register an instruction wants the value
617    /// in saves a move as well, and following the answer would take the value away from it. The
618    /// value is one no two address instruction writes, such as a load.
619    fn swapped(&mut self, value: Value<'_>, seconds: &[usize]) -> Option<PhysReg> {
620        // A value that is itself the answer of a two address instruction is tied to its own source
621        // already, and following the answer it is read by would break that tie to save the same
622        // copy somewhere else.
623        if self.reuses[index(value.reg)].is_some() {
624            return None;
625        }
626        for &answer in seconds {
627            let (Some(at), Some(reuse)) = (self.at[answer], self.reuses[answer]) else { continue };
628            let Some(written) = self.values[answer] else { continue };
629            // An answer whose first source ends where it starts can still go over that one, which
630            // saves the same copy without swapping anything, and taking its register here would
631            // stop it moving there when the function is settled.
632            if self.commuted[answer].is_some()
633                || self.reg_of(reuse.source) == Some(at)
634                || assign::apart(self.live, written.reg, reuse.source)
635            {
636                continue;
637            }
638            self.commuted[answer] = Some(reuse.inst);
639            if self.free(value, at, Want::Allowed) {
640                return Some(at);
641            }
642            self.commuted[answer] = None;
643        }
644        None
645    }
646
647    /// The register that is cheapest to take back for `value`, if any is cheaper than sending
648    /// `value` to the stack.
649    fn cheapest(&mut self, value: Value<'_>, order: &[PhysReg]) -> Option<PhysReg> {
650        let mut best: Option<(u128, u128, PhysReg)> = None;
651        for &at in order {
652            if self.insists(value, at, Want::Allowed) {
653                continue;
654            }
655            let clashes = self.clashes(value, at);
656            let weights = clashes.iter().filter_map(|&other| self.values[other]).map(|v| v.weight);
657            let (heaviest, total) = weights.fold((0, 0), |(most, sum), w| (most.max(w), sum + w));
658            if heaviest >= value.weight {
659                continue;
660            }
661            if best.is_none_or(|(most, sum, _)| (heaviest, total) < (most, sum)) {
662                best = Some((heaviest, total, at));
663            }
664        }
665        best.map(|(_, _, at)| at)
666    }
667
668    /// Takes `at` back from the values in it that are in the way of `value`, and says which.
669    fn evict(&mut self, value: Value<'_>, at: PhysReg) -> Vec<usize> {
670        let clashes = self.clashes(value, at);
671        let index = self.slot(value.class, at);
672        self.remove(index, &clashes);
673        for &other in &clashes {
674            self.at[other] = None;
675            self.commuted[other] = None;
676            self.saves[other].clear();
677        }
678        clashes
679    }
680
681    /// The register that is cheapest for `value` to be put away in around every instruction that
682    /// destroys it, if one costs less than `spilled`, with those instructions.
683    ///
684    /// Only a register nothing else is in and nothing insists on for anything but destroying it.
685    /// The value itself is never written by one of the instructions, since then there is nothing to
686    /// put away in front of it.
687    fn saved(
688        &mut self,
689        func: &Func,
690        value: Value<'_>,
691        order: &[PhysReg],
692        spilled: u128,
693        saveable: &Map<Point, (Inst, u128)>,
694    ) -> Option<(PhysReg, Vec<Inst>)> {
695        let mut best: Option<(u128, PhysReg, Vec<Inst>)> = None;
696        for &at in order {
697            if self.work > self.budget {
698                return None;
699            }
700            let found = self.blocked.destroyed(
701                value.reg,
702                value.class,
703                value.area,
704                value.range,
705                at,
706                |point| saveable.contains_key(&point),
707            );
708            let Some(points) = found else { continue };
709            let mut insts = Vec::new();
710            let mut spent = Some(0u128);
711            for point in &points {
712                let Some(&(inst, weight)) = saveable.get(point) else { continue };
713                let written = func[func[inst].operands]
714                    .iter()
715                    .any(|operand| operand.reg == value.reg && operand.role.is_def());
716                spent = spent.filter(|_| !written).map(|spent| spent + 2 * weight);
717                insts.push(inst);
718            }
719            let Some(spent) = spent else { continue };
720            if spent >= spilled || best.as_ref().is_some_and(|&(least, _, _)| least <= spent) {
721                continue;
722            }
723            if self.clashes(value, at).is_empty() {
724                best = Some((spent, at, insts));
725            }
726        }
727        best.map(|(_, at, insts)| (at, insts))
728    }
729
730    /// Moves each value into the register the most values tied to it are in, of those that are free
731    /// for it and hold more of them than where it is now.
732    ///
733    /// A tie is a two address instruction or a block parameter, and each one met is a copy the
734    /// rewrite does not have to write. Placing values in priority order can leave the two ends of a
735    /// tie apart though the register one of them is in stayed free for the other, because the other
736    /// was placed first and had nothing yet to follow. Every move meets more ties than it breaks, so
737    /// this ends.
738    fn settle(&mut self, reused: &Answers, passed: &[Vec<Reg>], received: &[Vec<Reg>]) {
739        let mut moved = true;
740        while moved && self.work <= self.budget {
741            moved = false;
742            for number in 0..self.at.len() {
743                let (Some(value), Some(now)) = (self.values[number], self.at[number]) else {
744                    continue;
745                };
746                let reuse = self.reuses[number];
747                let source = reuse.and_then(|reuse| self.reg_of(reuse.source));
748                let second =
749                    reuse.and_then(|reuse| reuse.second).and_then(|second| self.reg_of(second));
750                let mut wanted: Vec<PhysReg> = source.into_iter().chain(second).collect();
751                for &answer in &reused[number] {
752                    if self.commuted[answer].is_none() {
753                        wanted.extend(self.at[answer]);
754                    }
755                }
756                let partners = passed[number].iter().chain(&received[number]);
757                wanted.extend(partners.filter_map(|&other| self.reg_of(other)));
758                let met = |at: PhysReg| wanted.iter().filter(|&&reg| reg == at).count();
759                let here = met(now);
760                let mut better: Vec<(usize, PhysReg)> = Vec::new();
761                for &at in &wanted {
762                    let count = met(at);
763                    if count > here && !better.contains(&(count, at)) {
764                        better.push((count, at));
765                    }
766                }
767                if better.is_empty() {
768                    continue;
769                }
770                better.sort_by_key(|&(count, _)| Reverse(count));
771                let index = self.slot(value.class, now);
772                self.remove(index, &[number]);
773                self.at[number] = None;
774                let was = self.commuted[number];
775                let mut to = now;
776                for (_, at) in better {
777                    self.commuted[number] = match reuse {
778                        Some(reuse) if second == Some(at) && source != Some(at) => Some(reuse.inst),
779                        _ => None,
780                    };
781                    if self.free(value, at, Want::Allowed) {
782                        to = at;
783                        moved = true;
784                        break;
785                    }
786                }
787                if to == now {
788                    self.commuted[number] = was;
789                } else {
790                    self.saves[number].clear();
791                }
792                self.take(value, to);
793            }
794        }
795    }
796
797    fn take(&mut self, value: Value<'_>, at: PhysReg) {
798        let number = index(value.reg);
799        self.at[number] = Some(at);
800        let index = self.slot(value.class, at);
801        self.held[index].1.push((number, value.range));
802        let pieces = &mut self.pieces[index];
803        if pieces.kept {
804            for piece in value.area.pieces() {
805                pieces.insert(piece, value.reg);
806            }
807        }
808    }
809}
810
811/// The late point of every instruction a value may be put away around, with the instruction and how
812/// often its block runs.
813///
814/// Every instruction but the last of a block that leaves more than one way, since what goes behind
815/// that one has to go at the start of each block it leaves to and a value brought back there is
816/// brought back on edges it may not be live on.
817fn saveable(func: &Func, order: &Order) -> Map<Point, (Inst, u128)> {
818    let mut saveable = Map::default();
819    for block in func.blocks() {
820        let weight = u128::from(func[block].weight.raw().max(1));
821        let last = if func[block].succs.len() > 1 { func.insts(block).last() } else { None };
822        for inst in func.insts(block) {
823            if Some(inst) != last {
824                saveable.insert(order.late(inst), (inst, weight));
825            }
826        }
827    }
828    saveable
829}
830
831/// How much of the line a value is live over.
832pub(crate) fn size(area: Area<'_>) -> u32 {
833    area.pieces().map(|piece| piece.end - piece.start + 1).sum()
834}
835
836/// How often each value is read or written, each time counted by how often its block runs.
837///
838/// A block that says nothing about how often it runs counts as running once, so a function with no
839/// weights on it is counted by how many times each value is named.
840pub(crate) fn costs(func: &Func) -> Vec<u128> {
841    let mut costs = vec![0u128; func.vregs()];
842    let mut add = |reg: Reg, weight: u128| {
843        let number = reg.number().and_then(|number| usize::try_from(number).ok());
844        if let Some(cost) = number.and_then(|number| costs.get_mut(number)) {
845            *cost += weight;
846        }
847    };
848    for block in func.blocks() {
849        let weight = u128::from(func[block].weight.raw().max(1));
850        for param in &func[block].params {
851            add(param.reg, weight);
852        }
853        for inst in func.insts(block) {
854            for operand in &func[func[inst].operands] {
855                add(operand.reg, weight);
856            }
857        }
858        for call in &func[block].succs {
859            for &arg in &call.args {
860                add(arg, weight);
861            }
862        }
863    }
864    costs
865}
866
867/// For each parameter of a block, the values the edges into it pass it.
868fn received(func: &Func) -> Vec<Vec<Reg>> {
869    let mut received = vec![Vec::new(); func.vregs()];
870    for block in func.blocks() {
871        for call in &func[block].succs {
872            for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
873                let number = param.reg.number().and_then(|number| usize::try_from(number).ok());
874                let Some(from) = number.and_then(|number| received.get_mut(number)) else {
875                    continue;
876                };
877                if !from.contains(&arg) {
878                    from.push(arg);
879                }
880            }
881        }
882    }
883    received
884}
885
886/// Lists of answers by value, in one buffer, with where each value's list starts in it.
887///
888/// Most values have no list at all, and a list of its own for each one that does was one
889/// allocation per value for every function the allocator placed.
890struct Answers {
891    starts: Vec<usize>,
892    all: Vec<usize>,
893}
894
895impl std::ops::Index<usize> for Answers {
896    type Output = [usize];
897
898    fn index(&self, number: usize) -> &[usize] {
899        &self.all[self.starts[number]..self.starts[number + 1]]
900    }
901}
902
903/// For each value, the answers of the instructions whose reuse `of` names it, in order.
904fn answers(reuses: &[Option<Reuse>], of: impl Fn(Reuse) -> Option<Reg>) -> Answers {
905    let number = |reuse: &Option<Reuse>| {
906        let reg = reuse.and_then(&of)?;
907        let number = usize::try_from(reg.number()?).ok()?;
908        (number < reuses.len()).then_some(number)
909    };
910    // Counted first, then each count turned into where its list ends, and the answers put in from
911    // the back so that each end comes down to where its list starts.
912    let mut starts = vec![0; reuses.len() + 1];
913    for reuse in reuses {
914        if let Some(number) = number(reuse) {
915            starts[number] += 1;
916        }
917    }
918    let mut total = 0;
919    for start in &mut starts {
920        total += *start;
921        *start = total;
922    }
923    let mut all = vec![0; total];
924    for (answer, reuse) in reuses.iter().enumerate().rev() {
925        if let Some(number) = number(reuse) {
926            starts[number] -= 1;
927            all[starts[number]] = answer;
928        }
929    }
930    Answers { starts, all }
931}
932
933/// For each value, the answers of two address instructions that reuse it as their first source.
934fn reused(reuses: &[Option<Reuse>]) -> Answers {
935    answers(reuses, |reuse| Some(reuse.source))
936}
937
938/// The answers that could be written over each value as the second source of an instruction that
939/// reads its sources either way round.
940fn seconds(reuses: &[Option<Reuse>]) -> Answers {
941    answers(reuses, |reuse| reuse.second)
942}
943
944fn index(reg: Reg) -> usize {
945    usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
946}
947
948#[cfg(test)]
949mod tests {
950    use rucc_base::Interner;
951    use rucc_mir::{BlockCall, Constraint, Flags, Opcode, Operand, Param};
952    use rucc_target::x86_64::{GPR, RAX, RCX, REGS, SYSV};
953
954    use super::*;
955    use crate::check;
956
957    fn env() -> Env {
958        let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
959        Env::new().with(GPR, order, scratch)
960    }
961
962    fn narrow(count: usize) -> Env {
963        Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
964    }
965
966    fn named(place: Option<Place>) -> String {
967        match place {
968            Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
969            Some(Place::Slot(_)) => "slot".to_string(),
970            None => "nowhere".to_string(),
971        }
972    }
973
974    /// Where every value went, after asking the checker whether the machine could run it.
975    fn places(func: &mut Func, env: &Env) -> Vec<String> {
976        let order = Order::of(func);
977        let live = Live::of(func, &order);
978        let assignment = within(func, &order, &live, env, BUDGET).expect("inside the budget");
979        // The sources of an instruction that commutes are swapped before the check, as `run_with`
980        // swaps them.
981        for &inst in assignment.commuted() {
982            let list = func[inst].operands;
983            func[list].swap(1, 2);
984        }
985        let problems = check::check(func, &order, &live, &assignment);
986        assert!(problems.is_empty(), "{}", check::report(&problems));
987        (0..func.vregs())
988            .map(|number| {
989                let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
990                named(assignment.place(reg))
991            })
992            .collect()
993    }
994
995    fn linear(func: &Func, env: &Env) -> Vec<String> {
996        let order = Order::of(func);
997        let live = Live::of(func, &order);
998        let assignment = assign::assign(func, &order, &live, env);
999        (0..func.vregs())
1000            .map(|number| {
1001                let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
1002                named(assignment.place(reg))
1003            })
1004            .collect()
1005    }
1006
1007    #[test]
1008    fn a_value_the_spill_phase_picked_goes_to_the_stack_and_the_rest_fit() {
1009        let mut names = Interner::new();
1010        let mut func = Func::new(names.intern("f"));
1011        let opcode = Opcode::new(names.intern("x64.nop"));
1012        let block = func.create_block();
1013        let busy = func.new_vreg(GPR);
1014        let once = func.new_vreg(GPR);
1015        let other = func.new_vreg(GPR);
1016        func.build(block, opcode).def(busy, GPR).finish();
1017        func.build(block, opcode).def(once, GPR).finish();
1018        func.build(block, opcode).def(other, GPR).finish();
1019        for _ in 0..3 {
1020            func.build(block, opcode).uses(busy, GPR).uses(other, GPR).finish();
1021        }
1022        func.build(block, opcode).uses(once, GPR).uses(busy, GPR).uses(other, GPR).finish();
1023
1024        let env = narrow(2);
1025        let order = Order::of(&func);
1026        let live = Live::of(&func, &order);
1027        let pressure = Pressure::of(&func, &order, &live, &env);
1028        let early = spill::choose(&func, &live, &pressure);
1029        assert_eq!(early, [once]);
1030        let assignment = placed(&func, &order, &live, &env, BUDGET, &early).expect("in budget");
1031        let problems = check::check(&func, &order, &live, &assignment);
1032        assert!(problems.is_empty(), "{}", check::report(&problems));
1033        assert_eq!(named(assignment.place(once)), "slot");
1034        assert_eq!(assignment.spilled(), 1);
1035    }
1036
1037    /// A value sent ahead is put away around a call the loop seldom makes, as one that lost its
1038    /// register in the queue is, rather than read from the stack in every turn.
1039    #[test]
1040    fn a_value_sent_ahead_is_put_away_around_the_call_the_loop_seldom_makes() {
1041        let mut names = Interner::new();
1042        let mut func = Func::new(names.intern("f"));
1043        let opcode = Opcode::new(names.intern("x64.nop"));
1044        let [entry, head, cold, skip, latch, back, out] = [(); 7].map(|()| func.create_block());
1045        let step = func.new_vreg(GPR);
1046        func.build(entry, opcode).def(step, GPR).finish();
1047        *func.succs_mut(entry) = vec![BlockCall::to(head)];
1048        func.build(head, opcode).uses(step, GPR).finish();
1049        *func.succs_mut(head) = vec![BlockCall::to(cold), BlockCall::to(skip)];
1050        // A call, as far as the allocator can tell: both registers it hands out are destroyed.
1051        let call = func
1052            .build(cold, opcode)
1053            .operand(Operand::write(Reg::physical(RAX), GPR))
1054            .operand(Operand::write(Reg::physical(RCX), GPR))
1055            .finish();
1056        *func.succs_mut(cold) = vec![BlockCall::to(latch)];
1057        *func.succs_mut(skip) = vec![BlockCall::to(latch)];
1058        func.build(latch, opcode).uses(step, GPR).finish();
1059        *func.succs_mut(latch) = vec![BlockCall::to(back), BlockCall::to(out)];
1060        *func.succs_mut(back) = vec![BlockCall::to(head)];
1061        func.build(out, opcode).uses(step, GPR).finish();
1062        for (block, often) in [(head, 100), (skip, 99), (latch, 100), (back, 99)] {
1063            func.set_weight(block, rucc_mir::Weight::parts(often * rucc_mir::Weight::SCALE));
1064        }
1065
1066        let env = narrow(2);
1067        let order = Order::of(&func);
1068        let live = Live::of(&func, &order);
1069        let assignment = placed(&func, &order, &live, &env, BUDGET, &[step]).expect("in budget");
1070        let problems = check::check(&func, &order, &live, &assignment);
1071        assert!(problems.is_empty(), "{}", check::report(&problems));
1072        assert_ne!(named(assignment.place(step)), "slot");
1073        let saves = assignment.saves();
1074        assert_eq!(saves.len(), 1);
1075        assert_eq!((saves[0].reg, saves[0].inst), (step, call));
1076    }
1077
1078    #[test]
1079    fn two_values_that_are_never_both_wanted_share_a_register() {
1080        let mut names = Interner::new();
1081        let mut func = Func::new(names.intern("f"));
1082        let opcode = Opcode::new(names.intern("x64.nop"));
1083        let block = func.create_block();
1084        let first = func.new_vreg(GPR);
1085        let second = func.new_vreg(GPR);
1086        func.build(block, opcode).def(first, GPR).finish();
1087        func.build(block, opcode).uses(first, GPR).finish();
1088        func.build(block, opcode).def(second, GPR).finish();
1089        func.build(block, opcode).uses(second, GPR).finish();
1090
1091        assert_eq!(places(&mut func, &env()), ["rax", "rax"]);
1092    }
1093
1094    #[test]
1095    fn the_value_read_most_often_keeps_its_register_though_it_is_wanted_longest() {
1096        let mut names = Interner::new();
1097        let mut func = Func::new(names.intern("f"));
1098        let opcode = Opcode::new(names.intern("x64.nop"));
1099        let block = func.create_block();
1100        let busy = func.new_vreg(GPR);
1101        let once = func.new_vreg(GPR);
1102        func.build(block, opcode).def(busy, GPR).finish();
1103        func.build(block, opcode).def(once, GPR).finish();
1104        for _ in 0..6 {
1105            func.build(block, opcode).uses(busy, GPR).finish();
1106        }
1107        func.build(block, opcode).uses(once, GPR).finish();
1108        func.build(block, opcode).uses(busy, GPR).finish();
1109
1110        // With one register the linear scan sends the value that ends last to the stack, which is
1111        // the one read seven times. Weighing them keeps that one and sends the one read once.
1112        assert_eq!(linear(&func, &narrow(1)), ["slot", "rax"]);
1113        assert_eq!(places(&mut func, &narrow(1)), ["rax", "slot"]);
1114    }
1115
1116    #[test]
1117    fn a_value_read_in_a_loop_keeps_its_register_over_one_read_outside_it() {
1118        let mut names = Interner::new();
1119        let mut func = Func::new(names.intern("f"));
1120        let opcode = Opcode::new(names.intern("x64.nop"));
1121        let entry = func.create_block();
1122        let body = func.create_block();
1123        let out = func.create_block();
1124        let step = func.new_vreg(GPR);
1125        let cold = func.new_vreg(GPR);
1126        func.build(entry, opcode).def(cold, GPR).finish();
1127        func.build(entry, opcode).def(step, GPR).finish();
1128        *func.succs_mut(entry) = vec![BlockCall::to(body)];
1129        func.build(body, opcode).uses(step, GPR).finish();
1130        *func.succs_mut(body) = vec![BlockCall::to(body), BlockCall::to(out)];
1131        func.set_weight(body, rucc_mir::Weight::parts(100 * rucc_mir::Weight::SCALE));
1132        func.build(out, opcode).uses(cold, GPR).finish();
1133        func.build(out, opcode).uses(step, GPR).finish();
1134
1135        // Read once in the loop and once after it, against a value read once after it: the count
1136        // of reads is the same and it is how often the loop runs that decides.
1137        assert_eq!(places(&mut func, &narrow(1)), ["rax", "slot"]);
1138    }
1139
1140    #[test]
1141    fn a_long_value_gives_its_register_back_to_a_short_busy_one() {
1142        let mut names = Interner::new();
1143        let mut func = Func::new(names.intern("f"));
1144        let opcode = Opcode::new(names.intern("x64.nop"));
1145        let block = func.create_block();
1146        let long = func.new_vreg(GPR);
1147        let short = func.new_vreg(GPR);
1148        func.build(block, opcode).def(long, GPR).finish();
1149        for _ in 0..4 {
1150            func.build(block, opcode).finish();
1151        }
1152        func.build(block, opcode).def(short, GPR).finish();
1153        for _ in 0..4 {
1154            func.build(block, opcode).uses(short, GPR).finish();
1155        }
1156        func.build(block, opcode).uses(long, GPR).finish();
1157
1158        // The long one is placed first, since it is the harder to place, and then loses the one
1159        // register to the short one, which weighs more, and has nowhere else to go.
1160        assert_eq!(places(&mut func, &narrow(1)), ["slot", "rax"]);
1161    }
1162
1163    #[test]
1164    fn the_answer_of_a_two_address_instruction_goes_where_its_source_ends() {
1165        let mut names = Interner::new();
1166        let mut func = Func::new(names.intern("f"));
1167        let opcode = Opcode::new(names.intern("x64.nop"));
1168        let block = func.create_block();
1169        let left = func.new_vreg(GPR);
1170        let right = func.new_vreg(GPR);
1171        let sum = func.new_vreg(GPR);
1172        func.build(block, opcode).def(left, GPR).finish();
1173        func.build(block, opcode).def(right, GPR).finish();
1174        func.build(block, opcode)
1175            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1176            .uses(left, GPR)
1177            .uses(right, GPR)
1178            .finish();
1179        func.build(block, opcode).uses(right, GPR).finish();
1180        func.build(block, opcode).uses(sum, GPR).finish();
1181
1182        let places = places(&mut func, &env());
1183        assert_eq!(places[2], places[0]);
1184        assert_ne!(places[1], places[0]);
1185    }
1186
1187    #[test]
1188    fn a_source_placed_after_its_answer_goes_where_the_answer_is() {
1189        let mut names = Interner::new();
1190        let mut func = Func::new(names.intern("f"));
1191        let opcode = Opcode::new(names.intern("x64.nop"));
1192        let block = func.create_block();
1193        let left = func.new_vreg(GPR);
1194        let sum = func.new_vreg(GPR);
1195        func.build(block, opcode).def(left, GPR).finish();
1196        func.build(block, opcode)
1197            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1198            .uses(left, GPR)
1199            .finish();
1200        for _ in 0..6 {
1201            func.build(block, opcode).uses(sum, GPR).finish();
1202        }
1203
1204        // The answer is the longer of the two, so it is placed first, and the source finds it.
1205        let places = places(&mut func, &env());
1206        assert_eq!(places[0], places[1]);
1207    }
1208
1209    #[test]
1210    fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1211        let mut names = Interner::new();
1212        let mut func = Func::new(names.intern("f"));
1213        let opcode = Opcode::new(names.intern("x64.nop"));
1214        let entry = func.create_block();
1215        let head = func.create_block();
1216        let out = func.create_block();
1217        let seed = func.new_vreg(GPR);
1218        let total = func.new_vreg(GPR);
1219        let term = func.new_vreg(GPR);
1220        let next = func.new_vreg(GPR);
1221        func.build(entry, opcode).def(seed, GPR).finish();
1222        *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1223        func.params_mut(head).push(Param { reg: total, class: GPR });
1224        func.build(head, opcode).def(term, GPR).finish();
1225        func.build(head, opcode)
1226            .flags(Flags::COMMUTES)
1227            .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1228            .uses(total, GPR)
1229            .uses(term, GPR)
1230            .finish();
1231        *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1232
1233        let places = places(&mut func, &env());
1234        assert_eq!(places[3], places[1]);
1235    }
1236
1237    #[test]
1238    fn an_answer_whose_first_source_lives_on_goes_where_the_second_one_ends() {
1239        let mut names = Interner::new();
1240        let mut func = Func::new(names.intern("f"));
1241        let opcode = Opcode::new(names.intern("x64.nop"));
1242        let block = func.create_block();
1243        let base = func.new_vreg(GPR);
1244        let entry = func.new_vreg(GPR);
1245        let target = func.new_vreg(GPR);
1246        func.build(block, opcode).def(base, GPR).finish();
1247        func.build(block, opcode).def(entry, GPR).finish();
1248        func.build(block, opcode)
1249            .flags(Flags::COMMUTES)
1250            .operand(Operand::write(target, GPR).with(Constraint::Reuse(1)))
1251            .uses(base, GPR)
1252            .uses(entry, GPR)
1253            .finish();
1254        func.build(block, opcode).uses(target, GPR).finish();
1255        func.build(block, opcode).uses(base, GPR).finish();
1256
1257        let places = places(&mut func, &env());
1258        assert_eq!(places[2], places[1]);
1259        assert_ne!(places[2], places[0]);
1260    }
1261
1262    #[test]
1263    fn an_offset_added_to_a_base_the_loop_reads_again_goes_where_the_answer_went() {
1264        let mut names = Interner::new();
1265        let mut func = Func::new(names.intern("f"));
1266        let opcode = Opcode::new(names.intern("x64.nop"));
1267        let entry = func.create_block();
1268        let head = func.create_block();
1269        let out = func.create_block();
1270        let base = func.new_vreg(GPR);
1271        let at = func.new_vreg(GPR);
1272        let offset = func.new_vreg(GPR);
1273        let target = func.new_vreg(GPR);
1274        let later = func.new_vreg(GPR);
1275        func.build(entry, opcode).def(base, GPR).finish();
1276        *func.succs_mut(entry) = vec![BlockCall::to(head)];
1277        func.build(head, opcode).def(at, GPR).finish();
1278        func.build(head, opcode).def(offset, GPR).uses(base, GPR).uses(at, GPR).finish();
1279        func.build(head, opcode)
1280            .flags(Flags::COMMUTES)
1281            .operand(Operand::write(target, GPR).with(Constraint::Reuse(1)))
1282            .uses(base, GPR)
1283            .uses(offset, GPR)
1284            .finish();
1285        func.build(head, opcode).def(later, GPR).finish();
1286        func.build(head, opcode).uses(target, GPR).finish();
1287        for _ in 0..4 {
1288            func.build(head, opcode).finish();
1289        }
1290        func.build(head, opcode).uses(later, GPR).finish();
1291        *func.succs_mut(head) = vec![BlockCall::to(head), BlockCall::to(out)];
1292
1293        // The answer is placed before the offset, which is wanted over less of the line, and the
1294        // base the loop reads again has the only register the answer could have followed. The
1295        // offset is placed last and finds the register `later` has after the add free before it,
1296        // which is where it went before it looked at the answer, and the answer could not then be
1297        // moved to it. tamnd/rucc#2064.
1298        let places = places(&mut func, &env());
1299        assert_eq!(places[3], places[2]);
1300        assert_ne!(places[3], places[0]);
1301    }
1302
1303    #[test]
1304    fn a_register_an_instruction_insists_on_is_left_to_the_value_it_names() {
1305        let mut names = Interner::new();
1306        let mut func = Func::new(names.intern("f"));
1307        let opcode = Opcode::new(names.intern("x64.nop"));
1308        let block = func.create_block();
1309        let kept = func.new_vreg(GPR);
1310        let passed = func.new_vreg(GPR);
1311        func.build(block, opcode).def(kept, GPR).finish();
1312        func.build(block, opcode).def(passed, GPR).finish();
1313        func.build(block, opcode)
1314            .operand(Operand::read(passed, GPR).with(Constraint::Fixed(RAX)))
1315            .finish();
1316        func.build(block, opcode).uses(kept, GPR).finish();
1317
1318        let places = places(&mut func, &env());
1319        assert_eq!(places[1], "rax");
1320        assert_ne!(places[0], "rax");
1321    }
1322
1323    #[test]
1324    fn a_value_only_memory_can_hold_goes_to_the_stack() {
1325        let mut names = Interner::new();
1326        let mut func = Func::new(names.intern("f"));
1327        let opcode = Opcode::new(names.intern("x64.nop"));
1328        let block = func.create_block();
1329        let value = func.new_vreg(GPR);
1330        func.build(block, opcode).def(value, GPR).finish();
1331        func.build(block, opcode)
1332            .operand(Operand::read(value, GPR).with(Constraint::Stack))
1333            .finish();
1334
1335        assert_eq!(places(&mut func, &env()), ["slot"]);
1336    }
1337
1338    #[test]
1339    fn a_function_over_the_budget_gets_the_linear_scan_answer() {
1340        let mut names = Interner::new();
1341        let mut func = Func::new(names.intern("f"));
1342        let opcode = Opcode::new(names.intern("x64.nop"));
1343        let block = func.create_block();
1344        let busy = func.new_vreg(GPR);
1345        let once = func.new_vreg(GPR);
1346        func.build(block, opcode).def(busy, GPR).finish();
1347        func.build(block, opcode).def(once, GPR).finish();
1348        for _ in 0..6 {
1349            func.build(block, opcode).uses(busy, GPR).finish();
1350        }
1351        func.build(block, opcode).uses(once, GPR).finish();
1352        func.build(block, opcode).uses(busy, GPR).finish();
1353
1354        let order = Order::of(&func);
1355        let live = Live::of(&func, &order);
1356        assert!(within(&func, &order, &live, &narrow(1), 0).is_none());
1357        let fallen = linear(&func, &narrow(1));
1358        assert_eq!(fallen, ["slot", "rax"]);
1359    }
1360
1361    #[test]
1362    fn the_cheaper_of_the_two_answers_is_the_one_kept() {
1363        let mut names = Interner::new();
1364        let mut func = Func::new(names.intern("f"));
1365        let opcode = Opcode::new(names.intern("x64.nop"));
1366        let block = func.create_block();
1367        let busy = func.new_vreg(GPR);
1368        let once = func.new_vreg(GPR);
1369        func.build(block, opcode).def(busy, GPR).finish();
1370        func.build(block, opcode).def(once, GPR).finish();
1371        for _ in 0..6 {
1372            func.build(block, opcode).uses(busy, GPR).finish();
1373        }
1374        func.build(block, opcode).uses(once, GPR).finish();
1375        func.build(block, opcode).uses(busy, GPR).finish();
1376
1377        let order = Order::of(&func);
1378        let live = Live::of(&func, &order);
1379        let env = narrow(1);
1380        let linear = assign::assign(&func, &order, &live, &env);
1381        let ours = within(&func, &order, &live, &env, BUDGET).expect("inside the budget");
1382        // The linear scan puts `busy` on the stack, which is its write and its seven reads. This
1383        // puts `once` there, which is one write and one read.
1384        let once_through = u128::from(func[block].weight.raw());
1385        assert_eq!(cost(&func, &order, &linear), 8 * once_through);
1386        assert_eq!(cost(&func, &order, &ours), 2 * once_through);
1387        let kept = assign(&func, &order, &live, &env);
1388        assert_eq!(kept.place(busy), ours.place(busy));
1389        assert_eq!(kept.place(once), ours.place(once));
1390    }
1391
1392    #[test]
1393    fn a_copy_left_between_a_two_address_answer_and_its_source_is_counted() {
1394        let mut names = Interner::new();
1395        let mut func = Func::new(names.intern("f"));
1396        let opcode = Opcode::new(names.intern("x64.nop"));
1397        let block = func.create_block();
1398        let left = func.new_vreg(GPR);
1399        let right = func.new_vreg(GPR);
1400        let sum = func.new_vreg(GPR);
1401        func.build(block, opcode).def(left, GPR).finish();
1402        func.build(block, opcode).def(right, GPR).finish();
1403        func.build(block, opcode)
1404            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1405            .uses(left, GPR)
1406            .uses(right, GPR)
1407            .finish();
1408        func.build(block, opcode).uses(sum, GPR).finish();
1409
1410        let order = Order::of(&func);
1411        let live = Live::of(&func, &order);
1412        let chosen = assign(&func, &order, &live, &env());
1413        assert_eq!(cost(&func, &order, &chosen), 0);
1414        let mut apart = chosen.clone();
1415        apart.put(sum, chosen.place(right).expect("a place for right"));
1416        assert_eq!(cost(&func, &order, &apart), u128::from(func[block].weight.raw()));
1417    }
1418
1419    /// A value written, then `calls` instructions that destroy both registers there are, then
1420    /// `reads` reads of the value.
1421    fn around_calls(calls: usize, reads: usize) -> Vec<String> {
1422        let mut names = Interner::new();
1423        let mut func = Func::new(names.intern("f"));
1424        let opcode = Opcode::new(names.intern("x64.nop"));
1425        let block = func.create_block();
1426        let value = func.new_vreg(GPR);
1427        func.build(block, opcode).def(value, GPR).finish();
1428        for _ in 0..calls {
1429            func.build(block, opcode)
1430                .operand(Operand::write(Reg::physical(RAX), GPR))
1431                .operand(Operand::write(Reg::physical(RCX), GPR))
1432                .finish();
1433        }
1434        for _ in 0..reads {
1435            func.build(block, opcode).uses(value, GPR).finish();
1436        }
1437        places(&mut func, &narrow(2))
1438    }
1439
1440    #[test]
1441    fn a_value_is_put_away_around_a_call_only_when_that_is_cheaper_than_the_stack() {
1442        // One call and ten reads is a store and a load against ten loads.
1443        assert_eq!(around_calls(1, 10), ["rax"]);
1444        // Three calls and one read is six against a store and a load.
1445        assert_eq!(around_calls(3, 1), ["slot"]);
1446    }
1447
1448    #[test]
1449    fn many_values_in_few_registers_come_out_as_something_the_machine_can_run() {
1450        let mut names = Interner::new();
1451        let mut func = Func::new(names.intern("f"));
1452        let opcode = Opcode::new(names.intern("x64.nop"));
1453        let block = func.create_block();
1454        let regs: Vec<Reg> = (0..24).map(|_| func.new_vreg(GPR)).collect();
1455        for &reg in &regs {
1456            func.build(block, opcode).def(reg, GPR).finish();
1457        }
1458        for (at, &reg) in regs.iter().enumerate().rev() {
1459            for _ in 0..(at % 5) {
1460                func.build(block, opcode).uses(reg, GPR).finish();
1461            }
1462            func.build(block, opcode).uses(reg, GPR).finish();
1463        }
1464
1465        let places = places(&mut func, &narrow(4));
1466        assert_eq!(places.iter().filter(|place| *place != "slot").count(), 4);
1467    }
1468}