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