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