1use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33use rucc_target::Slot;
34
35use crate::inst::{
36 Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
37 ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo, VaInfo,
38 Value, ValueData, ValueList,
39};
40use crate::module::{Linkage, Visibility};
41use crate::{Attrs, Flags, FloatPred, IntPred, Opcode, Type};
42
43#[derive(Debug)]
45pub struct Func {
46 pub name: Symbol,
48 pub linkage: Linkage,
50 pub visibility: Visibility,
52 pub section: Option<Symbol>,
55 pub attrs: Attrs,
58
59 values: Vec<ValueData>,
60 insts: Vec<InstData>,
61 inst_layout: Vec<InstLayout>,
62 inst_spans: Vec<Span>,
63 blocks: Vec<BlockData>,
64
65 value_pool: Vec<Value>,
66 block_calls: Vec<BlockCall>,
67 imms: Vec<Imm>,
68 mem: Vec<MemInfo>,
69 calls: Vec<CallInfo>,
70 abis: Vec<Abi>,
71 switches: Vec<SwitchInfo>,
72 asms: Vec<AsmInfo>,
73 slots: Vec<Slot>,
74 va_objects: Vec<VaInfo>,
75 signatures: Vec<Signature>,
76
77 first_block: Option<Block>,
78 last_block: Option<Block>,
79}
80
81impl Func {
82 #[must_use]
89 pub fn new(name: Symbol, signature: Signature) -> Self {
90 Self {
91 name,
92 linkage: Linkage::External,
93 visibility: Visibility::Default,
94 section: None,
95 attrs: Attrs::NONE,
96 values: Vec::new(),
97 insts: Vec::new(),
98 inst_layout: Vec::new(),
99 inst_spans: Vec::new(),
100 blocks: Vec::new(),
101 value_pool: Vec::new(),
102 block_calls: Vec::new(),
103 imms: Vec::new(),
104 mem: Vec::new(),
105 calls: Vec::new(),
106 abis: Vec::new(),
107 switches: Vec::new(),
108 asms: Vec::new(),
109 slots: Vec::new(),
110 va_objects: Vec::new(),
111 signatures: vec![signature],
112 first_block: None,
113 last_block: None,
114 }
115 }
116
117 #[must_use]
119 pub fn signature(&self) -> &Signature {
120 &self.signatures[0]
121 }
122
123 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
125 self.signatures.iter()
126 }
127
128 pub fn add_signature(&mut self, signature: Signature) -> Sig {
130 self.signatures.push(signature);
131 Idx::from_usize(self.signatures.len() - 1)
132 }
133
134 #[must_use]
139 pub fn entry(&self) -> Option<Block> {
140 self.first_block
141 }
142
143 #[must_use]
150 pub fn is_declaration(&self) -> bool {
151 self.first_block.is_none()
152 }
153
154 pub fn create_block(&mut self) -> Block {
158 let block = Idx::from_usize(self.blocks.len());
159 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
160 match self.last_block {
161 Some(last) => self.blocks[last.index()].next = Some(block),
162 None => self.first_block = Some(block),
163 }
164 self.last_block = Some(block);
165 block
166 }
167
168 pub fn remove_block(&mut self, block: Block) {
181 assert!(self.first_block != Some(block), "the entry block is not removable");
182 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
183 match prev {
184 Some(prev) => self.blocks[prev.index()].next = next,
185 None => self.first_block = next,
186 }
187 match next {
188 Some(next) => self.blocks[next.index()].prev = prev,
189 None => self.last_block = prev,
190 }
191 let insts: Vec<Inst> = self.insts(block).collect();
195 for inst in insts {
196 self.inst_layout[inst.index()] = InstLayout::default();
197 }
198 self.blocks[block.index()] = BlockData::default();
199 }
200
201 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
210 let index = u32::try_from(self.blocks[block.index()].params.len())
211 .expect("a block with four billion parameters");
212 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
213 self.blocks[block.index()].params.push(value);
214 value
215 }
216
217 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
229 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
230 params.retain(|&value| keep(value));
231 for (index, &value) in params.iter().enumerate() {
232 let index = u32::try_from(index).expect("a block with four billion parameters");
233 self.values[value.index()].def = Def::Param { block, index };
234 }
235 self.blocks[block.index()].params = params;
236 }
237
238 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
240 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
241 }
242
243 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
245 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
246 self.inst_layout[inst.index()].next
247 })
248 }
249
250 #[must_use]
252 pub fn terminator(&self, block: Block) -> Option<Inst> {
253 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
254 }
255
256 #[must_use]
262 pub fn is_terminator(&self, inst: Inst) -> bool {
263 let data = &self[inst];
264 match data.extra {
265 Extra::Asm(info) => {
266 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
267 }
268 _ => data.opcode.is_terminator(),
269 }
270 }
271
272 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
283 let inst = Idx::from_usize(self.insts.len());
284 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
285 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
286 for (index, &ty) in results.iter().enumerate() {
287 let index = u8::try_from(index).expect("checked just above");
288 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
289 }
290 self.insts.push(data);
291 self.inst_layout.push(InstLayout::default());
292 self.inst_spans.push(span);
293 inst
294 }
295
296 pub fn append_inst(&mut self, block: Block, inst: Inst) {
303 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
304 let last = self.blocks[block.index()].last;
305 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
306 match last {
307 Some(last) => self.inst_layout[last.index()].next = Some(inst),
308 None => self.blocks[block.index()].first = Some(inst),
309 }
310 self.blocks[block.index()].last = Some(inst);
311 }
312
313 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
319 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
320 let at = self.inst_layout[before.index()];
321 let block = at.block.expect("the instruction to insert before is not in a block");
322 self.inst_layout[inst.index()] =
323 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
324 self.inst_layout[before.index()].prev = Some(inst);
325 match at.prev {
326 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
327 None => self.blocks[block.index()].first = Some(inst),
328 }
329 }
330
331 pub fn remove_inst(&mut self, inst: Inst) {
341 let at = self.inst_layout[inst.index()];
342 let block = at.block.expect("the instruction is not in a block");
343 match at.prev {
344 Some(prev) => self.inst_layout[prev.index()].next = at.next,
345 None => self.blocks[block.index()].first = at.next,
346 }
347 match at.next {
348 Some(next) => self.inst_layout[next.index()].prev = at.prev,
349 None => self.blocks[block.index()].last = at.prev,
350 }
351 self.inst_layout[inst.index()] = InstLayout::default();
352 }
353
354 #[must_use]
356 pub fn block_of(&self, inst: Inst) -> Option<Block> {
357 self.inst_layout[inst.index()].block
358 }
359
360 #[must_use]
362 pub fn span(&self, inst: Inst) -> Span {
363 self.inst_spans[inst.index()]
364 }
365
366 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
371 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
372 }
373
374 #[must_use]
381 pub fn target_list(&self, inst: Inst) -> BlockCallList {
382 match self[inst].extra {
383 Extra::Targets(targets) => targets,
384 Extra::Switch(info) => self.switches[info.index()].targets,
385 Extra::Asm(info) => self.asms[info.index()].targets,
386 _ => BlockCallList::EMPTY,
387 }
388 }
389
390 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
394 let start = Idx::from_usize(self.value_pool.len());
395 self.value_pool.extend_from_slice(values);
396 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
397 }
398
399 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
406 let range = list.as_usize_range();
407 if range.end == self.value_pool.len() {
408 self.value_pool.push(value);
409 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
410 }
411 let start = self.value_pool.len();
412 self.value_pool.extend_from_within(range);
413 self.value_pool.push(value);
414 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
415 }
416
417 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
422 for value in &mut self.value_pool[list.as_usize_range()] {
423 *value = with(*value);
424 }
425 }
426
427 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
429 let start = Idx::from_usize(self.block_calls.len());
430 self.block_calls.extend_from_slice(calls);
431 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
432 }
433
434 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
436 self.block_calls[at.index()] = call;
437 }
438
439 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
441 let start = Idx::from_usize(self.imms.len());
442 self.imms.extend_from_slice(imms);
443 ImmList::new(start, Idx::from_usize(self.imms.len()))
444 }
445
446 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
448 self.imms.push(imm);
449 Idx::from_usize(self.imms.len() - 1)
450 }
451
452 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
454 let start = Idx::from_usize(self.slots.len());
455 self.slots.extend_from_slice(slots);
456 SlotList::new(start, Idx::from_usize(self.slots.len()))
457 }
458
459 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
461 self.va_objects.push(info);
462 Idx::from_usize(self.va_objects.len() - 1)
463 }
464
465 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
467 self.mem.push(info);
468 Idx::from_usize(self.mem.len() - 1)
469 }
470
471 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
473 let start = Idx::from_usize(self.abis.len());
474 self.abis.extend_from_slice(abis);
475 AbiList::new(start, Idx::from_usize(self.abis.len()))
476 }
477
478 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
480 self.calls.push(info);
481 Idx::from_usize(self.calls.len() - 1)
482 }
483
484 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
486 self.switches.push(info);
487 Idx::from_usize(self.switches.len() - 1)
488 }
489
490 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
492 self.asms.push(info);
493 Idx::from_usize(self.asms.len() - 1)
494 }
495
496 #[must_use]
499 pub fn counts(&self) -> Counts {
500 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
501 }
502
503 fn add_value(&mut self, data: ValueData) -> Value {
504 self.values.push(data);
505 Idx::from_usize(self.values.len() - 1)
506 }
507}
508
509#[derive(Clone, Copy, Debug, PartialEq, Eq)]
511pub struct Counts {
512 pub values: usize,
514 pub insts: usize,
516 pub blocks: usize,
518}
519
520impl Index<Value> for Func {
523 type Output = ValueData;
524
525 fn index(&self, value: Value) -> &ValueData {
526 &self.values[value.index()]
527 }
528}
529
530impl Index<Inst> for Func {
531 type Output = InstData;
532
533 fn index(&self, inst: Inst) -> &InstData {
534 &self.insts[inst.index()]
535 }
536}
537
538impl IndexMut<Inst> for Func {
539 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
540 &mut self.insts[inst.index()]
541 }
542}
543
544impl Index<Block> for Func {
545 type Output = BlockData;
546
547 fn index(&self, block: Block) -> &BlockData {
548 &self.blocks[block.index()]
549 }
550}
551
552impl Index<Sig> for Func {
553 type Output = Signature;
554
555 fn index(&self, sig: Sig) -> &Signature {
556 &self.signatures[sig.index()]
557 }
558}
559
560impl Index<ValueList> for Func {
561 type Output = [Value];
562
563 fn index(&self, list: ValueList) -> &[Value] {
564 &self.value_pool[list.as_usize_range()]
565 }
566}
567
568impl Index<BlockCallList> for Func {
569 type Output = [BlockCall];
570
571 fn index(&self, list: BlockCallList) -> &[BlockCall] {
572 &self.block_calls[list.as_usize_range()]
573 }
574}
575
576impl Index<Idx<BlockCall>> for Func {
577 type Output = BlockCall;
578
579 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
580 &self.block_calls[at.index()]
581 }
582}
583
584impl Index<ImmList> for Func {
585 type Output = [Imm];
586
587 fn index(&self, list: ImmList) -> &[Imm] {
588 &self.imms[list.as_usize_range()]
589 }
590}
591
592impl Index<Idx<Imm>> for Func {
593 type Output = Imm;
594
595 fn index(&self, at: Idx<Imm>) -> &Imm {
596 &self.imms[at.index()]
597 }
598}
599
600impl Index<Idx<MemInfo>> for Func {
601 type Output = MemInfo;
602
603 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
604 &self.mem[at.index()]
605 }
606}
607
608impl Index<AbiList> for Func {
609 type Output = [Abi];
610
611 fn index(&self, list: AbiList) -> &[Abi] {
612 &self.abis[list.as_usize_range()]
613 }
614}
615
616impl Index<SlotList> for Func {
617 type Output = [Slot];
618
619 fn index(&self, list: SlotList) -> &[Slot] {
620 &self.slots[list.as_usize_range()]
621 }
622}
623
624impl Index<Idx<VaInfo>> for Func {
625 type Output = VaInfo;
626
627 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
628 &self.va_objects[at.index()]
629 }
630}
631
632impl Index<Idx<CallInfo>> for Func {
633 type Output = CallInfo;
634
635 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
636 &self.calls[at.index()]
637 }
638}
639
640impl Index<Idx<SwitchInfo>> for Func {
641 type Output = SwitchInfo;
642
643 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
644 &self.switches[at.index()]
645 }
646}
647
648impl Index<Idx<AsmInfo>> for Func {
649 type Output = AsmInfo;
650
651 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
652 &self.asms[at.index()]
653 }
654}
655
656#[derive(Debug)]
663pub struct Builder<'a> {
664 func: &'a mut Func,
665 block: Block,
666 span: Span,
667}
668
669impl<'a> Builder<'a> {
670 pub fn new(func: &'a mut Func, block: Block) -> Self {
672 Self { func, block, span: Span::DUMMY }
673 }
674
675 #[must_use]
677 pub fn at(mut self, span: Span) -> Self {
678 self.span = span;
679 self
680 }
681
682 pub fn set_span(&mut self, span: Span) {
684 self.span = span;
685 }
686
687 pub fn func(&mut self) -> &mut Func {
689 self.func
690 }
691
692 #[must_use]
694 pub fn block(&self) -> Block {
695 self.block
696 }
697
698 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
700 let inst = self.func.create_inst(data, results, self.span);
701 self.func.append_inst(self.block, inst);
702 inst
703 }
704
705 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
711 let inst = self.inst(data, &[ty]);
712 self.func[inst].first_result.expect("one result was asked for")
713 }
714
715 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
721 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
722 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
723 }
724
725 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
727 let imm = self.func.add_imm(Imm::from_bits(bits));
728 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
729 }
730
731 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
733 let ty = self.func[lhs].ty;
734 let args = self.func.push_values(&[lhs, rhs]);
735 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
736 }
737
738 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
740 let args = self.func.push_values(&[arg]);
741 self.value(InstData { args, ..InstData::new(opcode) }, ty)
742 }
743
744 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
746 let ty = self.func[lhs].ty.with_lane(Type::I1);
747 let args = self.func.push_values(&[lhs, rhs]);
748 self.value(
749 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
750 ty,
751 )
752 }
753
754 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
756 let ty = self.func[lhs].ty.with_lane(Type::I1);
757 let args = self.func.push_values(&[lhs, rhs]);
758 self.value(
759 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
760 ty,
761 )
762 }
763
764 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
766 let mem = self.func.add_mem(info);
767 let args = self.func.push_values(&[addr]);
768 self.value(
769 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
770 ty,
771 )
772 }
773
774 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
776 let mem = self.func.add_mem(info);
777 let args = self.func.push_values(&[value, addr]);
778 self.inst(
779 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
780 &[],
781 )
782 }
783
784 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
786 let call = self.block_call(target, args);
787 let targets = self.func.push_block_calls(&[call]);
788 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
789 }
790
791 pub fn block_addr(&mut self, target: Block) -> Value {
797 let call = self.block_call(target, &[]);
798 let targets = self.func.push_block_calls(&[call]);
799 self.value(
800 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
801 Type::PTR,
802 )
803 }
804
805 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
811 let calls: Vec<BlockCall> =
812 targets.iter().map(|&target| self.block_call(target, &[])).collect();
813 let targets = self.func.push_block_calls(&calls);
814 let args = self.func.push_values(&[addr]);
815 self.inst(
816 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
817 &[],
818 )
819 }
820
821 pub fn br_if(
823 &mut self,
824 cond: Value,
825 then_block: Block,
826 then_args: &[Value],
827 else_block: Block,
828 else_args: &[Value],
829 ) -> Inst {
830 let then_call = self.block_call(then_block, then_args);
831 let else_call = self.block_call(else_block, else_args);
832 let targets = self.func.push_block_calls(&[then_call, else_call]);
833 let args = self.func.push_values(&[cond]);
834 self.inst(
835 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
836 &[],
837 )
838 }
839
840 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
847 let ty = self.func[value].ty.lane();
848 let mut calls = vec![self.block_call(default, &[])];
849 let mut values = Vec::with_capacity(cases.len());
850 for &(value, block) in cases {
851 calls.push(self.block_call(block, &[]));
852 values.push(Imm::int(value, ty));
853 }
854 let targets = self.func.push_block_calls(&calls);
855 let cases = self.func.push_imms(&values);
856 let info = self.func.add_switch(SwitchInfo { targets, cases });
857 let args = self.func.push_values(&[value]);
858 self.inst(
859 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
860 &[],
861 )
862 }
863
864 pub fn ret(&mut self, values: &[Value]) -> Inst {
866 let args = self.func.push_values(values);
867 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
868 }
869
870 pub fn unreachable(&mut self) -> Inst {
872 self.inst(InstData::new(Opcode::Unreachable), &[])
873 }
874
875 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
877 self.call_varargs(callee, signature, args, &[])
878 }
879
880 pub fn call_varargs(
886 &mut self,
887 callee: Symbol,
888 signature: Sig,
889 args: &[Value],
890 varargs: &[Abi],
891 ) -> Inst {
892 let varargs = self.func.push_abis(varargs);
893 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
894 let returns: Vec<Type> = self.func[signature].return_types().collect();
895 let args = self.func.push_values(args);
896 self.inst(
897 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
898 &returns,
899 )
900 }
901
902 pub fn inline_asm(
908 &mut self,
909 info: AsmInfo,
910 args: &[Value],
911 results: &[Type],
912 flags: Flags,
913 ) -> Inst {
914 let info = self.func.add_asm(info);
915 let args = self.func.push_values(args);
916 self.inst(
917 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
918 results,
919 )
920 }
921
922 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
923 BlockCall { block, args: self.func.push_values(args) }
924 }
925}
926
927#[cfg(test)]
928mod tests {
929 use rucc_base::Interner;
930
931 use super::*;
932 use crate::MemOrder;
933 use crate::inst::BlockCallList;
934
935 fn sum() -> (Func, Block, Block, Block) {
937 let mut names = Interner::new();
938 let i32_ = Type::int(32);
939 let mut func = Func::new(
940 names.intern("sum"),
941 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
942 );
943
944 let entry = func.create_block();
945 let n = func.append_param(entry, i32_);
946 let header = func.create_block();
947 let acc = func.append_param(header, i32_);
948 let i = func.append_param(header, i32_);
949 let exit = func.create_block();
950 let result = func.append_param(exit, i32_);
951
952 let mut b = Builder::new(&mut func, entry);
953 let zero = b.iconst(i32_, 0);
954 let cmp = b.icmp(IntPred::Sle, n, zero);
955 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
956
957 let mut b = Builder::new(&mut func, header);
958 let one = b.iconst(i32_, 1);
959 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
960 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
961 let done = b.icmp(IntPred::Sge, next, n);
962 b.br_if(done, exit, &[total], header, &[total, next]);
963
964 let mut b = Builder::new(&mut func, exit);
965 b.ret(&[result]);
966
967 (func, entry, header, exit)
968 }
969
970 #[test]
971 fn the_blocks_come_back_in_the_order_they_were_made() {
972 let (func, entry, header, exit) = sum();
973 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
974 assert_eq!(func.entry(), Some(entry));
975 }
976
977 #[test]
978 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
979 let (mut func, entry, header, exit) = sum();
980 let inside: Vec<Inst> = func.insts(header).collect();
981 func.remove_block(header);
982 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
983 assert_eq!(func.entry(), Some(entry));
984 assert_eq!(func[entry].next, Some(exit));
985 assert_eq!(func[exit].prev, Some(entry));
986 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
988 assert!(func.insts(header).next().is_none());
989 }
990
991 #[test]
992 fn each_block_holds_what_was_appended_to_it() {
993 let (func, entry, header, exit) = sum();
994 let opcodes =
995 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
996 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
997 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
998 assert_eq!(opcodes(exit), ["return"]);
999 }
1000
1001 #[test]
1002 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1003 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1006 let block = func.create_block();
1007 let plain = func.add_asm(AsmInfo {
1008 template: Symbol::from_raw(0),
1009 constraints: Symbol::from_raw(0),
1010 clobbers: Symbol::from_raw(0),
1011 targets: BlockCallList::EMPTY,
1012 });
1013 let call = BlockCall { block, args: ValueList::EMPTY };
1014 let targets = func.push_block_calls(&[call]);
1015 let labelled = func.add_asm(AsmInfo {
1016 template: Symbol::from_raw(0),
1017 constraints: Symbol::from_raw(0),
1018 clobbers: Symbol::from_raw(0),
1019 targets,
1020 });
1021
1022 let mut make = |extra| {
1023 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1024 func.create_inst(data, &[], Span::DUMMY)
1025 };
1026 let plain = make(Extra::Asm(plain));
1027 let labelled = make(Extra::Asm(labelled));
1028 assert!(!func.is_terminator(plain));
1029 assert!(func.is_terminator(labelled));
1030 }
1031
1032 #[test]
1033 fn every_block_ends_in_its_terminator() {
1034 let (func, entry, header, exit) = sum();
1035 for block in [entry, header, exit] {
1036 let last = func.terminator(block).expect("a terminator");
1037 assert_eq!(Some(last), func.insts(block).last());
1038 }
1039 }
1040
1041 #[test]
1042 fn a_branch_carries_the_arguments_the_block_takes() {
1043 let (func, entry, header, _) = sum();
1044 let br = func.terminator(entry).expect("a terminator");
1045 let calls: Vec<BlockCall> = func.successors(br).collect();
1046 assert_eq!(calls.len(), 2);
1047 assert_eq!(calls[1].block, header);
1049 assert_eq!(func[calls[1].args].len(), 2);
1050 assert_eq!(func[header].params.len(), 2);
1051 assert_eq!(func[calls[0].args].len(), 1);
1052 }
1053
1054 #[test]
1055 fn a_value_knows_what_defined_it() {
1056 let (func, entry, _, _) = sum();
1057 let first = func.insts(entry).next().expect("an instruction");
1058 let value = func[first].first_result.expect("a result");
1059 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1060 assert_eq!(func[value].ty, Type::int(32));
1061
1062 let param = func[entry].params[0];
1063 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1064 }
1065
1066 #[test]
1067 fn a_comparison_produces_one_bit() {
1068 let (func, entry, _, _) = sum();
1069 let cmp = func.insts(entry).nth(1).expect("the comparison");
1070 let value = func[cmp].first_result.expect("a result");
1071 assert_eq!(func[value].ty, Type::I1);
1072 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1073 }
1074
1075 #[test]
1076 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1077 let (func, _, header, _) = sum();
1078 let add = func.insts(header).nth(1).expect("the addition");
1079 assert_eq!(func[add].flags, Flags::NSW);
1080 let cmp = func.insts(header).nth(3).expect("the comparison");
1081 assert_eq!(func[cmp].flags, Flags::NONE);
1082 }
1083
1084 #[test]
1085 fn removing_an_instruction_takes_it_out_of_the_middle() {
1086 let (mut func, _, header, _) = sum();
1087 let add = func.insts(header).nth(1).expect("the addition");
1088 func.remove_inst(add);
1089 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1090 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1091 assert_eq!(func.block_of(add), None);
1092 }
1093
1094 #[test]
1095 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1096 let (mut func, entry, _, _) = sum();
1097 let first = func.insts(entry).next().expect("an instruction");
1098 let last = func.terminator(entry).expect("a terminator");
1099 func.remove_inst(first);
1100 func.remove_inst(last);
1101 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1102 assert_eq!(opcodes, ["icmp"]);
1103 assert_eq!(func[entry].first, func[entry].last);
1104 }
1105
1106 #[test]
1107 fn removing_the_only_instruction_empties_the_block() {
1108 let (mut func, _, _, exit) = sum();
1109 let only = func.insts(exit).next().expect("an instruction");
1110 func.remove_inst(only);
1111 assert_eq!(func.insts(exit).count(), 0);
1112 assert_eq!(func[exit].first, None);
1113 assert_eq!(func[exit].last, None);
1114 }
1115
1116 #[test]
1117 fn inserting_before_puts_it_in_the_right_place() {
1118 let (mut func, entry, _, _) = sum();
1119 let cmp = func.insts(entry).nth(1).expect("the comparison");
1120 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1121 func.insert_before(made, cmp);
1122 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1123 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1124 }
1125
1126 #[test]
1127 fn inserting_before_the_first_makes_it_the_first() {
1128 let (mut func, entry, _, _) = sum();
1129 let first = func.insts(entry).next().expect("an instruction");
1130 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1131 func.insert_before(made, first);
1132 assert_eq!(func.insts(entry).next(), Some(made));
1133 assert_eq!(func[entry].first, Some(made));
1134 }
1135
1136 #[test]
1137 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1138 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1139 let block = func.create_block();
1140 let a = func.append_param(block, Type::int(32));
1141 let b = func.append_param(block, Type::int(32));
1142 let list = func.push_values(&[a]);
1143 let grown = func.append_arg(list, b);
1144 assert_eq!(func[grown], [a, b]);
1145 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1146 }
1147
1148 #[test]
1149 fn a_list_is_copied_when_something_is_behind_it() {
1150 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1151 let block = func.create_block();
1152 let a = func.append_param(block, Type::int(32));
1153 let b = func.append_param(block, Type::int(32));
1154 let list = func.push_values(&[a, a]);
1155 let behind = func.push_values(&[b]);
1156 let grown = func.append_arg(list, b);
1157 assert_eq!(func[grown], [a, a, b]);
1158 assert_eq!(func[list], [a, a], "the old run is still readable");
1159 assert_eq!(func[behind], [b], "and so is what was behind it");
1160 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1161 }
1162
1163 #[test]
1164 fn a_parameter_added_late_is_the_next_one_along() {
1165 let (mut func, entry, header, _) = sum();
1169 let extra = func.append_param(header, Type::int(32));
1170 assert_eq!(func[header].params.len(), 3);
1171 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1172
1173 let br = func.terminator(entry).expect("a terminator");
1174 let call = func.successors(br).nth(1).expect("the branch to the header");
1175 let grown = func.append_arg(call.args, extra);
1176 assert_eq!(func[grown].len(), 3);
1177 }
1178
1179 #[test]
1180 fn a_span_rides_along_with_the_instruction() {
1181 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1182 let block = func.create_block();
1183 let span = Span::new(10, 20);
1184 let mut b = Builder::new(&mut func, block).at(span);
1185 let value = b.iconst(Type::int(32), 7);
1186 let inst = match func[value].def {
1187 Def::Result { inst, .. } => inst,
1188 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1189 };
1190 assert_eq!(func.span(inst), span);
1191 }
1192
1193 #[test]
1194 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1195 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1196 let block = func.create_block();
1197 let addr = func.append_param(block, Type::PTR);
1198 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1199 let mut b = Builder::new(&mut func, block);
1200 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1201 let store = b.store(value, addr, info, Flags::VOLATILE);
1202 assert_eq!(func[store].results, 0);
1203 assert_eq!(func[store].flags, Flags::VOLATILE);
1204 assert_eq!(func[value].ty, Type::int(32));
1205 }
1206
1207 #[test]
1208 fn a_call_produces_what_its_signature_returns() {
1209 let mut names = Interner::new();
1210 let mut func = Func::new(names.intern("caller"), Signature::new());
1211 let sig = func.add_signature(
1212 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1213 );
1214 let block = func.create_block();
1215 let arg = func.append_param(block, Type::int(32));
1216 let callee = names.intern("callee");
1217 let mut b = Builder::new(&mut func, block);
1218 let call = b.call(callee, sig, &[arg]);
1219 assert_eq!(func[call].results, 1);
1220 let value = func[call].first_result.expect("a result");
1221 assert_eq!(func[value].ty, Type::int(64));
1222 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1223 }
1224
1225 #[test]
1226 fn the_counts_are_what_was_made() {
1227 let (func, _, _, _) = sum();
1228 let counts = func.counts();
1229 assert_eq!(counts.blocks, 3);
1230 assert_eq!(counts.insts, 9);
1231 assert_eq!(counts.values, 4 + 6);
1234 }
1235
1236 #[test]
1237 #[should_panic(expected = "the instruction is in a block")]
1238 fn appending_an_instruction_twice_is_refused() {
1239 let (mut func, entry, _, _) = sum();
1240 let first = func.insts(entry).next().expect("an instruction");
1241 func.append_inst(entry, first);
1242 }
1243
1244 #[test]
1245 #[should_panic(expected = "the instruction is not in a block")]
1246 fn removing_an_instruction_twice_is_refused() {
1247 let (mut func, entry, _, _) = sum();
1248 let first = func.insts(entry).next().expect("an instruction");
1249 func.remove_inst(first);
1250 func.remove_inst(first);
1251 }
1252}