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 align: Option<u32>,
62 pub attrs: Attrs,
65
66 values: Vec<ValueData>,
67 insts: Vec<InstData>,
68 inst_layout: Vec<InstLayout>,
69 inst_spans: Vec<Span>,
70 blocks: Vec<BlockData>,
71
72 value_pool: Vec<Value>,
73 block_calls: Vec<BlockCall>,
74 imms: Vec<Imm>,
75 mem: Vec<MemInfo>,
76 calls: Vec<CallInfo>,
77 abis: Vec<Abi>,
78 switches: Vec<SwitchInfo>,
79 asms: Vec<AsmInfo>,
80 slots: Vec<Slot>,
81 va_objects: Vec<VaInfo>,
82 signatures: Vec<Signature>,
83
84 first_block: Option<Block>,
85 last_block: Option<Block>,
86}
87
88impl Func {
89 #[must_use]
96 pub fn new(name: Symbol, signature: Signature) -> Self {
97 Self {
98 name,
99 linkage: Linkage::External,
100 visibility: Visibility::Default,
101 section: None,
102 align: None,
103 attrs: Attrs::NONE,
104 values: Vec::new(),
105 insts: Vec::new(),
106 inst_layout: Vec::new(),
107 inst_spans: Vec::new(),
108 blocks: Vec::new(),
109 value_pool: Vec::new(),
110 block_calls: Vec::new(),
111 imms: Vec::new(),
112 mem: Vec::new(),
113 calls: Vec::new(),
114 abis: Vec::new(),
115 switches: Vec::new(),
116 asms: Vec::new(),
117 slots: Vec::new(),
118 va_objects: Vec::new(),
119 signatures: vec![signature],
120 first_block: None,
121 last_block: None,
122 }
123 }
124
125 #[must_use]
127 pub fn signature(&self) -> &Signature {
128 &self.signatures[0]
129 }
130
131 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
133 self.signatures.iter()
134 }
135
136 pub fn add_signature(&mut self, signature: Signature) -> Sig {
138 self.signatures.push(signature);
139 Idx::from_usize(self.signatures.len() - 1)
140 }
141
142 #[must_use]
147 pub fn entry(&self) -> Option<Block> {
148 self.first_block
149 }
150
151 #[must_use]
158 pub fn is_declaration(&self) -> bool {
159 self.first_block.is_none()
160 }
161
162 pub fn create_block(&mut self) -> Block {
166 let block = Idx::from_usize(self.blocks.len());
167 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
168 match self.last_block {
169 Some(last) => self.blocks[last.index()].next = Some(block),
170 None => self.first_block = Some(block),
171 }
172 self.last_block = Some(block);
173 block
174 }
175
176 pub fn remove_block(&mut self, block: Block) {
189 assert!(self.first_block != Some(block), "the entry block is not removable");
190 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
191 match prev {
192 Some(prev) => self.blocks[prev.index()].next = next,
193 None => self.first_block = next,
194 }
195 match next {
196 Some(next) => self.blocks[next.index()].prev = prev,
197 None => self.last_block = prev,
198 }
199 let insts: Vec<Inst> = self.insts(block).collect();
203 for inst in insts {
204 self.inst_layout[inst.index()] = InstLayout::default();
205 }
206 self.blocks[block.index()] = BlockData::default();
207 }
208
209 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
218 let index = u32::try_from(self.blocks[block.index()].params.len())
219 .expect("a block with four billion parameters");
220 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
221 self.blocks[block.index()].params.push(value);
222 value
223 }
224
225 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
237 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
238 params.retain(|&value| keep(value));
239 for (index, &value) in params.iter().enumerate() {
240 let index = u32::try_from(index).expect("a block with four billion parameters");
241 self.values[value.index()].def = Def::Param { block, index };
242 }
243 self.blocks[block.index()].params = params;
244 }
245
246 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
248 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
249 }
250
251 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
253 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
254 self.inst_layout[inst.index()].next
255 })
256 }
257
258 #[must_use]
260 pub fn terminator(&self, block: Block) -> Option<Inst> {
261 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
262 }
263
264 #[must_use]
270 pub fn is_terminator(&self, inst: Inst) -> bool {
271 let data = &self[inst];
272 match data.extra {
273 Extra::Asm(info) => {
274 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
275 }
276 _ => data.opcode.is_terminator(),
277 }
278 }
279
280 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
291 let inst = Idx::from_usize(self.insts.len());
292 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
293 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
294 for (index, &ty) in results.iter().enumerate() {
295 let index = u8::try_from(index).expect("checked just above");
296 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
297 }
298 self.insts.push(data);
299 self.inst_layout.push(InstLayout::default());
300 self.inst_spans.push(span);
301 inst
302 }
303
304 pub fn append_inst(&mut self, block: Block, inst: Inst) {
311 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
312 let last = self.blocks[block.index()].last;
313 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
314 match last {
315 Some(last) => self.inst_layout[last.index()].next = Some(inst),
316 None => self.blocks[block.index()].first = Some(inst),
317 }
318 self.blocks[block.index()].last = Some(inst);
319 }
320
321 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
327 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
328 let at = self.inst_layout[before.index()];
329 let block = at.block.expect("the instruction to insert before is not in a block");
330 self.inst_layout[inst.index()] =
331 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
332 self.inst_layout[before.index()].prev = Some(inst);
333 match at.prev {
334 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
335 None => self.blocks[block.index()].first = Some(inst),
336 }
337 }
338
339 pub fn remove_inst(&mut self, inst: Inst) {
349 let at = self.inst_layout[inst.index()];
350 let block = at.block.expect("the instruction is not in a block");
351 match at.prev {
352 Some(prev) => self.inst_layout[prev.index()].next = at.next,
353 None => self.blocks[block.index()].first = at.next,
354 }
355 match at.next {
356 Some(next) => self.inst_layout[next.index()].prev = at.prev,
357 None => self.blocks[block.index()].last = at.prev,
358 }
359 self.inst_layout[inst.index()] = InstLayout::default();
360 }
361
362 #[must_use]
364 pub fn block_of(&self, inst: Inst) -> Option<Block> {
365 self.inst_layout[inst.index()].block
366 }
367
368 #[must_use]
370 pub fn span(&self, inst: Inst) -> Span {
371 self.inst_spans[inst.index()]
372 }
373
374 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
379 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
380 }
381
382 #[must_use]
389 pub fn target_list(&self, inst: Inst) -> BlockCallList {
390 match self[inst].extra {
391 Extra::Targets(targets) => targets,
392 Extra::Switch(info) => self.switches[info.index()].targets,
393 Extra::Asm(info) => self.asms[info.index()].targets,
394 _ => BlockCallList::EMPTY,
395 }
396 }
397
398 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
402 let start = Idx::from_usize(self.value_pool.len());
403 self.value_pool.extend_from_slice(values);
404 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
405 }
406
407 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
414 let range = list.as_usize_range();
415 if range.end == self.value_pool.len() {
416 self.value_pool.push(value);
417 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
418 }
419 let start = self.value_pool.len();
420 self.value_pool.extend_from_within(range);
421 self.value_pool.push(value);
422 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
423 }
424
425 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
430 for value in &mut self.value_pool[list.as_usize_range()] {
431 *value = with(*value);
432 }
433 }
434
435 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
437 let start = Idx::from_usize(self.block_calls.len());
438 self.block_calls.extend_from_slice(calls);
439 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
440 }
441
442 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
444 self.block_calls[at.index()] = call;
445 }
446
447 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
449 let start = Idx::from_usize(self.imms.len());
450 self.imms.extend_from_slice(imms);
451 ImmList::new(start, Idx::from_usize(self.imms.len()))
452 }
453
454 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
456 self.imms.push(imm);
457 Idx::from_usize(self.imms.len() - 1)
458 }
459
460 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
462 let start = Idx::from_usize(self.slots.len());
463 self.slots.extend_from_slice(slots);
464 SlotList::new(start, Idx::from_usize(self.slots.len()))
465 }
466
467 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
469 self.va_objects.push(info);
470 Idx::from_usize(self.va_objects.len() - 1)
471 }
472
473 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
475 self.mem.push(info);
476 Idx::from_usize(self.mem.len() - 1)
477 }
478
479 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
481 let start = Idx::from_usize(self.abis.len());
482 self.abis.extend_from_slice(abis);
483 AbiList::new(start, Idx::from_usize(self.abis.len()))
484 }
485
486 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
488 self.calls.push(info);
489 Idx::from_usize(self.calls.len() - 1)
490 }
491
492 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
494 self.switches.push(info);
495 Idx::from_usize(self.switches.len() - 1)
496 }
497
498 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
500 self.asms.push(info);
501 Idx::from_usize(self.asms.len() - 1)
502 }
503
504 #[must_use]
507 pub fn counts(&self) -> Counts {
508 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
509 }
510
511 fn add_value(&mut self, data: ValueData) -> Value {
512 self.values.push(data);
513 Idx::from_usize(self.values.len() - 1)
514 }
515}
516
517#[derive(Clone, Copy, Debug, PartialEq, Eq)]
519pub struct Counts {
520 pub values: usize,
522 pub insts: usize,
524 pub blocks: usize,
526}
527
528impl Index<Value> for Func {
531 type Output = ValueData;
532
533 fn index(&self, value: Value) -> &ValueData {
534 &self.values[value.index()]
535 }
536}
537
538impl Index<Inst> for Func {
539 type Output = InstData;
540
541 fn index(&self, inst: Inst) -> &InstData {
542 &self.insts[inst.index()]
543 }
544}
545
546impl IndexMut<Inst> for Func {
547 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
548 &mut self.insts[inst.index()]
549 }
550}
551
552impl Index<Block> for Func {
553 type Output = BlockData;
554
555 fn index(&self, block: Block) -> &BlockData {
556 &self.blocks[block.index()]
557 }
558}
559
560impl Index<Sig> for Func {
561 type Output = Signature;
562
563 fn index(&self, sig: Sig) -> &Signature {
564 &self.signatures[sig.index()]
565 }
566}
567
568impl Index<ValueList> for Func {
569 type Output = [Value];
570
571 fn index(&self, list: ValueList) -> &[Value] {
572 &self.value_pool[list.as_usize_range()]
573 }
574}
575
576impl Index<BlockCallList> for Func {
577 type Output = [BlockCall];
578
579 fn index(&self, list: BlockCallList) -> &[BlockCall] {
580 &self.block_calls[list.as_usize_range()]
581 }
582}
583
584impl Index<Idx<BlockCall>> for Func {
585 type Output = BlockCall;
586
587 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
588 &self.block_calls[at.index()]
589 }
590}
591
592impl Index<ImmList> for Func {
593 type Output = [Imm];
594
595 fn index(&self, list: ImmList) -> &[Imm] {
596 &self.imms[list.as_usize_range()]
597 }
598}
599
600impl Index<Idx<Imm>> for Func {
601 type Output = Imm;
602
603 fn index(&self, at: Idx<Imm>) -> &Imm {
604 &self.imms[at.index()]
605 }
606}
607
608impl Index<Idx<MemInfo>> for Func {
609 type Output = MemInfo;
610
611 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
612 &self.mem[at.index()]
613 }
614}
615
616impl Index<AbiList> for Func {
617 type Output = [Abi];
618
619 fn index(&self, list: AbiList) -> &[Abi] {
620 &self.abis[list.as_usize_range()]
621 }
622}
623
624impl Index<SlotList> for Func {
625 type Output = [Slot];
626
627 fn index(&self, list: SlotList) -> &[Slot] {
628 &self.slots[list.as_usize_range()]
629 }
630}
631
632impl Index<Idx<VaInfo>> for Func {
633 type Output = VaInfo;
634
635 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
636 &self.va_objects[at.index()]
637 }
638}
639
640impl Index<Idx<CallInfo>> for Func {
641 type Output = CallInfo;
642
643 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
644 &self.calls[at.index()]
645 }
646}
647
648impl Index<Idx<SwitchInfo>> for Func {
649 type Output = SwitchInfo;
650
651 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
652 &self.switches[at.index()]
653 }
654}
655
656impl Index<Idx<AsmInfo>> for Func {
657 type Output = AsmInfo;
658
659 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
660 &self.asms[at.index()]
661 }
662}
663
664#[derive(Debug)]
671pub struct Builder<'a> {
672 func: &'a mut Func,
673 block: Block,
674 span: Span,
675}
676
677impl<'a> Builder<'a> {
678 pub fn new(func: &'a mut Func, block: Block) -> Self {
680 Self { func, block, span: Span::DUMMY }
681 }
682
683 #[must_use]
685 pub fn at(mut self, span: Span) -> Self {
686 self.span = span;
687 self
688 }
689
690 pub fn set_span(&mut self, span: Span) {
692 self.span = span;
693 }
694
695 pub fn func(&mut self) -> &mut Func {
697 self.func
698 }
699
700 #[must_use]
702 pub fn block(&self) -> Block {
703 self.block
704 }
705
706 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
708 let inst = self.func.create_inst(data, results, self.span);
709 self.func.append_inst(self.block, inst);
710 inst
711 }
712
713 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
719 let inst = self.inst(data, &[ty]);
720 self.func[inst].first_result.expect("one result was asked for")
721 }
722
723 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
729 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
730 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
731 }
732
733 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
735 let imm = self.func.add_imm(Imm::from_bits(bits));
736 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
737 }
738
739 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
741 let ty = self.func[lhs].ty;
742 let args = self.func.push_values(&[lhs, rhs]);
743 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
744 }
745
746 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
748 let args = self.func.push_values(&[arg]);
749 self.value(InstData { args, ..InstData::new(opcode) }, ty)
750 }
751
752 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
754 let ty = self.func[lhs].ty.with_lane(Type::I1);
755 let args = self.func.push_values(&[lhs, rhs]);
756 self.value(
757 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
758 ty,
759 )
760 }
761
762 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
764 let ty = self.func[lhs].ty.with_lane(Type::I1);
765 let args = self.func.push_values(&[lhs, rhs]);
766 self.value(
767 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
768 ty,
769 )
770 }
771
772 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
774 let mem = self.func.add_mem(info);
775 let args = self.func.push_values(&[addr]);
776 self.value(
777 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
778 ty,
779 )
780 }
781
782 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
784 let mem = self.func.add_mem(info);
785 let args = self.func.push_values(&[value, addr]);
786 self.inst(
787 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
788 &[],
789 )
790 }
791
792 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
794 let call = self.block_call(target, args);
795 let targets = self.func.push_block_calls(&[call]);
796 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
797 }
798
799 pub fn block_addr(&mut self, target: Block) -> Value {
805 let call = self.block_call(target, &[]);
806 let targets = self.func.push_block_calls(&[call]);
807 self.value(
808 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
809 Type::PTR,
810 )
811 }
812
813 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
819 let calls: Vec<BlockCall> =
820 targets.iter().map(|&target| self.block_call(target, &[])).collect();
821 let targets = self.func.push_block_calls(&calls);
822 let args = self.func.push_values(&[addr]);
823 self.inst(
824 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
825 &[],
826 )
827 }
828
829 pub fn br_if(
831 &mut self,
832 cond: Value,
833 then_block: Block,
834 then_args: &[Value],
835 else_block: Block,
836 else_args: &[Value],
837 ) -> Inst {
838 let then_call = self.block_call(then_block, then_args);
839 let else_call = self.block_call(else_block, else_args);
840 let targets = self.func.push_block_calls(&[then_call, else_call]);
841 let args = self.func.push_values(&[cond]);
842 self.inst(
843 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
844 &[],
845 )
846 }
847
848 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
855 let ty = self.func[value].ty.lane();
856 let mut calls = vec![self.block_call(default, &[])];
857 let mut values = Vec::with_capacity(cases.len());
858 for &(value, block) in cases {
859 calls.push(self.block_call(block, &[]));
860 values.push(Imm::int(value, ty));
861 }
862 let targets = self.func.push_block_calls(&calls);
863 let cases = self.func.push_imms(&values);
864 let info = self.func.add_switch(SwitchInfo { targets, cases });
865 let args = self.func.push_values(&[value]);
866 self.inst(
867 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
868 &[],
869 )
870 }
871
872 pub fn ret(&mut self, values: &[Value]) -> Inst {
874 let args = self.func.push_values(values);
875 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
876 }
877
878 pub fn unreachable(&mut self) -> Inst {
880 self.inst(InstData::new(Opcode::Unreachable), &[])
881 }
882
883 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
885 self.call_varargs(callee, signature, args, &[])
886 }
887
888 pub fn call_varargs(
894 &mut self,
895 callee: Symbol,
896 signature: Sig,
897 args: &[Value],
898 varargs: &[Abi],
899 ) -> Inst {
900 let varargs = self.func.push_abis(varargs);
901 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
902 let returns: Vec<Type> = self.func[signature].return_types().collect();
903 let args = self.func.push_values(args);
904 self.inst(
905 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
906 &returns,
907 )
908 }
909
910 pub fn inline_asm(
916 &mut self,
917 info: AsmInfo,
918 args: &[Value],
919 results: &[Type],
920 flags: Flags,
921 ) -> Inst {
922 let info = self.func.add_asm(info);
923 let args = self.func.push_values(args);
924 self.inst(
925 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
926 results,
927 )
928 }
929
930 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
931 BlockCall { block, args: self.func.push_values(args) }
932 }
933}
934
935#[cfg(test)]
936mod tests {
937 use rucc_base::Interner;
938
939 use super::*;
940 use crate::MemOrder;
941 use crate::inst::BlockCallList;
942
943 fn sum() -> (Func, Block, Block, Block) {
945 let mut names = Interner::new();
946 let i32_ = Type::int(32);
947 let mut func = Func::new(
948 names.intern("sum"),
949 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
950 );
951
952 let entry = func.create_block();
953 let n = func.append_param(entry, i32_);
954 let header = func.create_block();
955 let acc = func.append_param(header, i32_);
956 let i = func.append_param(header, i32_);
957 let exit = func.create_block();
958 let result = func.append_param(exit, i32_);
959
960 let mut b = Builder::new(&mut func, entry);
961 let zero = b.iconst(i32_, 0);
962 let cmp = b.icmp(IntPred::Sle, n, zero);
963 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
964
965 let mut b = Builder::new(&mut func, header);
966 let one = b.iconst(i32_, 1);
967 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
968 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
969 let done = b.icmp(IntPred::Sge, next, n);
970 b.br_if(done, exit, &[total], header, &[total, next]);
971
972 let mut b = Builder::new(&mut func, exit);
973 b.ret(&[result]);
974
975 (func, entry, header, exit)
976 }
977
978 #[test]
979 fn the_blocks_come_back_in_the_order_they_were_made() {
980 let (func, entry, header, exit) = sum();
981 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
982 assert_eq!(func.entry(), Some(entry));
983 }
984
985 #[test]
986 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
987 let (mut func, entry, header, exit) = sum();
988 let inside: Vec<Inst> = func.insts(header).collect();
989 func.remove_block(header);
990 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
991 assert_eq!(func.entry(), Some(entry));
992 assert_eq!(func[entry].next, Some(exit));
993 assert_eq!(func[exit].prev, Some(entry));
994 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
996 assert!(func.insts(header).next().is_none());
997 }
998
999 #[test]
1000 fn each_block_holds_what_was_appended_to_it() {
1001 let (func, entry, header, exit) = sum();
1002 let opcodes =
1003 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1004 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1005 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1006 assert_eq!(opcodes(exit), ["return"]);
1007 }
1008
1009 #[test]
1010 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1011 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1014 let block = func.create_block();
1015 let plain = func.add_asm(AsmInfo {
1016 template: Symbol::from_raw(0),
1017 constraints: Symbol::from_raw(0),
1018 clobbers: Symbol::from_raw(0),
1019 targets: BlockCallList::EMPTY,
1020 });
1021 let call = BlockCall { block, args: ValueList::EMPTY };
1022 let targets = func.push_block_calls(&[call]);
1023 let labelled = func.add_asm(AsmInfo {
1024 template: Symbol::from_raw(0),
1025 constraints: Symbol::from_raw(0),
1026 clobbers: Symbol::from_raw(0),
1027 targets,
1028 });
1029
1030 let mut make = |extra| {
1031 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1032 func.create_inst(data, &[], Span::DUMMY)
1033 };
1034 let plain = make(Extra::Asm(plain));
1035 let labelled = make(Extra::Asm(labelled));
1036 assert!(!func.is_terminator(plain));
1037 assert!(func.is_terminator(labelled));
1038 }
1039
1040 #[test]
1041 fn every_block_ends_in_its_terminator() {
1042 let (func, entry, header, exit) = sum();
1043 for block in [entry, header, exit] {
1044 let last = func.terminator(block).expect("a terminator");
1045 assert_eq!(Some(last), func.insts(block).last());
1046 }
1047 }
1048
1049 #[test]
1050 fn a_branch_carries_the_arguments_the_block_takes() {
1051 let (func, entry, header, _) = sum();
1052 let br = func.terminator(entry).expect("a terminator");
1053 let calls: Vec<BlockCall> = func.successors(br).collect();
1054 assert_eq!(calls.len(), 2);
1055 assert_eq!(calls[1].block, header);
1057 assert_eq!(func[calls[1].args].len(), 2);
1058 assert_eq!(func[header].params.len(), 2);
1059 assert_eq!(func[calls[0].args].len(), 1);
1060 }
1061
1062 #[test]
1063 fn a_value_knows_what_defined_it() {
1064 let (func, entry, _, _) = sum();
1065 let first = func.insts(entry).next().expect("an instruction");
1066 let value = func[first].first_result.expect("a result");
1067 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1068 assert_eq!(func[value].ty, Type::int(32));
1069
1070 let param = func[entry].params[0];
1071 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1072 }
1073
1074 #[test]
1075 fn a_comparison_produces_one_bit() {
1076 let (func, entry, _, _) = sum();
1077 let cmp = func.insts(entry).nth(1).expect("the comparison");
1078 let value = func[cmp].first_result.expect("a result");
1079 assert_eq!(func[value].ty, Type::I1);
1080 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1081 }
1082
1083 #[test]
1084 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1085 let (func, _, header, _) = sum();
1086 let add = func.insts(header).nth(1).expect("the addition");
1087 assert_eq!(func[add].flags, Flags::NSW);
1088 let cmp = func.insts(header).nth(3).expect("the comparison");
1089 assert_eq!(func[cmp].flags, Flags::NONE);
1090 }
1091
1092 #[test]
1093 fn removing_an_instruction_takes_it_out_of_the_middle() {
1094 let (mut func, _, header, _) = sum();
1095 let add = func.insts(header).nth(1).expect("the addition");
1096 func.remove_inst(add);
1097 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1098 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1099 assert_eq!(func.block_of(add), None);
1100 }
1101
1102 #[test]
1103 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1104 let (mut func, entry, _, _) = sum();
1105 let first = func.insts(entry).next().expect("an instruction");
1106 let last = func.terminator(entry).expect("a terminator");
1107 func.remove_inst(first);
1108 func.remove_inst(last);
1109 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1110 assert_eq!(opcodes, ["icmp"]);
1111 assert_eq!(func[entry].first, func[entry].last);
1112 }
1113
1114 #[test]
1115 fn removing_the_only_instruction_empties_the_block() {
1116 let (mut func, _, _, exit) = sum();
1117 let only = func.insts(exit).next().expect("an instruction");
1118 func.remove_inst(only);
1119 assert_eq!(func.insts(exit).count(), 0);
1120 assert_eq!(func[exit].first, None);
1121 assert_eq!(func[exit].last, None);
1122 }
1123
1124 #[test]
1125 fn inserting_before_puts_it_in_the_right_place() {
1126 let (mut func, entry, _, _) = sum();
1127 let cmp = func.insts(entry).nth(1).expect("the comparison");
1128 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1129 func.insert_before(made, cmp);
1130 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1131 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1132 }
1133
1134 #[test]
1135 fn inserting_before_the_first_makes_it_the_first() {
1136 let (mut func, entry, _, _) = sum();
1137 let first = func.insts(entry).next().expect("an instruction");
1138 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1139 func.insert_before(made, first);
1140 assert_eq!(func.insts(entry).next(), Some(made));
1141 assert_eq!(func[entry].first, Some(made));
1142 }
1143
1144 #[test]
1145 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1146 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1147 let block = func.create_block();
1148 let a = func.append_param(block, Type::int(32));
1149 let b = func.append_param(block, Type::int(32));
1150 let list = func.push_values(&[a]);
1151 let grown = func.append_arg(list, b);
1152 assert_eq!(func[grown], [a, b]);
1153 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1154 }
1155
1156 #[test]
1157 fn a_list_is_copied_when_something_is_behind_it() {
1158 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1159 let block = func.create_block();
1160 let a = func.append_param(block, Type::int(32));
1161 let b = func.append_param(block, Type::int(32));
1162 let list = func.push_values(&[a, a]);
1163 let behind = func.push_values(&[b]);
1164 let grown = func.append_arg(list, b);
1165 assert_eq!(func[grown], [a, a, b]);
1166 assert_eq!(func[list], [a, a], "the old run is still readable");
1167 assert_eq!(func[behind], [b], "and so is what was behind it");
1168 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1169 }
1170
1171 #[test]
1172 fn a_parameter_added_late_is_the_next_one_along() {
1173 let (mut func, entry, header, _) = sum();
1177 let extra = func.append_param(header, Type::int(32));
1178 assert_eq!(func[header].params.len(), 3);
1179 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1180
1181 let br = func.terminator(entry).expect("a terminator");
1182 let call = func.successors(br).nth(1).expect("the branch to the header");
1183 let grown = func.append_arg(call.args, extra);
1184 assert_eq!(func[grown].len(), 3);
1185 }
1186
1187 #[test]
1188 fn a_span_rides_along_with_the_instruction() {
1189 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1190 let block = func.create_block();
1191 let span = Span::new(10, 20);
1192 let mut b = Builder::new(&mut func, block).at(span);
1193 let value = b.iconst(Type::int(32), 7);
1194 let inst = match func[value].def {
1195 Def::Result { inst, .. } => inst,
1196 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1197 };
1198 assert_eq!(func.span(inst), span);
1199 }
1200
1201 #[test]
1202 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1203 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1204 let block = func.create_block();
1205 let addr = func.append_param(block, Type::PTR);
1206 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1207 let mut b = Builder::new(&mut func, block);
1208 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1209 let store = b.store(value, addr, info, Flags::VOLATILE);
1210 assert_eq!(func[store].results, 0);
1211 assert_eq!(func[store].flags, Flags::VOLATILE);
1212 assert_eq!(func[value].ty, Type::int(32));
1213 }
1214
1215 #[test]
1216 fn a_call_produces_what_its_signature_returns() {
1217 let mut names = Interner::new();
1218 let mut func = Func::new(names.intern("caller"), Signature::new());
1219 let sig = func.add_signature(
1220 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1221 );
1222 let block = func.create_block();
1223 let arg = func.append_param(block, Type::int(32));
1224 let callee = names.intern("callee");
1225 let mut b = Builder::new(&mut func, block);
1226 let call = b.call(callee, sig, &[arg]);
1227 assert_eq!(func[call].results, 1);
1228 let value = func[call].first_result.expect("a result");
1229 assert_eq!(func[value].ty, Type::int(64));
1230 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1231 }
1232
1233 #[test]
1234 fn the_counts_are_what_was_made() {
1235 let (func, _, _, _) = sum();
1236 let counts = func.counts();
1237 assert_eq!(counts.blocks, 3);
1238 assert_eq!(counts.insts, 9);
1239 assert_eq!(counts.values, 4 + 6);
1242 }
1243
1244 #[test]
1245 #[should_panic(expected = "the instruction is in a block")]
1246 fn appending_an_instruction_twice_is_refused() {
1247 let (mut func, entry, _, _) = sum();
1248 let first = func.insts(entry).next().expect("an instruction");
1249 func.append_inst(entry, first);
1250 }
1251
1252 #[test]
1253 #[should_panic(expected = "the instruction is not in a block")]
1254 fn removing_an_instruction_twice_is_refused() {
1255 let (mut func, entry, _, _) = sum();
1256 let first = func.insts(entry).next().expect("an instruction");
1257 func.remove_inst(first);
1258 func.remove_inst(first);
1259 }
1260}