1use std::collections::HashMap;
58use std::fmt;
59
60use rucc_mir::{Constraint, Func, Inst, Reg, Role};
61use rucc_target::{PhysReg, RegClass};
62
63use crate::assign::{Assignment, Place};
64use crate::live::{Area, Live, Range};
65use crate::order::{Order, Point};
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum Problem {
70 Nowhere {
72 reg: Reg,
74 },
75 Shared {
78 first: Reg,
80 second: Reg,
82 place: Place,
84 },
85 InTheWay {
88 reg: Reg,
90 at: PhysReg,
92 inst: Inst,
94 },
95 NotOnTheStack {
97 reg: Reg,
99 inst: Inst,
101 },
102 NeverWritten {
105 reg: Reg,
107 },
108}
109
110impl fmt::Display for Problem {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self {
113 Problem::Nowhere { reg } => write!(f, "{} has nowhere to live", name(*reg)),
114 Problem::Shared { first, second, place } => {
115 let (first, second) = (name(*first), name(*second));
116 write!(f, "{first} and {second} are both live and both in {}", place_name(*place))
117 }
118 Problem::InTheWay { reg, at, inst } => {
119 let reg = name(*reg);
120 let inst = inst.index();
121 write!(f, "{reg} is in register {}, which instruction {inst} wants", at.number())
122 }
123 Problem::NotOnTheStack { reg, inst } => {
124 let reg = name(*reg);
125 write!(f, "{reg} is not on the stack, and instruction {} needs it", inst.index())
126 }
127 Problem::NeverWritten { reg } => {
128 write!(f, "{} is read before anything writes it", name(*reg))
129 }
130 }
131 }
132}
133
134#[must_use]
145pub fn check(func: &Func, order: &Order, live: &Live, assignment: &Assignment) -> Vec<Problem> {
146 let mut problems = Vec::new();
147 if let Some(entry) = func.entry() {
150 for reg in live.live_in(entry) {
151 problems.push(Problem::NeverWritten { reg });
152 }
153 }
154 let reuses = reuses(func, order);
155 let mut values = Vec::new();
156 for (number, reuse) in reuses.iter().enumerate() {
157 let reg = Reg::virtual_reg(u32::try_from(number).expect("a register number"));
158 let (Some(mut area), Some(class)) = (live.area(reg), func.class_of(reg)) else {
159 continue;
160 };
161 let Some(place) = assignment.place(reg) else {
162 problems.push(Problem::Nowhere { reg });
163 continue;
164 };
165 if let Some(reuse) = reuse {
170 area = area.with(reuse.at);
171 }
172 values.push(Value { reg, class, range: area.hull(), area, place });
173 }
174 overlaps(&values, &reuses, live, &mut problems);
175 instructions(func, order, assignment, &values, &reuses, &mut problems);
176 problems
177}
178
179#[must_use]
181pub fn report(problems: &[Problem]) -> String {
182 let places = if problems.len() == 1 { "place" } else { "places" };
183 let mut report = format!("the allocation is wrong in {} {places}", problems.len());
184 for problem in problems {
185 report.push_str("\n ");
186 report.push_str(&problem.to_string());
187 }
188 report
189}
190
191#[derive(Debug, Clone, Copy)]
193struct Value<'a> {
194 reg: Reg,
195 class: RegClass,
196 range: Range,
198 area: Area<'a>,
201 place: Place,
202}
203
204#[derive(Debug, Clone, Copy)]
206struct Reuse {
207 source: Reg,
208 at: Point,
209}
210
211fn overlaps(
224 values: &[Value<'_>],
225 reuses: &[Option<Reuse>],
226 live: &Live,
227 problems: &mut Vec<Problem>,
228) {
229 let mut sorted = values.to_vec();
230 sorted.sort_by_key(|value| (value.range.start, value.reg));
231 let mut places: HashMap<(Place, Option<RegClass>), Vec<usize>> = HashMap::new();
232 for (position, value) in sorted.iter().enumerate() {
233 places.entry(place_of(*value)).or_default().push(position);
234 }
235 let mut found = Vec::new();
236 for positions in places.values() {
237 let mut active: Vec<usize> = Vec::new();
238 for &position in positions {
239 let value = sorted[position];
240 active.retain(|&held| sorted[held].range.end >= value.range.start);
241 for &held in &active {
242 let held_value = sorted[held];
243 if !held_value.area.overlaps(value.area)
244 || coalesced(held_value, value, reuses, live)
245 {
246 continue;
247 }
248 let problem = Problem::Shared {
249 first: held_value.reg,
250 second: value.reg,
251 place: value.place,
252 };
253 found.push((position, held, problem));
254 }
255 active.push(position);
256 }
257 }
258 found.sort_by_key(|&(position, held, _)| (position, held));
261 problems.extend(found.into_iter().map(|(_, _, problem)| problem));
262}
263
264fn place_of(value: Value<'_>) -> (Place, Option<RegClass>) {
270 match value.place {
271 Place::Reg(_) => (value.place, Some(value.class)),
272 Place::Slot(_) => (value.place, None),
273 }
274}
275
276fn coalesced(first: Value<'_>, second: Value<'_>, reuses: &[Option<Reuse>], live: &Live) -> bool {
288 let pair = |source: Value<'_>, dest: Value<'_>| {
289 let Some(reuse) = reuses[index(dest.reg)] else { return false };
290 reuse.source == source.reg && crate::assign::apart(live, source.reg, dest.reg)
291 };
292 pair(first, second) || pair(second, first)
293}
294
295fn instructions(
298 func: &Func,
299 order: &Order,
300 assignment: &Assignment,
301 values: &[Value<'_>],
302 reuses: &[Option<Reuse>],
303 problems: &mut Vec<Problem>,
304) {
305 let mut held: HashMap<PhysReg, Vec<Value<'_>>> = HashMap::new();
308 for value in values {
309 if let Place::Reg(at) = value.place {
310 held.entry(at).or_default().push(*value);
311 }
312 }
313 for block in func.blocks() {
314 for inst in func.insts(block) {
315 for operand in &func[func[inst].operands] {
316 if operand.constraint == Constraint::Stack
317 && matches!(assignment.place(operand.reg), Some(Place::Reg(_)))
318 {
319 problems.push(Problem::NotOnTheStack { reg: operand.reg, inst });
320 }
321 let at = match operand.constraint {
325 Constraint::Fixed(at) => Some(at),
326 _ => operand.reg.phys(),
327 };
328 let Some(at) = at else { continue };
329 let Some(here) = held.get(&at) else { continue };
330 let early = order.early(inst);
331 let point = if operand.role == Role::Def { order.late(inst) } else { early };
332 for value in here {
333 let mine = value.reg == operand.reg
334 || reuses[index(value.reg)].is_some_and(|reuse| {
335 reuse.source == operand.reg
336 && reuse.at == early
337 && value.place == Place::Reg(at)
338 });
339 if mine || value.class != operand.class {
340 continue;
341 }
342 let width = func.width(value.reg);
345 let under = |above| width.is_some_and(|width| width <= above);
346 if matches!(operand.constraint, Constraint::Above(above) if under(above)) {
347 continue;
348 }
349 if value.place == Place::Reg(at) && value.area.covers(point) {
354 problems.push(Problem::InTheWay { reg: value.reg, at, inst });
355 }
356 }
357 }
358 }
359 }
360}
361
362fn reuses(func: &Func, order: &Order) -> Vec<Option<Reuse>> {
364 let mut reuses = vec![None; func.vregs()];
365 for block in func.blocks() {
366 for inst in func.insts(block) {
367 let operands = &func[func[inst].operands];
368 for operand in operands {
369 let Constraint::Reuse(other) = operand.constraint else { continue };
370 let number = operand.reg.number().and_then(|number| usize::try_from(number).ok());
371 let Some(number) = number else { continue };
372 let source = operands[usize::from(other)].reg;
373 reuses[number] = Some(Reuse { source, at: order.early(inst) });
374 }
375 }
376 }
377 reuses
378}
379
380fn index(reg: Reg) -> usize {
383 reg.number().and_then(|number| usize::try_from(number).ok()).unwrap_or(0)
384}
385
386fn name(reg: Reg) -> String {
388 match reg.number() {
389 Some(number) => format!("%{number}"),
390 None => format!("register {}", reg.phys().expect("a physical register").number()),
391 }
392}
393
394fn place_name(place: Place) -> String {
397 match place {
398 Place::Reg(at) => format!("register {}", at.number()),
399 Place::Slot(slot) => format!("slot {slot}"),
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use rucc_base::Interner;
406 use rucc_mir::{BlockCall, Opcode, Operand};
407 use rucc_target::x86_64::{GPR, RAX, RCX, RDX, SYSV};
408
409 use super::*;
410 use crate::assign::{Env, assign};
411
412 fn env() -> Env {
414 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
415 Env::new().with(GPR, order, scratch)
416 }
417
418 fn allocated(func: &Func) -> Vec<String> {
421 let order = Order::of(func);
422 let live = Live::of(func, &order);
423 let assignment = assign(func, &order, &live, &env());
424 said(func, &order, &live, &assignment)
425 }
426
427 fn said(func: &Func, order: &Order, live: &Live, assignment: &Assignment) -> Vec<String> {
429 check(func, order, live, assignment).iter().map(ToString::to_string).collect()
430 }
431
432 fn read(func: &Func) -> (Order, Live) {
434 let order = Order::of(func);
435 let live = Live::of(func, &order);
436 (order, live)
437 }
438
439 fn under_the_top(width: u32) -> Vec<String> {
441 let mut names = Interner::new();
442 let mut func = Func::new(names.intern("f"));
443 let opcode = Opcode::new(names.intern("x64.nop"));
444 let block = func.create_block();
445 let held = func.new_vreg(GPR);
446 func.set_width(held, width);
447 func.build(block, opcode).def(held, GPR).finish();
448 func.build(block, opcode)
449 .operand(Operand::write(Reg::physical(RCX), GPR).with(Constraint::Above(8)))
450 .finish();
451 func.build(block, opcode).uses(held, GPR).finish();
452 let (order, live) = read(&func);
453 let mut assignment = Assignment::empty(func.vregs());
454 assignment.put(held, Place::Reg(RCX));
455 said(&func, &order, &live, &assignment)
456 }
457
458 #[test]
459 fn a_value_under_the_part_an_instruction_writes_is_not_in_its_way() {
460 assert!(under_the_top(8).is_empty(), "{:?}", under_the_top(8));
461 let wide = under_the_top(16);
462 assert!(wide.len() == 1 && wide[0].contains("%0"), "{wide:?}");
463 assert_eq!(under_the_top(0), wide);
464 }
465
466 #[test]
467 fn an_allocation_the_allocator_worked_out_has_nothing_wrong_with_it() {
468 let mut names = Interner::new();
469 let mut func = Func::new(names.intern("f"));
470 let opcode = Opcode::new(names.intern("x64.nop"));
471 let block = func.create_block();
472 let first = func.new_vreg(GPR);
473 let second = func.new_vreg(GPR);
474 func.build(block, opcode).def(first, GPR).finish();
475 func.build(block, opcode).def(second, GPR).finish();
476 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
477
478 assert_eq!(allocated(&func), Vec::<String>::new());
479 }
480
481 #[test]
482 fn a_value_with_nowhere_to_live_is_found() {
483 let mut names = Interner::new();
484 let mut func = Func::new(names.intern("f"));
485 let opcode = Opcode::new(names.intern("x64.nop"));
486 let block = func.create_block();
487 let only = func.new_vreg(GPR);
488 func.build(block, opcode).def(only, GPR).finish();
489 func.build(block, opcode).uses(only, GPR).finish();
490
491 let (order, live) = read(&func);
492 let assignment = Assignment::empty(func.vregs());
493
494 assert_eq!(said(&func, &order, &live, &assignment), ["%0 has nowhere to live"]);
495 }
496
497 #[test]
498 fn a_value_read_before_anything_writes_it_is_found() {
499 let mut names = Interner::new();
500 let mut func = Func::new(names.intern("f"));
501 let opcode = Opcode::new(names.intern("x64.nop"));
502 let block = func.create_block();
503 let never = func.new_vreg(GPR);
504 func.build(block, opcode).uses(never, GPR).finish();
505
506 let (order, live) = read(&func);
507 let mut assignment = Assignment::empty(func.vregs());
508 assignment.put(never, Place::Reg(RAX));
509
510 assert_eq!(
511 said(&func, &order, &live, &assignment),
512 ["%0 is read before anything writes it"]
513 );
514 }
515
516 #[test]
517 fn two_values_that_are_both_wanted_and_share_a_register_are_found() {
518 let mut names = Interner::new();
519 let mut func = Func::new(names.intern("f"));
520 let opcode = Opcode::new(names.intern("x64.nop"));
521 let block = func.create_block();
522 let first = func.new_vreg(GPR);
523 let second = func.new_vreg(GPR);
524 func.build(block, opcode).def(first, GPR).finish();
525 func.build(block, opcode).def(second, GPR).finish();
526 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
527
528 let (order, live) = read(&func);
529 let mut assignment = Assignment::empty(func.vregs());
530 assignment.put(first, Place::Reg(RAX));
531 assignment.put(second, Place::Reg(RAX));
532
533 let said = said(&func, &order, &live, &assignment);
534 assert_eq!(said, ["%0 and %1 are both live and both in register 0"]);
535 }
536
537 #[test]
538 fn values_sharing_different_places_are_reported_in_the_order_they_start() {
539 let mut names = Interner::new();
543 let mut func = Func::new(names.intern("f"));
544 let opcode = Opcode::new(names.intern("x64.nop"));
545 let block = func.create_block();
546 let regs: Vec<Reg> = (0..6).map(|_| func.new_vreg(GPR)).collect();
547 for reg in ®s {
548 func.build(block, opcode).def(*reg, GPR).finish();
549 }
550 let mut last = func.build(block, opcode);
551 for reg in ®s {
552 last = last.uses(*reg, GPR);
553 }
554 last.finish();
555
556 let (order, live) = read(&func);
557 let mut assignment = Assignment::empty(func.vregs());
558 let places = [Place::Slot(0), Place::Reg(RCX), Place::Reg(RAX)];
559 for (number, reg) in regs.iter().enumerate() {
560 assignment.put(*reg, places[number % 3]);
561 }
562
563 let rcx = RCX.number();
564 let rax = RAX.number();
565 assert_eq!(
566 said(&func, &order, &live, &assignment),
567 [
568 "%0 and %3 are both live and both in slot 0".to_string(),
569 format!("%1 and %4 are both live and both in register {rcx}"),
570 format!("%2 and %5 are both live and both in register {rax}"),
571 ]
572 );
573 }
574
575 #[test]
576 fn a_value_that_lives_in_a_hole_of_another_may_share_its_register() {
577 let mut names = Interner::new();
578 let mut func = Func::new(names.intern("f"));
579 let opcode = Opcode::new(names.intern("x64.nop"));
580 let entry = func.create_block();
581 let arm = func.create_block();
582 let tail = func.create_block();
583 let across = func.new_vreg(GPR);
584 let inside = func.new_vreg(GPR);
585 func.build(entry, opcode).def(across, GPR).finish();
586 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
587 func.build(arm, opcode).def(inside, GPR).finish();
588 func.build(arm, opcode).uses(inside, GPR).finish();
589 func.build(tail, opcode).uses(across, GPR).finish();
590
591 let (order, live) = read(&func);
592 let mut assignment = Assignment::empty(func.vregs());
593 assignment.put(across, Place::Reg(RAX));
594 assignment.put(inside, Place::Reg(RAX));
595
596 assert_eq!(said(&func, &order, &live, &assignment), Vec::<String>::new());
602 }
603
604 #[test]
605 fn two_values_that_are_both_wanted_and_share_a_slot_are_found() {
606 let mut names = Interner::new();
607 let mut func = Func::new(names.intern("f"));
608 let opcode = Opcode::new(names.intern("x64.nop"));
609 let block = func.create_block();
610 let first = func.new_vreg(GPR);
611 let second = func.new_vreg(GPR);
612 func.build(block, opcode).def(first, GPR).finish();
613 func.build(block, opcode).def(second, GPR).finish();
614 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
615
616 let (order, live) = read(&func);
617 let mut assignment = Assignment::empty(func.vregs());
618 let slot = assignment.take_slot(GPR);
619 assignment.put(first, Place::Slot(slot));
620 assignment.put(second, Place::Slot(slot));
621
622 let said = said(&func, &order, &live, &assignment);
623 assert_eq!(said, ["%0 and %1 are both live and both in slot 0"]);
624 }
625
626 #[test]
627 fn two_values_that_are_never_both_wanted_may_share_anything() {
628 let mut names = Interner::new();
629 let mut func = Func::new(names.intern("f"));
630 let opcode = Opcode::new(names.intern("x64.nop"));
631 let block = func.create_block();
632 let first = func.new_vreg(GPR);
633 let second = func.new_vreg(GPR);
634 func.build(block, opcode).def(first, GPR).finish();
635 func.build(block, opcode).uses(first, GPR).finish();
636 func.build(block, opcode).def(second, GPR).finish();
637 func.build(block, opcode).uses(second, GPR).finish();
638
639 let (order, live) = read(&func);
640 let mut assignment = Assignment::empty(func.vregs());
641 assignment.put(first, Place::Reg(RAX));
642 assignment.put(second, Place::Reg(RAX));
643
644 assert_eq!(said(&func, &order, &live, &assignment), Vec::<String>::new());
645 }
646
647 #[test]
648 fn a_value_left_in_a_register_an_instruction_wants_is_found() {
649 let mut names = Interner::new();
650 let mut func = Func::new(names.intern("f"));
651 let nop = Opcode::new(names.intern("x64.nop"));
652 let divide = Opcode::new(names.intern("x64.idiv"));
653 let block = func.create_block();
654 let held = func.new_vreg(GPR);
655 let dividend = func.new_vreg(GPR);
656 func.build(block, nop).def(held, GPR).finish();
657 func.build(block, nop).def(dividend, GPR).finish();
658 func.build(block, divide)
661 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
662 .finish();
663 func.build(block, nop).uses(held, GPR).finish();
664
665 let (order, live) = read(&func);
666 let mut assignment = Assignment::empty(func.vregs());
667 assignment.put(held, Place::Reg(RAX));
668 assignment.put(dividend, Place::Reg(RCX));
669
670 let said = said(&func, &order, &live, &assignment);
671 assert_eq!(said, ["%0 is in register 0, which instruction 2 wants"]);
672 }
673
674 #[test]
675 fn the_value_an_instruction_wants_a_register_for_may_be_in_it_already() {
676 let mut names = Interner::new();
677 let mut func = Func::new(names.intern("f"));
678 let nop = Opcode::new(names.intern("x64.nop"));
679 let divide = Opcode::new(names.intern("x64.idiv"));
680 let block = func.create_block();
681 let dividend = func.new_vreg(GPR);
682 func.build(block, nop).def(dividend, GPR).finish();
683 func.build(block, divide)
684 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
685 .finish();
686
687 let (order, live) = read(&func);
688 let mut assignment = Assignment::empty(func.vregs());
689 assignment.put(dividend, Place::Reg(RAX));
690
691 assert_eq!(said(&func, &order, &live, &assignment), Vec::<String>::new());
694 }
695
696 #[test]
697 fn a_value_that_can_only_be_read_from_memory_and_is_in_a_register_is_found() {
698 let mut names = Interner::new();
699 let mut func = Func::new(names.intern("f"));
700 let nop = Opcode::new(names.intern("x64.nop"));
701 let wide = Opcode::new(names.intern("x64.wide"));
702 let block = func.create_block();
703 let only = func.new_vreg(GPR);
704 func.build(block, nop).def(only, GPR).finish();
705 func.build(block, wide).operand(Operand::read(only, GPR).with(Constraint::Stack)).finish();
706
707 let (order, live) = read(&func);
708 let mut assignment = Assignment::empty(func.vregs());
709 assignment.put(only, Place::Reg(RAX));
710
711 let said = said(&func, &order, &live, &assignment);
712 assert_eq!(said, ["%0 is not on the stack, and instruction 1 needs it"]);
713 }
714
715 #[test]
716 fn a_two_address_instruction_may_write_the_register_it_read_a_finished_value_from() {
717 let mut names = Interner::new();
718 let mut func = Func::new(names.intern("f"));
719 let nop = Opcode::new(names.intern("x64.nop"));
720 let add = Opcode::new(names.intern("x64.add"));
721 let block = func.create_block();
722 let left = func.new_vreg(GPR);
723 let right = func.new_vreg(GPR);
724 let sum = func.new_vreg(GPR);
725 func.build(block, nop).def(left, GPR).finish();
726 func.build(block, nop).def(right, GPR).finish();
727 func.build(block, add)
728 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
729 .uses(left, GPR)
730 .uses(right, GPR)
731 .finish();
732 func.build(block, nop).uses(sum, GPR).finish();
733
734 let (order, live) = read(&func);
735 let mut assignment = Assignment::empty(func.vregs());
736 assignment.put(left, Place::Reg(RAX));
737 assignment.put(right, Place::Reg(RCX));
738 assignment.put(sum, Place::Reg(RAX));
739
740 assert_eq!(said(&func, &order, &live, &assignment), Vec::<String>::new());
743 }
744
745 #[test]
746 fn a_two_address_instruction_may_not_write_over_a_value_wanted_afterwards() {
747 let mut names = Interner::new();
748 let mut func = Func::new(names.intern("f"));
749 let nop = Opcode::new(names.intern("x64.nop"));
750 let add = Opcode::new(names.intern("x64.add"));
751 let block = func.create_block();
752 let left = func.new_vreg(GPR);
753 let right = func.new_vreg(GPR);
754 let sum = func.new_vreg(GPR);
755 func.build(block, nop).def(left, GPR).finish();
756 func.build(block, nop).def(right, GPR).finish();
757 func.build(block, add)
758 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
759 .uses(left, GPR)
760 .uses(right, GPR)
761 .finish();
762 func.build(block, nop).uses(sum, GPR).uses(left, GPR).finish();
763
764 let (order, live) = read(&func);
765 let mut assignment = Assignment::empty(func.vregs());
766 assignment.put(left, Place::Reg(RAX));
767 assignment.put(right, Place::Reg(RCX));
768 assignment.put(sum, Place::Reg(RAX));
769
770 let said = said(&func, &order, &live, &assignment);
773 assert_eq!(said, ["%0 and %2 are both live and both in register 0"]);
774 }
775
776 #[test]
777 fn a_two_address_instruction_may_not_write_the_register_it_reads_its_other_operand_from() {
778 let mut names = Interner::new();
779 let mut func = Func::new(names.intern("f"));
780 let nop = Opcode::new(names.intern("x64.nop"));
781 let add = Opcode::new(names.intern("x64.add"));
782 let block = func.create_block();
783 let left = func.new_vreg(GPR);
784 let right = func.new_vreg(GPR);
785 let sum = func.new_vreg(GPR);
786 func.build(block, nop).def(left, GPR).finish();
787 func.build(block, nop).def(right, GPR).finish();
788 func.build(block, add)
789 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
790 .uses(left, GPR)
791 .uses(right, GPR)
792 .finish();
793 func.build(block, nop).uses(sum, GPR).finish();
794
795 let (order, live) = read(&func);
796 let mut assignment = Assignment::empty(func.vregs());
797 assignment.put(left, Place::Reg(RAX));
798 assignment.put(right, Place::Reg(RCX));
799 assignment.put(sum, Place::Reg(RCX));
800
801 let said = said(&func, &order, &live, &assignment);
804 assert_eq!(said, ["%1 and %2 are both live and both in register 1"]);
805 }
806
807 #[test]
808 fn a_two_address_instruction_may_not_write_the_register_it_read_over_its_own_last_answer() {
809 let mut names = Interner::new();
810 let mut func = Func::new(names.intern("f"));
811 let nop = Opcode::new(names.intern("x64.nop"));
812 let add = Opcode::new(names.intern("x64.add"));
813 let head = func.create_block();
814 let latch = func.create_block();
815 let out = func.create_block();
816 let source = func.new_vreg(GPR);
817 let carried = func.new_vreg(GPR);
818 func.build(head, nop).def(source, GPR).finish();
819 func.build(head, nop).def(carried, GPR).finish();
820 *func.succs_mut(head) = vec![BlockCall::to(latch)];
821 func.build(latch, add)
822 .operand(Operand::write(carried, GPR).with(Constraint::Reuse(1)))
823 .uses(source, GPR)
824 .uses(carried, GPR)
825 .finish();
826 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
827 func.build(out, nop).uses(carried, GPR).finish();
828
829 let (order, live) = read(&func);
830 let mut assignment = Assignment::empty(func.vregs());
831 assignment.put(source, Place::Reg(RAX));
832 assignment.put(carried, Place::Reg(RAX));
833
834 let said = said(&func, &order, &live, &assignment);
838 assert_eq!(said, ["%0 and %1 are both live and both in register 0"]);
839 }
840
841 #[test]
842 fn a_two_address_answer_with_a_hole_in_front_of_it_still_may_not_take_the_other_operand() {
843 let mut names = Interner::new();
844 let mut func = Func::new(names.intern("f"));
845 let nop = Opcode::new(names.intern("x64.nop"));
846 let add = Opcode::new(names.intern("x64.add"));
847 let entry = func.create_block();
848 let head = func.create_block();
849 let arm = func.create_block();
850 let latch = func.create_block();
851 let out = func.create_block();
852 let seed = func.new_vreg(GPR);
853 let sum = func.new_vreg(GPR);
854 let inside = func.new_vreg(GPR);
855 let loaded = func.new_vreg(GPR);
856 func.build(entry, nop).def(seed, GPR).finish();
857 func.build(entry, nop).def(sum, GPR).finish();
858 *func.succs_mut(entry) = vec![BlockCall::to(head)];
859 func.build(head, nop).uses(sum, GPR).finish();
860 *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
861 func.build(arm, nop).def(inside, GPR).finish();
862 func.build(arm, nop).uses(inside, GPR).finish();
863 *func.succs_mut(arm) = vec![BlockCall::to(out)];
864 func.build(latch, nop).def(loaded, GPR).finish();
865 func.build(latch, add)
866 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
867 .uses(seed, GPR)
868 .uses(loaded, GPR)
869 .finish();
870 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
871
872 let (order, live) = read(&func);
873 let mut assignment = Assignment::empty(func.vregs());
874 assignment.put(seed, Place::Reg(RCX));
875 assignment.put(sum, Place::Reg(RAX));
876 assignment.put(inside, Place::Reg(RDX));
877 assignment.put(loaded, Place::Reg(RAX));
878
879 let said = said(&func, &order, &live, &assignment);
885 assert_eq!(said, ["%1 and %3 are both live and both in register 0"]);
886 }
887
888 #[test]
889 fn a_report_names_every_problem() {
890 let mut names = Interner::new();
891 let mut func = Func::new(names.intern("f"));
892 let opcode = Opcode::new(names.intern("x64.nop"));
893 let block = func.create_block();
894 let first = func.new_vreg(GPR);
895 let second = func.new_vreg(GPR);
896 func.build(block, opcode).def(first, GPR).finish();
897 func.build(block, opcode).def(second, GPR).finish();
898 func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
899
900 let (order, live) = read(&func);
901 let mut assignment = Assignment::empty(func.vregs());
902 assignment.put(first, Place::Reg(RAX));
903 assignment.put(second, Place::Reg(RAX));
904
905 let problems = check(&func, &order, &live, &assignment);
906 assert_eq!(
907 report(&problems),
908 "the allocation is wrong in 1 place\n %0 and %1 are both live and both in register 0"
909 );
910 assert_eq!(report(&[]), "the allocation is wrong in 0 places");
911 }
912}