1use std::ops::{Index, IndexMut};
29
30use rucc_base::{Idx, IdxRange, Symbol};
31use rucc_diag::Span;
32use rucc_target::RegClass;
33
34use crate::inst::{
35 Amode, Block, BlockCall, BlockData, Imm, ImmRef, Inst, InstData, InstLayout, Mem, MemRef,
36 Opcode, Operand, OperandList, Param, Reg,
37};
38
39#[derive(Debug)]
41pub struct Func {
42 pub name: Symbol,
44
45 insts: Vec<InstData>,
46 inst_layout: Vec<InstLayout>,
47 inst_spans: Vec<Span>,
48 blocks: Vec<BlockData>,
49
50 operands: Vec<Operand>,
51 imms: Vec<Imm>,
52 amodes: Vec<Amode>,
53 vregs: Vec<RegClass>,
56
57 first_block: Option<Block>,
58 last_block: Option<Block>,
59}
60
61impl Func {
62 #[must_use]
64 pub fn new(name: Symbol) -> Self {
65 Self {
66 name,
67 insts: Vec::new(),
68 inst_layout: Vec::new(),
69 inst_spans: Vec::new(),
70 blocks: Vec::new(),
71 operands: Vec::new(),
72 imms: Vec::new(),
73 amodes: Vec::new(),
74 vregs: Vec::new(),
75 first_block: None,
76 last_block: None,
77 }
78 }
79
80 pub fn new_vreg(&mut self, class: RegClass) -> Reg {
88 let number = u32::try_from(self.vregs.len()).expect("too many virtual registers");
89 self.vregs.push(class);
90 Reg::virtual_reg(number)
91 }
92
93 #[must_use]
96 pub fn vregs(&self) -> usize {
97 self.vregs.len()
98 }
99
100 #[must_use]
103 pub fn class_of(&self, reg: Reg) -> Option<RegClass> {
104 self.vregs.get(usize::try_from(reg.number()?).ok()?).copied()
105 }
106
107 pub fn create_block(&mut self) -> Block {
111 let block = Idx::from_usize(self.blocks.len());
112 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
113 match self.last_block {
114 Some(last) => self.blocks[last.index()].next = Some(block),
115 None => self.first_block = Some(block),
116 }
117 self.last_block = Some(block);
118 block
119 }
120
121 #[must_use]
123 pub fn entry(&self) -> Option<Block> {
124 self.first_block
125 }
126
127 #[must_use]
130 pub fn block_count(&self) -> usize {
131 self.blocks.len()
132 }
133
134 #[must_use]
138 pub fn inst_count(&self) -> usize {
139 self.insts.len()
140 }
141
142 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
144 std::iter::successors(self.first_block, |&block| self[block].next)
145 }
146
147 pub fn set_block_order(&mut self, order: &[Block]) {
163 assert_eq!(order.len(), self.blocks.len(), "the order is not every block of the function");
164 let mut seen = vec![false; self.blocks.len()];
165 for &block in order {
166 assert!(!seen[block.index()], "the order names a block twice");
167 seen[block.index()] = true;
168 }
169 for (at, &block) in order.iter().enumerate() {
170 let data = &mut self.blocks[block.index()];
171 data.prev = at.checked_sub(1).map(|before| order[before]);
172 data.next = order.get(at + 1).copied();
173 }
174 self.first_block = order.first().copied();
175 self.last_block = order.last().copied();
176 }
177
178 pub fn append_param(&mut self, block: Block, class: RegClass) -> Reg {
184 let reg = self.new_vreg(class);
185 self.blocks[block.index()].params.push(Param { reg, class });
186 reg
187 }
188
189 pub fn append_given_param(&mut self, block: Block, param: Param) {
192 self.blocks[block.index()].params.push(param);
193 }
194
195 pub fn params_mut(&mut self, block: Block) -> &mut Vec<Param> {
201 &mut self.blocks[block.index()].params
202 }
203
204 pub fn succs_mut(&mut self, block: Block) -> &mut Vec<BlockCall> {
209 &mut self.blocks[block.index()].succs
210 }
211
212 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
216 std::iter::successors(self[block].first_inst, |&inst| self.inst_layout[inst.index()].next)
217 }
218
219 #[must_use]
221 pub fn terminator(&self, block: Block) -> Option<Inst> {
222 self[block].last_inst
223 }
224
225 #[must_use]
228 pub fn block_of(&self, inst: Inst) -> Option<Block> {
229 self.inst_layout[inst.index()].block
230 }
231
232 #[must_use]
234 pub fn span(&self, inst: Inst) -> Span {
235 self.inst_spans[inst.index()]
236 }
237
238 pub fn build(&mut self, block: Block, opcode: Opcode) -> InstBuilder<'_> {
243 InstBuilder {
244 func: self,
245 block: Some(block),
246 opcode,
247 operands: Vec::new(),
248 imm: None,
249 mem: None,
250 symbol: None,
251 span: Span::DUMMY,
252 }
253 }
254
255 pub fn append_inst(&mut self, block: Block, inst: Inst) {
262 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
263 let last = self.blocks[block.index()].last_inst;
264 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
265 match last {
266 Some(last) => self.inst_layout[last.index()].next = Some(inst),
267 None => self.blocks[block.index()].first_inst = Some(inst),
268 }
269 self.blocks[block.index()].last_inst = Some(inst);
270 }
271
272 pub fn insert_after(&mut self, after: Inst, inst: Inst) {
279 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
280 let layout = self.inst_layout[after.index()];
281 let block = layout.block.expect("the instruction to insert after is in no block");
282 self.inst_layout[inst.index()] =
283 InstLayout { block: Some(block), prev: Some(after), next: layout.next };
284 self.inst_layout[after.index()].next = Some(inst);
285 match layout.next {
286 Some(next) => self.inst_layout[next.index()].prev = Some(inst),
287 None => self.blocks[block.index()].last_inst = Some(inst),
288 }
289 }
290
291 pub fn build_loose(&mut self, opcode: Opcode) -> InstBuilder<'_> {
298 InstBuilder {
299 func: self,
300 block: None,
301 opcode,
302 operands: Vec::new(),
303 imm: None,
304 mem: None,
305 symbol: None,
306 span: Span::DUMMY,
307 }
308 }
309
310 pub fn prepend_inst(&mut self, block: Block, inst: Inst) {
316 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
317 let first = self.blocks[block.index()].first_inst;
318 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: None, next: first };
319 match first {
320 Some(first) => self.inst_layout[first.index()].prev = Some(inst),
321 None => self.blocks[block.index()].last_inst = Some(inst),
322 }
323 self.blocks[block.index()].first_inst = Some(inst);
324 }
325
326 pub fn insert_before(&mut self, before: Inst, inst: Inst) {
337 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
338 let layout = self.inst_layout[before.index()];
339 let block = layout.block.expect("the instruction to insert before is in no block");
340 self.inst_layout[inst.index()] =
341 InstLayout { block: Some(block), prev: layout.prev, next: Some(before) };
342 self.inst_layout[before.index()].prev = Some(inst);
343 match layout.prev {
344 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
345 None => self.blocks[block.index()].first_inst = Some(inst),
346 }
347 }
348
349 pub fn remove_inst(&mut self, inst: Inst) {
354 let layout = self.inst_layout[inst.index()];
355 let Some(block) = layout.block else { return };
356 match layout.prev {
357 Some(prev) => self.inst_layout[prev.index()].next = layout.next,
358 None => self.blocks[block.index()].first_inst = layout.next,
359 }
360 match layout.next {
361 Some(next) => self.inst_layout[next.index()].prev = layout.prev,
362 None => self.blocks[block.index()].last_inst = layout.prev,
363 }
364 self.inst_layout[inst.index()] = InstLayout::default();
365 }
366
367 pub fn push_operands(&mut self, operands: &[Operand]) -> OperandList {
371 let start = Idx::from_usize(self.operands.len());
372 self.operands.extend_from_slice(operands);
373 IdxRange::new(start, Idx::from_usize(self.operands.len()))
374 }
375
376 pub fn add_imm(&mut self, value: i64) -> ImmRef {
378 self.imms.push(Imm(value));
379 Idx::from_usize(self.imms.len() - 1)
380 }
381
382 pub fn add_amode(&mut self, amode: Amode) -> MemRef {
384 self.amodes.push(amode);
385 Idx::from_usize(self.amodes.len() - 1)
386 }
387
388 pub fn create_inst(&mut self, data: InstData, span: Span) -> Inst {
390 self.insts.push(data);
391 self.inst_layout.push(InstLayout::default());
392 self.inst_spans.push(span);
393 Idx::from_usize(self.insts.len() - 1)
394 }
395}
396
397impl Index<Inst> for Func {
398 type Output = InstData;
399
400 fn index(&self, inst: Inst) -> &InstData {
401 &self.insts[inst.index()]
402 }
403}
404
405impl IndexMut<Inst> for Func {
406 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
407 &mut self.insts[inst.index()]
408 }
409}
410
411impl Index<Block> for Func {
412 type Output = BlockData;
413
414 fn index(&self, block: Block) -> &BlockData {
415 &self.blocks[block.index()]
416 }
417}
418
419impl Index<OperandList> for Func {
420 type Output = [Operand];
421
422 fn index(&self, list: OperandList) -> &[Operand] {
423 &self.operands[list.as_usize_range()]
424 }
425}
426
427impl IndexMut<OperandList> for Func {
428 fn index_mut(&mut self, list: OperandList) -> &mut [Operand] {
429 &mut self.operands[list.as_usize_range()]
430 }
431}
432
433impl Index<ImmRef> for Func {
434 type Output = Imm;
435
436 fn index(&self, at: ImmRef) -> &Imm {
437 &self.imms[at.index()]
438 }
439}
440
441impl Index<MemRef> for Func {
442 type Output = Amode;
443
444 fn index(&self, at: MemRef) -> &Amode {
445 &self.amodes[at.index()]
446 }
447}
448
449impl IndexMut<MemRef> for Func {
450 fn index_mut(&mut self, at: MemRef) -> &mut Amode {
451 &mut self.amodes[at.index()]
452 }
453}
454
455#[derive(Debug)]
460pub struct InstBuilder<'a> {
461 func: &'a mut Func,
462 block: Option<Block>,
463 opcode: Opcode,
464 operands: Vec<Operand>,
465 imm: Option<i64>,
466 mem: Option<Amode>,
467 symbol: Option<Symbol>,
468 span: Span,
469}
470
471impl InstBuilder<'_> {
472 #[must_use]
480 pub fn operand(mut self, operand: Operand) -> Self {
481 assert!(self.mem.is_none(), "the memory operand's registers come last");
482 if operand.role.is_def() {
483 let reads = self.operands.iter().any(|earlier| !earlier.role.is_def());
484 assert!(!reads, "the operands an instruction writes come first");
485 }
486 self.operands.push(operand);
487 self
488 }
489
490 #[must_use]
492 pub fn def(self, reg: Reg, class: RegClass) -> Self {
493 self.operand(Operand::write(reg, class))
494 }
495
496 #[must_use]
498 pub fn uses(self, reg: Reg, class: RegClass) -> Self {
499 self.operand(Operand::read(reg, class))
500 }
501
502 #[must_use]
508 pub fn mem(mut self, mem: Mem) -> Self {
509 assert!(self.mem.is_none(), "the instruction already has a memory operand");
510 let mut amode = Amode {
511 base: None,
512 index: None,
513 scale: mem.scale.max(1),
514 disp: mem.disp,
515 symbol: mem.symbol,
516 };
517 if let Some(base) = mem.base {
518 amode.base = Some(self.next_operand());
519 self.operands.push(base);
520 }
521 if let Some(index) = mem.index {
522 amode.index = Some(self.next_operand());
523 self.operands.push(index);
524 }
525 self.mem = Some(amode);
526 self
527 }
528
529 #[must_use]
531 pub fn imm(mut self, value: i64) -> Self {
532 self.imm = Some(value);
533 self
534 }
535
536 #[must_use]
538 pub fn symbol(mut self, symbol: Symbol) -> Self {
539 self.symbol = Some(symbol);
540 self
541 }
542
543 #[must_use]
545 pub fn at(mut self, span: Span) -> Self {
546 self.span = span;
547 self
548 }
549
550 pub fn finish(self) -> Inst {
553 let InstBuilder { func, block, opcode, operands, imm, mem, symbol, span } = self;
554 let data = InstData {
555 opcode,
556 operands: func.push_operands(&operands),
557 imm: imm.map(|value| func.add_imm(value)),
558 mem: mem.map(|amode| func.add_amode(amode)),
559 symbol,
560 };
561 let inst = func.create_inst(data, span);
562 if let Some(block) = block {
563 func.append_inst(block, inst);
564 }
565 inst
566 }
567
568 fn next_operand(&self) -> u8 {
575 u8::try_from(self.operands.len()).expect("too many operands on one instruction")
576 }
577}
578
579#[must_use]
582pub fn defs(operands: &[Operand]) -> usize {
583 operands.iter().position(|operand| !operand.role.is_def()).unwrap_or(operands.len())
584}
585
586#[cfg(test)]
587mod tests {
588 use rucc_base::Interner;
589
590 use super::*;
591
592 fn class() -> RegClass {
593 RegClass::new(0)
594 }
595
596 #[test]
597 fn the_blocks_can_be_put_in_another_order_and_keep_everything_in_them() {
598 let mut names = Interner::new();
599 let mut func = Func::new(names.intern("f"));
600 let opcode = Opcode::new(names.intern("x64.nop"));
601 let blocks: Vec<Block> = (0..4).map(|_| func.create_block()).collect();
602 let marker = func.build(blocks[3], opcode).finish();
603
604 func.set_block_order(&[blocks[0], blocks[3], blocks[1], blocks[2]]);
605 assert_eq!(
606 func.blocks().collect::<Vec<_>>(),
607 vec![blocks[0], blocks[3], blocks[1], blocks[2]]
608 );
609 assert_eq!(func.entry(), Some(blocks[0]));
610 assert_eq!(func.block_of(marker), Some(blocks[3]));
613 assert_eq!(func.insts(blocks[3]).collect::<Vec<_>>(), vec![marker]);
614
615 func.set_block_order(&[blocks[2], blocks[1], blocks[0], blocks[3]]);
617 assert_eq!(func.entry(), Some(blocks[2]));
618 let mut back = Vec::new();
619 let mut at = Some(blocks[3]);
620 while let Some(block) = at {
621 back.push(block);
622 at = func[block].prev;
623 }
624 assert_eq!(back, vec![blocks[3], blocks[0], blocks[1], blocks[2]]);
625 }
626
627 #[test]
628 #[should_panic(expected = "the order names a block twice")]
629 fn an_order_that_names_a_block_twice_is_refused_rather_than_made_into_a_loop() {
630 let mut names = Interner::new();
631 let mut func = Func::new(names.intern("f"));
632 let first = func.create_block();
633 let _second = func.create_block();
634 func.set_block_order(&[first, first]);
635 }
636
637 #[test]
638 #[should_panic(expected = "the order is not every block of the function")]
639 fn an_order_that_leaves_a_block_out_is_refused() {
640 let mut names = Interner::new();
641 let mut func = Func::new(names.intern("f"));
642 let first = func.create_block();
643 let _second = func.create_block();
644 func.set_block_order(&[first]);
645 }
646
647 #[test]
648 fn instructions_come_back_in_the_order_they_were_built() {
649 let mut names = Interner::new();
650 let mut func = Func::new(names.intern("f"));
651 let block = func.create_block();
652 let opcode = Opcode::new(names.intern("x64.nop"));
653 let first = func.build(block, opcode).finish();
654 let second = func.build(block, opcode).finish();
655 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, second]);
656 assert_eq!(func.terminator(block), Some(second));
657 assert_eq!(func.block_of(first), Some(block));
658 }
659
660 #[test]
661 fn a_removed_instruction_is_in_no_block_and_the_rest_still_link_up() {
662 let mut names = Interner::new();
663 let mut func = Func::new(names.intern("f"));
664 let block = func.create_block();
665 let opcode = Opcode::new(names.intern("x64.nop"));
666 let first = func.build(block, opcode).finish();
667 let second = func.build(block, opcode).finish();
668 let third = func.build(block, opcode).finish();
669 func.remove_inst(second);
670 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, third]);
671 assert_eq!(func.block_of(second), None);
672 }
673
674 #[test]
675 fn an_instruction_can_be_put_back_between_two_others() {
676 let mut names = Interner::new();
677 let mut func = Func::new(names.intern("f"));
678 let block = func.create_block();
679 let opcode = Opcode::new(names.intern("x64.nop"));
680 let first = func.build(block, opcode).finish();
681 let last = func.build(block, opcode).finish();
682 let spill = func.create_inst(InstData::new(opcode), Span::DUMMY);
683 func.insert_after(first, spill);
684 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, spill, last]);
685 assert_eq!(func.terminator(block), Some(last));
686 }
687
688 #[test]
689 fn an_instruction_can_be_put_in_front_of_the_first_one_in_a_block() {
690 let mut names = Interner::new();
691 let mut func = Func::new(names.intern("f"));
692 let block = func.create_block();
693 let opcode = Opcode::new(names.intern("x64.nop"));
694 let first = func.build(block, opcode).finish();
695 let last = func.build(block, opcode).finish();
696 let reload = func.create_inst(InstData::new(opcode), Span::DUMMY);
697 let prologue = func.create_inst(InstData::new(opcode), Span::DUMMY);
698 func.insert_before(last, reload);
699 func.prepend_inst(block, prologue);
700 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![prologue, first, reload, last]);
701 assert_eq!(func.terminator(block), Some(last));
702 assert_eq!(func.block_of(prologue), Some(block));
703 }
704
705 #[test]
706 fn the_first_instruction_in_an_empty_block_is_also_its_last() {
707 let mut names = Interner::new();
708 let mut func = Func::new(names.intern("f"));
709 let block = func.create_block();
710 let opcode = Opcode::new(names.intern("x64.ret"));
711 let only = func.create_inst(InstData::new(opcode), Span::DUMMY);
712 func.prepend_inst(block, only);
713 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![only]);
714 assert_eq!(func.terminator(block), Some(only));
715 }
716
717 #[test]
718 fn a_memory_operand_names_the_operands_holding_its_registers() {
719 let mut names = Interner::new();
720 let mut func = Func::new(names.intern("f"));
721 let block = func.create_block();
722 let base = func.new_vreg(class());
723 let index = func.new_vreg(class());
724 let dest = func.new_vreg(class());
725 let inst = func
726 .build(block, Opcode::new(names.intern("x64.lea")))
727 .def(dest, class())
728 .mem(
729 Mem::at(Operand::read(base, class()))
730 .indexed(Operand::read(index, class()), 4)
731 .plus(16),
732 )
733 .finish();
734 let data = func[inst];
735 let amode = func[data.mem.expect("it was given a memory operand")];
736 assert_eq!(amode.base, Some(1));
737 assert_eq!(amode.index, Some(2));
738 assert_eq!(amode.scale, 4);
739 assert_eq!(amode.disp, 16);
740 assert_eq!(func[data.operands][1].reg, base);
741 assert_eq!(defs(&func[data.operands]), 1);
742 }
743
744 #[test]
745 #[should_panic(expected = "the operands an instruction writes come first")]
746 fn a_def_after_a_use_is_refused() {
747 let mut names = Interner::new();
748 let mut func = Func::new(names.intern("f"));
749 let block = func.create_block();
750 let reg = func.new_vreg(class());
751 let _ = func
752 .build(block, Opcode::new(names.intern("x64.add")))
753 .uses(reg, class())
754 .def(reg, class());
755 }
756
757 #[test]
758 fn a_block_parameter_is_a_virtual_register_of_its_class() {
759 let mut names = Interner::new();
760 let mut func = Func::new(names.intern("f"));
761 let block = func.create_block();
762 let param = func.append_param(block, class());
763 assert_eq!(func[block].params, vec![Param { reg: param, class: class() }]);
764 assert_eq!(func.class_of(param), Some(class()));
765 assert_eq!(func.vregs(), 1);
766 assert_eq!(func.entry(), Some(block));
767 }
768}