1use std::cmp::Reverse;
106
107use rucc_mir::{Constraint, Flags, Func, Inst, Operand, Reg, Role};
108use rucc_target::{PhysReg, RegClass};
109
110use crate::live::{Area, Live, Range};
111use crate::order::{Order, Point};
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub enum Place {
116 Reg(PhysReg),
118 Slot(u32),
121}
122
123#[derive(Debug, Clone, Default)]
133pub struct Env {
134 classes: Vec<Class>,
135}
136
137#[derive(Debug, Clone, Default)]
139struct Class {
140 order: Vec<PhysReg>,
141 scratch: Vec<PhysReg>,
142}
143
144impl Env {
145 #[must_use]
147 pub fn new() -> Self {
148 Self::default()
149 }
150
151 #[must_use]
153 pub fn with(mut self, class: RegClass, order: &[PhysReg], scratch: &[PhysReg]) -> Self {
154 let index = usize::from(class.number());
155 if self.classes.len() <= index {
156 self.classes.resize(index + 1, Class::default());
157 }
158 self.classes[index] = Class { order: order.to_vec(), scratch: scratch.to_vec() };
159 self
160 }
161
162 #[must_use]
164 pub fn order(&self, class: RegClass) -> &[PhysReg] {
165 self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.order)
166 }
167
168 pub(crate) fn offered(&self) -> impl Iterator<Item = &[PhysReg]> + '_ {
170 self.classes.iter().map(|class| class.order.as_slice())
171 }
172
173 #[must_use]
175 pub fn scratch(&self, class: RegClass) -> &[PhysReg] {
176 self.classes.get(usize::from(class.number())).map_or(&[], |class| &class.scratch)
177 }
178}
179
180#[derive(Debug, Clone)]
182pub struct Assignment {
183 places: Vec<Option<Place>>,
184 slots: Vec<RegClass>,
185 commuted: Vec<Inst>,
186}
187
188impl Assignment {
189 pub(crate) fn commute(&mut self, inst: Inst) {
191 self.commuted.push(inst);
192 }
193
194 #[must_use]
201 pub fn empty(vregs: usize) -> Self {
202 Self { places: vec![None; vregs], slots: Vec::new(), commuted: Vec::new() }
203 }
204
205 #[must_use]
211 pub fn commuted(&self) -> &[Inst] {
212 &self.commuted
213 }
214
215 pub fn put(&mut self, reg: Reg, place: Place) {
222 self.places[index(reg)] = Some(place);
223 }
224
225 pub fn take_slot(&mut self, class: RegClass) -> u32 {
231 let slot = u32::try_from(self.slots.len()).expect("too many spilled values");
232 self.slots.push(class);
233 slot
234 }
235
236 #[must_use]
239 pub fn place(&self, reg: Reg) -> Option<Place> {
240 self.places.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
241 }
242
243 #[must_use]
245 pub fn slots(&self) -> &[RegClass] {
246 &self.slots
247 }
248
249 pub fn placed(&self) -> impl Iterator<Item = (Reg, Place)> + '_ {
255 self.places.iter().enumerate().filter_map(|(number, place)| {
256 let number = u32::try_from(number).ok()?;
257 Some((Reg::virtual_reg(number), (*place)?))
258 })
259 }
260
261 #[must_use]
263 pub fn spilled(&self) -> usize {
264 self.slots.len()
265 }
266
267 pub(crate) fn spill(&mut self, reg: Reg, class: RegClass) {
269 let slot = self.take_slot(class);
270 self.put(reg, Place::Slot(slot));
271 }
272}
273
274#[derive(Debug, Clone, Copy)]
276struct Interval<'a> {
277 reg: Reg,
278 class: RegClass,
279 range: Range,
282 area: Area<'a>,
285}
286
287#[derive(Debug, Clone, Copy)]
289struct Held<'a> {
290 reg: Reg,
291 class: RegClass,
292 range: Range,
293 area: Area<'a>,
294 at: PhysReg,
295 since: usize,
298}
299
300#[derive(Default)]
309struct Active<'a> {
310 by: Vec<Vec<Held<'a>>>,
311 soonest: Vec<Point>,
315 count: usize,
317 pieces: Vec<Vec<Pieces>>,
320}
321
322impl<'a> Active<'a> {
323 fn at(&self, at: PhysReg) -> &[Held<'a>] {
325 self.by.get(usize::from(at.number())).map_or(&[], Vec::as_slice)
326 }
327
328 fn push(&mut self, reg: Reg, class: RegClass, range: Range, area: Area<'a>, at: PhysReg) {
329 let slot = usize::from(at.number());
330 if self.by.len() <= slot {
331 self.by.resize_with(slot + 1, Vec::new);
332 self.soonest.resize(slot + 1, Point::MAX);
333 }
334 self.by[slot].push(Held { reg, class, range, area, at, since: self.count });
335 self.soonest[slot] = self.soonest[slot].min(range.end);
336 self.count += 1;
337 let held = &self.by[slot];
338 let pieces = pieces_mut(&mut self.pieces, class, slot);
339 if pieces.kept {
340 pieces.drop_before(range.start);
341 for piece in area.pieces() {
342 pieces.insert(piece, reg);
343 }
344 } else if held.len() > FEW {
345 pieces.kept = true;
347 for held in held.iter().filter(|held| held.class == class) {
348 for piece in held.area.pieces() {
349 pieces.insert(piece, held.reg);
350 }
351 }
352 }
353 }
354
355 fn taken(&self, class: RegClass, at: PhysReg, area: Area<'_>, except: Option<Reg>) -> bool {
357 let held = self.at(at);
358 if held.len() > FEW {
359 if let Some(answer) = self.listed(class, at, area, except) {
360 return answer;
361 }
362 }
363 held.iter()
364 .any(|held| held.class == class && Some(held.reg) != except && held.area.overlaps(area))
365 }
366
367 #[inline(never)]
371 fn listed(
372 &self,
373 class: RegClass,
374 at: PhysReg,
375 area: Area<'_>,
376 except: Option<Reg>,
377 ) -> Option<bool> {
378 let by = self.pieces.get(usize::from(class.number()))?;
379 let pieces = by.get(usize::from(at.number()))?;
380 (pieces.kept && !pieces.broken).then(|| pieces.touch(area, except))
381 }
382
383 #[inline(never)]
386 fn owners(&self, class: RegClass, slot: usize, area: Area<'_>) -> Option<Vec<Reg>> {
387 let pieces = self.pieces.get(usize::from(class.number()))?.get(slot)?;
388 if pieces.kept { pieces.owners(area) } else { None }
389 }
390
391 fn evict(
393 &mut self,
394 class: RegClass,
395 at: PhysReg,
396 goes: impl Fn(&Held<'a>) -> bool,
397 mut gone: impl FnMut(&Held<'a>),
398 ) {
399 let slot = usize::from(at.number());
400 let mut taken = Vec::new();
401 self.by[slot].retain(|held| {
402 let out = held.class == class && goes(held);
403 if out {
404 gone(held);
405 taken.push((held.reg, held.area));
406 }
407 !out
408 });
409 let pieces = pieces_mut(&mut self.pieces, class, slot);
410 if pieces.kept {
411 for (reg, area) in taken {
412 for piece in area.pieces() {
413 pieces.remove(piece, reg);
414 }
415 }
416 }
417 }
418
419 fn expire(&mut self, point: Point) {
425 for (held, soonest) in self.by.iter_mut().zip(&mut self.soonest) {
426 if *soonest >= point {
427 continue;
428 }
429 held.retain(|held| held.range.end >= point);
430 *soonest = held.iter().map(|held| held.range.end).min().unwrap_or(Point::MAX);
431 }
432 }
433}
434
435pub(crate) const FEW: usize = 4;
439
440fn pieces_mut(pieces: &mut Vec<Vec<Pieces>>, class: RegClass, slot: usize) -> &mut Pieces {
442 let class = usize::from(class.number());
443 if pieces.len() <= class {
444 pieces.resize_with(class + 1, Vec::new);
445 }
446 let by = &mut pieces[class];
447 if by.len() <= slot {
448 by.resize_with(slot + 1, Pieces::default);
449 }
450 &mut by[slot]
451}
452
453#[derive(Default)]
467pub(crate) struct Pieces {
468 list: Vec<(Point, Point, Reg)>,
470 broken: bool,
472 pub(crate) kept: bool,
475}
476
477impl Pieces {
478 #[inline(never)]
479 pub(crate) fn insert(&mut self, piece: Range, reg: Reg) {
480 let key = (piece.start, piece.end);
481 let at = self.list.partition_point(|&(start, end, _)| (start, end) <= key);
482 let after = at == 0 || self.list[at - 1].1 <= piece.end;
483 let before = self.list.get(at).is_none_or(|next| piece.end <= next.1);
484 if !(after && before) {
485 self.broken = true;
486 }
487 self.list.insert(at, (piece.start, piece.end, reg));
488 }
489
490 pub(crate) fn remove(&mut self, piece: Range, reg: Reg) {
491 let from = self.list.partition_point(|&(start, _, _)| start < piece.start);
492 let found = self.list[from..]
493 .iter()
494 .take_while(|&&(start, _, _)| start == piece.start)
495 .position(|&(_, end, owner)| end == piece.end && owner == reg);
496 if let Some(offset) = found {
497 self.list.remove(from + offset);
498 }
499 }
500
501 fn drop_before(&mut self, point: Point) {
504 if !self.broken {
505 let gone = self.list.partition_point(|&(_, end, _)| end < point);
506 self.list.drain(..gone);
507 }
508 }
509
510 fn touch(&self, area: Area<'_>, except: Option<Reg>) -> bool {
512 area.pieces().any(|piece| {
513 let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
514 self.list[..below]
515 .iter()
516 .rev()
517 .find(|&&(_, _, owner)| Some(owner) != except)
518 .is_some_and(|&(_, end, _)| end >= piece.start)
519 })
520 }
521
522 pub(crate) fn owners(&self, area: Area<'_>) -> Option<Vec<Reg>> {
527 if self.broken {
528 return None;
529 }
530 let mut owners = Vec::new();
531 for piece in area.pieces() {
532 let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
533 let touching =
534 self.list[..below].iter().rev().take_while(|&&(_, end, _)| end >= piece.start);
535 owners.extend(touching.map(|&(_, _, owner)| owner));
536 }
537 owners.sort_unstable();
538 owners.dedup();
539 Some(owners)
540 }
541}
542
543#[derive(Debug, Clone, Copy)]
545struct Blocked {
546 class: RegClass,
547 at: PhysReg,
548 point: Point,
552 by: Option<Reg>,
557 above: Option<u8>,
561}
562
563impl Blocked {
564 fn reaches(&self, width: Option<u8>) -> bool {
567 match (self.above, width) {
568 (Some(above), Some(width)) => width > above,
569 _ => true,
570 }
571 }
572}
573
574#[derive(Debug, Clone, Copy)]
576pub(crate) struct Reuse {
577 pub(crate) source: Reg,
579 pub(crate) second: Option<Reg>,
582 pub(crate) at: Point,
584 pub(crate) inst: Inst,
586}
587
588#[must_use]
595pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
596 let blocked = blocked(func, order);
597 let forced = forced(func);
598 let reuses = reuses(func, order);
599 let hints = hints(func);
600 let passed = passed(func);
601
602 let mut intervals = Vec::with_capacity(func.vregs());
603 for (number, reuse) in reuses.iter().enumerate() {
604 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
605 let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
606 continue;
607 };
608 if let Some(reuse) = reuse {
609 area = area.with(reuse.at);
610 }
611 intervals.push(Interval { reg, class, range: area.hull(), area });
612 }
613 intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
614
615 let mut assignment = Assignment::empty(func.vregs());
616 let mut active = Active::default();
617 for interval in intervals {
618 active.expire(interval.range.start);
619 if forced.contains(&interval.reg) {
620 assignment.spill(interval.reg, interval.class);
621 continue;
622 }
623 assert!(
628 !env.order(interval.class).is_empty(),
629 "a value in class {}, which the target hands out no registers from",
630 interval.class.number()
631 );
632 let reuse = reuses[index(interval.reg)];
633 let coalesced = |source| coalesce(&assignment, &active, &blocked, live, interval, source);
634 let first = reuse.and_then(|reuse| coalesced(reuse.source));
635 let second = reuse.and_then(|reuse| reuse.second).and_then(coalesced);
636 let hinted_at = |at: Option<PhysReg>| {
647 at.is_some_and(|at| {
648 hints[index(interval.reg)].contains(&at)
649 || passed[index(interval.reg)]
650 .iter()
651 .any(|¶m| assignment.place(param) == Some(Place::Reg(at)))
652 })
653 };
654 let commute =
655 second.is_some() && (first.is_none() || hinted_at(second) && !hinted_at(first));
656 let two_address = if commute { second } else { first };
657 if let (true, Some(reuse)) = (commute, reuse) {
658 assignment.commuted.push(reuse.inst);
659 }
660 let hinted = hints[index(interval.reg)].iter().copied().find(|&at| {
664 env.order(interval.class).contains(&at)
665 && available(&active, &blocked, interval, at, None, Want::Clear)
666 });
667 let scan = |want| {
672 env.order(interval.class)
673 .iter()
674 .copied()
675 .find(|&at| available(&active, &blocked, interval, at, None, want))
676 };
677 let chosen =
678 two_address.or(hinted).or_else(|| scan(Want::Clear)).or_else(|| scan(Want::Allowed));
679 match chosen {
680 Some(at) => {
681 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
682 active.push(interval.reg, interval.class, interval.range, interval.area, at);
683 }
684 None => spill_one(&mut assignment, &mut active, &blocked, interval),
685 }
686 }
687 assignment
688}
689
690#[derive(Debug, Clone, Copy, PartialEq, Eq)]
692pub(crate) enum Want {
693 Clear,
695 Allowed,
699}
700
701pub(crate) struct Blocks {
717 all: Vec<Blocked>,
719 points: Vec<Point>,
721 spans: Vec<(usize, usize)>,
724 stride: usize,
726 widths: Vec<Option<u8>>,
729}
730
731impl Blocks {
732 pub(crate) fn insists(
736 &self,
737 reg: Reg,
738 class: RegClass,
739 area: Area<'_>,
740 range: Range,
741 at: PhysReg,
742 want: Want,
743 ) -> bool {
744 self.over(class, at, range).any(|one| {
745 one.by != Some(reg)
746 && one.reaches(self.width(reg))
747 && (want == Want::Clear || area.covers(one.point))
748 })
749 }
750
751 fn width(&self, reg: Reg) -> Option<u8> {
753 let number = usize::try_from(reg.number()?).ok()?;
754 self.widths.get(number).copied().flatten()
755 }
756
757 pub(crate) fn taken(&self) -> impl Iterator<Item = (RegClass, PhysReg, Point)> + '_ {
762 self.all
763 .iter()
764 .filter(|one| one.by.is_none() && one.above.is_none())
765 .map(|one| (one.class, one.at, one.point))
766 }
767
768 #[inline]
773 fn over(
774 &self,
775 class: RegClass,
776 at: PhysReg,
777 range: Range,
778 ) -> impl Iterator<Item = &Blocked> + '_ {
779 let (low, high) = if usize::from(at.number()) < self.stride {
780 let key = usize::from(class.number()) * self.stride + usize::from(at.number());
781 self.spans.get(key).copied().unwrap_or((0, 0))
782 } else {
783 (0, 0)
784 };
785 let first = low + self.points[low..high].partition_point(|&point| point < range.start);
786 self.all[first..high].iter().take_while(move |one| one.point <= range.end)
787 }
788}
789
790fn available(
799 active: &Active<'_>,
800 blocked: &Blocks,
801 interval: Interval<'_>,
802 at: PhysReg,
803 except: Option<Reg>,
804 want: Want,
805) -> bool {
806 let taken = active.taken(interval.class, at, interval.area, except);
807 let width = blocked.width(interval.reg);
808 let insisted = blocked.over(interval.class, at, interval.range).any(|one| {
809 one.by != Some(interval.reg)
810 && one.reaches(width)
811 && (want == Want::Clear || interval.area.covers(one.point))
812 });
813 !taken && !insisted
814}
815
816fn coalesce(
819 assignment: &Assignment,
820 active: &Active<'_>,
821 blocked: &Blocks,
822 live: &Live,
823 interval: Interval<'_>,
824 source: Reg,
825) -> Option<PhysReg> {
826 let Some(Place::Reg(at)) = assignment.place(source) else { return None };
827 active.at(at).iter().find(|held| held.reg == source)?;
828 let free = available(active, blocked, interval, at, Some(source), Want::Allowed);
844 (apart(live, source, interval.reg) && free).then_some(at)
845}
846
847pub(crate) fn apart(live: &Live, first: Reg, second: Reg) -> bool {
849 match (live.area(first), live.area(second)) {
850 (Some(first), Some(second)) => !first.overlaps(second),
851 _ => false,
852 }
853}
854
855fn spill_one<'a>(
863 assignment: &mut Assignment,
864 active: &mut Active<'a>,
865 blocked: &Blocks,
866 interval: Interval<'a>,
867) {
868 let mut costs: Vec<(usize, PhysReg, usize, Point)> = Vec::new();
874 for (slot, values) in active.by.iter().enumerate() {
875 let owners = if values.len() > FEW {
878 active.owners(interval.class, slot, interval.area)
879 } else {
880 None
881 };
882 for held in values {
883 if held.class != interval.class {
884 continue;
885 }
886 let touches = match &owners {
887 Some(owners) => owners.binary_search(&held.reg).is_ok(),
888 None => held.area.overlaps(interval.area),
889 };
890 if !touches {
891 continue;
892 }
893 match costs.iter_mut().find(|(_, at, _, _)| *at == held.at) {
894 Some((first, _, count, reach)) => {
895 *first = (*first).min(held.since);
896 *count += 1;
897 *reach = (*reach).max(held.range.end);
898 }
899 None => costs.push((held.since, held.at, 1, held.range.end)),
900 }
901 }
902 }
903 costs.sort_unstable_by_key(|&(first, _, _, _)| first);
904 let none = Active::default();
907 let chosen = costs
908 .iter()
909 .filter(|&&(_, at, _, reach)| {
910 reach > interval.range.end
911 && available(&none, blocked, interval, at, None, Want::Allowed)
912 })
913 .min_by_key(|&&(_, _, count, reach)| (count, Reverse(reach)))
914 .map(|&(_, at, _, _)| at);
915 match chosen {
916 Some(at) => {
917 active.evict(
918 interval.class,
919 at,
920 |held| held.area.overlaps(interval.area),
921 |held| assignment.spill(held.reg, held.class),
922 );
923 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
924 active.push(interval.reg, interval.class, interval.range, interval.area, at);
925 }
926 None => assignment.spill(interval.reg, interval.class),
927 }
928}
929
930pub(crate) fn blocked(func: &Func, order: &Order) -> Blocks {
936 let mut blocked = Vec::new();
937 let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
938 for block in func.blocks() {
939 for inst in func.insts(block) {
940 let operands = &func[func[inst].operands];
941 claimed.clear();
942 for operand in operands {
943 if let Some(at) = insisted(operand) {
944 let key = (operand.class, at);
945 if !claimed.contains(&key) {
946 claimed.push(key);
947 }
948 }
949 }
950 for &(class, at) in &claimed {
951 for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
956 {
957 let mut named = false;
958 for operand in operands {
959 let mine = insisted(operand) == Some(at) && operand.class == class;
960 if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
961 continue;
962 }
963 named = true;
964 let by = operand.reg.is_virtual().then_some(operand.reg);
965 let above = match operand.constraint {
966 Constraint::Above(above) => Some(above),
967 _ => None,
968 };
969 blocked.push(Blocked { class, at, point, by, above });
970 }
971 if !named && role == Role::Def {
990 blocked.push(Blocked { class, at, point, by: None, above: None });
991 }
992 }
993 }
994 }
995 }
996 blocked.sort_by_key(|one: &Blocked| (one.class, one.at, one.point));
1002 let widths = (0..func.vregs())
1003 .map(|number| func.width(Reg::virtual_reg(u32::try_from(number).ok()?)))
1004 .collect();
1005 let points = blocked.iter().map(|one| one.point).collect();
1006 let stride = blocked.iter().map(|one| usize::from(one.at.number()) + 1).max().unwrap_or(0);
1007 let classes = blocked.last().map_or(0, |one| usize::from(one.class.number()) + 1);
1008 let mut spans = vec![(0, 0); classes * stride];
1009 for (index, one) in blocked.iter().enumerate() {
1010 let key = usize::from(one.class.number()) * stride + usize::from(one.at.number());
1011 let span = &mut spans[key];
1012 if span.1 == 0 {
1013 span.0 = index;
1014 }
1015 span.1 = index + 1;
1016 }
1017 Blocks { all: blocked, points, spans, stride, widths }
1018}
1019
1020fn insisted(operand: &Operand) -> Option<PhysReg> {
1023 match operand.constraint {
1024 Constraint::Fixed(at) => Some(at),
1025 _ => operand.reg.phys(),
1026 }
1027}
1028
1029pub(crate) fn hints(func: &Func) -> Vec<Vec<PhysReg>> {
1039 let mut hints = vec![Vec::new(); func.vregs()];
1040 for block in func.blocks() {
1041 for inst in func.insts(block) {
1042 for operand in &func[func[inst].operands] {
1043 let Constraint::Fixed(at) = operand.constraint else { continue };
1044 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1045 let Some(number) = number else { continue };
1046 let wanted: &mut Vec<PhysReg> = &mut hints[number];
1047 if func.class_of(operand.reg) == Some(operand.class) && !wanted.contains(&at) {
1048 wanted.push(at);
1049 }
1050 }
1051 }
1052 }
1053 hints
1054}
1055
1056pub(crate) fn passed(func: &Func) -> Vec<Vec<Reg>> {
1058 let mut passed = vec![Vec::new(); func.vregs()];
1059 for block in func.blocks() {
1060 for call in &func[block].succs {
1061 for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
1062 let number = arg.number().and_then(|number| usize::try_from(number).ok());
1063 let Some(number) = number else { continue };
1064 let to: &mut Vec<Reg> = &mut passed[number];
1065 if !to.contains(¶m.reg) {
1066 to.push(param.reg);
1067 }
1068 }
1069 }
1070 }
1071 passed
1072}
1073
1074pub(crate) fn forced(func: &Func) -> Vec<Reg> {
1076 let mut forced = Vec::new();
1077 for block in func.blocks() {
1078 for inst in func.insts(block) {
1079 for operand in &func[func[inst].operands] {
1080 if operand.constraint == Constraint::Stack
1081 && operand.reg.is_virtual()
1082 && !forced.contains(&operand.reg)
1083 {
1084 forced.push(operand.reg);
1085 }
1086 }
1087 }
1088 }
1089 forced
1090}
1091
1092pub(crate) fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
1094 let mut reuses = vec![None; func.vregs()];
1095 for block in func.blocks() {
1096 for inst in func.insts(block) {
1097 let operands = &func[func[inst].operands];
1098 for operand in operands {
1099 let Constraint::Reuse(other) = operand.constraint else { continue };
1100 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1101 let Some(number) = number else { continue };
1102 let source = operands[usize::from(other)].reg;
1103 let second = if func[inst].flags.contains(Flags::COMMUTES) {
1104 swappable(operands, usize::from(other))
1105 } else {
1106 None
1107 };
1108 reuses[number] = Some(Reuse { source, second, at: order.early(inst), inst });
1109 }
1110 }
1111 }
1112 reuses
1113}
1114
1115fn swappable(operands: &[Operand], other: usize) -> Option<Reg> {
1122 let [answer, first, second] = operands else { return None };
1123 let same = second.class == first.class && second.class == answer.class;
1124 let plain = second.role == Role::Use && second.constraint == Constraint::Reg;
1125 (other == 1 && same && plain && second.reg.is_virtual() && second.reg != first.reg)
1126 .then_some(second.reg)
1127}
1128
1129fn index(reg: Reg) -> usize {
1131 usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
1132}
1133
1134#[cfg(test)]
1135mod tests {
1136 use rucc_base::Interner;
1137 use rucc_mir::{BlockCall, Opcode, Operand, Param};
1138 use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, RSI, SYSV};
1139
1140 use super::*;
1141
1142 fn env() -> Env {
1144 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
1145 Env::new().with(GPR, order, scratch)
1146 }
1147
1148 fn narrow(count: usize) -> Env {
1151 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
1152 }
1153
1154 fn named(place: Option<Place>) -> String {
1156 match place {
1157 Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
1158 Some(Place::Slot(slot)) => format!("slot {slot}"),
1159 None => "nowhere".to_string(),
1160 }
1161 }
1162
1163 fn places(func: &Func, env: &Env) -> Vec<String> {
1165 let order = Order::of(func);
1166 let live = Live::of(func, &order);
1167 let assignment = assign(func, &order, &live, env);
1168 (0..func.vregs())
1169 .map(|number| {
1170 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
1171 named(assignment.place(reg))
1172 })
1173 .collect()
1174 }
1175
1176 #[test]
1177 fn two_values_that_are_never_both_wanted_share_a_register() {
1178 let mut names = Interner::new();
1179 let mut func = Func::new(names.intern("f"));
1180 let opcode = Opcode::new(names.intern("x64.nop"));
1181 let block = func.create_block();
1182 let first = func.new_vreg(GPR);
1183 let second = func.new_vreg(GPR);
1184 func.build(block, opcode).def(first, GPR).finish();
1185 func.build(block, opcode).uses(first, GPR).finish();
1186 func.build(block, opcode).def(second, GPR).finish();
1187 func.build(block, opcode).uses(second, GPR).finish();
1188
1189 assert_eq!(places(&func, &env()), ["rax", "rax"]);
1192 }
1193
1194 fn over_the_top(width: u32) -> Func {
1197 let mut names = Interner::new();
1198 let mut func = Func::new(names.intern("f"));
1199 let opcode = Opcode::new(names.intern("x64.nop"));
1200 let block = func.create_block();
1201 let held = func.new_vreg(GPR);
1202 func.set_width(held, width);
1203 func.build(block, opcode).def(held, GPR).finish();
1204 func.build(block, opcode)
1205 .operand(Operand::write(Reg::physical(RAX), GPR))
1206 .operand(Operand::write(Reg::physical(RCX), GPR).with(Constraint::Above(8)))
1207 .finish();
1208 func.build(block, opcode).uses(held, GPR).finish();
1209 func
1210 }
1211
1212 #[test]
1213 fn a_value_that_fits_under_what_an_instruction_writes_stays_in_the_register() {
1214 assert_eq!(places(&over_the_top(8), &narrow(2)), ["rcx"]);
1215 assert_eq!(places(&over_the_top(4), &narrow(2)), ["rcx"]);
1216 }
1217
1218 #[test]
1219 fn a_value_wider_than_that_or_of_no_known_width_does_not() {
1220 assert_eq!(places(&over_the_top(16), &narrow(2)), ["slot 0"]);
1221 assert_eq!(places(&over_the_top(0), &narrow(2)), ["slot 0"]);
1222 }
1223
1224 #[test]
1225 fn two_values_that_are_both_wanted_do_not() {
1226 let mut names = Interner::new();
1227 let mut func = Func::new(names.intern("f"));
1228 let opcode = Opcode::new(names.intern("x64.nop"));
1229 let block = func.create_block();
1230 let first = func.new_vreg(GPR);
1231 let second = func.new_vreg(GPR);
1232 func.build(block, opcode).def(first, GPR).finish();
1233 func.build(block, opcode).def(second, GPR).finish();
1234 func.build(block, opcode).uses(first, GPR).finish();
1235 func.build(block, opcode).uses(second, GPR).finish();
1236
1237 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1238 }
1239
1240 #[test]
1241 fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
1242 let mut names = Interner::new();
1243 let mut func = Func::new(names.intern("f"));
1244 let opcode = Opcode::new(names.intern("x64.nop"));
1245 let block = func.create_block();
1246 let wanted = func.new_vreg(GPR);
1247 let spare = func.new_vreg(GPR);
1248 func.build(block, opcode)
1251 .def(wanted, GPR)
1252 .operand(Operand::write_early(spare, GPR))
1253 .finish();
1254 func.build(block, opcode).uses(wanted, GPR).finish();
1255
1256 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1262 }
1263
1264 #[test]
1265 fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
1266 let mut names = Interner::new();
1267 let mut func = Func::new(names.intern("f"));
1268 let opcode = Opcode::new(names.intern("x64.nop"));
1269 let block = func.create_block();
1270 let long = func.new_vreg(GPR);
1271 let short = func.new_vreg(GPR);
1272 let third = func.new_vreg(GPR);
1273 func.build(block, opcode).def(long, GPR).finish();
1274 func.build(block, opcode).def(short, GPR).finish();
1275 func.build(block, opcode).def(third, GPR).finish();
1276 func.build(block, opcode).uses(short, GPR).finish();
1277 func.build(block, opcode).uses(third, GPR).finish();
1278 func.build(block, opcode).uses(long, GPR).finish();
1279
1280 assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
1283 }
1284
1285 #[test]
1286 fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
1287 let mut names = Interner::new();
1288 let mut func = Func::new(names.intern("f"));
1289 let opcode = Opcode::new(names.intern("x64.nop"));
1290 let block = func.create_block();
1291 let across = func.new_vreg(GPR);
1292 let dividend = func.new_vreg(GPR);
1293 let quotient = func.new_vreg(GPR);
1294 let remainder = func.new_vreg(GPR);
1295 func.build(block, opcode).def(across, GPR).finish();
1296 func.build(block, opcode).def(dividend, GPR).finish();
1297 func.build(block, opcode)
1298 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1299 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1300 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1301 .finish();
1302 func.build(block, opcode).uses(across, GPR).finish();
1303
1304 assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
1309 }
1310
1311 #[test]
1321 fn a_value_that_dies_at_an_instruction_stays_out_of_what_it_fills_first() {
1322 let mut names = Interner::new();
1323 let mut func = Func::new(names.intern("f"));
1324 let opcode = Opcode::new(names.intern("x64.nop"));
1325 let block = func.create_block();
1326 let across = func.new_vreg(GPR);
1327 let dividend = func.new_vreg(GPR);
1328 let divisor = func.new_vreg(GPR);
1329 let remainder = func.new_vreg(GPR);
1330 func.build(block, opcode).def(across, GPR).finish();
1331 func.build(block, opcode).def(dividend, GPR).finish();
1332 func.build(block, opcode).def(divisor, GPR).finish();
1333 func.build(block, opcode)
1334 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1335 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1336 .operand(Operand::read(divisor, GPR))
1337 .finish();
1338 func.build(block, opcode).uses(across, GPR).uses(remainder, GPR).finish();
1339
1340 assert_eq!(places(&func, &narrow(4)), ["rcx", "rax", "rsi", "rdx"]);
1344 }
1345
1346 #[test]
1347 fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
1348 let mut names = Interner::new();
1349 let mut func = Func::new(names.intern("f"));
1350 let opcode = Opcode::new(names.intern("x64.nop"));
1351 let block = func.create_block();
1352 let dividend = func.new_vreg(GPR);
1353 let quotient = func.new_vreg(GPR);
1354 func.build(block, opcode).def(dividend, GPR).finish();
1355 func.build(block, opcode)
1356 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1357 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1358 .finish();
1359 func.build(block, opcode).uses(dividend, GPR).finish();
1360
1361 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1365 }
1366
1367 #[test]
1368 fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
1369 let mut names = Interner::new();
1370 let mut func = Func::new(names.intern("f"));
1371 let opcode = Opcode::new(names.intern("x64.nop"));
1372 let block = func.create_block();
1373 let value = func.new_vreg(GPR);
1374 func.build(block, opcode).def(value, GPR).finish();
1375 func.build(block, opcode)
1376 .operand(Operand::read(value, GPR).with(Constraint::Stack))
1377 .finish();
1378
1379 assert_eq!(places(&func, &env()), ["slot 0"]);
1380 }
1381
1382 #[test]
1383 fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
1384 let mut names = Interner::new();
1385 let mut func = Func::new(names.intern("f"));
1386 let opcode = Opcode::new(names.intern("x64.nop"));
1387 let block = func.create_block();
1388 let left = func.new_vreg(GPR);
1389 let right = func.new_vreg(GPR);
1390 let sum = func.new_vreg(GPR);
1391 func.build(block, opcode).def(left, GPR).finish();
1392 func.build(block, opcode).def(right, GPR).finish();
1393 func.build(block, opcode)
1394 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1395 .uses(left, GPR)
1396 .uses(right, GPR)
1397 .finish();
1398 func.build(block, opcode).uses(right, GPR).finish();
1399
1400 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1403 }
1404
1405 #[test]
1406 fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
1407 let mut names = Interner::new();
1408 let mut func = Func::new(names.intern("f"));
1409 let opcode = Opcode::new(names.intern("x64.nop"));
1410 let block = func.create_block();
1411 let left = func.new_vreg(GPR);
1412 let right = func.new_vreg(GPR);
1413 let sum = func.new_vreg(GPR);
1414 func.build(block, opcode).def(left, GPR).finish();
1415 func.build(block, opcode).def(right, GPR).finish();
1416 func.build(block, opcode)
1417 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1418 .uses(left, GPR)
1419 .uses(right, GPR)
1420 .finish();
1421 func.build(block, opcode).uses(left, GPR).finish();
1422
1423 assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
1427 }
1428
1429 #[test]
1430 fn an_answer_that_commutes_goes_over_the_source_that_is_finished_with() {
1431 let mut names = Interner::new();
1432 let mut func = Func::new(names.intern("f"));
1433 let opcode = Opcode::new(names.intern("x64.nop"));
1434 let block = func.create_block();
1435 let left = func.new_vreg(GPR);
1436 let right = func.new_vreg(GPR);
1437 let sum = func.new_vreg(GPR);
1438 func.build(block, opcode).def(left, GPR).finish();
1439 func.build(block, opcode).def(right, GPR).finish();
1440 let add = func
1441 .build(block, opcode)
1442 .flags(Flags::COMMUTES)
1443 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1444 .uses(left, GPR)
1445 .uses(right, GPR)
1446 .finish();
1447 func.build(block, opcode).uses(left, GPR).uses(sum, GPR).finish();
1448
1449 assert_eq!(places(&func, &env()), ["rax", "rcx", "rcx"]);
1453 let order = Order::of(&func);
1454 let live = Live::of(&func, &order);
1455 let assignment = assign(&func, &order, &live, &env());
1456 assert_eq!(assignment.commuted(), [add]);
1457
1458 let allocation = crate::run(&mut func, &env(), "f", true);
1462 assert!(allocation.edits.is_empty());
1463 let operands = &func[func[add].operands];
1464 let (first, second) = (operands[1].reg.phys(), operands[2].reg.phys());
1465 assert_eq!((first, second), (Some(RCX), Some(RAX)));
1466 }
1467
1468 #[test]
1469 fn an_answer_that_commutes_takes_the_source_something_after_it_wants() {
1470 let mut names = Interner::new();
1471 let mut func = Func::new(names.intern("f"));
1472 let opcode = Opcode::new(names.intern("x64.nop"));
1473 let block = func.create_block();
1474 let left = func.new_vreg(GPR);
1475 let right = func.new_vreg(GPR);
1476 let sum = func.new_vreg(GPR);
1477 func.build(block, opcode).def(left, GPR).finish();
1478 func.build(block, opcode)
1479 .operand(Operand::write(right, GPR).with(Constraint::Fixed(RAX)))
1480 .finish();
1481 let add = func
1482 .build(block, opcode)
1483 .flags(Flags::COMMUTES)
1484 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1485 .uses(left, GPR)
1486 .uses(right, GPR)
1487 .finish();
1488 func.build(block, opcode)
1489 .operand(Operand::read(sum, GPR).with(Constraint::Fixed(RAX)))
1490 .finish();
1491
1492 let names = places(&func, &env());
1496 assert_eq!(names[2], "rax");
1497 assert_ne!(names[0], "rax");
1498 let allocation = crate::run(&mut func, &env(), "f", true);
1499 assert!(allocation.edits.is_empty());
1500 assert_eq!(func[func[add].operands][1].reg.phys(), Some(RAX));
1501 }
1502
1503 #[test]
1504 fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1505 let mut names = Interner::new();
1506 let mut func = Func::new(names.intern("f"));
1507 let opcode = Opcode::new(names.intern("x64.nop"));
1508 let entry = func.create_block();
1509 let head = func.create_block();
1510 let out = func.create_block();
1511 let seed = func.new_vreg(GPR);
1512 let total = func.new_vreg(GPR);
1513 let term = func.new_vreg(GPR);
1514 let next = func.new_vreg(GPR);
1515 func.build(entry, opcode).def(seed, GPR).finish();
1516 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1517 func.params_mut(head).push(Param { reg: total, class: GPR });
1518 func.build(head, opcode).def(term, GPR).finish();
1519 let add = func
1520 .build(head, opcode)
1521 .flags(Flags::COMMUTES)
1522 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1523 .uses(total, GPR)
1524 .uses(term, GPR)
1525 .finish();
1526 func.build(head, opcode)
1527 .operand(Operand::read(next, GPR).with(Constraint::Fixed(RSI)))
1528 .finish();
1529 *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1530
1531 let order = Order::of(&func);
1535 let live = Live::of(&func, &order);
1536 let assignment = assign(&func, &order, &live, &env());
1537 assert_eq!(assignment.place(next), assignment.place(total));
1538 assert!(!assignment.commuted().contains(&add));
1539 }
1540
1541 #[test]
1542 fn an_answer_that_does_not_commute_leaves_its_sources_where_they_are() {
1543 let mut names = Interner::new();
1544 let mut func = Func::new(names.intern("f"));
1545 let opcode = Opcode::new(names.intern("x64.nop"));
1546 let block = func.create_block();
1547 let left = func.new_vreg(GPR);
1548 let right = func.new_vreg(GPR);
1549 let sum = func.new_vreg(GPR);
1550 func.build(block, opcode).def(left, GPR).finish();
1551 func.build(block, opcode).def(right, GPR).finish();
1552 func.build(block, opcode)
1553 .flags(Flags::COMMUTES)
1554 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1555 .uses(left, GPR)
1556 .uses(right, GPR)
1557 .finish();
1558 func.build(block, opcode).uses(right, GPR).finish();
1559
1560 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1563 let order = Order::of(&func);
1564 let live = Live::of(&func, &order);
1565 assert!(assign(&func, &order, &live, &env()).commuted().is_empty());
1566 }
1567
1568 #[test]
1569 fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
1570 let mut names = Interner::new();
1571 let mut func = Func::new(names.intern("f"));
1572 let opcode = Opcode::new(names.intern("x64.nop"));
1573 let head = func.create_block();
1574 let body = func.create_block();
1575 let carried = func.new_vreg(GPR);
1576 let inside = func.new_vreg(GPR);
1577 func.build(head, opcode).def(carried, GPR).finish();
1578 *func.succs_mut(head) = vec![BlockCall::to(body)];
1579 func.build(body, opcode).def(inside, GPR).finish();
1580 func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
1581 *func.succs_mut(body) = vec![BlockCall::to(body)];
1582
1583 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1586 }
1587
1588 #[test]
1589 fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
1590 let mut names = Interner::new();
1591 let mut func = Func::new(names.intern("f"));
1592 let opcode = Opcode::new(names.intern("x64.nop"));
1593 let head = func.create_block();
1594 let latch = func.create_block();
1595 let out = func.create_block();
1596 let source = func.new_vreg(GPR);
1597 let carried = func.new_vreg(GPR);
1598 func.build(head, opcode).def(source, GPR).finish();
1599 func.build(head, opcode).def(carried, GPR).finish();
1600 *func.succs_mut(head) = vec![BlockCall::to(latch)];
1601 func.build(latch, opcode)
1604 .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
1605 .uses(source, GPR)
1606 .uses(carried, GPR)
1607 .finish();
1608 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1609 func.build(out, opcode).uses(carried, GPR).finish();
1610
1611 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1616
1617 let order = Order::of(&func);
1620 let live = Live::of(&func, &order);
1621 let assignment = assign(&func, &order, &live, &env());
1622 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1623 }
1624
1625 #[test]
1626 fn a_two_address_answer_with_a_hole_in_front_of_it_does_not_take_its_other_operand() {
1627 let mut names = Interner::new();
1628 let mut func = Func::new(names.intern("f"));
1629 let nop = Opcode::new(names.intern("x64.nop"));
1630 let add = Opcode::new(names.intern("x64.add"));
1631 let entry = func.create_block();
1632 let head = func.create_block();
1633 let arm = func.create_block();
1634 let latch = func.create_block();
1635 let out = func.create_block();
1636 let seed = func.new_vreg(GPR);
1637 let sum = func.new_vreg(GPR);
1638 let inside = func.new_vreg(GPR);
1639 let loaded = func.new_vreg(GPR);
1640 func.build(entry, nop).def(seed, GPR).finish();
1641 func.build(entry, nop).def(sum, GPR).finish();
1642 *func.succs_mut(entry) = vec![BlockCall::to(head)];
1643 func.build(head, nop).uses(sum, GPR).finish();
1644 *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
1645 func.build(arm, nop).def(inside, GPR).finish();
1646 func.build(arm, nop).uses(inside, GPR).finish();
1647 *func.succs_mut(arm) = vec![BlockCall::to(out)];
1648 func.build(latch, nop).def(loaded, GPR).finish();
1649 func.build(latch, add)
1650 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1651 .uses(seed, GPR)
1652 .uses(loaded, GPR)
1653 .finish();
1654 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1655
1656 let places = places(&func, &env());
1661 assert_ne!(places[index(sum)], places[index(loaded)]);
1662
1663 let order = Order::of(&func);
1664 let live = Live::of(&func, &order);
1665 let assignment = assign(&func, &order, &live, &env());
1666 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1667 }
1668
1669 #[test]
1670 fn a_sum_a_loop_carries_round_keeps_its_register_past_an_arm_laid_out_after_it() {
1671 let mut names = Interner::new();
1672 let mut func = Func::new(names.intern("f"));
1673 let nop = Opcode::new(names.intern("x64.nop"));
1674 let add = Opcode::new(names.intern("x64.add"));
1675 let entry = func.create_block();
1676 let head = func.create_block();
1677 let join = func.create_block();
1678 let arm = func.create_block();
1679 let out = func.create_block();
1680 let seed = func.new_vreg(GPR);
1681 let term = func.new_vreg(GPR);
1682 let next = func.new_vreg(GPR);
1683 func.build(entry, nop).def(seed, GPR).finish();
1684 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1685 let total = func.append_param(head, GPR);
1686 func.build(head, nop).def(term, GPR).finish();
1687 *func.succs_mut(head) = vec![BlockCall::to(join), BlockCall::to(arm)];
1688 func.build(join, add)
1689 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1690 .uses(total, GPR)
1691 .uses(term, GPR)
1692 .finish();
1693 *func.succs_mut(join) =
1694 vec![BlockCall::with(head, vec![next]), BlockCall::with(out, vec![next])];
1695 func.build(arm, nop).def(term, GPR).finish();
1698 *func.succs_mut(arm) = vec![BlockCall::to(join)];
1699 let result = func.append_param(out, GPR);
1700 func.build(out, nop).uses(result, GPR).finish();
1701
1702 let places = places(&func, &env());
1705 assert_eq!(places[index(next)], places[index(total)]);
1706
1707 let order = Order::of(&func);
1708 let live = Live::of(&func, &order);
1709 let assignment = assign(&func, &order, &live, &env());
1710 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1711 }
1712
1713 fn arms(reaches: bool) -> Func {
1717 let mut names = Interner::new();
1718 let mut func = Func::new(names.intern("f"));
1719 let opcode = Opcode::new(names.intern("x64.nop"));
1720 let entry = func.create_block();
1721 let arm = func.create_block();
1722 let tail = func.create_block();
1723 let first = func.new_vreg(GPR);
1724 let second = func.new_vreg(GPR);
1725 func.build(entry, opcode).def(first, GPR).finish();
1726 func.build(entry, opcode).def(second, GPR).finish();
1727 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1728 func.build(arm, opcode).operand(Operand::write(Reg::physical(RAX), GPR)).finish();
1731 *func.succs_mut(arm) = if reaches { vec![BlockCall::to(tail)] } else { Vec::new() };
1732 func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1733 func
1734 }
1735
1736 #[test]
1737 fn a_register_a_clobber_takes_beats_the_stack_for_a_value_not_live_in_that_block() {
1738 let func = arms(false);
1739
1740 assert_eq!(places(&func, &narrow(2)), ["rcx", "rax"]);
1746
1747 let order = Order::of(&func);
1748 let live = Live::of(&func, &order);
1749 let assignment = assign(&func, &order, &live, &narrow(2));
1750 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1751 }
1752
1753 #[test]
1754 fn a_register_a_clobber_takes_is_not_free_to_a_value_that_is_live_there() {
1755 let func = arms(true);
1756
1757 assert_eq!(places(&func, &narrow(2)), ["rcx", "slot 0"]);
1761 }
1762
1763 fn dies_at_the_clobber(here: bool) -> Func {
1766 let mut names = Interner::new();
1767 let mut func = Func::new(names.intern("f"));
1768 let opcode = Opcode::new(names.intern("x64.nop"));
1769 let entry = func.create_block();
1770 let value = func.new_vreg(GPR);
1771 func.build(entry, opcode).def(value, GPR).finish();
1772 let call = func.build(entry, opcode).operand(Operand::write(Reg::physical(RAX), GPR));
1773 if here {
1774 call.uses(value, GPR).finish();
1775 } else {
1776 call.finish();
1777 func.build(entry, opcode).uses(value, GPR).finish();
1778 }
1779 func
1780 }
1781
1782 #[test]
1790 fn a_value_that_dies_where_a_register_is_destroyed_may_be_in_that_register() {
1791 let func = dies_at_the_clobber(true);
1792 assert_eq!(places(&func, &narrow(1)), ["rax"]);
1793
1794 let order = Order::of(&func);
1795 let live = Live::of(&func, &order);
1796 let assignment = assign(&func, &order, &live, &narrow(1));
1797 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1798 }
1799
1800 #[test]
1803 fn a_value_read_after_the_instruction_that_destroys_a_register_is_not_in_it() {
1804 let func = dies_at_the_clobber(false);
1805 assert_eq!(places(&func, &narrow(1)), ["slot 0"]);
1806 }
1807
1808 #[test]
1809 fn a_hint_is_followed_when_the_register_is_clear_and_not_when_it_is_merely_allowed() {
1810 let mut names = Interner::new();
1811 let mut func = Func::new(names.intern("f"));
1812 let opcode = Opcode::new(names.intern("x64.nop"));
1813 let entry = func.create_block();
1814 let mid = func.create_block();
1815 let tail = func.create_block();
1816 let first = func.new_vreg(GPR);
1817 let second = func.new_vreg(GPR);
1818 func.build(entry, opcode).def(first, GPR).finish();
1819 func.build(entry, opcode).def(second, GPR).finish();
1820 *func.succs_mut(entry) = vec![BlockCall::to(mid), BlockCall::to(tail)];
1821 func.build(mid, opcode)
1824 .operand(Operand::read(second, GPR).with(Constraint::Fixed(RAX)))
1825 .finish();
1826 func.build(tail, opcode)
1827 .operand(Operand::read(first, GPR).with(Constraint::Fixed(RAX)))
1828 .finish();
1829
1830 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1835 }
1836
1837 #[test]
1838 fn a_value_living_in_a_hole_of_another_gets_the_same_register() {
1839 let mut names = Interner::new();
1840 let mut func = Func::new(names.intern("f"));
1841 let opcode = Opcode::new(names.intern("x64.nop"));
1842 let entry = func.create_block();
1843 let arm = func.create_block();
1844 let tail = func.create_block();
1845 let across = func.new_vreg(GPR);
1846 let inside = func.new_vreg(GPR);
1847 func.build(entry, opcode).def(across, GPR).finish();
1848 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1849 func.build(arm, opcode).def(inside, GPR).finish();
1850 func.build(arm, opcode).uses(inside, GPR).finish();
1851 func.build(tail, opcode).uses(across, GPR).finish();
1852
1853 assert_eq!(places(&func, &narrow(1)), ["rax", "rax"]);
1859
1860 let order = Order::of(&func);
1861 let live = Live::of(&func, &order);
1862 let assignment = assign(&func, &order, &live, &narrow(1));
1863 assert_eq!(assignment.spilled(), 0);
1864 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1865 }
1866
1867 #[test]
1868 fn a_register_a_clobber_takes_is_the_last_one_offered_rather_than_the_first() {
1869 let func = arms(false);
1870
1871 assert_eq!(places(&func, &narrow(3)), ["rcx", "rdx"]);
1875 }
1876
1877 #[test]
1878 fn a_frame_says_what_each_of_its_slots_is_for() {
1879 let mut names = Interner::new();
1880 let mut func = Func::new(names.intern("f"));
1881 let opcode = Opcode::new(names.intern("x64.nop"));
1882 let block = func.create_block();
1883 let first = func.new_vreg(GPR);
1884 let second = func.new_vreg(GPR);
1885 func.build(block, opcode).def(first, GPR).finish();
1886 func.build(block, opcode).def(second, GPR).finish();
1887 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
1888
1889 let order = Order::of(&func);
1890 let live = Live::of(&func, &order);
1891 let assignment = assign(&func, &order, &live, &narrow(1));
1892 assert_eq!(assignment.spilled(), 1);
1893 assert_eq!(assignment.slots(), [GPR]);
1894 assert_eq!(assignment.place(Reg::physical(RCX)), None);
1897 assert_eq!(env().scratch(GPR), [R13, R14, R15]);
1898 }
1899
1900 fn ranges(pairs: &[(Point, Point)]) -> Vec<Range> {
1902 pairs.iter().map(|&(start, end)| Range { start, end }).collect()
1903 }
1904
1905 #[test]
1906 fn the_pieces_of_a_register_answer_what_a_walk_over_its_values_would() {
1907 let held = [
1909 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1910 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1911 (Reg::virtual_reg(2), ranges(&[(10, 19), (31, 40)])),
1912 ];
1913 let mut pieces = Pieces::default();
1914 for (reg, list) in &held {
1915 for &piece in list {
1916 pieces.insert(piece, *reg);
1917 }
1918 }
1919 assert!(!pieces.broken);
1920 let asked = [
1921 ranges(&[(41, 50)]),
1922 ranges(&[(40, 50)]),
1923 ranges(&[(9, 9)]),
1924 ranges(&[(3, 3), (41, 42)]),
1925 ranges(&[(50, 60)]),
1926 ranges(&[(15, 15)]),
1927 ];
1928 for list in &asked {
1929 let area = Area::of_pieces(list);
1930 for except in [None, Some(Reg::virtual_reg(0)), Some(Reg::virtual_reg(2))] {
1931 let walked = held.iter().any(|(reg, pieces)| {
1932 Some(*reg) != except && Area::of_pieces(pieces).overlaps(area)
1933 });
1934 assert_eq!(pieces.touch(area, except), walked, "{list:?} except {except:?}");
1935 }
1936 }
1937 }
1938
1939 #[test]
1940 fn the_owners_of_the_pieces_an_area_touches_are_the_values_a_walk_would_find() {
1941 let held = [
1942 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1943 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1944 (Reg::virtual_reg(2), ranges(&[(10, 19), (30, 40)])),
1945 ];
1946 let mut pieces = Pieces::default();
1947 for (reg, list) in &held {
1948 for &piece in list {
1949 pieces.insert(piece, *reg);
1950 }
1951 }
1952 let asked = [
1953 ranges(&[(41, 50)]),
1954 ranges(&[(30, 30)]),
1955 ranges(&[(3, 12)]),
1956 ranges(&[(3, 3), (25, 42)]),
1957 ranges(&[(0, 50)]),
1958 ];
1959 for list in &asked {
1960 let area = Area::of_pieces(list);
1961 let walked: Vec<Reg> = held
1962 .iter()
1963 .filter(|(_, pieces)| Area::of_pieces(pieces).overlaps(area))
1964 .map(|&(reg, _)| reg)
1965 .collect();
1966 assert_eq!(pieces.owners(area), Some(walked), "{list:?}");
1967 }
1968 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(3));
1969 assert_eq!(pieces.owners(Area::of_pieces(&asked[0])), None);
1970 }
1971
1972 #[test]
1973 fn pieces_that_end_out_of_order_are_marked() {
1974 let mut pieces = Pieces::default();
1975 pieces.insert(Range { start: 0, end: 10 }, Reg::virtual_reg(0));
1976 pieces.insert(Range { start: 12, end: 20 }, Reg::virtual_reg(1));
1977 assert!(!pieces.broken);
1978 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(2));
1980 assert!(pieces.broken);
1981 }
1982
1983 #[test]
1984 fn a_value_taken_out_of_a_register_leaves_its_pieces_with_it() {
1985 let mut pieces = Pieces::default();
1986 let (first, second) = (Reg::virtual_reg(0), Reg::virtual_reg(1));
1987 pieces.insert(Range { start: 0, end: 10 }, first);
1988 pieces.insert(Range { start: 12, end: 20 }, second);
1989 let asked = ranges(&[(15, 16)]);
1990 assert!(pieces.touch(Area::of_pieces(&asked), None));
1991 pieces.remove(Range { start: 12, end: 20 }, second);
1992 assert!(!pieces.touch(Area::of_pieces(&asked), None));
1993 pieces.drop_before(11);
1994 assert!(pieces.list.is_empty());
1995 }
1996}