1use rucc_mir::{Block, Constraint, Func, Inst, Operand, Param, Reg};
83use rucc_target::{PhysReg, RegClass};
84
85use crate::assign::{Assignment, Env, Place};
86use crate::moves::{self, Move};
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub struct Edit {
91 pub at: At,
93 pub mov: Move<Place>,
95 pub class: RegClass,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum At {
102 Before(Inst),
104 After(Inst),
107 StartOf(Block),
109 EndOf(Block),
112}
113
114#[must_use]
124pub fn rewrite(func: &mut Func, assignment: &Assignment, env: &Env) -> Vec<Edit> {
125 let blocks: Vec<Block> = func.blocks().collect();
126 assert!(
127 func.entry().is_none_or(|entry| func[entry].params.is_empty()),
128 "what arrives in a function is not a block parameter"
129 );
130
131 let mut edits = Vec::new();
132 for &block in &blocks {
133 let insts: Vec<Inst> = func.insts(block).collect();
134 for inst in insts {
135 instruction(func, assignment, env, inst, &mut edits);
136 }
137 }
138
139 let preds = preds(func, &blocks);
140 for &block in &blocks {
141 edges(func, assignment, env, block, &preds, &mut edits);
142 }
143 for &block in &blocks {
144 func.params_mut(block).clear();
145 for call in func.succs_mut(block) {
146 call.args.clear();
147 }
148 }
149 edits
150}
151
152fn instruction(
154 func: &mut Func,
155 assignment: &Assignment,
156 env: &Env,
157 inst: Inst,
158 edits: &mut Vec<Edit>,
159) {
160 let list = func[inst].operands;
161 let mut operands: Vec<Operand> = func[list].to_vec();
162 let mut before: Vec<(Move<Place>, RegClass)> = Vec::new();
163 let mut after: Vec<(Move<Place>, RegClass)> = Vec::new();
164 let mut taken = Taken::new();
165
166 let places: Vec<Place> =
169 operands.iter().map(|operand| place(assignment, operand.reg)).collect();
170
171 let mut reusing: Vec<usize> = Vec::new();
175
176 for (index, operand) in operands.iter_mut().enumerate() {
177 let fixed = match operand.constraint {
178 Constraint::Fixed(at) => Some(at),
179 _ => None,
180 };
181 let at = match (place(assignment, operand.reg), fixed) {
182 (Place::Reg(at), None) => at,
183 (Place::Reg(at), Some(fixed)) => {
184 if at != fixed {
185 let (there, here) = (Place::Reg(fixed), Place::Reg(at));
186 push(&mut before, &mut after, operand, Move::new(there, here));
187 }
188 fixed
189 }
190 (Place::Slot(_), None) if matches!(operand.constraint, Constraint::Reuse(_)) => {
191 reusing.push(index);
192 continue;
193 }
194 (Place::Slot(slot), fixed) => {
195 let at = match fixed {
200 Some(fixed) => fixed,
201 None if operand.role.is_def() => taken.written_into(env, operand.class),
202 None => taken.read_into(env, operand.class),
203 };
204 push(
205 &mut before,
206 &mut after,
207 operand,
208 Move::new(Place::Reg(at), Place::Slot(slot)),
209 );
210 at
211 }
212 };
213 operand.reg = Reg::physical(at);
214 }
215
216 for index in reusing {
217 let Constraint::Reuse(other) = operands[index].constraint else {
218 unreachable!("only an operand that reuses another was left for this pass")
219 };
220 let Place::Slot(slot) = places[index] else {
221 unreachable!("only a spilled operand was left for this pass")
222 };
223 let other = usize::from(other);
238 let at = match places[other] {
239 Place::Slot(_) => phys(operands[other].reg),
240 Place::Reg(_) => taken.read_into(env, operands[index].class),
241 };
242 push(
243 &mut before,
244 &mut after,
245 &operands[index],
246 Move::new(Place::Reg(at), Place::Slot(slot)),
247 );
248 operands[index].reg = Reg::physical(at);
249 }
250
251 for index in 0..operands.len() {
255 let Constraint::Reuse(other) = operands[index].constraint else { continue };
256 let (to, from) = (operands[index], operands[usize::from(other)]);
257 if to.reg != from.reg {
258 let mov = Move::new(Place::Reg(phys(to.reg)), Place::Reg(phys(from.reg)));
259 before.push((mov, to.class));
260 }
261 }
262
263 func[list].copy_from_slice(&operands);
264 edits.extend(before.into_iter().map(|(mov, class)| Edit { at: At::Before(inst), mov, class }));
265 edits.extend(after.into_iter().map(|(mov, class)| Edit { at: At::After(inst), mov, class }));
266}
267
268#[derive(Debug, Default)]
288struct Taken {
289 read: Vec<usize>,
291 written: Vec<usize>,
293}
294
295impl Taken {
296 fn new() -> Self {
298 Self::default()
299 }
300
301 fn read_into(&mut self, env: &Env, class: RegClass) -> PhysReg {
307 Self::take(&mut self.read, env, class)
308 }
309
310 fn written_into(&mut self, env: &Env, class: RegClass) -> PhysReg {
316 Self::take(&mut self.written, env, class)
317 }
318
319 fn take(counts: &mut Vec<usize>, env: &Env, class: RegClass) -> PhysReg {
327 let index = usize::from(class.number());
328 if counts.len() <= index {
329 counts.resize(index + 1, 0);
330 }
331 let scratch = *env
332 .scratch(class)
333 .get(counts[index])
334 .expect("an instruction wanting more scratch registers than the class has");
335 counts[index] += 1;
336 scratch
337 }
338}
339
340fn push(
343 before: &mut Vec<(Move<Place>, RegClass)>,
344 after: &mut Vec<(Move<Place>, RegClass)>,
345 operand: &Operand,
346 mov: Move<Place>,
347) {
348 if operand.role.is_def() {
349 after.push((Move::new(mov.from, mov.to), operand.class));
350 } else {
351 before.push((mov, operand.class));
352 }
353}
354
355fn edges(
357 func: &mut Func,
358 assignment: &Assignment,
359 env: &Env,
360 block: Block,
361 preds: &[usize],
362 edits: &mut Vec<Edit>,
363) {
364 let succs = func[block].succs.clone();
365 let single = succs.len() == 1;
366 for call in &succs {
367 let params = func[call.block].params.clone();
368 assert_eq!(
369 params.len(),
370 call.args.len(),
371 "an edge carries what the block it goes to asks for"
372 );
373 if params.is_empty() {
374 continue;
375 }
376 assert!(
377 single || preds[call.block.index()] == 1,
378 "a critical edge has nowhere to put its moves and has to be split before allocation"
379 );
380 let at = if single { At::EndOf(block) } else { At::StartOf(call.block) };
381 edits.extend(edge(assignment, env, ¶ms, &call.args, at));
382 }
383}
384
385fn edge(assignment: &Assignment, env: &Env, params: &[Param], args: &[Reg], at: At) -> Vec<Edit> {
387 let mut classes: Vec<RegClass> = params.iter().map(|param| param.class).collect();
388 classes.sort_unstable();
389 classes.dedup();
390
391 let mut edits = Vec::new();
392 for class in classes {
393 let parallel: Vec<Move<Place>> = params
396 .iter()
397 .zip(args)
398 .filter(|(param, _)| param.class == class)
399 .map(|(param, &arg)| Move::new(place(assignment, param.reg), place(assignment, arg)))
400 .collect();
401 let scratch = env.scratch(class);
402 let cycle = *scratch
403 .first()
404 .expect("a class whose values are passed on an edge and which has no scratch register");
405 for mov in moves::sequence(¶llel, Place::Reg(cycle)) {
406 match (mov.to, mov.from) {
407 (Place::Slot(_), Place::Slot(_)) => {
411 let through = Place::Reg(*scratch.get(1).expect(
412 "a class passing a spilled value to a spilled parameter and having only \
413 one scratch register",
414 ));
415 edits.push(Edit { at, mov: Move::new(through, mov.from), class });
416 edits.push(Edit { at, mov: Move::new(mov.to, through), class });
417 }
418 _ => edits.push(Edit { at, mov, class }),
419 }
420 }
421 }
422 edits
423}
424
425fn preds(func: &Func, blocks: &[Block]) -> Vec<usize> {
427 let mut preds = vec![0; func.block_count()];
428 for &block in blocks {
429 for call in &func[block].succs {
430 preds[call.block.index()] += 1;
431 }
432 }
433 preds
434}
435
436fn place(assignment: &Assignment, reg: Reg) -> Place {
438 assignment.place(reg).unwrap_or_else(|| Place::Reg(phys(reg)))
439}
440
441fn phys(reg: Reg) -> PhysReg {
443 reg.phys().expect("a register the assignment says nothing about and that is not a register")
444}
445
446#[cfg(test)]
447mod tests {
448 use rucc_base::Interner;
449 use rucc_mir::{BlockCall, Opcode};
450 use rucc_target::x86_64::{GPR, RAX, RDX, REGS, SYSV, XMM};
451
452 use super::*;
453 use crate::assign::assign;
454 use crate::live::Live;
455 use crate::order::Order;
456
457 fn env() -> Env {
459 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
460 Env::new().with(GPR, order, scratch)
461 }
462
463 fn narrow(count: usize) -> Env {
465 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 2])
466 }
467
468 fn named(class: RegClass, place: Place) -> String {
473 match place {
474 Place::Reg(reg) => REGS.name(class, reg).expect("a register").to_string(),
475 Place::Slot(slot) => format!("slot{slot}"),
476 }
477 }
478
479 fn run(func: &mut Func, env: &Env) -> Vec<String> {
481 let order = Order::of(func);
482 let live = Live::of(func, &order);
483 let assignment = assign(func, &order, &live, env);
484 rewrite(func, &assignment, env)
485 .into_iter()
486 .map(|edit| {
487 let at = match edit.at {
488 At::Before(inst) => format!("before {}", inst.index()),
489 At::After(inst) => format!("after {}", inst.index()),
490 At::StartOf(block) => format!("start of {}", block.index()),
491 At::EndOf(block) => format!("end of {}", block.index()),
492 };
493 format!(
494 "{at}: {} = {}",
495 named(edit.class, edit.mov.to),
496 named(edit.class, edit.mov.from)
497 )
498 })
499 .collect()
500 }
501
502 fn operands(func: &Func, inst: Inst) -> Vec<String> {
504 func[func[inst].operands]
505 .iter()
506 .map(|operand| named(operand.class, Place::Reg(phys(operand.reg))))
507 .collect()
508 }
509
510 #[test]
511 fn every_operand_ends_up_naming_the_register_its_value_was_given() {
512 let mut names = Interner::new();
513 let mut func = Func::new(names.intern("f"));
514 let opcode = Opcode::new(names.intern("x64.nop"));
515 let block = func.create_block();
516 let first = func.new_vreg(GPR);
517 let second = func.new_vreg(GPR);
518 func.build(block, opcode).def(first, GPR).finish();
519 func.build(block, opcode).def(second, GPR).finish();
520 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
521
522 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
523 assert_eq!(operands(&func, read), ["rax", "rcx"]);
524 }
525
526 #[test]
527 fn a_register_an_instruction_insists_on_costs_nothing_when_the_values_can_have_it() {
528 let mut names = Interner::new();
529 let mut func = Func::new(names.intern("f"));
530 let opcode = Opcode::new(names.intern("x64.nop"));
531 let block = func.create_block();
532 let dividend = func.new_vreg(GPR);
533 let quotient = func.new_vreg(GPR);
534 func.build(block, opcode).def(dividend, GPR).finish();
535 let divide = func
536 .build(block, opcode)
537 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
538 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
539 .finish();
540 func.build(block, opcode).uses(quotient, GPR).finish();
541
542 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
546 assert_eq!(operands(&func, divide), ["rax", "rax"]);
547 }
548
549 #[test]
550 fn a_register_an_instruction_insists_on_is_moved_into_when_the_value_cannot_have_it() {
551 let mut names = Interner::new();
552 let mut func = Func::new(names.intern("f"));
553 let opcode = Opcode::new(names.intern("x64.nop"));
554 let block = func.create_block();
555 let dividend = func.new_vreg(GPR);
556 let quotient = func.new_vreg(GPR);
557 func.build(block, opcode).def(dividend, GPR).finish();
558 let divide = func
559 .build(block, opcode)
560 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
561 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
562 .finish();
563 func.build(block, opcode).uses(quotient, GPR).finish();
564 func.build(block, opcode).uses(dividend, GPR).finish();
565
566 assert_eq!(run(&mut func, &env()), ["before 1: rax = rcx"]);
570 assert_eq!(operands(&func, divide), ["rax", "rax"]);
571 }
572
573 #[test]
574 fn a_two_address_instruction_that_did_not_get_its_register_copies_first() {
575 let mut names = Interner::new();
576 let mut func = Func::new(names.intern("f"));
577 let opcode = Opcode::new(names.intern("x64.nop"));
578 let block = func.create_block();
579 let left = func.new_vreg(GPR);
580 let right = func.new_vreg(GPR);
581 let sum = func.new_vreg(GPR);
582 func.build(block, opcode).def(left, GPR).finish();
583 func.build(block, opcode).def(right, GPR).finish();
584 let add = func
585 .build(block, opcode)
586 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
587 .uses(left, GPR)
588 .uses(right, GPR)
589 .finish();
590 func.build(block, opcode).uses(left, GPR).finish();
591
592 assert_eq!(run(&mut func, &env()), ["before 2: rdx = rax"]);
595 assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
596 }
597
598 #[test]
599 fn a_two_address_instruction_that_did_get_its_register_copies_nothing() {
600 let mut names = Interner::new();
601 let mut func = Func::new(names.intern("f"));
602 let opcode = Opcode::new(names.intern("x64.nop"));
603 let block = func.create_block();
604 let left = func.new_vreg(GPR);
605 let right = func.new_vreg(GPR);
606 let sum = func.new_vreg(GPR);
607 func.build(block, opcode).def(left, GPR).finish();
608 func.build(block, opcode).def(right, GPR).finish();
609 let add = func
610 .build(block, opcode)
611 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
612 .uses(left, GPR)
613 .uses(right, GPR)
614 .finish();
615 func.build(block, opcode).uses(right, GPR).finish();
616
617 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
618 assert_eq!(operands(&func, add), ["rax", "rax", "rcx"]);
619 }
620
621 #[test]
622 fn a_spilled_value_is_read_into_a_scratch_register_at_each_instruction_that_wants_it() {
623 let mut names = Interner::new();
624 let mut func = Func::new(names.intern("f"));
625 let opcode = Opcode::new(names.intern("x64.nop"));
626 let block = func.create_block();
627 let first = func.new_vreg(GPR);
628 let second = func.new_vreg(GPR);
629 func.build(block, opcode).def(first, GPR).finish();
630 func.build(block, opcode).def(second, GPR).finish();
631 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
632
633 assert_eq!(run(&mut func, &narrow(1)), ["after 1: slot0 = rcx", "before 2: rcx = slot0"]);
637 assert_eq!(operands(&func, read), ["rax", "rcx"]);
638 }
639
640 #[test]
647 fn a_two_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
648 let mut names = Interner::new();
649 let mut func = Func::new(names.intern("f"));
650 let opcode = Opcode::new(names.intern("x64.nop"));
651 let block = func.create_block();
652 let keeper = func.new_vreg(GPR);
653 let left = func.new_vreg(GPR);
654 let right = func.new_vreg(GPR);
655 let sum = func.new_vreg(GPR);
656 func.build(block, opcode).def(keeper, GPR).finish();
657 func.build(block, opcode)
658 .operand(Operand::write(left, GPR).with(Constraint::Stack))
659 .finish();
660 func.build(block, opcode)
661 .operand(Operand::write(right, GPR).with(Constraint::Stack))
662 .finish();
663 let add = func
664 .build(block, opcode)
665 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
666 .uses(left, GPR)
667 .uses(right, GPR)
668 .finish();
669 func.build(block, opcode).uses(keeper, GPR).finish();
670 func.build(block, opcode).uses(sum, GPR).finish();
671
672 assert_eq!(
676 run(&mut func, &narrow(1)),
677 [
678 "after 1: slot0 = rcx",
679 "after 2: slot1 = rcx",
680 "before 3: rcx = slot0",
681 "before 3: rdx = slot1",
682 "after 3: slot2 = rcx",
683 "before 5: rcx = slot2",
684 ]
685 );
686 assert_eq!(operands(&func, add), ["rcx", "rcx", "rdx"]);
687 }
688
689 #[test]
700 fn a_three_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
701 let mut names = Interner::new();
702 let mut func = Func::new(names.intern("f"));
703 let opcode = Opcode::new(names.intern("x64.nop"));
704 let block = func.create_block();
705 let keeper = func.new_vreg(GPR);
706 let base = func.new_vreg(GPR);
707 let index = func.new_vreg(GPR);
708 let address = func.new_vreg(GPR);
709 func.build(block, opcode).def(keeper, GPR).finish();
710 func.build(block, opcode)
711 .operand(Operand::write(base, GPR).with(Constraint::Stack))
712 .finish();
713 func.build(block, opcode)
714 .operand(Operand::write(index, GPR).with(Constraint::Stack))
715 .finish();
716 let lea =
717 func.build(block, opcode).def(address, GPR).uses(base, GPR).uses(index, GPR).finish();
718 func.build(block, opcode).uses(keeper, GPR).finish();
719 func.build(block, opcode).uses(address, GPR).finish();
720
721 assert_eq!(
724 run(&mut func, &narrow(1)),
725 [
726 "after 1: slot0 = rcx",
727 "after 2: slot1 = rcx",
728 "before 3: rcx = slot0",
729 "before 3: rdx = slot1",
730 "after 3: slot2 = rcx",
731 "before 5: rcx = slot2",
732 ]
733 );
734 assert_eq!(operands(&func, lea), ["rcx", "rcx", "rdx"]);
735 }
736
737 #[test]
744 fn a_spilled_answer_does_not_write_over_a_register_the_assignment_gave_to_something_else() {
745 let mut names = Interner::new();
746 let mut func = Func::new(names.intern("f"));
747 let opcode = Opcode::new(names.intern("x64.nop"));
748 let block = func.create_block();
749 let left = func.new_vreg(GPR);
750 let right = func.new_vreg(GPR);
751 let sum = func.new_vreg(GPR);
752 func.build(block, opcode).def(left, GPR).finish();
753 func.build(block, opcode)
754 .operand(Operand::write(right, GPR).with(Constraint::Stack))
755 .finish();
756 let add = func
757 .build(block, opcode)
758 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
759 .uses(left, GPR)
760 .uses(right, GPR)
761 .finish();
762 func.build(block, opcode).uses(left, GPR).finish();
763 func.build(block, opcode).uses(sum, GPR).finish();
764
765 assert_eq!(
768 run(&mut func, &narrow(1)),
769 [
770 "after 1: slot0 = rcx",
771 "before 2: rcx = slot0",
772 "before 2: rdx = rax",
773 "after 2: slot1 = rdx",
774 "before 4: rcx = slot1",
775 ]
776 );
777 assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
778 }
779
780 #[test]
785 fn an_instruction_reading_out_of_two_files_takes_the_first_scratch_register_of_each() {
786 let mut names = Interner::new();
787 let mut func = Func::new(names.intern("f"));
788 let opcode = Opcode::new(names.intern("x64.nop"));
789 let block = func.create_block();
790 let integer = func.new_vreg(GPR);
791 let number = func.new_vreg(XMM);
792 let spare = func.new_vreg(GPR);
793 let other = func.new_vreg(XMM);
794 func.build(block, opcode).def(integer, GPR).finish();
795 func.build(block, opcode).def(number, XMM).finish();
796 func.build(block, opcode).def(spare, GPR).finish();
797 func.build(block, opcode).def(other, XMM).finish();
798 func.build(block, opcode).uses(integer, GPR).uses(number, XMM).finish();
799 let read = func.build(block, opcode).uses(spare, GPR).uses(other, XMM).finish();
800
801 let env = Env::new().with(GPR, &SYSV.int_order[..1], &SYSV.int_order[1..3]).with(
804 XMM,
805 &SYSV.sse_order[..1],
806 &SYSV.sse_order[1..3],
807 );
808 assert_eq!(
809 run(&mut func, &env),
810 [
811 "after 2: slot0 = rcx",
812 "after 3: slot1 = xmm1",
813 "before 5: rcx = slot0",
814 "before 5: xmm1 = slot1",
815 ]
816 );
817 assert_eq!(operands(&func, read), ["rcx", "xmm1"]);
818 }
819
820 #[test]
821 fn an_edge_out_of_a_block_with_one_way_to_go_moves_at_the_end_of_it() {
822 let mut names = Interner::new();
823 let mut func = Func::new(names.intern("f"));
824 let opcode = Opcode::new(names.intern("x64.nop"));
825 let head = func.create_block();
826 let tail = func.create_block();
827 let held = func.new_vreg(GPR);
828 let carried = func.new_vreg(GPR);
829 func.build(head, opcode).def(held, GPR).finish();
830 func.build(head, opcode).def(carried, GPR).finish();
831 func.build(head, opcode).uses(held, GPR).finish();
832 let param = func.append_param(tail, GPR);
833 *func.succs_mut(head) = vec![BlockCall::with(tail, vec![carried])];
834 let read = func.build(tail, opcode).uses(param, GPR).finish();
835
836 assert_eq!(run(&mut func, &env()), ["end of 0: rax = rcx"]);
840 assert_eq!(operands(&func, read), ["rax"]);
841 assert!(func[tail].params.is_empty());
844 assert!(func[head].succs[0].args.is_empty());
845 }
846
847 #[test]
848 fn an_edge_out_of_a_block_with_a_choice_moves_at_the_start_of_where_it_goes() {
849 let mut names = Interner::new();
850 let mut func = Func::new(names.intern("f"));
851 let opcode = Opcode::new(names.intern("x64.nop"));
852 let head = func.create_block();
853 let left = func.create_block();
854 let right = func.create_block();
855 let held = func.new_vreg(GPR);
856 let carried = func.new_vreg(GPR);
857 func.build(head, opcode).def(held, GPR).finish();
858 func.build(head, opcode).def(carried, GPR).finish();
859 func.build(head, opcode).uses(held, GPR).finish();
860 let taken = func.append_param(left, GPR);
861 *func.succs_mut(head) = vec![BlockCall::with(left, vec![carried]), BlockCall::to(right)];
862 func.build(left, opcode).uses(taken, GPR).finish();
863
864 assert_eq!(run(&mut func, &env()), ["start of 1: rax = rcx"]);
868 }
869
870 #[test]
871 fn two_values_that_swap_on_an_edge_get_an_order_and_a_scratch_register() {
872 let mut names = Interner::new();
873 let mut func = Func::new(names.intern("f"));
874 let opcode = Opcode::new(names.intern("x64.nop"));
875 let head = func.create_block();
876 let body = func.create_block();
877 let first = func.new_vreg(GPR);
878 let second = func.new_vreg(GPR);
879 func.build(head, opcode).def(first, GPR).finish();
880 func.build(head, opcode).def(second, GPR).finish();
881 let left = func.append_param(body, GPR);
882 let right = func.append_param(body, GPR);
883 *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
884 func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
885 *func.succs_mut(body) = vec![BlockCall::with(body, vec![right, left])];
886
887 assert_eq!(
891 run(&mut func, &env()),
892 ["end of 1: r13 = rcx", "end of 1: rcx = rax", "end of 1: rax = r13"]
893 );
894 }
895
896 #[test]
897 fn a_spilled_value_handed_to_a_spilled_parameter_goes_through_a_register() {
898 let mut names = Interner::new();
899 let mut func = Func::new(names.intern("f"));
900 let opcode = Opcode::new(names.intern("x64.nop"));
901 let head = func.create_block();
902 let body = func.create_block();
903 let first = func.new_vreg(GPR);
904 let second = func.new_vreg(GPR);
905 func.build(head, opcode).def(first, GPR).finish();
906 func.build(head, opcode).def(second, GPR).finish();
907 let left = func.append_param(body, GPR);
908 let right = func.append_param(body, GPR);
909 *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
910 func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
911
912 assert_eq!(
917 run(&mut func, &narrow(1)),
918 [
919 "after 1: slot0 = rcx",
920 "before 2: rcx = slot1",
921 "end of 0: rdx = slot0",
922 "end of 0: slot1 = rdx",
923 ]
924 );
925 }
926
927 #[test]
928 #[should_panic(expected = "a critical edge has nowhere to put its moves")]
929 fn a_critical_edge_is_refused() {
930 let mut names = Interner::new();
931 let mut func = Func::new(names.intern("f"));
932 let opcode = Opcode::new(names.intern("x64.nop"));
933 let head = func.create_block();
934 let other = func.create_block();
935 let join = func.create_block();
936 let value = func.new_vreg(GPR);
937 func.build(head, opcode).def(value, GPR).finish();
938 let param = func.append_param(join, GPR);
939 *func.succs_mut(head) = vec![BlockCall::with(join, vec![value]), BlockCall::to(other)];
940 *func.succs_mut(other) = vec![BlockCall::with(join, vec![value])];
941 func.build(join, opcode).uses(param, GPR).finish();
942
943 let _ = run(&mut func, &env());
944 }
945
946 #[test]
947 #[should_panic(expected = "what arrives in a function is not a block parameter")]
948 fn a_parameter_on_the_entry_block_is_refused() {
949 let mut names = Interner::new();
950 let mut func = Func::new(names.intern("f"));
951 let block = func.create_block();
952 let param = func.append_param(block, GPR);
953 let opcode = Opcode::new(names.intern("x64.nop"));
954 func.build(block, opcode).uses(param, GPR).finish();
955
956 let _ = run(&mut func, &env());
957 }
958
959 #[test]
960 fn a_value_already_in_a_register_is_left_where_it_is() {
961 let mut names = Interner::new();
962 let mut func = Func::new(names.intern("f"));
963 let opcode = Opcode::new(names.intern("x64.nop"));
964 let block = func.create_block();
965 let inst = func.build(block, opcode).uses(Reg::physical(RDX), GPR).finish();
966
967 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
968 assert_eq!(operands(&func, inst), ["rdx"]);
969 }
970}