1use std::cmp::Reverse;
28use std::collections::{BTreeMap, BTreeSet, BinaryHeap};
29
30use rucc_mir::{Func, Reg};
31use rucc_target::RegClass;
32
33use crate::assign;
34use crate::backtrack;
35use crate::live::{Area, Live};
36use crate::order::Point;
37use crate::pressure::Pressure;
38
39#[derive(Debug, Clone, Copy)]
41struct Candidate<'a> {
42 reg: Reg,
43 area: Area<'a>,
44 weight: u128,
45 size: u32,
46}
47
48#[must_use]
56pub fn choose(func: &Func, live: &Live, pressure: &Pressure) -> Vec<Reg> {
57 let costs = backtrack::costs(func);
58 let mut forced = vec![false; func.vregs()];
59 for reg in assign::forced(func) {
60 forced[index(reg)] = true;
61 }
62 let mut classes: BTreeMap<RegClass, Vec<Candidate<'_>>> = BTreeMap::new();
63 for (number, &forced) in forced.iter().enumerate() {
64 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
65 let (Some(area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
66 continue;
67 };
68 if forced {
69 continue;
70 }
71 let size = backtrack::size(area);
72 let weight = costs[number] * 1024 / u128::from(size + 8);
73 classes.entry(class).or_default().push(Candidate { reg, area, weight, size });
74 }
75
76 let mut pressure = pressure.clone();
77 let mut chosen = Vec::new();
78 for (class, mut candidates) in classes {
79 candidates.sort_by_key(|candidate| candidate.area.hull().start);
80 let over: Vec<_> = pressure.over(class).collect();
81 let mut here: BTreeSet<(u128, Reverse<u32>, usize)> = BTreeSet::new();
87 let mut changes: BinaryHeap<Reverse<(Point, usize)>> = (candidates.iter().enumerate())
90 .map(|(one, candidate)| Reverse((candidate.area.hull().start, one)))
91 .collect();
92 let mut at = vec![(0, false); candidates.len()];
94 let mut gone = vec![false; candidates.len()];
96 for point in over {
97 if pressure.excess(class, point) == 0 {
100 continue;
101 }
102 while let Some(&Reverse((when, one))) = changes.peek() {
103 if when > point {
104 break;
105 }
106 changes.pop();
107 if gone[one] {
108 continue;
109 }
110 let candidate = &candidates[one];
111 let key = (candidate.weight, Reverse(candidate.size), one);
112 let (piece, inside) = &mut at[one];
113 let range = candidate.area.piece(*piece);
114 if *inside {
115 here.remove(&key);
116 *inside = false;
117 *piece += 1;
118 if *piece < candidate.area.count() {
119 changes.push(Reverse((candidate.area.piece(*piece).start, one)));
120 }
121 } else {
122 here.insert(key);
123 *inside = true;
124 if let Some(after) = range.end.checked_add(1) {
125 changes.push(Reverse((after, one)));
126 }
127 }
128 }
129 while pressure.excess(class, point) > 0 {
130 let Some((_, _, one)) = here.pop_first() else { break };
131 gone[one] = true;
132 pressure.lift(class, candidates[one].area);
133 chosen.push(candidates[one].reg);
134 }
135 }
136 }
137 chosen
138}
139
140fn index(reg: Reg) -> usize {
141 usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
142}
143
144#[cfg(test)]
145mod tests {
146 use rucc_base::Interner;
147 use rucc_mir::{BlockCall, Opcode, Weight};
148 use rucc_target::x86_64::{GPR, SYSV};
149
150 use super::*;
151 use crate::assign::Env;
152 use crate::order::Order;
153
154 fn narrow(count: usize) -> Env {
155 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
156 }
157
158 fn chosen(func: &Func, env: &Env) -> Vec<Reg> {
159 let order = Order::of(func);
160 let live = Live::of(func, &order);
161 let pressure = Pressure::of(func, &order, &live, env);
162 choose(func, &live, &pressure)
163 }
164
165 #[test]
166 fn nothing_goes_where_everything_fits() {
167 let mut names = Interner::new();
168 let mut func = Func::new(names.intern("f"));
169 let opcode = Opcode::new(names.intern("x64.nop"));
170 let block = func.create_block();
171 let first = func.new_vreg(GPR);
172 let second = func.new_vreg(GPR);
173 func.build(block, opcode).def(first, GPR).finish();
174 func.build(block, opcode).def(second, GPR).finish();
175 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
176
177 assert!(chosen(&func, &narrow(2)).is_empty());
178 }
179
180 #[test]
181 fn the_value_read_least_is_the_one_that_goes() {
182 let mut names = Interner::new();
183 let mut func = Func::new(names.intern("f"));
184 let opcode = Opcode::new(names.intern("x64.nop"));
185 let block = func.create_block();
186 let busy = func.new_vreg(GPR);
187 let once = func.new_vreg(GPR);
188 let other = func.new_vreg(GPR);
189 func.build(block, opcode).def(busy, GPR).finish();
190 func.build(block, opcode).def(once, GPR).finish();
191 func.build(block, opcode).def(other, GPR).finish();
192 for _ in 0..3 {
193 func.build(block, opcode).uses(busy, GPR).uses(other, GPR).finish();
194 }
195 func.build(block, opcode).uses(once, GPR).uses(busy, GPR).uses(other, GPR).finish();
196
197 assert_eq!(chosen(&func, &narrow(2)), [once]);
198 }
199
200 #[test]
201 fn a_value_read_in_a_loop_stays_and_one_read_outside_it_goes() {
202 let mut names = Interner::new();
203 let mut func = Func::new(names.intern("f"));
204 let opcode = Opcode::new(names.intern("x64.nop"));
205 let entry = func.create_block();
206 let body = func.create_block();
207 let out = func.create_block();
208 let step = func.new_vreg(GPR);
209 let cold = func.new_vreg(GPR);
210 func.build(entry, opcode).def(cold, GPR).finish();
211 func.build(entry, opcode).def(step, GPR).finish();
212 *func.succs_mut(entry) = vec![BlockCall::to(body)];
213 func.build(body, opcode).uses(step, GPR).finish();
214 *func.succs_mut(body) = vec![BlockCall::to(body), BlockCall::to(out)];
215 func.set_weight(body, Weight::parts(100 * Weight::SCALE));
216 func.build(out, opcode).uses(cold, GPR).finish();
217 func.build(out, opcode).uses(step, GPR).finish();
218
219 assert_eq!(chosen(&func, &narrow(1)), [cold]);
220 }
221
222 #[test]
223 fn one_long_light_value_settles_two_points_that_are_each_one_over() {
224 let mut names = Interner::new();
225 let mut func = Func::new(names.intern("f"));
226 let opcode = Opcode::new(names.intern("x64.nop"));
227 let block = func.create_block();
228 let long = func.new_vreg(GPR);
229 let first = func.new_vreg(GPR);
230 let second = func.new_vreg(GPR);
231 func.build(block, opcode).def(long, GPR).finish();
232 func.build(block, opcode).def(first, GPR).finish();
233 func.build(block, opcode).uses(first, GPR).finish();
234 for _ in 0..4 {
235 func.build(block, opcode).finish();
236 }
237 func.build(block, opcode).def(second, GPR).finish();
238 func.build(block, opcode).uses(second, GPR).finish();
239 func.build(block, opcode).uses(long, GPR).finish();
240
241 assert_eq!(chosen(&func, &narrow(1)), [long]);
244 }
245}