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 costs: Vec<(usize, PhysReg, usize, Point)>,
322}
323
324impl<'a> Active<'a> {
325 fn at(&self, at: PhysReg) -> &[Held<'a>] {
327 self.by.get(usize::from(at.number())).map_or(&[], Vec::as_slice)
328 }
329
330 fn push(&mut self, reg: Reg, class: RegClass, range: Range, area: Area<'a>, at: PhysReg) {
331 let slot = usize::from(at.number());
332 if self.by.len() <= slot {
333 self.by.resize_with(slot + 1, Vec::new);
334 self.soonest.resize(slot + 1, Point::MAX);
335 }
336 self.by[slot].push(Held { reg, class, range, area, at, since: self.count });
337 self.soonest[slot] = self.soonest[slot].min(range.end);
338 self.count += 1;
339 let held = &self.by[slot];
340 let pieces = pieces_mut(&mut self.pieces, class, slot);
341 if pieces.kept {
342 pieces.drop_before(range.start);
343 for piece in area.pieces() {
344 pieces.insert(piece, reg);
345 }
346 } else if held.len() > FEW {
347 pieces.kept = true;
349 for held in held.iter().filter(|held| held.class == class) {
350 for piece in held.area.pieces() {
351 pieces.insert(piece, held.reg);
352 }
353 }
354 }
355 }
356
357 fn taken(&self, class: RegClass, at: PhysReg, area: Area<'_>, except: Option<Reg>) -> bool {
359 let held = self.at(at);
360 if held.len() > FEW {
361 if let Some(answer) = self.listed(class, at, area, except) {
362 return answer;
363 }
364 }
365 held.iter()
366 .any(|held| held.class == class && Some(held.reg) != except && held.area.overlaps(area))
367 }
368
369 #[inline(never)]
373 fn listed(
374 &self,
375 class: RegClass,
376 at: PhysReg,
377 area: Area<'_>,
378 except: Option<Reg>,
379 ) -> Option<bool> {
380 let by = self.pieces.get(usize::from(class.number()))?;
381 let pieces = by.get(usize::from(at.number()))?;
382 (pieces.kept && !pieces.broken).then(|| pieces.touch(area, except))
383 }
384
385 #[inline(never)]
388 fn owners(&self, class: RegClass, slot: usize, area: Area<'_>) -> Option<Vec<Reg>> {
389 let pieces = self.pieces.get(usize::from(class.number()))?.get(slot)?;
390 if pieces.kept { pieces.owners(area) } else { None }
391 }
392
393 fn evict(
395 &mut self,
396 class: RegClass,
397 at: PhysReg,
398 goes: impl Fn(&Held<'a>) -> bool,
399 mut gone: impl FnMut(&Held<'a>),
400 ) {
401 let slot = usize::from(at.number());
402 let mut taken = Vec::new();
403 self.by[slot].retain(|held| {
404 let out = held.class == class && goes(held);
405 if out {
406 gone(held);
407 taken.push((held.reg, held.area));
408 }
409 !out
410 });
411 let pieces = pieces_mut(&mut self.pieces, class, slot);
412 if pieces.kept {
413 for (reg, area) in taken {
414 for piece in area.pieces() {
415 pieces.remove(piece, reg);
416 }
417 }
418 }
419 }
420
421 fn expire(&mut self, point: Point) {
427 for (held, soonest) in self.by.iter_mut().zip(&mut self.soonest) {
428 if *soonest >= point {
429 continue;
430 }
431 held.retain(|held| held.range.end >= point);
432 *soonest = held.iter().map(|held| held.range.end).min().unwrap_or(Point::MAX);
433 }
434 }
435}
436
437pub(crate) const FEW: usize = 4;
441
442fn pieces_mut(pieces: &mut Vec<Vec<Pieces>>, class: RegClass, slot: usize) -> &mut Pieces {
444 let class = usize::from(class.number());
445 if pieces.len() <= class {
446 pieces.resize_with(class + 1, Vec::new);
447 }
448 let by = &mut pieces[class];
449 if by.len() <= slot {
450 by.resize_with(slot + 1, Pieces::default);
451 }
452 &mut by[slot]
453}
454
455#[derive(Default)]
469pub(crate) struct Pieces {
470 list: Vec<(Point, Point, Reg)>,
472 broken: bool,
474 pub(crate) kept: bool,
477}
478
479impl Pieces {
480 #[inline(never)]
481 pub(crate) fn insert(&mut self, piece: Range, reg: Reg) {
482 let key = (piece.start, piece.end);
483 let at = self.list.partition_point(|&(start, end, _)| (start, end) <= key);
484 let after = at == 0 || self.list[at - 1].1 <= piece.end;
485 let before = self.list.get(at).is_none_or(|next| piece.end <= next.1);
486 if !(after && before) {
487 self.broken = true;
488 }
489 self.list.insert(at, (piece.start, piece.end, reg));
490 }
491
492 pub(crate) fn remove(&mut self, piece: Range, reg: Reg) {
493 let from = self.list.partition_point(|&(start, _, _)| start < piece.start);
494 let found = self.list[from..]
495 .iter()
496 .take_while(|&&(start, _, _)| start == piece.start)
497 .position(|&(_, end, owner)| end == piece.end && owner == reg);
498 if let Some(offset) = found {
499 self.list.remove(from + offset);
500 }
501 }
502
503 fn drop_before(&mut self, point: Point) {
506 if !self.broken {
507 let gone = self.list.partition_point(|&(_, end, _)| end < point);
508 self.list.drain(..gone);
509 }
510 }
511
512 fn touch(&self, area: Area<'_>, except: Option<Reg>) -> bool {
514 area.pieces().any(|piece| {
515 let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
516 self.list[..below]
517 .iter()
518 .rev()
519 .find(|&&(_, _, owner)| Some(owner) != except)
520 .is_some_and(|&(_, end, _)| end >= piece.start)
521 })
522 }
523
524 pub(crate) fn owners(&self, area: Area<'_>) -> Option<Vec<Reg>> {
529 if self.broken {
530 return None;
531 }
532 let mut owners = Vec::new();
533 for piece in area.pieces() {
534 let below = self.list.partition_point(|&(start, _, _)| start <= piece.end);
535 let touching =
536 self.list[..below].iter().rev().take_while(|&&(_, end, _)| end >= piece.start);
537 owners.extend(touching.map(|&(_, _, owner)| owner));
538 }
539 owners.sort_unstable();
540 owners.dedup();
541 Some(owners)
542 }
543}
544
545#[derive(Debug, Clone, Copy)]
547struct Blocked {
548 class: RegClass,
549 at: PhysReg,
550 point: Point,
554 by: Option<Reg>,
559 above: Option<u8>,
563}
564
565impl Blocked {
566 fn reaches(&self, width: Option<u8>) -> bool {
569 match (self.above, width) {
570 (Some(above), Some(width)) => width > above,
571 _ => true,
572 }
573 }
574}
575
576#[derive(Debug, Clone, Copy)]
578pub(crate) struct Reuse {
579 pub(crate) source: Reg,
581 pub(crate) second: Option<Reg>,
584 pub(crate) at: Point,
586 pub(crate) inst: Inst,
588}
589
590#[must_use]
597pub fn assign(func: &Func, order: &Order, live: &Live, env: &Env) -> Assignment {
598 let blocked = blocked(func, order);
599 let forced = forced(func);
600 let reuses = reuses(func, order);
601 let hints = hints(func);
602 let passed = passed(func);
603
604 let mut intervals = Vec::with_capacity(func.vregs());
605 for (number, reuse) in reuses.iter().enumerate() {
606 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
607 let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
608 continue;
609 };
610 if let Some(reuse) = reuse {
611 area = area.with(reuse.at);
612 }
613 intervals.push(Interval { reg, class, range: area.hull(), area });
614 }
615 intervals.sort_by_key(|interval| (interval.range.start, interval.reg));
616
617 let mut assignment = Assignment::empty(func.vregs());
618 let mut active = Active::default();
619 for interval in intervals {
620 active.expire(interval.range.start);
621 if forced.contains(&interval.reg) {
622 assignment.spill(interval.reg, interval.class);
623 continue;
624 }
625 assert!(
630 !env.order(interval.class).is_empty(),
631 "a value in class {}, which the target hands out no registers from",
632 interval.class.number()
633 );
634 let reuse = reuses[index(interval.reg)];
635 let coalesced = |source| coalesce(&assignment, &active, &blocked, live, interval, source);
636 let first = reuse.and_then(|reuse| coalesced(reuse.source));
637 let second = reuse.and_then(|reuse| reuse.second).and_then(coalesced);
638 let hinted_at = |at: Option<PhysReg>| {
649 at.is_some_and(|at| {
650 hints[index(interval.reg)].contains(&at)
651 || passed[index(interval.reg)]
652 .iter()
653 .any(|¶m| assignment.place(param) == Some(Place::Reg(at)))
654 })
655 };
656 let commute =
657 second.is_some() && (first.is_none() || hinted_at(second) && !hinted_at(first));
658 let two_address = if commute { second } else { first };
659 if let (true, Some(reuse)) = (commute, reuse) {
660 assignment.commuted.push(reuse.inst);
661 }
662 let hinted = hints[index(interval.reg)].iter().copied().find(|&at| {
666 env.order(interval.class).contains(&at)
667 && available(&active, &blocked, interval, at, None, Want::Clear)
668 });
669 let scan = |want| {
674 env.order(interval.class)
675 .iter()
676 .copied()
677 .find(|&at| available(&active, &blocked, interval, at, None, want))
678 };
679 let chosen =
680 two_address.or(hinted).or_else(|| scan(Want::Clear)).or_else(|| scan(Want::Allowed));
681 match chosen {
682 Some(at) => {
683 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
684 active.push(interval.reg, interval.class, interval.range, interval.area, at);
685 }
686 None => spill_one(&mut assignment, &mut active, &blocked, interval),
687 }
688 }
689 assignment
690}
691
692#[derive(Debug, Clone, Copy, PartialEq, Eq)]
694pub(crate) enum Want {
695 Clear,
697 Allowed,
701}
702
703pub(crate) struct Blocks {
719 all: Vec<Blocked>,
721 points: Vec<Point>,
723 spans: Vec<(usize, usize)>,
726 stride: usize,
728 widths: Vec<Option<u8>>,
731}
732
733impl Blocks {
734 pub(crate) fn insists(
738 &self,
739 reg: Reg,
740 class: RegClass,
741 area: Area<'_>,
742 range: Range,
743 at: PhysReg,
744 want: Want,
745 ) -> bool {
746 self.over(class, at, range).any(|one| {
747 one.by != Some(reg)
748 && one.reaches(self.width(reg))
749 && (want == Want::Clear || area.covers(one.point))
750 })
751 }
752
753 fn width(&self, reg: Reg) -> Option<u8> {
755 let number = usize::try_from(reg.number()?).ok()?;
756 self.widths.get(number).copied().flatten()
757 }
758
759 pub(crate) fn taken(&self) -> impl Iterator<Item = (RegClass, PhysReg, Point)> + '_ {
764 self.all
765 .iter()
766 .filter(|one| one.by.is_none() && one.above.is_none())
767 .map(|one| (one.class, one.at, one.point))
768 }
769
770 #[inline]
775 fn over(
776 &self,
777 class: RegClass,
778 at: PhysReg,
779 range: Range,
780 ) -> impl Iterator<Item = &Blocked> + '_ {
781 let (low, high) = if usize::from(at.number()) < self.stride {
782 let key = usize::from(class.number()) * self.stride + usize::from(at.number());
783 self.spans.get(key).copied().unwrap_or((0, 0))
784 } else {
785 (0, 0)
786 };
787 let first = low + self.points[low..high].partition_point(|&point| point < range.start);
788 self.all[first..high].iter().take_while(move |one| one.point <= range.end)
789 }
790}
791
792fn available(
801 active: &Active<'_>,
802 blocked: &Blocks,
803 interval: Interval<'_>,
804 at: PhysReg,
805 except: Option<Reg>,
806 want: Want,
807) -> bool {
808 let taken = active.taken(interval.class, at, interval.area, except);
809 let width = blocked.width(interval.reg);
810 let insisted = blocked.over(interval.class, at, interval.range).any(|one| {
811 one.by != Some(interval.reg)
812 && one.reaches(width)
813 && (want == Want::Clear || interval.area.covers(one.point))
814 });
815 !taken && !insisted
816}
817
818fn coalesce(
821 assignment: &Assignment,
822 active: &Active<'_>,
823 blocked: &Blocks,
824 live: &Live,
825 interval: Interval<'_>,
826 source: Reg,
827) -> Option<PhysReg> {
828 let Some(Place::Reg(at)) = assignment.place(source) else { return None };
829 active.at(at).iter().find(|held| held.reg == source)?;
830 let free = available(active, blocked, interval, at, Some(source), Want::Allowed);
846 (apart(live, source, interval.reg) && free).then_some(at)
847}
848
849pub(crate) fn apart(live: &Live, first: Reg, second: Reg) -> bool {
851 match (live.area(first), live.area(second)) {
852 (Some(first), Some(second)) => !first.overlaps(second),
853 _ => false,
854 }
855}
856
857fn spill_one<'a>(
865 assignment: &mut Assignment,
866 active: &mut Active<'a>,
867 blocked: &Blocks,
868 interval: Interval<'a>,
869) {
870 let mut costs = std::mem::take(&mut active.costs);
876 costs.clear();
877 for (slot, values) in active.by.iter().enumerate() {
878 let owners = if values.len() > FEW {
881 active.owners(interval.class, slot, interval.area)
882 } else {
883 None
884 };
885 for held in values {
886 if held.class != interval.class {
887 continue;
888 }
889 let touches = match &owners {
890 Some(owners) => owners.binary_search(&held.reg).is_ok(),
891 None => held.area.overlaps(interval.area),
892 };
893 if !touches {
894 continue;
895 }
896 match costs.iter_mut().find(|(_, at, _, _)| *at == held.at) {
897 Some((first, _, count, reach)) => {
898 *first = (*first).min(held.since);
899 *count += 1;
900 *reach = (*reach).max(held.range.end);
901 }
902 None => costs.push((held.since, held.at, 1, held.range.end)),
903 }
904 }
905 }
906 costs.sort_unstable_by_key(|&(first, _, _, _)| first);
907 let none = Active::default();
910 let chosen = costs
911 .iter()
912 .filter(|&&(_, at, _, reach)| {
913 reach > interval.range.end
914 && available(&none, blocked, interval, at, None, Want::Allowed)
915 })
916 .min_by_key(|&&(_, _, count, reach)| (count, Reverse(reach)))
917 .map(|&(_, at, _, _)| at);
918 active.costs = costs;
919 match chosen {
920 Some(at) => {
921 active.evict(
922 interval.class,
923 at,
924 |held| held.area.overlaps(interval.area),
925 |held| assignment.spill(held.reg, held.class),
926 );
927 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
928 active.push(interval.reg, interval.class, interval.range, interval.area, at);
929 }
930 None => assignment.spill(interval.reg, interval.class),
931 }
932}
933
934pub(crate) fn blocked(func: &Func, order: &Order) -> Blocks {
940 let mut blocked = Vec::new();
941 let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
942 for block in func.blocks() {
943 for inst in func.insts(block) {
944 let operands = &func[func[inst].operands];
945 claimed.clear();
946 for operand in operands {
947 if let Some(at) = insisted(operand) {
948 let key = (operand.class, at);
949 if !claimed.contains(&key) {
950 claimed.push(key);
951 }
952 }
953 }
954 for &(class, at) in &claimed {
955 for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
960 {
961 let mut named = false;
962 for operand in operands {
963 let mine = insisted(operand) == Some(at) && operand.class == class;
964 if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
965 continue;
966 }
967 named = true;
968 let by = operand.reg.is_virtual().then_some(operand.reg);
969 let above = match operand.constraint {
970 Constraint::Above(above) => Some(above),
971 _ => None,
972 };
973 blocked.push(Blocked { class, at, point, by, above });
974 }
975 if !named && role == Role::Def {
994 blocked.push(Blocked { class, at, point, by: None, above: None });
995 }
996 }
997 }
998 }
999 }
1000 blocked.sort_by_key(|one: &Blocked| (one.class, one.at, one.point));
1006 let widths = (0..func.vregs())
1007 .map(|number| func.width(Reg::virtual_reg(u32::try_from(number).ok()?)))
1008 .collect();
1009 let points = blocked.iter().map(|one| one.point).collect();
1010 let stride = blocked.iter().map(|one| usize::from(one.at.number()) + 1).max().unwrap_or(0);
1011 let classes = blocked.last().map_or(0, |one| usize::from(one.class.number()) + 1);
1012 let mut spans = vec![(0, 0); classes * stride];
1013 for (index, one) in blocked.iter().enumerate() {
1014 let key = usize::from(one.class.number()) * stride + usize::from(one.at.number());
1015 let span = &mut spans[key];
1016 if span.1 == 0 {
1017 span.0 = index;
1018 }
1019 span.1 = index + 1;
1020 }
1021 Blocks { all: blocked, points, spans, stride, widths }
1022}
1023
1024fn insisted(operand: &Operand) -> Option<PhysReg> {
1027 match operand.constraint {
1028 Constraint::Fixed(at) => Some(at),
1029 _ => operand.reg.phys(),
1030 }
1031}
1032
1033pub(crate) fn hints(func: &Func) -> Vec<Vec<PhysReg>> {
1043 let mut hints = vec![Vec::new(); func.vregs()];
1044 for block in func.blocks() {
1045 for inst in func.insts(block) {
1046 for operand in &func[func[inst].operands] {
1047 let Constraint::Fixed(at) = operand.constraint else { continue };
1048 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1049 let Some(number) = number else { continue };
1050 let wanted: &mut Vec<PhysReg> = &mut hints[number];
1051 if func.class_of(operand.reg) == Some(operand.class) && !wanted.contains(&at) {
1052 wanted.push(at);
1053 }
1054 }
1055 }
1056 }
1057 hints
1058}
1059
1060pub(crate) fn passed(func: &Func) -> Vec<Vec<Reg>> {
1062 let mut passed = vec![Vec::new(); func.vregs()];
1063 for block in func.blocks() {
1064 for call in &func[block].succs {
1065 for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
1066 let number = arg.number().and_then(|number| usize::try_from(number).ok());
1067 let Some(number) = number else { continue };
1068 let to: &mut Vec<Reg> = &mut passed[number];
1069 if !to.contains(¶m.reg) {
1070 to.push(param.reg);
1071 }
1072 }
1073 }
1074 }
1075 passed
1076}
1077
1078pub(crate) fn forced(func: &Func) -> Vec<Reg> {
1080 let mut forced = Vec::new();
1081 for block in func.blocks() {
1082 for inst in func.insts(block) {
1083 for operand in &func[func[inst].operands] {
1084 if operand.constraint == Constraint::Stack
1085 && operand.reg.is_virtual()
1086 && !forced.contains(&operand.reg)
1087 {
1088 forced.push(operand.reg);
1089 }
1090 }
1091 }
1092 }
1093 forced
1094}
1095
1096pub(crate) fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
1098 let mut reuses = vec![None; func.vregs()];
1099 for block in func.blocks() {
1100 for inst in func.insts(block) {
1101 let operands = &func[func[inst].operands];
1102 for operand in operands {
1103 let Constraint::Reuse(other) = operand.constraint else { continue };
1104 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1105 let Some(number) = number else { continue };
1106 let source = operands[usize::from(other)].reg;
1107 let second = if func[inst].flags.contains(Flags::COMMUTES) {
1108 swappable(operands, usize::from(other))
1109 } else {
1110 None
1111 };
1112 reuses[number] = Some(Reuse { source, second, at: order.early(inst), inst });
1113 }
1114 }
1115 }
1116 reuses
1117}
1118
1119fn swappable(operands: &[Operand], other: usize) -> Option<Reg> {
1126 let [answer, first, second] = operands else { return None };
1127 let same = second.class == first.class && second.class == answer.class;
1128 let plain = second.role == Role::Use && second.constraint == Constraint::Reg;
1129 (other == 1 && same && plain && second.reg.is_virtual() && second.reg != first.reg)
1130 .then_some(second.reg)
1131}
1132
1133fn index(reg: Reg) -> usize {
1135 usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
1136}
1137
1138#[cfg(test)]
1139mod tests {
1140 use rucc_base::Interner;
1141 use rucc_mir::{BlockCall, Opcode, Operand, Param};
1142 use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, RSI, SYSV};
1143
1144 use super::*;
1145
1146 fn env() -> Env {
1148 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
1149 Env::new().with(GPR, order, scratch)
1150 }
1151
1152 fn narrow(count: usize) -> Env {
1155 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
1156 }
1157
1158 fn named(place: Option<Place>) -> String {
1160 match place {
1161 Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
1162 Some(Place::Slot(slot)) => format!("slot {slot}"),
1163 None => "nowhere".to_string(),
1164 }
1165 }
1166
1167 fn places(func: &Func, env: &Env) -> Vec<String> {
1169 let order = Order::of(func);
1170 let live = Live::of(func, &order);
1171 let assignment = assign(func, &order, &live, env);
1172 (0..func.vregs())
1173 .map(|number| {
1174 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
1175 named(assignment.place(reg))
1176 })
1177 .collect()
1178 }
1179
1180 #[test]
1181 fn two_values_that_are_never_both_wanted_share_a_register() {
1182 let mut names = Interner::new();
1183 let mut func = Func::new(names.intern("f"));
1184 let opcode = Opcode::new(names.intern("x64.nop"));
1185 let block = func.create_block();
1186 let first = func.new_vreg(GPR);
1187 let second = func.new_vreg(GPR);
1188 func.build(block, opcode).def(first, GPR).finish();
1189 func.build(block, opcode).uses(first, GPR).finish();
1190 func.build(block, opcode).def(second, GPR).finish();
1191 func.build(block, opcode).uses(second, GPR).finish();
1192
1193 assert_eq!(places(&func, &env()), ["rax", "rax"]);
1196 }
1197
1198 fn over_the_top(width: u32) -> Func {
1201 let mut names = Interner::new();
1202 let mut func = Func::new(names.intern("f"));
1203 let opcode = Opcode::new(names.intern("x64.nop"));
1204 let block = func.create_block();
1205 let held = func.new_vreg(GPR);
1206 func.set_width(held, width);
1207 func.build(block, opcode).def(held, GPR).finish();
1208 func.build(block, opcode)
1209 .operand(Operand::write(Reg::physical(RAX), GPR))
1210 .operand(Operand::write(Reg::physical(RCX), GPR).with(Constraint::Above(8)))
1211 .finish();
1212 func.build(block, opcode).uses(held, GPR).finish();
1213 func
1214 }
1215
1216 #[test]
1217 fn a_value_that_fits_under_what_an_instruction_writes_stays_in_the_register() {
1218 assert_eq!(places(&over_the_top(8), &narrow(2)), ["rcx"]);
1219 assert_eq!(places(&over_the_top(4), &narrow(2)), ["rcx"]);
1220 }
1221
1222 #[test]
1223 fn a_value_wider_than_that_or_of_no_known_width_does_not() {
1224 assert_eq!(places(&over_the_top(16), &narrow(2)), ["slot 0"]);
1225 assert_eq!(places(&over_the_top(0), &narrow(2)), ["slot 0"]);
1226 }
1227
1228 #[test]
1229 fn two_values_that_are_both_wanted_do_not() {
1230 let mut names = Interner::new();
1231 let mut func = Func::new(names.intern("f"));
1232 let opcode = Opcode::new(names.intern("x64.nop"));
1233 let block = func.create_block();
1234 let first = func.new_vreg(GPR);
1235 let second = func.new_vreg(GPR);
1236 func.build(block, opcode).def(first, GPR).finish();
1237 func.build(block, opcode).def(second, GPR).finish();
1238 func.build(block, opcode).uses(first, GPR).finish();
1239 func.build(block, opcode).uses(second, GPR).finish();
1240
1241 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1242 }
1243
1244 #[test]
1245 fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
1246 let mut names = Interner::new();
1247 let mut func = Func::new(names.intern("f"));
1248 let opcode = Opcode::new(names.intern("x64.nop"));
1249 let block = func.create_block();
1250 let wanted = func.new_vreg(GPR);
1251 let spare = func.new_vreg(GPR);
1252 func.build(block, opcode)
1255 .def(wanted, GPR)
1256 .operand(Operand::write_early(spare, GPR))
1257 .finish();
1258 func.build(block, opcode).uses(wanted, GPR).finish();
1259
1260 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1266 }
1267
1268 #[test]
1269 fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
1270 let mut names = Interner::new();
1271 let mut func = Func::new(names.intern("f"));
1272 let opcode = Opcode::new(names.intern("x64.nop"));
1273 let block = func.create_block();
1274 let long = func.new_vreg(GPR);
1275 let short = func.new_vreg(GPR);
1276 let third = func.new_vreg(GPR);
1277 func.build(block, opcode).def(long, GPR).finish();
1278 func.build(block, opcode).def(short, GPR).finish();
1279 func.build(block, opcode).def(third, GPR).finish();
1280 func.build(block, opcode).uses(short, GPR).finish();
1281 func.build(block, opcode).uses(third, GPR).finish();
1282 func.build(block, opcode).uses(long, GPR).finish();
1283
1284 assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
1287 }
1288
1289 #[test]
1290 fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
1291 let mut names = Interner::new();
1292 let mut func = Func::new(names.intern("f"));
1293 let opcode = Opcode::new(names.intern("x64.nop"));
1294 let block = func.create_block();
1295 let across = func.new_vreg(GPR);
1296 let dividend = func.new_vreg(GPR);
1297 let quotient = func.new_vreg(GPR);
1298 let remainder = func.new_vreg(GPR);
1299 func.build(block, opcode).def(across, GPR).finish();
1300 func.build(block, opcode).def(dividend, GPR).finish();
1301 func.build(block, opcode)
1302 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1303 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1304 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1305 .finish();
1306 func.build(block, opcode).uses(across, GPR).finish();
1307
1308 assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
1313 }
1314
1315 #[test]
1325 fn a_value_that_dies_at_an_instruction_stays_out_of_what_it_fills_first() {
1326 let mut names = Interner::new();
1327 let mut func = Func::new(names.intern("f"));
1328 let opcode = Opcode::new(names.intern("x64.nop"));
1329 let block = func.create_block();
1330 let across = func.new_vreg(GPR);
1331 let dividend = func.new_vreg(GPR);
1332 let divisor = func.new_vreg(GPR);
1333 let remainder = func.new_vreg(GPR);
1334 func.build(block, opcode).def(across, GPR).finish();
1335 func.build(block, opcode).def(dividend, GPR).finish();
1336 func.build(block, opcode).def(divisor, GPR).finish();
1337 func.build(block, opcode)
1338 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1339 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1340 .operand(Operand::read(divisor, GPR))
1341 .finish();
1342 func.build(block, opcode).uses(across, GPR).uses(remainder, GPR).finish();
1343
1344 assert_eq!(places(&func, &narrow(4)), ["rcx", "rax", "rsi", "rdx"]);
1348 }
1349
1350 #[test]
1351 fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
1352 let mut names = Interner::new();
1353 let mut func = Func::new(names.intern("f"));
1354 let opcode = Opcode::new(names.intern("x64.nop"));
1355 let block = func.create_block();
1356 let dividend = func.new_vreg(GPR);
1357 let quotient = func.new_vreg(GPR);
1358 func.build(block, opcode).def(dividend, GPR).finish();
1359 func.build(block, opcode)
1360 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1361 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1362 .finish();
1363 func.build(block, opcode).uses(dividend, GPR).finish();
1364
1365 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1369 }
1370
1371 #[test]
1372 fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
1373 let mut names = Interner::new();
1374 let mut func = Func::new(names.intern("f"));
1375 let opcode = Opcode::new(names.intern("x64.nop"));
1376 let block = func.create_block();
1377 let value = func.new_vreg(GPR);
1378 func.build(block, opcode).def(value, GPR).finish();
1379 func.build(block, opcode)
1380 .operand(Operand::read(value, GPR).with(Constraint::Stack))
1381 .finish();
1382
1383 assert_eq!(places(&func, &env()), ["slot 0"]);
1384 }
1385
1386 #[test]
1387 fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
1388 let mut names = Interner::new();
1389 let mut func = Func::new(names.intern("f"));
1390 let opcode = Opcode::new(names.intern("x64.nop"));
1391 let block = func.create_block();
1392 let left = func.new_vreg(GPR);
1393 let right = func.new_vreg(GPR);
1394 let sum = func.new_vreg(GPR);
1395 func.build(block, opcode).def(left, GPR).finish();
1396 func.build(block, opcode).def(right, GPR).finish();
1397 func.build(block, opcode)
1398 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1399 .uses(left, GPR)
1400 .uses(right, GPR)
1401 .finish();
1402 func.build(block, opcode).uses(right, GPR).finish();
1403
1404 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1407 }
1408
1409 #[test]
1410 fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
1411 let mut names = Interner::new();
1412 let mut func = Func::new(names.intern("f"));
1413 let opcode = Opcode::new(names.intern("x64.nop"));
1414 let block = func.create_block();
1415 let left = func.new_vreg(GPR);
1416 let right = func.new_vreg(GPR);
1417 let sum = func.new_vreg(GPR);
1418 func.build(block, opcode).def(left, GPR).finish();
1419 func.build(block, opcode).def(right, GPR).finish();
1420 func.build(block, opcode)
1421 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1422 .uses(left, GPR)
1423 .uses(right, GPR)
1424 .finish();
1425 func.build(block, opcode).uses(left, GPR).finish();
1426
1427 assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
1431 }
1432
1433 #[test]
1434 fn an_answer_that_commutes_goes_over_the_source_that_is_finished_with() {
1435 let mut names = Interner::new();
1436 let mut func = Func::new(names.intern("f"));
1437 let opcode = Opcode::new(names.intern("x64.nop"));
1438 let block = func.create_block();
1439 let left = func.new_vreg(GPR);
1440 let right = func.new_vreg(GPR);
1441 let sum = func.new_vreg(GPR);
1442 func.build(block, opcode).def(left, GPR).finish();
1443 func.build(block, opcode).def(right, GPR).finish();
1444 let add = func
1445 .build(block, opcode)
1446 .flags(Flags::COMMUTES)
1447 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1448 .uses(left, GPR)
1449 .uses(right, GPR)
1450 .finish();
1451 func.build(block, opcode).uses(left, GPR).uses(sum, GPR).finish();
1452
1453 assert_eq!(places(&func, &env()), ["rax", "rcx", "rcx"]);
1457 let order = Order::of(&func);
1458 let live = Live::of(&func, &order);
1459 let assignment = assign(&func, &order, &live, &env());
1460 assert_eq!(assignment.commuted(), [add]);
1461
1462 let allocation = crate::run(&mut func, &env(), "f", true);
1466 assert!(allocation.edits.is_empty());
1467 let operands = &func[func[add].operands];
1468 let (first, second) = (operands[1].reg.phys(), operands[2].reg.phys());
1469 assert_eq!((first, second), (Some(RCX), Some(RAX)));
1470 }
1471
1472 #[test]
1473 fn an_answer_that_commutes_takes_the_source_something_after_it_wants() {
1474 let mut names = Interner::new();
1475 let mut func = Func::new(names.intern("f"));
1476 let opcode = Opcode::new(names.intern("x64.nop"));
1477 let block = func.create_block();
1478 let left = func.new_vreg(GPR);
1479 let right = func.new_vreg(GPR);
1480 let sum = func.new_vreg(GPR);
1481 func.build(block, opcode).def(left, GPR).finish();
1482 func.build(block, opcode)
1483 .operand(Operand::write(right, GPR).with(Constraint::Fixed(RAX)))
1484 .finish();
1485 let add = func
1486 .build(block, opcode)
1487 .flags(Flags::COMMUTES)
1488 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1489 .uses(left, GPR)
1490 .uses(right, GPR)
1491 .finish();
1492 func.build(block, opcode)
1493 .operand(Operand::read(sum, GPR).with(Constraint::Fixed(RAX)))
1494 .finish();
1495
1496 let names = places(&func, &env());
1500 assert_eq!(names[2], "rax");
1501 assert_ne!(names[0], "rax");
1502 let allocation = crate::run(&mut func, &env(), "f", true);
1503 assert!(allocation.edits.is_empty());
1504 assert_eq!(func[func[add].operands][1].reg.phys(), Some(RAX));
1505 }
1506
1507 #[test]
1508 fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1509 let mut names = Interner::new();
1510 let mut func = Func::new(names.intern("f"));
1511 let opcode = Opcode::new(names.intern("x64.nop"));
1512 let entry = func.create_block();
1513 let head = func.create_block();
1514 let out = func.create_block();
1515 let seed = func.new_vreg(GPR);
1516 let total = func.new_vreg(GPR);
1517 let term = func.new_vreg(GPR);
1518 let next = func.new_vreg(GPR);
1519 func.build(entry, opcode).def(seed, GPR).finish();
1520 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1521 func.params_mut(head).push(Param { reg: total, class: GPR });
1522 func.build(head, opcode).def(term, GPR).finish();
1523 let add = func
1524 .build(head, opcode)
1525 .flags(Flags::COMMUTES)
1526 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1527 .uses(total, GPR)
1528 .uses(term, GPR)
1529 .finish();
1530 func.build(head, opcode)
1531 .operand(Operand::read(next, GPR).with(Constraint::Fixed(RSI)))
1532 .finish();
1533 *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1534
1535 let order = Order::of(&func);
1539 let live = Live::of(&func, &order);
1540 let assignment = assign(&func, &order, &live, &env());
1541 assert_eq!(assignment.place(next), assignment.place(total));
1542 assert!(!assignment.commuted().contains(&add));
1543 }
1544
1545 #[test]
1546 fn an_answer_that_does_not_commute_leaves_its_sources_where_they_are() {
1547 let mut names = Interner::new();
1548 let mut func = Func::new(names.intern("f"));
1549 let opcode = Opcode::new(names.intern("x64.nop"));
1550 let block = func.create_block();
1551 let left = func.new_vreg(GPR);
1552 let right = func.new_vreg(GPR);
1553 let sum = func.new_vreg(GPR);
1554 func.build(block, opcode).def(left, GPR).finish();
1555 func.build(block, opcode).def(right, GPR).finish();
1556 func.build(block, opcode)
1557 .flags(Flags::COMMUTES)
1558 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1559 .uses(left, GPR)
1560 .uses(right, GPR)
1561 .finish();
1562 func.build(block, opcode).uses(right, GPR).finish();
1563
1564 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1567 let order = Order::of(&func);
1568 let live = Live::of(&func, &order);
1569 assert!(assign(&func, &order, &live, &env()).commuted().is_empty());
1570 }
1571
1572 #[test]
1573 fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
1574 let mut names = Interner::new();
1575 let mut func = Func::new(names.intern("f"));
1576 let opcode = Opcode::new(names.intern("x64.nop"));
1577 let head = func.create_block();
1578 let body = func.create_block();
1579 let carried = func.new_vreg(GPR);
1580 let inside = func.new_vreg(GPR);
1581 func.build(head, opcode).def(carried, GPR).finish();
1582 *func.succs_mut(head) = vec![BlockCall::to(body)];
1583 func.build(body, opcode).def(inside, GPR).finish();
1584 func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
1585 *func.succs_mut(body) = vec![BlockCall::to(body)];
1586
1587 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1590 }
1591
1592 #[test]
1593 fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
1594 let mut names = Interner::new();
1595 let mut func = Func::new(names.intern("f"));
1596 let opcode = Opcode::new(names.intern("x64.nop"));
1597 let head = func.create_block();
1598 let latch = func.create_block();
1599 let out = func.create_block();
1600 let source = func.new_vreg(GPR);
1601 let carried = func.new_vreg(GPR);
1602 func.build(head, opcode).def(source, GPR).finish();
1603 func.build(head, opcode).def(carried, GPR).finish();
1604 *func.succs_mut(head) = vec![BlockCall::to(latch)];
1605 func.build(latch, opcode)
1608 .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
1609 .uses(source, GPR)
1610 .uses(carried, GPR)
1611 .finish();
1612 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1613 func.build(out, opcode).uses(carried, GPR).finish();
1614
1615 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1620
1621 let order = Order::of(&func);
1624 let live = Live::of(&func, &order);
1625 let assignment = assign(&func, &order, &live, &env());
1626 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1627 }
1628
1629 #[test]
1630 fn a_two_address_answer_with_a_hole_in_front_of_it_does_not_take_its_other_operand() {
1631 let mut names = Interner::new();
1632 let mut func = Func::new(names.intern("f"));
1633 let nop = Opcode::new(names.intern("x64.nop"));
1634 let add = Opcode::new(names.intern("x64.add"));
1635 let entry = func.create_block();
1636 let head = func.create_block();
1637 let arm = func.create_block();
1638 let latch = func.create_block();
1639 let out = func.create_block();
1640 let seed = func.new_vreg(GPR);
1641 let sum = func.new_vreg(GPR);
1642 let inside = func.new_vreg(GPR);
1643 let loaded = func.new_vreg(GPR);
1644 func.build(entry, nop).def(seed, GPR).finish();
1645 func.build(entry, nop).def(sum, GPR).finish();
1646 *func.succs_mut(entry) = vec![BlockCall::to(head)];
1647 func.build(head, nop).uses(sum, GPR).finish();
1648 *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
1649 func.build(arm, nop).def(inside, GPR).finish();
1650 func.build(arm, nop).uses(inside, GPR).finish();
1651 *func.succs_mut(arm) = vec![BlockCall::to(out)];
1652 func.build(latch, nop).def(loaded, GPR).finish();
1653 func.build(latch, add)
1654 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1655 .uses(seed, GPR)
1656 .uses(loaded, GPR)
1657 .finish();
1658 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1659
1660 let places = places(&func, &env());
1665 assert_ne!(places[index(sum)], places[index(loaded)]);
1666
1667 let order = Order::of(&func);
1668 let live = Live::of(&func, &order);
1669 let assignment = assign(&func, &order, &live, &env());
1670 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1671 }
1672
1673 #[test]
1674 fn a_sum_a_loop_carries_round_keeps_its_register_past_an_arm_laid_out_after_it() {
1675 let mut names = Interner::new();
1676 let mut func = Func::new(names.intern("f"));
1677 let nop = Opcode::new(names.intern("x64.nop"));
1678 let add = Opcode::new(names.intern("x64.add"));
1679 let entry = func.create_block();
1680 let head = func.create_block();
1681 let join = func.create_block();
1682 let arm = func.create_block();
1683 let out = func.create_block();
1684 let seed = func.new_vreg(GPR);
1685 let term = func.new_vreg(GPR);
1686 let next = func.new_vreg(GPR);
1687 func.build(entry, nop).def(seed, GPR).finish();
1688 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1689 let total = func.append_param(head, GPR);
1690 func.build(head, nop).def(term, GPR).finish();
1691 *func.succs_mut(head) = vec![BlockCall::to(join), BlockCall::to(arm)];
1692 func.build(join, add)
1693 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1694 .uses(total, GPR)
1695 .uses(term, GPR)
1696 .finish();
1697 *func.succs_mut(join) =
1698 vec![BlockCall::with(head, vec![next]), BlockCall::with(out, vec![next])];
1699 func.build(arm, nop).def(term, GPR).finish();
1702 *func.succs_mut(arm) = vec![BlockCall::to(join)];
1703 let result = func.append_param(out, GPR);
1704 func.build(out, nop).uses(result, GPR).finish();
1705
1706 let places = places(&func, &env());
1709 assert_eq!(places[index(next)], places[index(total)]);
1710
1711 let order = Order::of(&func);
1712 let live = Live::of(&func, &order);
1713 let assignment = assign(&func, &order, &live, &env());
1714 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1715 }
1716
1717 fn arms(reaches: bool) -> Func {
1721 let mut names = Interner::new();
1722 let mut func = Func::new(names.intern("f"));
1723 let opcode = Opcode::new(names.intern("x64.nop"));
1724 let entry = func.create_block();
1725 let arm = func.create_block();
1726 let tail = func.create_block();
1727 let first = func.new_vreg(GPR);
1728 let second = func.new_vreg(GPR);
1729 func.build(entry, opcode).def(first, GPR).finish();
1730 func.build(entry, opcode).def(second, GPR).finish();
1731 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1732 func.build(arm, opcode).operand(Operand::write(Reg::physical(RAX), GPR)).finish();
1735 *func.succs_mut(arm) = if reaches { vec![BlockCall::to(tail)] } else { Vec::new() };
1736 func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1737 func
1738 }
1739
1740 #[test]
1741 fn a_register_a_clobber_takes_beats_the_stack_for_a_value_not_live_in_that_block() {
1742 let func = arms(false);
1743
1744 assert_eq!(places(&func, &narrow(2)), ["rcx", "rax"]);
1750
1751 let order = Order::of(&func);
1752 let live = Live::of(&func, &order);
1753 let assignment = assign(&func, &order, &live, &narrow(2));
1754 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1755 }
1756
1757 #[test]
1758 fn a_register_a_clobber_takes_is_not_free_to_a_value_that_is_live_there() {
1759 let func = arms(true);
1760
1761 assert_eq!(places(&func, &narrow(2)), ["rcx", "slot 0"]);
1765 }
1766
1767 fn dies_at_the_clobber(here: bool) -> Func {
1770 let mut names = Interner::new();
1771 let mut func = Func::new(names.intern("f"));
1772 let opcode = Opcode::new(names.intern("x64.nop"));
1773 let entry = func.create_block();
1774 let value = func.new_vreg(GPR);
1775 func.build(entry, opcode).def(value, GPR).finish();
1776 let call = func.build(entry, opcode).operand(Operand::write(Reg::physical(RAX), GPR));
1777 if here {
1778 call.uses(value, GPR).finish();
1779 } else {
1780 call.finish();
1781 func.build(entry, opcode).uses(value, GPR).finish();
1782 }
1783 func
1784 }
1785
1786 #[test]
1794 fn a_value_that_dies_where_a_register_is_destroyed_may_be_in_that_register() {
1795 let func = dies_at_the_clobber(true);
1796 assert_eq!(places(&func, &narrow(1)), ["rax"]);
1797
1798 let order = Order::of(&func);
1799 let live = Live::of(&func, &order);
1800 let assignment = assign(&func, &order, &live, &narrow(1));
1801 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1802 }
1803
1804 #[test]
1807 fn a_value_read_after_the_instruction_that_destroys_a_register_is_not_in_it() {
1808 let func = dies_at_the_clobber(false);
1809 assert_eq!(places(&func, &narrow(1)), ["slot 0"]);
1810 }
1811
1812 #[test]
1813 fn a_hint_is_followed_when_the_register_is_clear_and_not_when_it_is_merely_allowed() {
1814 let mut names = Interner::new();
1815 let mut func = Func::new(names.intern("f"));
1816 let opcode = Opcode::new(names.intern("x64.nop"));
1817 let entry = func.create_block();
1818 let mid = func.create_block();
1819 let tail = func.create_block();
1820 let first = func.new_vreg(GPR);
1821 let second = func.new_vreg(GPR);
1822 func.build(entry, opcode).def(first, GPR).finish();
1823 func.build(entry, opcode).def(second, GPR).finish();
1824 *func.succs_mut(entry) = vec![BlockCall::to(mid), BlockCall::to(tail)];
1825 func.build(mid, opcode)
1828 .operand(Operand::read(second, GPR).with(Constraint::Fixed(RAX)))
1829 .finish();
1830 func.build(tail, opcode)
1831 .operand(Operand::read(first, GPR).with(Constraint::Fixed(RAX)))
1832 .finish();
1833
1834 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1839 }
1840
1841 #[test]
1842 fn a_value_living_in_a_hole_of_another_gets_the_same_register() {
1843 let mut names = Interner::new();
1844 let mut func = Func::new(names.intern("f"));
1845 let opcode = Opcode::new(names.intern("x64.nop"));
1846 let entry = func.create_block();
1847 let arm = func.create_block();
1848 let tail = func.create_block();
1849 let across = func.new_vreg(GPR);
1850 let inside = func.new_vreg(GPR);
1851 func.build(entry, opcode).def(across, GPR).finish();
1852 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1853 func.build(arm, opcode).def(inside, GPR).finish();
1854 func.build(arm, opcode).uses(inside, GPR).finish();
1855 func.build(tail, opcode).uses(across, GPR).finish();
1856
1857 assert_eq!(places(&func, &narrow(1)), ["rax", "rax"]);
1863
1864 let order = Order::of(&func);
1865 let live = Live::of(&func, &order);
1866 let assignment = assign(&func, &order, &live, &narrow(1));
1867 assert_eq!(assignment.spilled(), 0);
1868 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1869 }
1870
1871 #[test]
1872 fn a_register_a_clobber_takes_is_the_last_one_offered_rather_than_the_first() {
1873 let func = arms(false);
1874
1875 assert_eq!(places(&func, &narrow(3)), ["rcx", "rdx"]);
1879 }
1880
1881 #[test]
1882 fn a_frame_says_what_each_of_its_slots_is_for() {
1883 let mut names = Interner::new();
1884 let mut func = Func::new(names.intern("f"));
1885 let opcode = Opcode::new(names.intern("x64.nop"));
1886 let block = func.create_block();
1887 let first = func.new_vreg(GPR);
1888 let second = func.new_vreg(GPR);
1889 func.build(block, opcode).def(first, GPR).finish();
1890 func.build(block, opcode).def(second, GPR).finish();
1891 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
1892
1893 let order = Order::of(&func);
1894 let live = Live::of(&func, &order);
1895 let assignment = assign(&func, &order, &live, &narrow(1));
1896 assert_eq!(assignment.spilled(), 1);
1897 assert_eq!(assignment.slots(), [GPR]);
1898 assert_eq!(assignment.place(Reg::physical(RCX)), None);
1901 assert_eq!(env().scratch(GPR), [R13, R14, R15]);
1902 }
1903
1904 fn ranges(pairs: &[(Point, Point)]) -> Vec<Range> {
1906 pairs.iter().map(|&(start, end)| Range { start, end }).collect()
1907 }
1908
1909 #[test]
1910 fn the_pieces_of_a_register_answer_what_a_walk_over_its_values_would() {
1911 let held = [
1913 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1914 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1915 (Reg::virtual_reg(2), ranges(&[(10, 19), (31, 40)])),
1916 ];
1917 let mut pieces = Pieces::default();
1918 for (reg, list) in &held {
1919 for &piece in list {
1920 pieces.insert(piece, *reg);
1921 }
1922 }
1923 assert!(!pieces.broken);
1924 let asked = [
1925 ranges(&[(41, 50)]),
1926 ranges(&[(40, 50)]),
1927 ranges(&[(9, 9)]),
1928 ranges(&[(3, 3), (41, 42)]),
1929 ranges(&[(50, 60)]),
1930 ranges(&[(15, 15)]),
1931 ];
1932 for list in &asked {
1933 let area = Area::of_pieces(list);
1934 for except in [None, Some(Reg::virtual_reg(0)), Some(Reg::virtual_reg(2))] {
1935 let walked = held.iter().any(|(reg, pieces)| {
1936 Some(*reg) != except && Area::of_pieces(pieces).overlaps(area)
1937 });
1938 assert_eq!(pieces.touch(area, except), walked, "{list:?} except {except:?}");
1939 }
1940 }
1941 }
1942
1943 #[test]
1944 fn the_owners_of_the_pieces_an_area_touches_are_the_values_a_walk_would_find() {
1945 let held = [
1946 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1947 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1948 (Reg::virtual_reg(2), ranges(&[(10, 19), (30, 40)])),
1949 ];
1950 let mut pieces = Pieces::default();
1951 for (reg, list) in &held {
1952 for &piece in list {
1953 pieces.insert(piece, *reg);
1954 }
1955 }
1956 let asked = [
1957 ranges(&[(41, 50)]),
1958 ranges(&[(30, 30)]),
1959 ranges(&[(3, 12)]),
1960 ranges(&[(3, 3), (25, 42)]),
1961 ranges(&[(0, 50)]),
1962 ];
1963 for list in &asked {
1964 let area = Area::of_pieces(list);
1965 let walked: Vec<Reg> = held
1966 .iter()
1967 .filter(|(_, pieces)| Area::of_pieces(pieces).overlaps(area))
1968 .map(|&(reg, _)| reg)
1969 .collect();
1970 assert_eq!(pieces.owners(area), Some(walked), "{list:?}");
1971 }
1972 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(3));
1973 assert_eq!(pieces.owners(Area::of_pieces(&asked[0])), None);
1974 }
1975
1976 #[test]
1977 fn pieces_that_end_out_of_order_are_marked() {
1978 let mut pieces = Pieces::default();
1979 pieces.insert(Range { start: 0, end: 10 }, Reg::virtual_reg(0));
1980 pieces.insert(Range { start: 12, end: 20 }, Reg::virtual_reg(1));
1981 assert!(!pieces.broken);
1982 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(2));
1984 assert!(pieces.broken);
1985 }
1986
1987 #[test]
1988 fn a_value_taken_out_of_a_register_leaves_its_pieces_with_it() {
1989 let mut pieces = Pieces::default();
1990 let (first, second) = (Reg::virtual_reg(0), Reg::virtual_reg(1));
1991 pieces.insert(Range { start: 0, end: 10 }, first);
1992 pieces.insert(Range { start: 12, end: 20 }, second);
1993 let asked = ranges(&[(15, 16)]);
1994 assert!(pieces.touch(Area::of_pieces(&asked), None));
1995 pieces.remove(Range { start: 12, end: 20 }, second);
1996 assert!(!pieces.touch(Area::of_pieces(&asked), None));
1997 pieces.drop_before(11);
1998 assert!(pieces.list.is_empty());
1999 }
2000}