1use rucc_mir::{Block, Func, Inst, Param, Reg};
46use rucc_target::RegClass;
47
48use crate::assign::{Assignment, Env, Place};
49use crate::legalize::{self, Spare, place};
50use crate::moves::{self, Move};
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct Edit {
55 pub at: At,
57 pub mov: Move<Place>,
59 pub class: RegClass,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65pub enum At {
66 Before(Inst),
68 After(Inst),
71 StartOf(Block),
73 EndOf(Block),
76}
77
78#[must_use]
93pub fn rewrite(func: &mut Func, assignment: &mut Assignment, env: &Env) -> Vec<Edit> {
94 let blocks: Vec<Block> = func.blocks().collect();
95 assert!(
96 func.entry().is_none_or(|entry| func[entry].params.is_empty()),
97 "what arrives in a function is not a block parameter"
98 );
99
100 let mut edits = Vec::new();
101 let mut spare = Spare::default();
102 for &block in &blocks {
103 let insts: Vec<Inst> = func.insts(block).collect();
104 for inst in insts {
105 instruction(func, assignment, env, &mut spare, inst, &mut edits);
106 }
107 }
108
109 let preds = preds(func, &blocks);
110 for &block in &blocks {
111 edges(func, assignment, env, block, &preds, &mut edits);
112 }
113 for &block in &blocks {
114 func.params_mut(block).clear();
115 for call in func.succs_mut(block) {
116 call.args.clear();
117 }
118 }
119 edits
120}
121
122fn instruction(
124 func: &mut Func,
125 assignment: &mut Assignment,
126 env: &Env,
127 spare: &mut Spare,
128 inst: Inst,
129 edits: &mut Vec<Edit>,
130) {
131 let legal = legalize::instruction(func, assignment, env, spare, inst);
132 let list = func[inst].operands;
133 func[list].copy_from_slice(&legal.operands);
134 edits.extend(legal.before.into_iter().map(|(mov, class)| Edit {
135 at: At::Before(inst),
136 mov,
137 class,
138 }));
139 edits.extend(legal.after.into_iter().map(|(mov, class)| Edit {
140 at: At::After(inst),
141 mov,
142 class,
143 }));
144}
145
146fn edges(
148 func: &mut Func,
149 assignment: &Assignment,
150 env: &Env,
151 block: Block,
152 preds: &[usize],
153 edits: &mut Vec<Edit>,
154) {
155 let succs = func[block].succs.clone();
156 let single = succs.len() == 1;
157 for call in &succs {
158 let params = func[call.block].params.clone();
159 assert_eq!(
160 params.len(),
161 call.args.len(),
162 "an edge carries what the block it goes to asks for"
163 );
164 if params.is_empty() {
165 continue;
166 }
167 assert!(
168 single || preds[call.block.index()] == 1,
169 "a critical edge has nowhere to put its moves and has to be split before allocation"
170 );
171 let at = if single { At::EndOf(block) } else { At::StartOf(call.block) };
172 edits.extend(edge(assignment, env, ¶ms, &call.args, at));
173 }
174}
175
176fn edge(assignment: &Assignment, env: &Env, params: &[Param], args: &[Reg], at: At) -> Vec<Edit> {
178 let mut classes: Vec<RegClass> = params.iter().map(|param| param.class).collect();
179 classes.sort_unstable();
180 classes.dedup();
181
182 let mut edits = Vec::new();
183 for class in classes {
184 let parallel: Vec<Move<Place>> = params
187 .iter()
188 .zip(args)
189 .filter(|(param, _)| param.class == class)
190 .map(|(param, &arg)| Move::new(place(assignment, param.reg), place(assignment, arg)))
191 .collect();
192 let scratch = env.scratch(class);
193 let cycle = *scratch
194 .first()
195 .expect("a class whose values are passed on an edge and which has no scratch register");
196 for mov in moves::sequence(¶llel, Place::Reg(cycle)) {
197 match (mov.to, mov.from) {
198 (Place::Slot(_), Place::Slot(_)) => {
202 let through = Place::Reg(*scratch.get(1).expect(
203 "a class passing a spilled value to a spilled parameter and having only \
204 one scratch register",
205 ));
206 edits.push(Edit { at, mov: Move::new(through, mov.from), class });
207 edits.push(Edit { at, mov: Move::new(mov.to, through), class });
208 }
209 _ => edits.push(Edit { at, mov, class }),
210 }
211 }
212 }
213 edits
214}
215
216fn preds(func: &Func, blocks: &[Block]) -> Vec<usize> {
218 let mut preds = vec![0; func.block_count()];
219 for &block in blocks {
220 for call in &func[block].succs {
221 preds[call.block.index()] += 1;
222 }
223 }
224 preds
225}
226
227#[cfg(test)]
228mod tests {
229 use rucc_base::Interner;
230 use rucc_mir::{BlockCall, Constraint, Opcode, Operand};
231 use rucc_target::x86_64::{GPR, RAX, RCX, RDX, REGS, RSI, SYSV, XMM};
232
233 use super::*;
234 use crate::assign::assign;
235 use crate::legalize::phys;
236 use crate::live::Live;
237 use crate::order::Order;
238
239 fn env() -> Env {
241 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
242 Env::new().with(GPR, order, scratch)
243 }
244
245 fn narrow(count: usize) -> Env {
247 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 2])
248 }
249
250 fn named(class: RegClass, place: Place) -> String {
255 match place {
256 Place::Reg(reg) => REGS.name(class, reg).expect("a register").to_string(),
257 Place::Slot(slot) => format!("slot{slot}"),
258 }
259 }
260
261 fn run(func: &mut Func, env: &Env) -> Vec<String> {
263 let order = Order::of(func);
264 let live = Live::of(func, &order);
265 let mut assignment = assign(func, &order, &live, env);
266 rewrite(func, &mut assignment, env)
267 .into_iter()
268 .map(|edit| {
269 let at = match edit.at {
270 At::Before(inst) => format!("before {}", inst.index()),
271 At::After(inst) => format!("after {}", inst.index()),
272 At::StartOf(block) => format!("start of {}", block.index()),
273 At::EndOf(block) => format!("end of {}", block.index()),
274 };
275 format!(
276 "{at}: {} = {}",
277 named(edit.class, edit.mov.to),
278 named(edit.class, edit.mov.from)
279 )
280 })
281 .collect()
282 }
283
284 fn operands(func: &Func, inst: Inst) -> Vec<String> {
286 func[func[inst].operands]
287 .iter()
288 .map(|operand| named(operand.class, Place::Reg(phys(operand.reg))))
289 .collect()
290 }
291
292 #[test]
293 fn every_operand_ends_up_naming_the_register_its_value_was_given() {
294 let mut names = Interner::new();
295 let mut func = Func::new(names.intern("f"));
296 let opcode = Opcode::new(names.intern("x64.nop"));
297 let block = func.create_block();
298 let first = func.new_vreg(GPR);
299 let second = func.new_vreg(GPR);
300 func.build(block, opcode).def(first, GPR).finish();
301 func.build(block, opcode).def(second, GPR).finish();
302 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
303
304 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
305 assert_eq!(operands(&func, read), ["rax", "rcx"]);
306 }
307
308 #[test]
309 fn a_register_an_instruction_insists_on_costs_nothing_when_the_values_can_have_it() {
310 let mut names = Interner::new();
311 let mut func = Func::new(names.intern("f"));
312 let opcode = Opcode::new(names.intern("x64.nop"));
313 let block = func.create_block();
314 let dividend = func.new_vreg(GPR);
315 let quotient = func.new_vreg(GPR);
316 func.build(block, opcode).def(dividend, GPR).finish();
317 let divide = func
318 .build(block, opcode)
319 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
320 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
321 .finish();
322 func.build(block, opcode).uses(quotient, GPR).finish();
323
324 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
328 assert_eq!(operands(&func, divide), ["rax", "rax"]);
329 }
330
331 #[test]
332 fn a_register_an_instruction_insists_on_is_moved_into_when_the_value_cannot_have_it() {
333 let mut names = Interner::new();
334 let mut func = Func::new(names.intern("f"));
335 let opcode = Opcode::new(names.intern("x64.nop"));
336 let block = func.create_block();
337 let dividend = func.new_vreg(GPR);
338 let quotient = func.new_vreg(GPR);
339 func.build(block, opcode).def(dividend, GPR).finish();
340 let divide = func
341 .build(block, opcode)
342 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
343 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
344 .finish();
345 func.build(block, opcode).uses(quotient, GPR).finish();
346 func.build(block, opcode).uses(dividend, GPR).finish();
347
348 assert_eq!(run(&mut func, &env()), ["before 1: rax = rcx"]);
352 assert_eq!(operands(&func, divide), ["rax", "rax"]);
353 }
354
355 #[test]
356 fn a_two_address_instruction_that_did_not_get_its_register_copies_first() {
357 let mut names = Interner::new();
358 let mut func = Func::new(names.intern("f"));
359 let opcode = Opcode::new(names.intern("x64.nop"));
360 let block = func.create_block();
361 let left = func.new_vreg(GPR);
362 let right = func.new_vreg(GPR);
363 let sum = func.new_vreg(GPR);
364 func.build(block, opcode).def(left, GPR).finish();
365 func.build(block, opcode).def(right, GPR).finish();
366 let add = func
367 .build(block, opcode)
368 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
369 .uses(left, GPR)
370 .uses(right, GPR)
371 .finish();
372 func.build(block, opcode).uses(left, GPR).finish();
373
374 assert_eq!(run(&mut func, &env()), ["before 2: rdx = rax"]);
377 assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
378 }
379
380 #[test]
381 fn a_two_address_instruction_that_did_get_its_register_copies_nothing() {
382 let mut names = Interner::new();
383 let mut func = Func::new(names.intern("f"));
384 let opcode = Opcode::new(names.intern("x64.nop"));
385 let block = func.create_block();
386 let left = func.new_vreg(GPR);
387 let right = func.new_vreg(GPR);
388 let sum = func.new_vreg(GPR);
389 func.build(block, opcode).def(left, GPR).finish();
390 func.build(block, opcode).def(right, GPR).finish();
391 let add = func
392 .build(block, opcode)
393 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
394 .uses(left, GPR)
395 .uses(right, GPR)
396 .finish();
397 func.build(block, opcode).uses(right, GPR).finish();
398
399 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
400 assert_eq!(operands(&func, add), ["rax", "rax", "rcx"]);
401 }
402
403 #[test]
404 fn a_spilled_value_is_read_into_a_scratch_register_at_each_instruction_that_wants_it() {
405 let mut names = Interner::new();
406 let mut func = Func::new(names.intern("f"));
407 let opcode = Opcode::new(names.intern("x64.nop"));
408 let block = func.create_block();
409 let first = func.new_vreg(GPR);
410 let second = func.new_vreg(GPR);
411 func.build(block, opcode).def(first, GPR).finish();
412 func.build(block, opcode).def(second, GPR).finish();
413 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
414
415 assert_eq!(run(&mut func, &narrow(1)), ["after 1: slot0 = rcx", "before 2: rcx = slot0"]);
419 assert_eq!(operands(&func, read), ["rax", "rcx"]);
420 }
421
422 #[test]
429 fn a_two_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
430 let mut names = Interner::new();
431 let mut func = Func::new(names.intern("f"));
432 let opcode = Opcode::new(names.intern("x64.nop"));
433 let block = func.create_block();
434 let keeper = func.new_vreg(GPR);
435 let left = func.new_vreg(GPR);
436 let right = func.new_vreg(GPR);
437 let sum = func.new_vreg(GPR);
438 func.build(block, opcode).def(keeper, GPR).finish();
439 func.build(block, opcode)
440 .operand(Operand::write(left, GPR).with(Constraint::Stack))
441 .finish();
442 func.build(block, opcode)
443 .operand(Operand::write(right, GPR).with(Constraint::Stack))
444 .finish();
445 let add = func
446 .build(block, opcode)
447 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
448 .uses(left, GPR)
449 .uses(right, GPR)
450 .finish();
451 func.build(block, opcode).uses(keeper, GPR).finish();
452 func.build(block, opcode).uses(sum, GPR).finish();
453
454 assert_eq!(
458 run(&mut func, &narrow(1)),
459 [
460 "after 1: slot0 = rcx",
461 "after 2: slot1 = rcx",
462 "before 3: rcx = slot0",
463 "before 3: rdx = slot1",
464 "after 3: slot2 = rcx",
465 "before 5: rcx = slot2",
466 ]
467 );
468 assert_eq!(operands(&func, add), ["rcx", "rcx", "rdx"]);
469 }
470
471 #[test]
482 fn a_three_address_instruction_whose_answer_and_operands_are_all_spilled_wants_two_registers() {
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 keeper = func.new_vreg(GPR);
488 let base = func.new_vreg(GPR);
489 let index = func.new_vreg(GPR);
490 let address = func.new_vreg(GPR);
491 func.build(block, opcode).def(keeper, GPR).finish();
492 func.build(block, opcode)
493 .operand(Operand::write(base, GPR).with(Constraint::Stack))
494 .finish();
495 func.build(block, opcode)
496 .operand(Operand::write(index, GPR).with(Constraint::Stack))
497 .finish();
498 let lea =
499 func.build(block, opcode).def(address, GPR).uses(base, GPR).uses(index, GPR).finish();
500 func.build(block, opcode).uses(keeper, GPR).finish();
501 func.build(block, opcode).uses(address, GPR).finish();
502
503 assert_eq!(
506 run(&mut func, &narrow(1)),
507 [
508 "after 1: slot0 = rcx",
509 "after 2: slot1 = rcx",
510 "before 3: rcx = slot0",
511 "before 3: rdx = slot1",
512 "after 3: slot2 = rcx",
513 "before 5: rcx = slot2",
514 ]
515 );
516 assert_eq!(operands(&func, lea), ["rcx", "rcx", "rdx"]);
517 }
518
519 #[test]
526 fn a_spilled_answer_does_not_write_over_a_register_the_assignment_gave_to_something_else() {
527 let mut names = Interner::new();
528 let mut func = Func::new(names.intern("f"));
529 let opcode = Opcode::new(names.intern("x64.nop"));
530 let block = func.create_block();
531 let left = func.new_vreg(GPR);
532 let right = func.new_vreg(GPR);
533 let sum = func.new_vreg(GPR);
534 func.build(block, opcode).def(left, GPR).finish();
535 func.build(block, opcode)
536 .operand(Operand::write(right, GPR).with(Constraint::Stack))
537 .finish();
538 let add = func
539 .build(block, opcode)
540 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
541 .uses(left, GPR)
542 .uses(right, GPR)
543 .finish();
544 func.build(block, opcode).uses(left, GPR).finish();
545 func.build(block, opcode).uses(sum, GPR).finish();
546
547 assert_eq!(
550 run(&mut func, &narrow(1)),
551 [
552 "after 1: slot0 = rcx",
553 "before 2: rcx = slot0",
554 "before 2: rdx = rax",
555 "after 2: slot1 = rdx",
556 "before 4: rcx = slot1",
557 ]
558 );
559 assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
560 }
561
562 #[test]
567 fn an_instruction_reading_out_of_two_files_takes_the_first_scratch_register_of_each() {
568 let mut names = Interner::new();
569 let mut func = Func::new(names.intern("f"));
570 let opcode = Opcode::new(names.intern("x64.nop"));
571 let block = func.create_block();
572 let integer = func.new_vreg(GPR);
573 let number = func.new_vreg(XMM);
574 let spare = func.new_vreg(GPR);
575 let other = func.new_vreg(XMM);
576 func.build(block, opcode).def(integer, GPR).finish();
577 func.build(block, opcode).def(number, XMM).finish();
578 func.build(block, opcode).def(spare, GPR).finish();
579 func.build(block, opcode).def(other, XMM).finish();
580 func.build(block, opcode).uses(integer, GPR).uses(number, XMM).finish();
581 let read = func.build(block, opcode).uses(spare, GPR).uses(other, XMM).finish();
582
583 let env = Env::new().with(GPR, &SYSV.int_order[..1], &SYSV.int_order[1..3]).with(
586 XMM,
587 &SYSV.sse_order[..1],
588 &SYSV.sse_order[1..3],
589 );
590 assert_eq!(
591 run(&mut func, &env),
592 [
593 "after 2: slot0 = rcx",
594 "after 3: slot1 = xmm1",
595 "before 5: rcx = slot0",
596 "before 5: xmm1 = slot1",
597 ]
598 );
599 assert_eq!(operands(&func, read), ["rcx", "xmm1"]);
600 }
601
602 #[test]
603 fn an_edge_out_of_a_block_with_one_way_to_go_moves_at_the_end_of_it() {
604 let mut names = Interner::new();
605 let mut func = Func::new(names.intern("f"));
606 let opcode = Opcode::new(names.intern("x64.nop"));
607 let head = func.create_block();
608 let tail = func.create_block();
609 let held = func.new_vreg(GPR);
610 let carried = func.new_vreg(GPR);
611 func.build(head, opcode).def(held, GPR).finish();
612 func.build(head, opcode).def(carried, GPR).finish();
613 func.build(head, opcode).uses(held, GPR).finish();
614 let param = func.append_param(tail, GPR);
615 *func.succs_mut(head) = vec![BlockCall::with(tail, vec![carried])];
616 let read = func.build(tail, opcode).uses(param, GPR).finish();
617
618 assert_eq!(run(&mut func, &env()), ["end of 0: rax = rcx"]);
622 assert_eq!(operands(&func, read), ["rax"]);
623 assert!(func[tail].params.is_empty());
626 assert!(func[head].succs[0].args.is_empty());
627 }
628
629 #[test]
630 fn an_edge_out_of_a_block_with_a_choice_moves_at_the_start_of_where_it_goes() {
631 let mut names = Interner::new();
632 let mut func = Func::new(names.intern("f"));
633 let opcode = Opcode::new(names.intern("x64.nop"));
634 let head = func.create_block();
635 let left = func.create_block();
636 let right = func.create_block();
637 let held = func.new_vreg(GPR);
638 let carried = func.new_vreg(GPR);
639 func.build(head, opcode).def(held, GPR).finish();
640 func.build(head, opcode).def(carried, GPR).finish();
641 func.build(head, opcode).uses(held, GPR).finish();
642 let taken = func.append_param(left, GPR);
643 *func.succs_mut(head) = vec![BlockCall::with(left, vec![carried]), BlockCall::to(right)];
644 func.build(left, opcode).uses(taken, GPR).finish();
645
646 assert_eq!(run(&mut func, &env()), ["start of 1: rax = rcx"]);
650 }
651
652 #[test]
653 fn two_values_that_swap_on_an_edge_get_an_order_and_a_scratch_register() {
654 let mut names = Interner::new();
655 let mut func = Func::new(names.intern("f"));
656 let opcode = Opcode::new(names.intern("x64.nop"));
657 let head = func.create_block();
658 let body = func.create_block();
659 let first = func.new_vreg(GPR);
660 let second = func.new_vreg(GPR);
661 func.build(head, opcode).def(first, GPR).finish();
662 func.build(head, opcode).def(second, GPR).finish();
663 let left = func.append_param(body, GPR);
664 let right = func.append_param(body, GPR);
665 *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
666 func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
667 *func.succs_mut(body) = vec![BlockCall::with(body, vec![right, left])];
668
669 assert_eq!(
673 run(&mut func, &env()),
674 ["end of 1: r13 = rcx", "end of 1: rcx = rax", "end of 1: rax = r13"]
675 );
676 }
677
678 #[test]
679 fn a_spilled_value_handed_to_a_spilled_parameter_goes_through_a_register() {
680 let mut names = Interner::new();
681 let mut func = Func::new(names.intern("f"));
682 let opcode = Opcode::new(names.intern("x64.nop"));
683 let head = func.create_block();
684 let body = func.create_block();
685 let first = func.new_vreg(GPR);
686 let second = func.new_vreg(GPR);
687 func.build(head, opcode).def(first, GPR).finish();
688 func.build(head, opcode).def(second, GPR).finish();
689 let left = func.append_param(body, GPR);
690 let right = func.append_param(body, GPR);
691 *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
692 func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
693
694 assert_eq!(
699 run(&mut func, &narrow(1)),
700 [
701 "after 1: slot0 = rcx",
702 "before 2: rcx = slot1",
703 "end of 0: rdx = slot0",
704 "end of 0: slot1 = rdx",
705 ]
706 );
707 }
708
709 #[test]
723 fn an_instruction_reading_three_spilled_values_borrows_a_register_for_the_third() {
724 let mut names = Interner::new();
725 let mut func = Func::new(names.intern("f"));
726 let opcode = Opcode::new(names.intern("x64.nop"));
727 let block = func.create_block();
728 let keeper = func.new_vreg(GPR);
729 let base = func.new_vreg(GPR);
730 let index = func.new_vreg(GPR);
731 let value = func.new_vreg(GPR);
732 func.build(block, opcode).def(keeper, GPR).finish();
733 for reg in [base, index, value] {
734 func.build(block, opcode)
735 .operand(Operand::write(reg, GPR).with(Constraint::Stack))
736 .finish();
737 }
738 let store =
739 func.build(block, opcode).uses(base, GPR).uses(index, GPR).uses(value, GPR).finish();
740 func.build(block, opcode).uses(keeper, GPR).finish();
741
742 assert_eq!(
743 run(&mut func, &narrow(2)),
744 [
745 "after 1: slot0 = rdx",
746 "after 2: slot1 = rdx",
747 "after 3: slot2 = rdx",
748 "before 4: slot3 = rax",
749 "before 4: rdx = slot0",
750 "before 4: rsi = slot1",
751 "before 4: rax = slot2",
752 "after 4: rax = slot3",
753 ]
754 );
755 assert_eq!(operands(&func, store), ["rdx", "rsi", "rax"]);
756 }
757
758 #[test]
765 fn a_register_the_instruction_only_writes_still_carries_a_value_in() {
766 let mut names = Interner::new();
767 let mut func = Func::new(names.intern("f"));
768 let opcode = Opcode::new(names.intern("x64.nop"));
769 let block = func.create_block();
770 let target = func.new_vreg(GPR);
771 func.build(block, opcode)
772 .operand(Operand::write(target, GPR).with(Constraint::Stack))
773 .finish();
774 let call = func
775 .build(block, opcode)
776 .def(Reg::physical(RDX), GPR)
777 .def(Reg::physical(RSI), GPR)
778 .uses(target, GPR)
779 .finish();
780
781 assert_eq!(run(&mut func, &narrow(2)), ["after 0: slot0 = rdx", "before 1: rdx = slot0"]);
782 assert_eq!(operands(&func, call), ["rdx", "rsi", "rdx"]);
783 }
784
785 #[test]
792 fn a_register_the_instruction_already_named_is_not_handed_out_as_scratch() {
793 let mut names = Interner::new();
794 let mut func = Func::new(names.intern("f"));
795 let opcode = Opcode::new(names.intern("x64.nop"));
796 let block = func.create_block();
797 let wanted = func.new_vreg(GPR);
798 let other = func.new_vreg(GPR);
799 for reg in [wanted, other] {
800 func.build(block, opcode)
801 .operand(Operand::write(reg, GPR).with(Constraint::Stack))
802 .finish();
803 }
804 let read = func
805 .build(block, opcode)
806 .operand(Operand::read(wanted, GPR).with(Constraint::Fixed(RCX)))
807 .uses(other, GPR)
808 .finish();
809
810 assert_eq!(
813 run(&mut func, &narrow(1)),
814 [
815 "after 0: slot0 = rcx",
816 "after 1: slot1 = rcx",
817 "before 2: rcx = slot0",
818 "before 2: rdx = slot1"
819 ]
820 );
821 assert_eq!(operands(&func, read), ["rcx", "rdx"]);
822 }
823
824 #[test]
825 #[should_panic(expected = "a critical edge has nowhere to put its moves")]
826 fn a_critical_edge_is_refused() {
827 let mut names = Interner::new();
828 let mut func = Func::new(names.intern("f"));
829 let opcode = Opcode::new(names.intern("x64.nop"));
830 let head = func.create_block();
831 let other = func.create_block();
832 let join = func.create_block();
833 let value = func.new_vreg(GPR);
834 func.build(head, opcode).def(value, GPR).finish();
835 let param = func.append_param(join, GPR);
836 *func.succs_mut(head) = vec![BlockCall::with(join, vec![value]), BlockCall::to(other)];
837 *func.succs_mut(other) = vec![BlockCall::with(join, vec![value])];
838 func.build(join, opcode).uses(param, GPR).finish();
839
840 let _ = run(&mut func, &env());
841 }
842
843 #[test]
844 #[should_panic(expected = "what arrives in a function is not a block parameter")]
845 fn a_parameter_on_the_entry_block_is_refused() {
846 let mut names = Interner::new();
847 let mut func = Func::new(names.intern("f"));
848 let block = func.create_block();
849 let param = func.append_param(block, GPR);
850 let opcode = Opcode::new(names.intern("x64.nop"));
851 func.build(block, opcode).uses(param, GPR).finish();
852
853 let _ = run(&mut func, &env());
854 }
855
856 #[test]
857 fn a_value_already_in_a_register_is_left_where_it_is() {
858 let mut names = Interner::new();
859 let mut func = Func::new(names.intern("f"));
860 let opcode = Opcode::new(names.intern("x64.nop"));
861 let block = func.create_block();
862 let inst = func.build(block, opcode).uses(Reg::physical(RDX), GPR).finish();
863
864 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
865 assert_eq!(operands(&func, inst), ["rdx"]);
866 }
867}