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,
704 Allowed,
708}
709
710pub(crate) struct Blocks {
726 all: Vec<Blocked>,
728 points: Vec<Point>,
730 spans: Vec<(usize, usize)>,
733 stride: usize,
735 widths: Vec<Option<u8>>,
738}
739
740impl Blocks {
741 pub(crate) fn insists(
746 &self,
747 reg: Reg,
748 class: RegClass,
749 area: Area<'_>,
750 range: Range,
751 at: PhysReg,
752 want: Want,
753 ) -> bool {
754 self.over(class, at, range).any(|one| {
755 one.by != Some(reg)
756 && one.reaches(self.width(reg))
757 && ((want == Want::Clear && one.by.is_some()) || area.covers(one.point))
758 })
759 }
760
761 fn width(&self, reg: Reg) -> Option<u8> {
763 let number = usize::try_from(reg.number()?).ok()?;
764 self.widths.get(number).copied().flatten()
765 }
766
767 pub(crate) fn taken(&self) -> impl Iterator<Item = (RegClass, PhysReg, Point)> + '_ {
772 self.all
773 .iter()
774 .filter(|one| one.by.is_none() && one.above.is_none())
775 .map(|one| (one.class, one.at, one.point))
776 }
777
778 #[inline]
783 fn over(
784 &self,
785 class: RegClass,
786 at: PhysReg,
787 range: Range,
788 ) -> impl Iterator<Item = &Blocked> + '_ {
789 let (low, high) = if usize::from(at.number()) < self.stride {
790 let key = usize::from(class.number()) * self.stride + usize::from(at.number());
791 self.spans.get(key).copied().unwrap_or((0, 0))
792 } else {
793 (0, 0)
794 };
795 let first = low + self.points[low..high].partition_point(|&point| point < range.start);
796 self.all[first..high].iter().take_while(move |one| one.point <= range.end)
797 }
798}
799
800fn available(
809 active: &Active<'_>,
810 blocked: &Blocks,
811 interval: Interval<'_>,
812 at: PhysReg,
813 except: Option<Reg>,
814 want: Want,
815) -> bool {
816 let taken = active.taken(interval.class, at, interval.area, except);
817 let width = blocked.width(interval.reg);
818 let insisted = blocked.over(interval.class, at, interval.range).any(|one| {
819 one.by != Some(interval.reg)
820 && one.reaches(width)
821 && ((want == Want::Clear && one.by.is_some()) || interval.area.covers(one.point))
822 });
823 !taken && !insisted
824}
825
826fn coalesce(
829 assignment: &Assignment,
830 active: &Active<'_>,
831 blocked: &Blocks,
832 live: &Live,
833 interval: Interval<'_>,
834 source: Reg,
835) -> Option<PhysReg> {
836 let Some(Place::Reg(at)) = assignment.place(source) else { return None };
837 active.at(at).iter().find(|held| held.reg == source)?;
838 let free = available(active, blocked, interval, at, Some(source), Want::Allowed);
854 (apart(live, source, interval.reg) && free).then_some(at)
855}
856
857pub(crate) fn apart(live: &Live, first: Reg, second: Reg) -> bool {
859 match (live.area(first), live.area(second)) {
860 (Some(first), Some(second)) => !first.overlaps(second),
861 _ => false,
862 }
863}
864
865fn spill_one<'a>(
873 assignment: &mut Assignment,
874 active: &mut Active<'a>,
875 blocked: &Blocks,
876 interval: Interval<'a>,
877) {
878 let mut costs = std::mem::take(&mut active.costs);
884 costs.clear();
885 for (slot, values) in active.by.iter().enumerate() {
886 let owners = if values.len() > FEW {
889 active.owners(interval.class, slot, interval.area)
890 } else {
891 None
892 };
893 for held in values {
894 if held.class != interval.class {
895 continue;
896 }
897 let touches = match &owners {
898 Some(owners) => owners.binary_search(&held.reg).is_ok(),
899 None => held.area.overlaps(interval.area),
900 };
901 if !touches {
902 continue;
903 }
904 match costs.iter_mut().find(|(_, at, _, _)| *at == held.at) {
905 Some((first, _, count, reach)) => {
906 *first = (*first).min(held.since);
907 *count += 1;
908 *reach = (*reach).max(held.range.end);
909 }
910 None => costs.push((held.since, held.at, 1, held.range.end)),
911 }
912 }
913 }
914 costs.sort_unstable_by_key(|&(first, _, _, _)| first);
915 let none = Active::default();
918 let chosen = costs
919 .iter()
920 .filter(|&&(_, at, _, reach)| {
921 reach > interval.range.end
922 && available(&none, blocked, interval, at, None, Want::Allowed)
923 })
924 .min_by_key(|&&(_, _, count, reach)| (count, Reverse(reach)))
925 .map(|&(_, at, _, _)| at);
926 active.costs = costs;
927 match chosen {
928 Some(at) => {
929 active.evict(
930 interval.class,
931 at,
932 |held| held.area.overlaps(interval.area),
933 |held| assignment.spill(held.reg, held.class),
934 );
935 assignment.places[index(interval.reg)] = Some(Place::Reg(at));
936 active.push(interval.reg, interval.class, interval.range, interval.area, at);
937 }
938 None => assignment.spill(interval.reg, interval.class),
939 }
940}
941
942pub(crate) fn blocked(func: &Func, order: &Order) -> Blocks {
948 let mut blocked = Vec::new();
949 let mut claimed: Vec<(RegClass, PhysReg)> = Vec::new();
950 for block in func.blocks() {
951 for inst in func.insts(block) {
952 let operands = &func[func[inst].operands];
953 claimed.clear();
954 for operand in operands {
955 if let Some(at) = insisted(operand) {
956 let key = (operand.class, at);
957 if !claimed.contains(&key) {
958 claimed.push(key);
959 }
960 }
961 }
962 for &(class, at) in &claimed {
963 for (point, role) in [(order.early(inst), Role::Use), (order.late(inst), Role::Def)]
968 {
969 let mut named = false;
970 for operand in operands {
971 let mine = insisted(operand) == Some(at) && operand.class == class;
972 if !mine || !(operand.role == role || operand.role == Role::EarlyDef) {
973 continue;
974 }
975 named = true;
976 let by = operand.reg.is_virtual().then_some(operand.reg);
977 let above = match operand.constraint {
978 Constraint::Above(above) => Some(above),
979 _ => None,
980 };
981 blocked.push(Blocked { class, at, point, by, above });
982 }
983 if !named && role == Role::Def {
1002 blocked.push(Blocked { class, at, point, by: None, above: None });
1003 }
1004 }
1005 }
1006 }
1007 }
1008 blocked.sort_by_key(|one: &Blocked| (one.class, one.at, one.point));
1014 let widths = (0..func.vregs())
1015 .map(|number| func.width(Reg::virtual_reg(u32::try_from(number).ok()?)))
1016 .collect();
1017 let points = blocked.iter().map(|one| one.point).collect();
1018 let stride = blocked.iter().map(|one| usize::from(one.at.number()) + 1).max().unwrap_or(0);
1019 let classes = blocked.last().map_or(0, |one| usize::from(one.class.number()) + 1);
1020 let mut spans = vec![(0, 0); classes * stride];
1021 for (index, one) in blocked.iter().enumerate() {
1022 let key = usize::from(one.class.number()) * stride + usize::from(one.at.number());
1023 let span = &mut spans[key];
1024 if span.1 == 0 {
1025 span.0 = index;
1026 }
1027 span.1 = index + 1;
1028 }
1029 Blocks { all: blocked, points, spans, stride, widths }
1030}
1031
1032fn insisted(operand: &Operand) -> Option<PhysReg> {
1035 match operand.constraint {
1036 Constraint::Fixed(at) => Some(at),
1037 _ => operand.reg.phys(),
1038 }
1039}
1040
1041pub(crate) fn hints(func: &Func) -> Vec<Vec<PhysReg>> {
1051 let mut hints = vec![Vec::new(); func.vregs()];
1052 for block in func.blocks() {
1053 for inst in func.insts(block) {
1054 for operand in &func[func[inst].operands] {
1055 let Constraint::Fixed(at) = operand.constraint else { continue };
1056 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1057 let Some(number) = number else { continue };
1058 let wanted: &mut Vec<PhysReg> = &mut hints[number];
1059 if func.class_of(operand.reg) == Some(operand.class) && !wanted.contains(&at) {
1060 wanted.push(at);
1061 }
1062 }
1063 }
1064 }
1065 hints
1066}
1067
1068pub(crate) fn passed(func: &Func) -> Vec<Vec<Reg>> {
1070 let mut passed = vec![Vec::new(); func.vregs()];
1071 for block in func.blocks() {
1072 for call in &func[block].succs {
1073 for (&arg, param) in call.args.iter().zip(&func[call.block].params) {
1074 let number = arg.number().and_then(|number| usize::try_from(number).ok());
1075 let Some(number) = number else { continue };
1076 let to: &mut Vec<Reg> = &mut passed[number];
1077 if !to.contains(¶m.reg) {
1078 to.push(param.reg);
1079 }
1080 }
1081 }
1082 }
1083 passed
1084}
1085
1086pub(crate) fn forced(func: &Func) -> Vec<Reg> {
1088 let mut forced = Vec::new();
1089 for block in func.blocks() {
1090 for inst in func.insts(block) {
1091 for operand in &func[func[inst].operands] {
1092 if operand.constraint == Constraint::Stack
1093 && operand.reg.is_virtual()
1094 && !forced.contains(&operand.reg)
1095 {
1096 forced.push(operand.reg);
1097 }
1098 }
1099 }
1100 }
1101 forced
1102}
1103
1104pub(crate) fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
1106 let mut reuses = vec![None; func.vregs()];
1107 for block in func.blocks() {
1108 for inst in func.insts(block) {
1109 let operands = &func[func[inst].operands];
1110 for operand in operands {
1111 let Constraint::Reuse(other) = operand.constraint else { continue };
1112 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
1113 let Some(number) = number else { continue };
1114 let source = operands[usize::from(other)].reg;
1115 let second = if func[inst].flags.contains(Flags::COMMUTES) {
1116 swappable(operands, usize::from(other))
1117 } else {
1118 None
1119 };
1120 reuses[number] = Some(Reuse { source, second, at: order.early(inst), inst });
1121 }
1122 }
1123 }
1124 reuses
1125}
1126
1127fn swappable(operands: &[Operand], other: usize) -> Option<Reg> {
1134 let [answer, first, second] = operands else { return None };
1135 let same = second.class == first.class && second.class == answer.class;
1136 let plain = second.role == Role::Use && second.constraint == Constraint::Reg;
1137 (other == 1 && same && plain && second.reg.is_virtual() && second.reg != first.reg)
1138 .then_some(second.reg)
1139}
1140
1141fn index(reg: Reg) -> usize {
1143 usize::try_from(reg.number().expect("a virtual register")).expect("a register number")
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148 use rucc_base::Interner;
1149 use rucc_mir::{BlockCall, Opcode, Operand, Param};
1150 use rucc_target::x86_64::{GPR, R13, R14, R15, RAX, RCX, RDX, REGS, RSI, SYSV};
1151
1152 use super::*;
1153
1154 fn env() -> Env {
1156 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
1157 Env::new().with(GPR, order, scratch)
1158 }
1159
1160 fn narrow(count: usize) -> Env {
1163 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 1])
1164 }
1165
1166 fn named(place: Option<Place>) -> String {
1168 match place {
1169 Some(Place::Reg(reg)) => REGS.name(GPR, reg).expect("a register").to_string(),
1170 Some(Place::Slot(slot)) => format!("slot {slot}"),
1171 None => "nowhere".to_string(),
1172 }
1173 }
1174
1175 fn places(func: &Func, env: &Env) -> Vec<String> {
1177 let order = Order::of(func);
1178 let live = Live::of(func, &order);
1179 let assignment = assign(func, &order, &live, env);
1180 (0..func.vregs())
1181 .map(|number| {
1182 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
1183 named(assignment.place(reg))
1184 })
1185 .collect()
1186 }
1187
1188 #[test]
1189 fn two_values_that_are_never_both_wanted_share_a_register() {
1190 let mut names = Interner::new();
1191 let mut func = Func::new(names.intern("f"));
1192 let opcode = Opcode::new(names.intern("x64.nop"));
1193 let block = func.create_block();
1194 let first = func.new_vreg(GPR);
1195 let second = func.new_vreg(GPR);
1196 func.build(block, opcode).def(first, GPR).finish();
1197 func.build(block, opcode).uses(first, GPR).finish();
1198 func.build(block, opcode).def(second, GPR).finish();
1199 func.build(block, opcode).uses(second, GPR).finish();
1200
1201 assert_eq!(places(&func, &env()), ["rax", "rax"]);
1204 }
1205
1206 fn over_the_top(width: u32) -> Func {
1209 let mut names = Interner::new();
1210 let mut func = Func::new(names.intern("f"));
1211 let opcode = Opcode::new(names.intern("x64.nop"));
1212 let block = func.create_block();
1213 let held = func.new_vreg(GPR);
1214 func.set_width(held, width);
1215 func.build(block, opcode).def(held, GPR).finish();
1216 func.build(block, opcode)
1217 .operand(Operand::write(Reg::physical(RAX), GPR))
1218 .operand(Operand::write(Reg::physical(RCX), GPR).with(Constraint::Above(8)))
1219 .finish();
1220 func.build(block, opcode).uses(held, GPR).finish();
1221 func
1222 }
1223
1224 #[test]
1225 fn a_value_that_fits_under_what_an_instruction_writes_stays_in_the_register() {
1226 assert_eq!(places(&over_the_top(8), &narrow(2)), ["rcx"]);
1227 assert_eq!(places(&over_the_top(4), &narrow(2)), ["rcx"]);
1228 }
1229
1230 #[test]
1231 fn a_value_wider_than_that_or_of_no_known_width_does_not() {
1232 assert_eq!(places(&over_the_top(16), &narrow(2)), ["slot 0"]);
1233 assert_eq!(places(&over_the_top(0), &narrow(2)), ["slot 0"]);
1234 }
1235
1236 #[test]
1237 fn two_values_that_are_both_wanted_do_not() {
1238 let mut names = Interner::new();
1239 let mut func = Func::new(names.intern("f"));
1240 let opcode = Opcode::new(names.intern("x64.nop"));
1241 let block = func.create_block();
1242 let first = func.new_vreg(GPR);
1243 let second = func.new_vreg(GPR);
1244 func.build(block, opcode).def(first, GPR).finish();
1245 func.build(block, opcode).def(second, GPR).finish();
1246 func.build(block, opcode).uses(first, GPR).finish();
1247 func.build(block, opcode).uses(second, GPR).finish();
1248
1249 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1250 }
1251
1252 #[test]
1253 fn a_value_written_early_that_nothing_reads_still_holds_its_register() {
1254 let mut names = Interner::new();
1255 let mut func = Func::new(names.intern("f"));
1256 let opcode = Opcode::new(names.intern("x64.nop"));
1257 let block = func.create_block();
1258 let wanted = func.new_vreg(GPR);
1259 let spare = func.new_vreg(GPR);
1260 func.build(block, opcode)
1263 .def(wanted, GPR)
1264 .operand(Operand::write_early(spare, GPR))
1265 .finish();
1266 func.build(block, opcode).uses(wanted, GPR).finish();
1267
1268 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1274 }
1275
1276 #[test]
1277 fn the_value_wanted_longest_is_the_one_that_goes_to_the_stack() {
1278 let mut names = Interner::new();
1279 let mut func = Func::new(names.intern("f"));
1280 let opcode = Opcode::new(names.intern("x64.nop"));
1281 let block = func.create_block();
1282 let long = func.new_vreg(GPR);
1283 let short = func.new_vreg(GPR);
1284 let third = func.new_vreg(GPR);
1285 func.build(block, opcode).def(long, GPR).finish();
1286 func.build(block, opcode).def(short, GPR).finish();
1287 func.build(block, opcode).def(third, GPR).finish();
1288 func.build(block, opcode).uses(short, GPR).finish();
1289 func.build(block, opcode).uses(third, GPR).finish();
1290 func.build(block, opcode).uses(long, GPR).finish();
1291
1292 assert_eq!(places(&func, &narrow(2)), ["slot 0", "rcx", "rax"]);
1295 }
1296
1297 #[test]
1298 fn a_register_an_instruction_insists_on_goes_to_the_values_that_asked_for_it() {
1299 let mut names = Interner::new();
1300 let mut func = Func::new(names.intern("f"));
1301 let opcode = Opcode::new(names.intern("x64.nop"));
1302 let block = func.create_block();
1303 let across = func.new_vreg(GPR);
1304 let dividend = func.new_vreg(GPR);
1305 let quotient = func.new_vreg(GPR);
1306 let remainder = func.new_vreg(GPR);
1307 func.build(block, opcode).def(across, GPR).finish();
1308 func.build(block, opcode).def(dividend, GPR).finish();
1309 func.build(block, opcode)
1310 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1311 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1312 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1313 .finish();
1314 func.build(block, opcode).uses(across, GPR).finish();
1315
1316 assert_eq!(places(&func, &env()), ["rcx", "rax", "rax", "rdx"]);
1321 }
1322
1323 #[test]
1333 fn a_value_that_dies_at_an_instruction_stays_out_of_what_it_fills_first() {
1334 let mut names = Interner::new();
1335 let mut func = Func::new(names.intern("f"));
1336 let opcode = Opcode::new(names.intern("x64.nop"));
1337 let block = func.create_block();
1338 let across = func.new_vreg(GPR);
1339 let dividend = func.new_vreg(GPR);
1340 let divisor = func.new_vreg(GPR);
1341 let remainder = func.new_vreg(GPR);
1342 func.build(block, opcode).def(across, GPR).finish();
1343 func.build(block, opcode).def(dividend, GPR).finish();
1344 func.build(block, opcode).def(divisor, GPR).finish();
1345 func.build(block, opcode)
1346 .operand(Operand::write_early(remainder, GPR).with(Constraint::Fixed(RDX)))
1347 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1348 .operand(Operand::read(divisor, GPR))
1349 .finish();
1350 func.build(block, opcode).uses(across, GPR).uses(remainder, GPR).finish();
1351
1352 assert_eq!(places(&func, &narrow(4)), ["rcx", "rax", "rsi", "rdx"]);
1356 }
1357
1358 #[test]
1359 fn a_value_wanted_after_the_instruction_that_insists_does_not_get_that_register() {
1360 let mut names = Interner::new();
1361 let mut func = Func::new(names.intern("f"));
1362 let opcode = Opcode::new(names.intern("x64.nop"));
1363 let block = func.create_block();
1364 let dividend = func.new_vreg(GPR);
1365 let quotient = func.new_vreg(GPR);
1366 func.build(block, opcode).def(dividend, GPR).finish();
1367 func.build(block, opcode)
1368 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
1369 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
1370 .finish();
1371 func.build(block, opcode).uses(dividend, GPR).finish();
1372
1373 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1377 }
1378
1379 #[test]
1380 fn a_value_an_instruction_can_only_read_from_memory_is_on_the_stack() {
1381 let mut names = Interner::new();
1382 let mut func = Func::new(names.intern("f"));
1383 let opcode = Opcode::new(names.intern("x64.nop"));
1384 let block = func.create_block();
1385 let value = func.new_vreg(GPR);
1386 func.build(block, opcode).def(value, GPR).finish();
1387 func.build(block, opcode)
1388 .operand(Operand::read(value, GPR).with(Constraint::Stack))
1389 .finish();
1390
1391 assert_eq!(places(&func, &env()), ["slot 0"]);
1392 }
1393
1394 #[test]
1395 fn a_two_address_instruction_writes_the_register_it_read_when_it_can() {
1396 let mut names = Interner::new();
1397 let mut func = Func::new(names.intern("f"));
1398 let opcode = Opcode::new(names.intern("x64.nop"));
1399 let block = func.create_block();
1400 let left = func.new_vreg(GPR);
1401 let right = func.new_vreg(GPR);
1402 let sum = func.new_vreg(GPR);
1403 func.build(block, opcode).def(left, GPR).finish();
1404 func.build(block, opcode).def(right, GPR).finish();
1405 func.build(block, opcode)
1406 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1407 .uses(left, GPR)
1408 .uses(right, GPR)
1409 .finish();
1410 func.build(block, opcode).uses(right, GPR).finish();
1411
1412 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1415 }
1416
1417 #[test]
1418 fn a_two_address_instruction_that_cannot_gets_a_register_nothing_it_reads_is_in() {
1419 let mut names = Interner::new();
1420 let mut func = Func::new(names.intern("f"));
1421 let opcode = Opcode::new(names.intern("x64.nop"));
1422 let block = func.create_block();
1423 let left = func.new_vreg(GPR);
1424 let right = func.new_vreg(GPR);
1425 let sum = func.new_vreg(GPR);
1426 func.build(block, opcode).def(left, GPR).finish();
1427 func.build(block, opcode).def(right, GPR).finish();
1428 func.build(block, opcode)
1429 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1430 .uses(left, GPR)
1431 .uses(right, GPR)
1432 .finish();
1433 func.build(block, opcode).uses(left, GPR).finish();
1434
1435 assert_eq!(places(&func, &env()), ["rax", "rcx", "rdx"]);
1439 }
1440
1441 #[test]
1442 fn an_answer_that_commutes_goes_over_the_source_that_is_finished_with() {
1443 let mut names = Interner::new();
1444 let mut func = Func::new(names.intern("f"));
1445 let opcode = Opcode::new(names.intern("x64.nop"));
1446 let block = func.create_block();
1447 let left = func.new_vreg(GPR);
1448 let right = func.new_vreg(GPR);
1449 let sum = func.new_vreg(GPR);
1450 func.build(block, opcode).def(left, GPR).finish();
1451 func.build(block, opcode).def(right, GPR).finish();
1452 let add = func
1453 .build(block, opcode)
1454 .flags(Flags::COMMUTES)
1455 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1456 .uses(left, GPR)
1457 .uses(right, GPR)
1458 .finish();
1459 func.build(block, opcode).uses(left, GPR).uses(sum, GPR).finish();
1460
1461 assert_eq!(places(&func, &env()), ["rax", "rcx", "rcx"]);
1465 let order = Order::of(&func);
1466 let live = Live::of(&func, &order);
1467 let assignment = assign(&func, &order, &live, &env());
1468 assert_eq!(assignment.commuted(), [add]);
1469
1470 let allocation = crate::run(&mut func, &env(), "f", true);
1474 assert!(allocation.edits.is_empty());
1475 let operands = &func[func[add].operands];
1476 let (first, second) = (operands[1].reg.phys(), operands[2].reg.phys());
1477 assert_eq!((first, second), (Some(RCX), Some(RAX)));
1478 }
1479
1480 #[test]
1481 fn an_answer_that_commutes_takes_the_source_something_after_it_wants() {
1482 let mut names = Interner::new();
1483 let mut func = Func::new(names.intern("f"));
1484 let opcode = Opcode::new(names.intern("x64.nop"));
1485 let block = func.create_block();
1486 let left = func.new_vreg(GPR);
1487 let right = func.new_vreg(GPR);
1488 let sum = func.new_vreg(GPR);
1489 func.build(block, opcode).def(left, GPR).finish();
1490 func.build(block, opcode)
1491 .operand(Operand::write(right, GPR).with(Constraint::Fixed(RAX)))
1492 .finish();
1493 let add = func
1494 .build(block, opcode)
1495 .flags(Flags::COMMUTES)
1496 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1497 .uses(left, GPR)
1498 .uses(right, GPR)
1499 .finish();
1500 func.build(block, opcode)
1501 .operand(Operand::read(sum, GPR).with(Constraint::Fixed(RAX)))
1502 .finish();
1503
1504 let names = places(&func, &env());
1508 assert_eq!(names[2], "rax");
1509 assert_ne!(names[0], "rax");
1510 let allocation = crate::run(&mut func, &env(), "f", true);
1511 assert!(allocation.edits.is_empty());
1512 assert_eq!(func[func[add].operands][1].reg.phys(), Some(RAX));
1513 }
1514
1515 #[test]
1516 fn an_answer_that_commutes_stays_where_the_loop_passes_it() {
1517 let mut names = Interner::new();
1518 let mut func = Func::new(names.intern("f"));
1519 let opcode = Opcode::new(names.intern("x64.nop"));
1520 let entry = func.create_block();
1521 let head = func.create_block();
1522 let out = func.create_block();
1523 let seed = func.new_vreg(GPR);
1524 let total = func.new_vreg(GPR);
1525 let term = func.new_vreg(GPR);
1526 let next = func.new_vreg(GPR);
1527 func.build(entry, opcode).def(seed, GPR).finish();
1528 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1529 func.params_mut(head).push(Param { reg: total, class: GPR });
1530 func.build(head, opcode).def(term, GPR).finish();
1531 let add = func
1532 .build(head, opcode)
1533 .flags(Flags::COMMUTES)
1534 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1535 .uses(total, GPR)
1536 .uses(term, GPR)
1537 .finish();
1538 func.build(head, opcode)
1539 .operand(Operand::read(next, GPR).with(Constraint::Fixed(RSI)))
1540 .finish();
1541 *func.succs_mut(head) = vec![BlockCall::with(head, vec![next]), BlockCall::to(out)];
1542
1543 let order = Order::of(&func);
1547 let live = Live::of(&func, &order);
1548 let assignment = assign(&func, &order, &live, &env());
1549 assert_eq!(assignment.place(next), assignment.place(total));
1550 assert!(!assignment.commuted().contains(&add));
1551 }
1552
1553 #[test]
1554 fn an_answer_that_does_not_commute_leaves_its_sources_where_they_are() {
1555 let mut names = Interner::new();
1556 let mut func = Func::new(names.intern("f"));
1557 let opcode = Opcode::new(names.intern("x64.nop"));
1558 let block = func.create_block();
1559 let left = func.new_vreg(GPR);
1560 let right = func.new_vreg(GPR);
1561 let sum = func.new_vreg(GPR);
1562 func.build(block, opcode).def(left, GPR).finish();
1563 func.build(block, opcode).def(right, GPR).finish();
1564 func.build(block, opcode)
1565 .flags(Flags::COMMUTES)
1566 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1567 .uses(left, GPR)
1568 .uses(right, GPR)
1569 .finish();
1570 func.build(block, opcode).uses(right, GPR).finish();
1571
1572 assert_eq!(places(&func, &env()), ["rax", "rcx", "rax"]);
1575 let order = Order::of(&func);
1576 let live = Live::of(&func, &order);
1577 assert!(assign(&func, &order, &live, &env()).commuted().is_empty());
1578 }
1579
1580 #[test]
1581 fn a_value_live_across_a_whole_loop_holds_its_register_over_all_of_it() {
1582 let mut names = Interner::new();
1583 let mut func = Func::new(names.intern("f"));
1584 let opcode = Opcode::new(names.intern("x64.nop"));
1585 let head = func.create_block();
1586 let body = func.create_block();
1587 let carried = func.new_vreg(GPR);
1588 let inside = func.new_vreg(GPR);
1589 func.build(head, opcode).def(carried, GPR).finish();
1590 *func.succs_mut(head) = vec![BlockCall::to(body)];
1591 func.build(body, opcode).def(inside, GPR).finish();
1592 func.build(body, opcode).uses(inside, GPR).uses(carried, GPR).finish();
1593 *func.succs_mut(body) = vec![BlockCall::to(body)];
1594
1595 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1598 }
1599
1600 #[test]
1601 fn a_two_address_answer_already_live_does_not_take_the_register_it_read() {
1602 let mut names = Interner::new();
1603 let mut func = Func::new(names.intern("f"));
1604 let opcode = Opcode::new(names.intern("x64.nop"));
1605 let head = func.create_block();
1606 let latch = func.create_block();
1607 let out = func.create_block();
1608 let source = func.new_vreg(GPR);
1609 let carried = func.new_vreg(GPR);
1610 func.build(head, opcode).def(source, GPR).finish();
1611 func.build(head, opcode).def(carried, GPR).finish();
1612 *func.succs_mut(head) = vec![BlockCall::to(latch)];
1613 func.build(latch, opcode)
1616 .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
1617 .uses(source, GPR)
1618 .uses(carried, GPR)
1619 .finish();
1620 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1621 func.build(out, opcode).uses(carried, GPR).finish();
1622
1623 assert_eq!(places(&func, &env()), ["rax", "rcx"]);
1628
1629 let order = Order::of(&func);
1632 let live = Live::of(&func, &order);
1633 let assignment = assign(&func, &order, &live, &env());
1634 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1635 }
1636
1637 #[test]
1638 fn a_two_address_answer_with_a_hole_in_front_of_it_does_not_take_its_other_operand() {
1639 let mut names = Interner::new();
1640 let mut func = Func::new(names.intern("f"));
1641 let nop = Opcode::new(names.intern("x64.nop"));
1642 let add = Opcode::new(names.intern("x64.add"));
1643 let entry = func.create_block();
1644 let head = func.create_block();
1645 let arm = func.create_block();
1646 let latch = func.create_block();
1647 let out = func.create_block();
1648 let seed = func.new_vreg(GPR);
1649 let sum = func.new_vreg(GPR);
1650 let inside = func.new_vreg(GPR);
1651 let loaded = func.new_vreg(GPR);
1652 func.build(entry, nop).def(seed, GPR).finish();
1653 func.build(entry, nop).def(sum, GPR).finish();
1654 *func.succs_mut(entry) = vec![BlockCall::to(head)];
1655 func.build(head, nop).uses(sum, GPR).finish();
1656 *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
1657 func.build(arm, nop).def(inside, GPR).finish();
1658 func.build(arm, nop).uses(inside, GPR).finish();
1659 *func.succs_mut(arm) = vec![BlockCall::to(out)];
1660 func.build(latch, nop).def(loaded, GPR).finish();
1661 func.build(latch, add)
1662 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
1663 .uses(seed, GPR)
1664 .uses(loaded, GPR)
1665 .finish();
1666 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
1667
1668 let places = places(&func, &env());
1673 assert_ne!(places[index(sum)], places[index(loaded)]);
1674
1675 let order = Order::of(&func);
1676 let live = Live::of(&func, &order);
1677 let assignment = assign(&func, &order, &live, &env());
1678 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1679 }
1680
1681 #[test]
1682 fn a_sum_a_loop_carries_round_keeps_its_register_past_an_arm_laid_out_after_it() {
1683 let mut names = Interner::new();
1684 let mut func = Func::new(names.intern("f"));
1685 let nop = Opcode::new(names.intern("x64.nop"));
1686 let add = Opcode::new(names.intern("x64.add"));
1687 let entry = func.create_block();
1688 let head = func.create_block();
1689 let join = func.create_block();
1690 let arm = func.create_block();
1691 let out = func.create_block();
1692 let seed = func.new_vreg(GPR);
1693 let term = func.new_vreg(GPR);
1694 let next = func.new_vreg(GPR);
1695 func.build(entry, nop).def(seed, GPR).finish();
1696 *func.succs_mut(entry) = vec![BlockCall::with(head, vec![seed])];
1697 let total = func.append_param(head, GPR);
1698 func.build(head, nop).def(term, GPR).finish();
1699 *func.succs_mut(head) = vec![BlockCall::to(join), BlockCall::to(arm)];
1700 func.build(join, add)
1701 .operand(Operand::write(next, GPR).with(Constraint::Reuse(1)))
1702 .uses(total, GPR)
1703 .uses(term, GPR)
1704 .finish();
1705 *func.succs_mut(join) =
1706 vec![BlockCall::with(head, vec![next]), BlockCall::with(out, vec![next])];
1707 func.build(arm, nop).def(term, GPR).finish();
1710 *func.succs_mut(arm) = vec![BlockCall::to(join)];
1711 let result = func.append_param(out, GPR);
1712 func.build(out, nop).uses(result, GPR).finish();
1713
1714 let places = places(&func, &env());
1717 assert_eq!(places[index(next)], places[index(total)]);
1718
1719 let order = Order::of(&func);
1720 let live = Live::of(&func, &order);
1721 let assignment = assign(&func, &order, &live, &env());
1722 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1723 }
1724
1725 fn arms(reaches: bool) -> Func {
1729 let mut names = Interner::new();
1730 let mut func = Func::new(names.intern("f"));
1731 let opcode = Opcode::new(names.intern("x64.nop"));
1732 let entry = func.create_block();
1733 let arm = func.create_block();
1734 let tail = func.create_block();
1735 let first = func.new_vreg(GPR);
1736 let second = func.new_vreg(GPR);
1737 func.build(entry, opcode).def(first, GPR).finish();
1738 func.build(entry, opcode).def(second, GPR).finish();
1739 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1740 func.build(arm, opcode).operand(Operand::write(Reg::physical(RAX), GPR)).finish();
1743 *func.succs_mut(arm) = if reaches { vec![BlockCall::to(tail)] } else { Vec::new() };
1744 func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1745 func
1746 }
1747
1748 #[test]
1749 fn a_register_a_clobber_takes_beats_the_stack_for_a_value_not_live_in_that_block() {
1750 let func = arms(false);
1751
1752 assert_eq!(places(&func, &narrow(2)), ["rax", "rcx"]);
1759
1760 let order = Order::of(&func);
1761 let live = Live::of(&func, &order);
1762 let assignment = assign(&func, &order, &live, &narrow(2));
1763 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1764 }
1765
1766 #[test]
1767 fn a_register_a_clobber_takes_is_not_free_to_a_value_that_is_live_there() {
1768 let func = arms(true);
1769
1770 assert_eq!(places(&func, &narrow(2)), ["rcx", "slot 0"]);
1774 }
1775
1776 fn dies_at_the_clobber(here: bool) -> Func {
1779 let mut names = Interner::new();
1780 let mut func = Func::new(names.intern("f"));
1781 let opcode = Opcode::new(names.intern("x64.nop"));
1782 let entry = func.create_block();
1783 let value = func.new_vreg(GPR);
1784 func.build(entry, opcode).def(value, GPR).finish();
1785 let call = func.build(entry, opcode).operand(Operand::write(Reg::physical(RAX), GPR));
1786 if here {
1787 call.uses(value, GPR).finish();
1788 } else {
1789 call.finish();
1790 func.build(entry, opcode).uses(value, GPR).finish();
1791 }
1792 func
1793 }
1794
1795 #[test]
1803 fn a_value_that_dies_where_a_register_is_destroyed_may_be_in_that_register() {
1804 let func = dies_at_the_clobber(true);
1805 assert_eq!(places(&func, &narrow(1)), ["rax"]);
1806
1807 let order = Order::of(&func);
1808 let live = Live::of(&func, &order);
1809 let assignment = assign(&func, &order, &live, &narrow(1));
1810 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1811 }
1812
1813 #[test]
1816 fn a_value_read_after_the_instruction_that_destroys_a_register_is_not_in_it() {
1817 let func = dies_at_the_clobber(false);
1818 assert_eq!(places(&func, &narrow(1)), ["slot 0"]);
1819 }
1820
1821 #[test]
1822 fn a_hint_is_followed_when_the_register_is_clear_and_not_when_it_is_merely_allowed() {
1823 let mut names = Interner::new();
1824 let mut func = Func::new(names.intern("f"));
1825 let opcode = Opcode::new(names.intern("x64.nop"));
1826 let entry = func.create_block();
1827 let mid = func.create_block();
1828 let tail = func.create_block();
1829 let first = func.new_vreg(GPR);
1830 let second = func.new_vreg(GPR);
1831 func.build(entry, opcode).def(first, GPR).finish();
1832 func.build(entry, opcode).def(second, GPR).finish();
1833 *func.succs_mut(entry) = vec![BlockCall::to(mid), BlockCall::to(tail)];
1834 func.build(mid, opcode)
1837 .operand(Operand::read(second, GPR).with(Constraint::Fixed(RAX)))
1838 .finish();
1839 func.build(tail, opcode)
1840 .operand(Operand::read(first, GPR).with(Constraint::Fixed(RAX)))
1841 .finish();
1842
1843 assert_eq!(places(&func, &env()), ["rcx", "rax"]);
1848 }
1849
1850 #[test]
1851 fn a_value_living_in_a_hole_of_another_gets_the_same_register() {
1852 let mut names = Interner::new();
1853 let mut func = Func::new(names.intern("f"));
1854 let opcode = Opcode::new(names.intern("x64.nop"));
1855 let entry = func.create_block();
1856 let arm = func.create_block();
1857 let tail = func.create_block();
1858 let across = func.new_vreg(GPR);
1859 let inside = func.new_vreg(GPR);
1860 func.build(entry, opcode).def(across, GPR).finish();
1861 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1862 func.build(arm, opcode).def(inside, GPR).finish();
1863 func.build(arm, opcode).uses(inside, GPR).finish();
1864 func.build(tail, opcode).uses(across, GPR).finish();
1865
1866 assert_eq!(places(&func, &narrow(1)), ["rax", "rax"]);
1872
1873 let order = Order::of(&func);
1874 let live = Live::of(&func, &order);
1875 let assignment = assign(&func, &order, &live, &narrow(1));
1876 assert_eq!(assignment.spilled(), 0);
1877 assert!(crate::check::check(&func, &order, &live, &assignment).is_empty());
1878 }
1879
1880 fn handed_in_the_arm() -> Func {
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 entry = func.create_block();
1887 let arm = func.create_block();
1888 let tail = func.create_block();
1889 let first = func.new_vreg(GPR);
1890 let second = func.new_vreg(GPR);
1891 let own = func.new_vreg(GPR);
1892 func.build(entry, opcode).def(first, GPR).finish();
1893 func.build(entry, opcode).def(second, GPR).finish();
1894 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
1895 func.build(arm, opcode).def(own, GPR).finish();
1896 func.build(arm, opcode)
1897 .operand(Operand::read(own, GPR).with(Constraint::Fixed(RAX)))
1898 .finish();
1899 func.build(tail, opcode).uses(first, GPR).uses(second, GPR).finish();
1900 func
1901 }
1902
1903 #[test]
1904 fn a_register_another_value_is_handed_is_the_last_one_offered_rather_than_the_first() {
1905 let func = handed_in_the_arm();
1909 assert_eq!(places(&func, &narrow(3)), ["rcx", "rdx", "rax"]);
1910 }
1911
1912 #[test]
1913 fn a_register_a_clobber_takes_is_clear_to_a_value_dead_where_it_is_taken() {
1914 let func = arms(false);
1915
1916 assert_eq!(places(&func, &narrow(3)), ["rax", "rcx"]);
1920 }
1921
1922 #[test]
1923 fn a_frame_says_what_each_of_its_slots_is_for() {
1924 let mut names = Interner::new();
1925 let mut func = Func::new(names.intern("f"));
1926 let opcode = Opcode::new(names.intern("x64.nop"));
1927 let block = func.create_block();
1928 let first = func.new_vreg(GPR);
1929 let second = func.new_vreg(GPR);
1930 func.build(block, opcode).def(first, GPR).finish();
1931 func.build(block, opcode).def(second, GPR).finish();
1932 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
1933
1934 let order = Order::of(&func);
1935 let live = Live::of(&func, &order);
1936 let assignment = assign(&func, &order, &live, &narrow(1));
1937 assert_eq!(assignment.spilled(), 1);
1938 assert_eq!(assignment.slots(), [GPR]);
1939 assert_eq!(assignment.place(Reg::physical(RCX)), None);
1942 assert_eq!(env().scratch(GPR), [R13, R14, R15]);
1943 }
1944
1945 fn ranges(pairs: &[(Point, Point)]) -> Vec<Range> {
1947 pairs.iter().map(|&(start, end)| Range { start, end }).collect()
1948 }
1949
1950 #[test]
1951 fn the_pieces_of_a_register_answer_what_a_walk_over_its_values_would() {
1952 let held = [
1954 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1955 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1956 (Reg::virtual_reg(2), ranges(&[(10, 19), (31, 40)])),
1957 ];
1958 let mut pieces = Pieces::default();
1959 for (reg, list) in &held {
1960 for &piece in list {
1961 pieces.insert(piece, *reg);
1962 }
1963 }
1964 assert!(!pieces.broken);
1965 let asked = [
1966 ranges(&[(41, 50)]),
1967 ranges(&[(40, 50)]),
1968 ranges(&[(9, 9)]),
1969 ranges(&[(3, 3), (41, 42)]),
1970 ranges(&[(50, 60)]),
1971 ranges(&[(15, 15)]),
1972 ];
1973 for list in &asked {
1974 let area = Area::of_pieces(list);
1975 for except in [None, Some(Reg::virtual_reg(0)), Some(Reg::virtual_reg(2))] {
1976 let walked = held.iter().any(|(reg, pieces)| {
1977 Some(*reg) != except && Area::of_pieces(pieces).overlaps(area)
1978 });
1979 assert_eq!(pieces.touch(area, except), walked, "{list:?} except {except:?}");
1980 }
1981 }
1982 }
1983
1984 #[test]
1985 fn the_owners_of_the_pieces_an_area_touches_are_the_values_a_walk_would_find() {
1986 let held = [
1987 (Reg::virtual_reg(0), ranges(&[(0, 4), (20, 30)])),
1988 (Reg::virtual_reg(1), ranges(&[(5, 9)])),
1989 (Reg::virtual_reg(2), ranges(&[(10, 19), (30, 40)])),
1990 ];
1991 let mut pieces = Pieces::default();
1992 for (reg, list) in &held {
1993 for &piece in list {
1994 pieces.insert(piece, *reg);
1995 }
1996 }
1997 let asked = [
1998 ranges(&[(41, 50)]),
1999 ranges(&[(30, 30)]),
2000 ranges(&[(3, 12)]),
2001 ranges(&[(3, 3), (25, 42)]),
2002 ranges(&[(0, 50)]),
2003 ];
2004 for list in &asked {
2005 let area = Area::of_pieces(list);
2006 let walked: Vec<Reg> = held
2007 .iter()
2008 .filter(|(_, pieces)| Area::of_pieces(pieces).overlaps(area))
2009 .map(|&(reg, _)| reg)
2010 .collect();
2011 assert_eq!(pieces.owners(area), Some(walked), "{list:?}");
2012 }
2013 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(3));
2014 assert_eq!(pieces.owners(Area::of_pieces(&asked[0])), None);
2015 }
2016
2017 #[test]
2018 fn pieces_that_end_out_of_order_are_marked() {
2019 let mut pieces = Pieces::default();
2020 pieces.insert(Range { start: 0, end: 10 }, Reg::virtual_reg(0));
2021 pieces.insert(Range { start: 12, end: 20 }, Reg::virtual_reg(1));
2022 assert!(!pieces.broken);
2023 pieces.insert(Range { start: 2, end: 3 }, Reg::virtual_reg(2));
2025 assert!(pieces.broken);
2026 }
2027
2028 #[test]
2029 fn a_value_taken_out_of_a_register_leaves_its_pieces_with_it() {
2030 let mut pieces = Pieces::default();
2031 let (first, second) = (Reg::virtual_reg(0), Reg::virtual_reg(1));
2032 pieces.insert(Range { start: 0, end: 10 }, first);
2033 pieces.insert(Range { start: 12, end: 20 }, second);
2034 let asked = ranges(&[(15, 16)]);
2035 assert!(pieces.touch(Area::of_pieces(&asked), None));
2036 pieces.remove(Range { start: 12, end: 20 }, second);
2037 assert!(!pieces.touch(Area::of_pieces(&asked), None));
2038 pieces.drop_before(11);
2039 assert!(pieces.list.is_empty());
2040 }
2041}