1use rucc_mir::{Constraint, Func, Reg};
54use rucc_target::{PhysReg, RegClass};
55
56use crate::live::{Live, Range};
57use crate::order::{Order, Point};
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Place {
62 Reg(PhysReg),
64 Slot(u32),
67}
68
69#[derive(Debug, Clone, Default)]
79pub struct Env {
80 classes: Vec<Class>,
81}
82
83#[derive(Debug, Clone, Default)]
85struct Class {
86 order: Vec<PhysReg>,
87 scratch: Vec<PhysReg>,
88}
89
90impl Env {
91 #[must_use]
93 pub fn new() -> Self {
94 Self::default()
95 }
96
97 #[must_use]
99 pub fn with(mut self, class: RegClass, order: &[PhysReg], scratch: &[PhysReg]) -> Self {
100 let index = usize::from(class.number());
101 if self.classes.len() <= index {
102 self.classes.resize(index + 1, Class::default());
103 }
104 self.classes[index] = Class { order: order.to_vec(), scratch: scratch.to_vec() };
105 self
106 }
107
108 #[must_use]
110 pub fn order(&self, class: RegClass) -> &[PhysReg] {
111 self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.order)
112 }
113
114 #[must_use]
116 pub fn scratch(&self, class: RegClass) -> &[PhysReg] {
117 self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.scratch)
118 }
119}
120
121#[derive(Debug, Clone)]
123pub struct Assignment {
124 places: Vec<Option<Place>>,
125 slots: Vec<RegClass>,
126}
127
128impl Assignment {
129 #[must_use]
136 pub fn empty(vregs: usize) -> Self {
137 Self { places: vec![None; vregs], slots: Vec::new() }
138 }
139
140 pub fn put(&mut self, reg: Reg, place: Place) {
147 self.places[index(reg)] = Some(place);
148 }
149
150 pub fn take_slot(&mut self, class: RegClass) -> u32 {
156 let slot = u32::try_from(self.slots.len()).expect("too many spilled values");
157 self.slots.push(class);
158 slot
159 }
160
161 #[must_use]
164 pub fn place(&self, reg: Reg) -> Option<Place> {
165 self.places.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
166 }
167
168 #[must_use]
170 pub fn slots(&self) -> &[RegClass] {
171 &self.slots
172 }
173
174 #[must_use]
176 pub fn spilled(&self) -> usize {
177 self.slots.len()
178 }
179
180 fn spill(&mut self, reg: Reg, class: RegClass) {
182 let slot = self.take_slot(class);
183 self.put(reg, Place::Slot(slot));
184 }
185}
186
187#[derive(Debug, Clone, Copy)]
189struct Interval {
190 reg: Reg,
191 class: RegClass,
192 range: Range,
193}
194
195#[derive(Debug, Clone, Copy)]
197struct Held {
198 reg: Reg,
199 class: RegClass,
200 range: Range,
201 at: PhysReg,
202}
203
204#[derive(Debug, Clone, Copy)]
206struct Blocked {
207 class: RegClass,
208 at: PhysReg,
209 range: Range,
210}
211
212#[derive(Debug, Clone, Copy)]
214struct Reuse {
215 source: Reg,
217 at: Point,
219}
220
221#[must_use]
228pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
229 let blocked = blocked(func, order);
230 let forced = forced(func);
231 let reuses = reuses(func, order);
232
233 let mut intervals = Vec::with_capacity(func.vregs());
234 for (number, reuse) in reuses.iter().enumerate() {
235 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
236 let (Some(mut range), Some(class)) = (live.range(reg), func.class_of(reg)) else {
237 continue;
238 };
239 if let Some(reuse) = reuse {
240 range.start = range.start.min(reuse.at);
241 }
242 intervals.push(Interval { reg, class, range });
243 }
244 intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
245
246 let mut assignment = Assignment::empty(func.vregs());
247 let mut active: Vec<Held> = Vec::new();
248 for interval in intervals {
249 active.retain(|held| held.range.end >= interval.range.start);
250 if forced.contains(&interval.reg) {
251 assignment.spill(interval.reg, interval.class);
252 continue;
253 }
254 assert!(
255 !env.order(interval.class).is_empty(),
256 "a value in a class the target hands out no registers from"
257 );
258 let two_address = reuses[index(interval.reg)]
259 .and_then(|reuse| coalesce(&assignment, &active, &blocked, interval, reuse));
260 let chosen = two_address.or_else(|| {
261 env.order(interval.class)
262 .iter()
263 .copied()
264 .find(|&at| available(&active, &blocked, interval, at, None))
265 });
266 match chosen {
267 Some(at) => {
268 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
269 let reg = interval.reg;
270 active.push(Held { reg, class: interval.class, range: interval.range, at });
271 }
272 None => spill_one(&mut assignment, &mut active, &blocked, interval),
273 }
274 }
275 assignment
276}
277
278fn available(
283 active: &[Held],
284 blocked: &[Blocked],
285 interval: Interval,
286 at: PhysReg,
287 except: Option<Reg>,
288) -> bool {
289 let taken = active
290 .iter()
291 .any(|held| held.at == at && held.class == interval.class && Some(held.reg) != except);
292 let insisted = blocked.iter().any(|one| {
293 one.at == at && one.class == interval.class && one.range.overlaps(interval.range)
294 });
295 !taken && !insisted
296}
297
298fn coalesce(
301 assignment: &Assignment,
302 active: &[Held],
303 blocked: &[Blocked],
304 interval: Interval,
305 reuse: Reuse,
306) -> Option<PhysReg> {
307 let Some(Place::Reg(at)) = assignment.place(reuse.source) else { return None };
308 let source = active.iter().find(|held| held.reg == reuse.source)?;
309 let dies = source.range.end == reuse.at;
312 (dies && available(active, blocked, interval, at, Some(reuse.source))).then_some(at)
313}
314
315fn spill_one(
318 assignment: &mut Assignment,
319 active: &mut Vec<Held>,
320 blocked: &[Blocked],
321 interval: Interval,
322) {
323 let victim = active
326 .iter()
327 .enumerate()
328 .filter(|(_, held)| held.class == interval.class)
329 .filter(|(_, held)| available(&[], blocked, interval, held.at, None))
330 .max_by_key(|(_, held)| held.range.end)
331 .map(|(at, held)| (at, held.at, held.range.end));
332 match victim {
333 Some((victim, at, end)) if end > interval.range.end => {
334 let held = active.remove(victim);
335 assignment.spill(held.reg, held.class);
336 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
337 let reg = interval.reg;
338 active.push(Held { reg, class: interval.class, range: interval.range, at });
339 }
340 _ => assignment.spill(interval.reg, interval.class),
341 }
342}
343
344fn blocked(func: &Func, order: &Order) -> Vec<Blocked> {
350 let mut blocked = Vec::new();
351 for block in func.blocks() {
352 for inst in func.insts(block) {
353 let range = Range { start: order.early(inst), end: order.late(inst) };
354 for operand in &func[func[inst].operands] {
355 let at = match operand.constraint {
356 Constraint::Fixed(at) => Some(at),
357 _ => operand.reg.phys(),
358 };
359 if let Some(at) = at {
360 blocked.push(Blocked { class: operand.class, at, range });
361 }
362 }
363 }
364 }
365 blocked
366}
367
368fn forced(func: &Func) -> Vec<Reg> {
370 let mut forced = Vec::new();
371 for block in func.blocks() {
372 for inst in func.insts(block) {
373 for operand in &func[func[inst].operands] {
374 if operand.constraint == Constraint::Stack
375 && operand.reg.is_virtual()
376 && !forced.contains(&operand.reg)
377 {
378 forced.push(operand.reg);
379 }
380 }
381 }
382 }
383 forced
384}
385
386fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
388 let mut reuses = vec![None; func.vregs()];
389 for block in func.blocks() {
390 for inst in func.insts(block) {
391 let operands = &func[func[inst].operands];
392 for operand in operands {
393 let Constraint::Reuse(other) = operand.constraint else { continue };
394 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
395 let Some(number) = number else { continue };
396 let source = operands[usize::from(other)].reg;
397 reuses[number] = Some(Reuse { source, at: order.early(inst) });
398 }
399 }
400 }
401 reuses
402}
403
404fn index(reg: Reg) -> usize {
406 usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
407}
408
409#[cfg(test)]
410mod tests {
411 use rucc_base::Interner;
412 use rucc_mir::{BlockCall, Opcode, Operand};
413 use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, SYSV};
414
415 use super::*;
416
417 fn env() -> Env {
419 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
420 Env::new().with(GPR, order, scratch)
421 }
422
423 fn narrow(count: usize) -> Env {
426 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
427 }
428
429 fn named(place: Option<Place>) -> String {
431 match place {
432 Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
433 Some(Place::Slot(slot)) => format!("slot {slot}"),
434 None => "nowhere".to_string(),
435 }
436 }
437
438 fn places(func: &Func, env: &Env) -> Vec<String> {
440 let order = Order::of(func);
441 let live = Live::of(func, &order);
442 let assignment = assign(func, &order, &live, env);
443 (0..func.vregs())
444 .map(|number| {
445 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
446 named(assignment.place(reg))
447 })
448 .collect()
449 }
450
451 #[test]
452 fn two_values_that_are_never_both_wanted_share_a_register() {
453 let mut names = Interner::new();
454 let mut func = Func::new(names.intern("f"));
455 let opcode = Opcode::new(names.intern("x64.nop"));
456 let block = func.create_block();
457 let first = func.new_vreg(GPR);
458 let second = func.new_vreg(GPR);
459 func.build(block, opcode).def(first, GPR).finish();
460 func.build(block, opcode).uses(first, GPR).finish();
461 func.build(block, opcode).def(second, GPR).finish();
462 func.build(block, opcode).uses(second, GPR).finish();
463
464 assert_eq!(places(&func, &env()), ["rax", "rax"]);
467 }
468
469 #[test]
470 fn two_values_that_are_both_wanted_do_not() {
471 let mut names = Interner::new();
472 let mut func = Func::new(names.intern("f"));
473 let opcode = Opcode::new(names.intern("x64.nop"));
474 let block = func.create_block();
475 let first = func.new_vreg(GPR);
476 let second = func.new_vreg(GPR);
477 func.build(block, opcode).def(first, GPR).finish();
478 func.build(block, opcode).def(second, GPR).finish();
479 func.build(block, opcode).uses(first, GPR).finish();
480 func.build(block, opcode).uses(second, GPR).finish();
481
482 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
483 }
484
485 #[test]
486 fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
487 let mut names = Interner::new();
488 let mut func = Func::new(names.intern("f"));
489 let opcode = Opcode::new(names.intern("x64.nop"));
490 let block = func.create_block();
491 let long = func.new_vreg(GPR);
492 let short = func.new_vreg(GPR);
493 let third = func.new_vreg(GPR);
494 func.build(block, opcode).def(long, GPR).finish();
495 func.build(block, opcode).def(short, GPR).finish();
496 func.build(block, opcode).def(third, GPR).finish();
497 func.build(block, opcode).uses(short, GPR).finish();
498 func.build(block, opcode).uses(third, GPR).finish();
499 func.build(block, opcode).uses(long, GPR).finish();
500
501 assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
504 }
505
506 #[test]
507 fn a_register_an_instruction_insists_on_is_left_alone_over_that_instruction() {
508 let mut names = Interner::new();
509 let mut func = Func::new(names.intern("f"));
510 let opcode = Opcode::new(names.intern("x64.nop"));
511 let block = func.create_block();
512 let across = func.new_vreg(GPR);
513 let dividend = func.new_vreg(GPR);
514 let quotient = func.new_vreg(GPR);
515 let remainder = func.new_vreg(GPR);
516 func.build(block, opcode).def(across, GPR).finish();
517 func.build(block, opcode).def(dividend, GPR).finish();
518 func.build(block, opcode)
519 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
520 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
521 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
522 .finish();
523 func.build(block, opcode).uses(across, GPR).finish();
524
525 assert_eq!(places(&func, &env()), ["rcx", "rsi", "rsi", "rdi"]);
529 }
530
531 #[test]
532 fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
533 let mut names = Interner::new();
534 let mut func = Func::new(names.intern("f"));
535 let opcode = Opcode::new(names.intern("x64.nop"));
536 let block = func.create_block();
537 let value = func.new_vreg(GPR);
538 func.build(block, opcode).def(value, GPR).finish();
539 func.build(block, opcode)
540 .operand(Operand::read(value, GPR).with(Constraint::Stack))
541 .finish();
542
543 assert_eq!(places(&func, &env()), ["slot 0"]);
544 }
545
546 #[test]
547 fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
548 let mut names = Interner::new();
549 let mut func = Func::new(names.intern("f"));
550 let opcode = Opcode::new(names.intern("x64.nop"));
551 let block = func.create_block();
552 let left = func.new_vreg(GPR);
553 let right = func.new_vreg(GPR);
554 let sum = func.new_vreg(GPR);
555 func.build(block, opcode).def(left, GPR).finish();
556 func.build(block, opcode).def(right, GPR).finish();
557 func.build(block, opcode)
558 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
559 .uses(left, GPR)
560 .uses(right, GPR)
561 .finish();
562 func.build(block, opcode).uses(right, GPR).finish();
563
564 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
567 }
568
569 #[test]
570 fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
571 let mut names = Interner::new();
572 let mut func = Func::new(names.intern("f"));
573 let opcode = Opcode::new(names.intern("x64.nop"));
574 let block = func.create_block();
575 let left = func.new_vreg(GPR);
576 let right = func.new_vreg(GPR);
577 let sum = func.new_vreg(GPR);
578 func.build(block, opcode).def(left, GPR).finish();
579 func.build(block, opcode).def(right, GPR).finish();
580 func.build(block, opcode)
581 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
582 .uses(left, GPR)
583 .uses(right, GPR)
584 .finish();
585 func.build(block, opcode).uses(left, GPR).finish();
586
587 assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
591 }
592
593 #[test]
594 fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
595 let mut names = Interner::new();
596 let mut func = Func::new(names.intern("f"));
597 let opcode = Opcode::new(names.intern("x64.nop"));
598 let head = func.create_block();
599 let body = func.create_block();
600 let carried = func.new_vreg(GPR);
601 let inside = func.new_vreg(GPR);
602 func.build(head, opcode).def(carried, GPR).finish();
603 *func.succs_mut(head) = vec![BlockCall::to(body)];
604 func.build(body, opcode).def(inside, GPR).finish();
605 func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
606 *func.succs_mut(body) = vec![BlockCall::to(body)];
607
608 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
611 }
612
613 #[test]
614 fn a_frame_says_what_each_of_its_slots_is_for() {
615 let mut names = Interner::new();
616 let mut func = Func::new(names.intern("f"));
617 let opcode = Opcode::new(names.intern("x64.nop"));
618 let block = func.create_block();
619 let first = func.new_vreg(GPR);
620 let second = func.new_vreg(GPR);
621 func.build(block, opcode).def(first, GPR).finish();
622 func.build(block, opcode).def(second, GPR).finish();
623 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
624
625 let order = Order::of(&func);
626 let live = Live::of(&func, &order);
627 let assignment = assign(&func, &order, &live, &narrow(1));
628 assert_eq!(assignment.spilled(), 1);
629 assert_eq!(assignment.slots(), [GPR]);
630 assert_eq!(assignment.place(Reg::physical(RCX)), None);
633 assert_eq!(env().scratch(GPR), [R13, R14, R15]);
634 }
635}