1use rucc_mir::{Block, Constraint, Func, Inst, Operand, Param, Reg};
42use rucc_target::{PhysReg, RegClass};
43
44use crate::assign::{Assignment, Env, Place};
45use crate::moves::{self, Move};
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub struct Edit {
50 pub at: At,
52 pub mov: Move<Place>,
54 pub class: RegClass,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum At {
61 Before(Inst),
63 After(Inst),
66 StartOf(Block),
68 EndOf(Block),
70}
71
72#[must_use]
81pub fn rewrite(func: &mut Func, assignment: &Assignment, env: &Env) -> Vec<Edit> {
82 let blocks: Vec<Block> = func.blocks().collect();
83 assert!(
84 func.entry().is_none_or(|entry| func[entry].params.is_empty()),
85 "what arrives in a function is not a block parameter"
86 );
87
88 let mut edits = Vec::new();
89 for &block in &blocks {
90 let insts: Vec<Inst> = func.insts(block).collect();
91 for inst in insts {
92 instruction(func, assignment, env, inst, &mut edits);
93 }
94 }
95
96 let preds = preds(func, &blocks);
97 for &block in &blocks {
98 edges(func, assignment, env, block, &preds, &mut edits);
99 }
100 for &block in &blocks {
101 func.params_mut(block).clear();
102 for call in func.succs_mut(block) {
103 call.args.clear();
104 }
105 }
106 edits
107}
108
109fn instruction(
111 func: &mut Func,
112 assignment: &Assignment,
113 env: &Env,
114 inst: Inst,
115 edits: &mut Vec<Edit>,
116) {
117 let list = func[inst].operands;
118 let mut operands: Vec<Operand> = func[list].to_vec();
119 let mut before: Vec<(Move<Place>, RegClass)> = Vec::new();
120 let mut after: Vec<(Move<Place>, RegClass)> = Vec::new();
121 let mut taken = 0;
122
123 for operand in &mut operands {
124 let fixed = match operand.constraint {
125 Constraint::Fixed(at) => Some(at),
126 _ => None,
127 };
128 let at = match (place(assignment, operand.reg), fixed) {
129 (Place::Reg(at), None) => at,
130 (Place::Reg(at), Some(fixed)) => {
131 if at != fixed {
132 let (there, here) = (Place::Reg(fixed), Place::Reg(at));
133 push(&mut before, &mut after, operand, Move::new(there, here));
134 }
135 fixed
136 }
137 (Place::Slot(slot), fixed) => {
138 let at = fixed.unwrap_or_else(|| {
139 let scratch = *env
140 .scratch(operand.class)
141 .get(taken)
142 .expect("an instruction wanting more scratch registers than the class has");
143 taken += 1;
144 scratch
145 });
146 push(
147 &mut before,
148 &mut after,
149 operand,
150 Move::new(Place::Reg(at), Place::Slot(slot)),
151 );
152 at
153 }
154 };
155 operand.reg = Reg::physical(at);
156 }
157
158 for index in 0..operands.len() {
162 let Constraint::Reuse(other) = operands[index].constraint else { continue };
163 let (to, from) = (operands[index], operands[usize::from(other)]);
164 if to.reg != from.reg {
165 let mov = Move::new(Place::Reg(phys(to.reg)), Place::Reg(phys(from.reg)));
166 before.push((mov, to.class));
167 }
168 }
169
170 func[list].copy_from_slice(&operands);
171 edits.extend(before.into_iter().map(|(mov, class)| Edit { at: At::Before(inst), mov, class }));
172 edits.extend(after.into_iter().map(|(mov, class)| Edit { at: At::After(inst), mov, class }));
173}
174
175fn push(
178 before: &mut Vec<(Move<Place>, RegClass)>,
179 after: &mut Vec<(Move<Place>, RegClass)>,
180 operand: &Operand,
181 mov: Move<Place>,
182) {
183 if operand.role.is_def() {
184 after.push((Move::new(mov.from, mov.to), operand.class));
185 } else {
186 before.push((mov, operand.class));
187 }
188}
189
190fn edges(
192 func: &mut Func,
193 assignment: &Assignment,
194 env: &Env,
195 block: Block,
196 preds: &[usize],
197 edits: &mut Vec<Edit>,
198) {
199 let succs = func[block].succs.clone();
200 let single = succs.len() == 1;
201 for call in &succs {
202 let params = func[call.block].params.clone();
203 assert_eq!(
204 params.len(),
205 call.args.len(),
206 "an edge carries what the block it goes to asks for"
207 );
208 if params.is_empty() {
209 continue;
210 }
211 assert!(
212 single || preds[call.block.index()] == 1,
213 "a critical edge has nowhere to put its moves and has to be split before allocation"
214 );
215 let at = if single { At::EndOf(block) } else { At::StartOf(call.block) };
216 edits.extend(edge(assignment, env, ¶ms, &call.args, at));
217 }
218}
219
220fn edge(assignment: &Assignment, env: &Env, params: &[Param], args: &[Reg], at: At) -> Vec<Edit> {
222 let mut classes: Vec<RegClass> = params.iter().map(|param| param.class).collect();
223 classes.sort_unstable();
224 classes.dedup();
225
226 let mut edits = Vec::new();
227 for class in classes {
228 let parallel: Vec<Move<Place>> = params
231 .iter()
232 .zip(args)
233 .filter(|(param, _)| param.class == class)
234 .map(|(param, &arg)| Move::new(place(assignment, param.reg), place(assignment, arg)))
235 .collect();
236 let scratch = *env
237 .scratch(class)
238 .first()
239 .expect("a class whose values are passed on an edge and which has no scratch register");
240 edits.extend(moves::sequence(¶llel, Place::Reg(scratch)).into_iter().map(|mov| Edit {
241 at,
242 mov,
243 class,
244 }));
245 }
246 edits
247}
248
249fn preds(func: &Func, blocks: &[Block]) -> Vec<usize> {
251 let mut preds = vec![0; func.block_count()];
252 for &block in blocks {
253 for call in &func[block].succs {
254 preds[call.block.index()] += 1;
255 }
256 }
257 preds
258}
259
260fn place(assignment: &Assignment, reg: Reg) -> Place {
262 assignment.place(reg).unwrap_or_else(|| Place::Reg(phys(reg)))
263}
264
265fn phys(reg: Reg) -> PhysReg {
267 reg.phys().expect("a register the assignment says nothing about and that is not a register")
268}
269
270#[cfg(test)]
271mod tests {
272 use rucc_base::Interner;
273 use rucc_mir::{BlockCall, Opcode};
274 use rucc_target::x86_64::{GPR, RAX, RDX, REGS, SYSV};
275
276 use super::*;
277 use crate::assign::assign;
278 use crate::live::Live;
279 use crate::order::Order;
280
281 fn env() -> Env {
283 let (order, scratch) = SYSV.int_order.split_at(SYSV.int_order.len() - 3);
284 Env::new().with(GPR, order, scratch)
285 }
286
287 fn narrow(count: usize) -> Env {
289 Env::new().with(GPR, &SYSV.int_order[..count], &SYSV.int_order[count..count + 2])
290 }
291
292 fn named(place: Place) -> String {
294 match place {
295 Place::Reg(reg) => REGS.name(GPR, reg).expect("a register").to_string(),
296 Place::Slot(slot) => format!("slot{slot}"),
297 }
298 }
299
300 fn run(func: &mut Func, env: &Env) -> Vec<String> {
302 let order = Order::of(func);
303 let live = Live::of(func, &order);
304 let assignment = assign(func, &order, &live, env);
305 rewrite(func, &assignment, env)
306 .into_iter()
307 .map(|edit| {
308 let at = match edit.at {
309 At::Before(inst) => format!("before {}", inst.index()),
310 At::After(inst) => format!("after {}", inst.index()),
311 At::StartOf(block) => format!("start of {}", block.index()),
312 At::EndOf(block) => format!("end of {}", block.index()),
313 };
314 format!("{at}: {} = {}", named(edit.mov.to), named(edit.mov.from))
315 })
316 .collect()
317 }
318
319 fn operands(func: &Func, inst: Inst) -> Vec<String> {
321 func[func[inst].operands]
322 .iter()
323 .map(|operand| named(Place::Reg(phys(operand.reg))))
324 .collect()
325 }
326
327 #[test]
328 fn every_operand_ends_up_naming_the_register_its_value_was_given() {
329 let mut names = Interner::new();
330 let mut func = Func::new(names.intern("f"));
331 let opcode = Opcode::new(names.intern("x64.nop"));
332 let block = func.create_block();
333 let first = func.new_vreg(GPR);
334 let second = func.new_vreg(GPR);
335 func.build(block, opcode).def(first, GPR).finish();
336 func.build(block, opcode).def(second, GPR).finish();
337 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
338
339 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
340 assert_eq!(operands(&func, read), ["rax", "rcx"]);
341 }
342
343 #[test]
344 fn a_register_an_instruction_insists_on_is_moved_into_and_out_of() {
345 let mut names = Interner::new();
346 let mut func = Func::new(names.intern("f"));
347 let opcode = Opcode::new(names.intern("x64.nop"));
348 let block = func.create_block();
349 let dividend = func.new_vreg(GPR);
350 let quotient = func.new_vreg(GPR);
351 func.build(block, opcode).def(dividend, GPR).finish();
352 let divide = func
353 .build(block, opcode)
354 .operand(Operand::write(quotient, GPR).with(Constraint::Fixed(RAX)))
355 .operand(Operand::read(dividend, GPR).with(Constraint::Fixed(RAX)))
356 .finish();
357 func.build(block, opcode).uses(quotient, GPR).finish();
358
359 assert_eq!(run(&mut func, &env()), ["before 1: rax = rcx", "after 1: rcx = rax"]);
363 assert_eq!(operands(&func, divide), ["rax", "rax"]);
364 }
365
366 #[test]
367 fn a_two_address_instruction_that_did_not_get_its_register_copies_first() {
368 let mut names = Interner::new();
369 let mut func = Func::new(names.intern("f"));
370 let opcode = Opcode::new(names.intern("x64.nop"));
371 let block = func.create_block();
372 let left = func.new_vreg(GPR);
373 let right = func.new_vreg(GPR);
374 let sum = func.new_vreg(GPR);
375 func.build(block, opcode).def(left, GPR).finish();
376 func.build(block, opcode).def(right, GPR).finish();
377 let add = func
378 .build(block, opcode)
379 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
380 .uses(left, GPR)
381 .uses(right, GPR)
382 .finish();
383 func.build(block, opcode).uses(left, GPR).finish();
384
385 assert_eq!(run(&mut func, &env()), ["before 2: rdx = rax"]);
388 assert_eq!(operands(&func, add), ["rdx", "rax", "rcx"]);
389 }
390
391 #[test]
392 fn a_two_address_instruction_that_did_get_its_register_copies_nothing() {
393 let mut names = Interner::new();
394 let mut func = Func::new(names.intern("f"));
395 let opcode = Opcode::new(names.intern("x64.nop"));
396 let block = func.create_block();
397 let left = func.new_vreg(GPR);
398 let right = func.new_vreg(GPR);
399 let sum = func.new_vreg(GPR);
400 func.build(block, opcode).def(left, GPR).finish();
401 func.build(block, opcode).def(right, GPR).finish();
402 let add = func
403 .build(block, opcode)
404 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
405 .uses(left, GPR)
406 .uses(right, GPR)
407 .finish();
408 func.build(block, opcode).uses(right, GPR).finish();
409
410 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
411 assert_eq!(operands(&func, add), ["rax", "rax", "rcx"]);
412 }
413
414 #[test]
415 fn a_spilled_value_is_read_into_a_scratch_register_at_each_instruction_that_wants_it() {
416 let mut names = Interner::new();
417 let mut func = Func::new(names.intern("f"));
418 let opcode = Opcode::new(names.intern("x64.nop"));
419 let block = func.create_block();
420 let first = func.new_vreg(GPR);
421 let second = func.new_vreg(GPR);
422 func.build(block, opcode).def(first, GPR).finish();
423 func.build(block, opcode).def(second, GPR).finish();
424 let read = func.build(block, opcode).uses(first, GPR).uses(second, GPR).finish();
425
426 assert_eq!(run(&mut func, &narrow(1)), ["after 1: slot0 = rcx", "before 2: rcx = slot0"]);
430 assert_eq!(operands(&func, read), ["rax", "rcx"]);
431 }
432
433 #[test]
434 fn an_edge_out_of_a_block_with_one_way_to_go_moves_at_the_end_of_it() {
435 let mut names = Interner::new();
436 let mut func = Func::new(names.intern("f"));
437 let opcode = Opcode::new(names.intern("x64.nop"));
438 let head = func.create_block();
439 let tail = func.create_block();
440 let held = func.new_vreg(GPR);
441 let carried = func.new_vreg(GPR);
442 func.build(head, opcode).def(held, GPR).finish();
443 func.build(head, opcode).def(carried, GPR).finish();
444 func.build(head, opcode).uses(held, GPR).finish();
445 let param = func.append_param(tail, GPR);
446 *func.succs_mut(head) = vec![BlockCall::with(tail, vec![carried])];
447 let read = func.build(tail, opcode).uses(param, GPR).finish();
448
449 assert_eq!(run(&mut func, &env()), ["end of 0: rax = rcx"]);
453 assert_eq!(operands(&func, read), ["rax"]);
454 assert!(func[tail].params.is_empty());
457 assert!(func[head].succs[0].args.is_empty());
458 }
459
460 #[test]
461 fn an_edge_out_of_a_block_with_a_choice_moves_at_the_start_of_where_it_goes() {
462 let mut names = Interner::new();
463 let mut func = Func::new(names.intern("f"));
464 let opcode = Opcode::new(names.intern("x64.nop"));
465 let head = func.create_block();
466 let left = func.create_block();
467 let right = func.create_block();
468 let held = func.new_vreg(GPR);
469 let carried = func.new_vreg(GPR);
470 func.build(head, opcode).def(held, GPR).finish();
471 func.build(head, opcode).def(carried, GPR).finish();
472 func.build(head, opcode).uses(held, GPR).finish();
473 let taken = func.append_param(left, GPR);
474 *func.succs_mut(head) = vec![BlockCall::with(left, vec![carried]), BlockCall::to(right)];
475 func.build(left, opcode).uses(taken, GPR).finish();
476
477 assert_eq!(run(&mut func, &env()), ["start of 1: rax = rcx"]);
481 }
482
483 #[test]
484 fn two_values_that_swap_on_an_edge_get_an_order_and_a_scratch_register() {
485 let mut names = Interner::new();
486 let mut func = Func::new(names.intern("f"));
487 let opcode = Opcode::new(names.intern("x64.nop"));
488 let head = func.create_block();
489 let body = func.create_block();
490 let first = func.new_vreg(GPR);
491 let second = func.new_vreg(GPR);
492 func.build(head, opcode).def(first, GPR).finish();
493 func.build(head, opcode).def(second, GPR).finish();
494 let left = func.append_param(body, GPR);
495 let right = func.append_param(body, GPR);
496 *func.succs_mut(head) = vec![BlockCall::with(body, vec![first, second])];
497 func.build(body, opcode).uses(left, GPR).uses(right, GPR).finish();
498 *func.succs_mut(body) = vec![BlockCall::with(body, vec![right, left])];
499
500 assert_eq!(
504 run(&mut func, &env()),
505 ["end of 1: r13 = rcx", "end of 1: rcx = rax", "end of 1: rax = r13"]
506 );
507 }
508
509 #[test]
510 #[should_panic(expected = "a critical edge has nowhere to put its moves")]
511 fn a_critical_edge_is_refused() {
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 head = func.create_block();
516 let other = func.create_block();
517 let join = func.create_block();
518 let value = func.new_vreg(GPR);
519 func.build(head, opcode).def(value, GPR).finish();
520 let param = func.append_param(join, GPR);
521 *func.succs_mut(head) = vec![BlockCall::with(join, vec![value]), BlockCall::to(other)];
522 *func.succs_mut(other) = vec![BlockCall::with(join, vec![value])];
523 func.build(join, opcode).uses(param, GPR).finish();
524
525 let _ = run(&mut func, &env());
526 }
527
528 #[test]
529 #[should_panic(expected = "what arrives in a function is not a block parameter")]
530 fn a_parameter_on_the_entry_block_is_refused() {
531 let mut names = Interner::new();
532 let mut func = Func::new(names.intern("f"));
533 let block = func.create_block();
534 let param = func.append_param(block, GPR);
535 let opcode = Opcode::new(names.intern("x64.nop"));
536 func.build(block, opcode).uses(param, GPR).finish();
537
538 let _ = run(&mut func, &env());
539 }
540
541 #[test]
542 fn a_value_already_in_a_register_is_left_where_it_is() {
543 let mut names = Interner::new();
544 let mut func = Func::new(names.intern("f"));
545 let opcode = Opcode::new(names.intern("x64.nop"));
546 let block = func.create_block();
547 let inst = func.build(block, opcode).uses(Reg::physical(RDX), GPR).finish();
548
549 assert_eq!(run(&mut func, &env()), Vec::<String>::new());
550 assert_eq!(operands(&func, inst), ["rdx"]);
551 }
552}