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 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
136 std::iter::successors(self.first_block, |&block| self[block].next)
137 }
138
139 pub fn append_param(&mut self, block: Block, class: RegClass) -> Reg {
145 let reg = self.new_vreg(class);
146 self.blocks[block.index()].params.push(Param { reg, class });
147 reg
148 }
149
150 pub fn append_given_param(&mut self, block: Block, param: Param) {
153 self.blocks[block.index()].params.push(param);
154 }
155
156 pub fn succs_mut(&mut self, block: Block) -> &mut Vec<BlockCall> {
161 &mut self.blocks[block.index()].succs
162 }
163
164 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
168 std::iter::successors(self[block].first_inst, |&inst| self.inst_layout[inst.index()].next)
169 }
170
171 #[must_use]
173 pub fn terminator(&self, block: Block) -> Option<Inst> {
174 self[block].last_inst
175 }
176
177 #[must_use]
180 pub fn block_of(&self, inst: Inst) -> Option<Block> {
181 self.inst_layout[inst.index()].block
182 }
183
184 #[must_use]
186 pub fn span(&self, inst: Inst) -> Span {
187 self.inst_spans[inst.index()]
188 }
189
190 pub fn build(&mut self, block: Block, opcode: Opcode) -> InstBuilder<'_> {
195 InstBuilder {
196 func: self,
197 block,
198 opcode,
199 operands: Vec::new(),
200 imm: None,
201 mem: None,
202 symbol: None,
203 span: Span::DUMMY,
204 }
205 }
206
207 pub fn append_inst(&mut self, block: Block, inst: Inst) {
214 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
215 let last = self.blocks[block.index()].last_inst;
216 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
217 match last {
218 Some(last) => self.inst_layout[last.index()].next = Some(inst),
219 None => self.blocks[block.index()].first_inst = Some(inst),
220 }
221 self.blocks[block.index()].last_inst = Some(inst);
222 }
223
224 pub fn insert_after(&mut self, after: Inst, inst: Inst) {
231 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
232 let layout = self.inst_layout[after.index()];
233 let block = layout.block.expect("the instruction to insert after is in no block");
234 self.inst_layout[inst.index()] =
235 InstLayout { block: Some(block), prev: Some(after), next: layout.next };
236 self.inst_layout[after.index()].next = Some(inst);
237 match layout.next {
238 Some(next) => self.inst_layout[next.index()].prev = Some(inst),
239 None => self.blocks[block.index()].last_inst = Some(inst),
240 }
241 }
242
243 pub fn remove_inst(&mut self, inst: Inst) {
248 let layout = self.inst_layout[inst.index()];
249 let Some(block) = layout.block else { return };
250 match layout.prev {
251 Some(prev) => self.inst_layout[prev.index()].next = layout.next,
252 None => self.blocks[block.index()].first_inst = layout.next,
253 }
254 match layout.next {
255 Some(next) => self.inst_layout[next.index()].prev = layout.prev,
256 None => self.blocks[block.index()].last_inst = layout.prev,
257 }
258 self.inst_layout[inst.index()] = InstLayout::default();
259 }
260
261 pub fn push_operands(&mut self, operands: &[Operand]) -> OperandList {
265 let start = Idx::from_usize(self.operands.len());
266 self.operands.extend_from_slice(operands);
267 IdxRange::new(start, Idx::from_usize(self.operands.len()))
268 }
269
270 pub fn add_imm(&mut self, value: i64) -> ImmRef {
272 self.imms.push(Imm(value));
273 Idx::from_usize(self.imms.len() - 1)
274 }
275
276 pub fn add_amode(&mut self, amode: Amode) -> MemRef {
278 self.amodes.push(amode);
279 Idx::from_usize(self.amodes.len() - 1)
280 }
281
282 pub fn create_inst(&mut self, data: InstData, span: Span) -> Inst {
284 self.insts.push(data);
285 self.inst_layout.push(InstLayout::default());
286 self.inst_spans.push(span);
287 Idx::from_usize(self.insts.len() - 1)
288 }
289}
290
291impl Index<Inst> for Func {
292 type Output = InstData;
293
294 fn index(&self, inst: Inst) -> &InstData {
295 &self.insts[inst.index()]
296 }
297}
298
299impl IndexMut<Inst> for Func {
300 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
301 &mut self.insts[inst.index()]
302 }
303}
304
305impl Index<Block> for Func {
306 type Output = BlockData;
307
308 fn index(&self, block: Block) -> &BlockData {
309 &self.blocks[block.index()]
310 }
311}
312
313impl Index<OperandList> for Func {
314 type Output = [Operand];
315
316 fn index(&self, list: OperandList) -> &[Operand] {
317 &self.operands[list.as_usize_range()]
318 }
319}
320
321impl IndexMut<OperandList> for Func {
322 fn index_mut(&mut self, list: OperandList) -> &mut [Operand] {
323 &mut self.operands[list.as_usize_range()]
324 }
325}
326
327impl Index<ImmRef> for Func {
328 type Output = Imm;
329
330 fn index(&self, at: ImmRef) -> &Imm {
331 &self.imms[at.index()]
332 }
333}
334
335impl Index<MemRef> for Func {
336 type Output = Amode;
337
338 fn index(&self, at: MemRef) -> &Amode {
339 &self.amodes[at.index()]
340 }
341}
342
343#[derive(Debug)]
348pub struct InstBuilder<'a> {
349 func: &'a mut Func,
350 block: Block,
351 opcode: Opcode,
352 operands: Vec<Operand>,
353 imm: Option<i64>,
354 mem: Option<Amode>,
355 symbol: Option<Symbol>,
356 span: Span,
357}
358
359impl InstBuilder<'_> {
360 #[must_use]
368 pub fn operand(mut self, operand: Operand) -> Self {
369 assert!(self.mem.is_none(), "the memory operand's registers come last");
370 if operand.role.is_def() {
371 let reads = self.operands.iter().any(|earlier| !earlier.role.is_def());
372 assert!(!reads, "the operands an instruction writes come first");
373 }
374 self.operands.push(operand);
375 self
376 }
377
378 #[must_use]
380 pub fn def(self, reg: Reg, class: RegClass) -> Self {
381 self.operand(Operand::write(reg, class))
382 }
383
384 #[must_use]
386 pub fn uses(self, reg: Reg, class: RegClass) -> Self {
387 self.operand(Operand::read(reg, class))
388 }
389
390 #[must_use]
396 pub fn mem(mut self, mem: Mem) -> Self {
397 assert!(self.mem.is_none(), "the instruction already has a memory operand");
398 let mut amode = Amode {
399 base: None,
400 index: None,
401 scale: mem.scale.max(1),
402 disp: mem.disp,
403 symbol: mem.symbol,
404 };
405 if let Some(base) = mem.base {
406 amode.base = Some(self.next_operand());
407 self.operands.push(base);
408 }
409 if let Some(index) = mem.index {
410 amode.index = Some(self.next_operand());
411 self.operands.push(index);
412 }
413 self.mem = Some(amode);
414 self
415 }
416
417 #[must_use]
419 pub fn imm(mut self, value: i64) -> Self {
420 self.imm = Some(value);
421 self
422 }
423
424 #[must_use]
426 pub fn symbol(mut self, symbol: Symbol) -> Self {
427 self.symbol = Some(symbol);
428 self
429 }
430
431 #[must_use]
433 pub fn at(mut self, span: Span) -> Self {
434 self.span = span;
435 self
436 }
437
438 pub fn finish(self) -> Inst {
440 let InstBuilder { func, block, opcode, operands, imm, mem, symbol, span } = self;
441 let data = InstData {
442 opcode,
443 operands: func.push_operands(&operands),
444 imm: imm.map(|value| func.add_imm(value)),
445 mem: mem.map(|amode| func.add_amode(amode)),
446 symbol,
447 };
448 let inst = func.create_inst(data, span);
449 func.append_inst(block, inst);
450 inst
451 }
452
453 fn next_operand(&self) -> u8 {
460 u8::try_from(self.operands.len()).expect("too many operands on one instruction")
461 }
462}
463
464#[must_use]
467pub fn defs(operands: &[Operand]) -> usize {
468 operands.iter().position(|operand| !operand.role.is_def()).unwrap_or(operands.len())
469}
470
471#[cfg(test)]
472mod tests {
473 use rucc_base::Interner;
474
475 use super::*;
476
477 fn class() -> RegClass {
478 RegClass::new(0)
479 }
480
481 #[test]
482 fn instructions_come_back_in_the_order_they_were_built() {
483 let mut names = Interner::new();
484 let mut func = Func::new(names.intern("f"));
485 let block = func.create_block();
486 let opcode = Opcode::new(names.intern("x64.nop"));
487 let first = func.build(block, opcode).finish();
488 let second = func.build(block, opcode).finish();
489 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, second]);
490 assert_eq!(func.terminator(block), Some(second));
491 assert_eq!(func.block_of(first), Some(block));
492 }
493
494 #[test]
495 fn a_removed_instruction_is_in_no_block_and_the_rest_still_link_up() {
496 let mut names = Interner::new();
497 let mut func = Func::new(names.intern("f"));
498 let block = func.create_block();
499 let opcode = Opcode::new(names.intern("x64.nop"));
500 let first = func.build(block, opcode).finish();
501 let second = func.build(block, opcode).finish();
502 let third = func.build(block, opcode).finish();
503 func.remove_inst(second);
504 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, third]);
505 assert_eq!(func.block_of(second), None);
506 }
507
508 #[test]
509 fn an_instruction_can_be_put_back_between_two_others() {
510 let mut names = Interner::new();
511 let mut func = Func::new(names.intern("f"));
512 let block = func.create_block();
513 let opcode = Opcode::new(names.intern("x64.nop"));
514 let first = func.build(block, opcode).finish();
515 let last = func.build(block, opcode).finish();
516 let spill = func.create_inst(InstData::new(opcode), Span::DUMMY);
517 func.insert_after(first, spill);
518 assert_eq!(func.insts(block).collect::<Vec<_>>(), vec![first, spill, last]);
519 assert_eq!(func.terminator(block), Some(last));
520 }
521
522 #[test]
523 fn a_memory_operand_names_the_operands_holding_its_registers() {
524 let mut names = Interner::new();
525 let mut func = Func::new(names.intern("f"));
526 let block = func.create_block();
527 let base = func.new_vreg(class());
528 let index = func.new_vreg(class());
529 let dest = func.new_vreg(class());
530 let inst = func
531 .build(block, Opcode::new(names.intern("x64.lea")))
532 .def(dest, class())
533 .mem(
534 Mem::at(Operand::read(base, class()))
535 .indexed(Operand::read(index, class()), 4)
536 .plus(16),
537 )
538 .finish();
539 let data = func[inst];
540 let amode = func[data.mem.expect("it was given a memory operand")];
541 assert_eq!(amode.base, Some(1));
542 assert_eq!(amode.index, Some(2));
543 assert_eq!(amode.scale, 4);
544 assert_eq!(amode.disp, 16);
545 assert_eq!(func[data.operands][1].reg, base);
546 assert_eq!(defs(&func[data.operands]), 1);
547 }
548
549 #[test]
550 #[should_panic(expected = "the operands an instruction writes come first")]
551 fn a_def_after_a_use_is_refused() {
552 let mut names = Interner::new();
553 let mut func = Func::new(names.intern("f"));
554 let block = func.create_block();
555 let reg = func.new_vreg(class());
556 let _ = func
557 .build(block, Opcode::new(names.intern("x64.add")))
558 .uses(reg, class())
559 .def(reg, class());
560 }
561
562 #[test]
563 fn a_block_parameter_is_a_virtual_register_of_its_class() {
564 let mut names = Interner::new();
565 let mut func = Func::new(names.intern("f"));
566 let block = func.create_block();
567 let param = func.append_param(block, class());
568 assert_eq!(func[block].params, vec![Param { reg: param, class: class() }]);
569 assert_eq!(func.class_of(param), Some(class()));
570 assert_eq!(func.vregs(), 1);
571 assert_eq!(func.entry(), Some(block));
572 }
573}