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, Facts, 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 facts: Vec<(Value, Facts)>,
84
85 first_block: Option<Block>,
86 last_block: Option<Block>,
87}
88
89impl Func {
90 #[must_use]
97 pub fn new(name: Symbol, signature: Signature) -> Self {
98 Self {
99 name,
100 linkage: Linkage::External,
101 visibility: Visibility::Default,
102 section: None,
103 align: None,
104 attrs: Attrs::NONE,
105 values: Vec::new(),
106 insts: Vec::new(),
107 inst_layout: Vec::new(),
108 inst_spans: Vec::new(),
109 blocks: Vec::new(),
110 value_pool: Vec::new(),
111 block_calls: Vec::new(),
112 imms: Vec::new(),
113 mem: Vec::new(),
114 calls: Vec::new(),
115 abis: Vec::new(),
116 switches: Vec::new(),
117 asms: Vec::new(),
118 slots: Vec::new(),
119 va_objects: Vec::new(),
120 signatures: vec![signature],
121 facts: Vec::new(),
122 first_block: None,
123 last_block: None,
124 }
125 }
126
127 #[must_use]
129 pub fn signature(&self) -> &Signature {
130 &self.signatures[0]
131 }
132
133 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
135 self.signatures.iter()
136 }
137
138 pub fn add_signature(&mut self, signature: Signature) -> Sig {
140 self.signatures.push(signature);
141 Idx::from_usize(self.signatures.len() - 1)
142 }
143
144 #[must_use]
149 pub fn entry(&self) -> Option<Block> {
150 self.first_block
151 }
152
153 #[must_use]
160 pub fn is_declaration(&self) -> bool {
161 self.first_block.is_none()
162 }
163
164 pub fn create_block(&mut self) -> Block {
168 let block = Idx::from_usize(self.blocks.len());
169 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
170 match self.last_block {
171 Some(last) => self.blocks[last.index()].next = Some(block),
172 None => self.first_block = Some(block),
173 }
174 self.last_block = Some(block);
175 block
176 }
177
178 pub fn remove_block(&mut self, block: Block) {
191 assert!(self.first_block != Some(block), "the entry block is not removable");
192 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
193 match prev {
194 Some(prev) => self.blocks[prev.index()].next = next,
195 None => self.first_block = next,
196 }
197 match next {
198 Some(next) => self.blocks[next.index()].prev = prev,
199 None => self.last_block = prev,
200 }
201 let insts: Vec<Inst> = self.insts(block).collect();
205 for inst in insts {
206 self.inst_layout[inst.index()] = InstLayout::default();
207 }
208 self.blocks[block.index()] = BlockData::default();
209 }
210
211 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
220 let index = u32::try_from(self.blocks[block.index()].params.len())
221 .expect("a block with four billion parameters");
222 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
223 self.blocks[block.index()].params.push(value);
224 value
225 }
226
227 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
239 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
240 params.retain(|&value| keep(value));
241 for (index, &value) in params.iter().enumerate() {
242 let index = u32::try_from(index).expect("a block with four billion parameters");
243 self.values[value.index()].def = Def::Param { block, index };
244 }
245 self.blocks[block.index()].params = params;
246 }
247
248 pub fn retype(&mut self, value: Value, ty: Type) {
260 self.values[value.index()].ty = ty;
261 }
262
263 pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
268 (0..self.values.len()).map(Idx::from_usize)
269 }
270
271 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
273 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
274 }
275
276 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
278 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
279 self.inst_layout[inst.index()].next
280 })
281 }
282
283 #[must_use]
285 pub fn terminator(&self, block: Block) -> Option<Inst> {
286 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
287 }
288
289 #[must_use]
295 pub fn is_terminator(&self, inst: Inst) -> bool {
296 let data = &self[inst];
297 match data.extra {
298 Extra::Asm(info) => {
299 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
300 }
301 _ => data.opcode.is_terminator(),
302 }
303 }
304
305 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
316 let inst = Idx::from_usize(self.insts.len());
317 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
318 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
319 for (index, &ty) in results.iter().enumerate() {
320 let index = u8::try_from(index).expect("checked just above");
321 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
322 }
323 self.insts.push(data);
324 self.inst_layout.push(InstLayout::default());
325 self.inst_spans.push(span);
326 inst
327 }
328
329 pub fn append_inst(&mut self, block: Block, inst: Inst) {
336 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
337 let last = self.blocks[block.index()].last;
338 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
339 match last {
340 Some(last) => self.inst_layout[last.index()].next = Some(inst),
341 None => self.blocks[block.index()].first = Some(inst),
342 }
343 self.blocks[block.index()].last = Some(inst);
344 }
345
346 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
352 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
353 let at = self.inst_layout[before.index()];
354 let block = at.block.expect("the instruction to insert before is not in a block");
355 self.inst_layout[inst.index()] =
356 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
357 self.inst_layout[before.index()].prev = Some(inst);
358 match at.prev {
359 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
360 None => self.blocks[block.index()].first = Some(inst),
361 }
362 }
363
364 pub fn remove_inst(&mut self, inst: Inst) {
374 let at = self.inst_layout[inst.index()];
375 let block = at.block.expect("the instruction is not in a block");
376 match at.prev {
377 Some(prev) => self.inst_layout[prev.index()].next = at.next,
378 None => self.blocks[block.index()].first = at.next,
379 }
380 match at.next {
381 Some(next) => self.inst_layout[next.index()].prev = at.prev,
382 None => self.blocks[block.index()].last = at.prev,
383 }
384 self.inst_layout[inst.index()] = InstLayout::default();
385 }
386
387 #[must_use]
389 pub fn block_of(&self, inst: Inst) -> Option<Block> {
390 self.inst_layout[inst.index()].block
391 }
392
393 #[must_use]
405 pub fn mem_in(&self, inst: Inst) -> Option<Value> {
406 let args = &self[self[inst].args];
407 args.last().copied().filter(|&arg| self[arg].ty.is_mem())
408 }
409
410 #[must_use]
420 pub fn mem_out(&self, inst: Inst) -> Option<Value> {
421 self[inst].results().last().filter(|&result| self[result].ty.is_mem())
422 }
423
424 #[must_use]
426 pub fn carries_mem(&self, inst: Inst) -> bool {
427 self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
428 }
429
430 pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
446 assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
447 assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
448 assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
449 let data = self[inst];
450 let mut args = self[data.args].to_vec();
451 args.push(incoming);
452 let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
453 if data.opcode.writes_memory() {
454 results.push(Type::MEM);
455 }
456 let span = self.span(inst);
457 let args = self.push_values(&args);
458 self.create_inst(InstData { args, ..data }, &results, span)
459 }
460
461 #[must_use]
463 pub fn span(&self, inst: Inst) -> Span {
464 self.inst_spans[inst.index()]
465 }
466
467 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
472 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
473 }
474
475 #[must_use]
482 pub fn target_list(&self, inst: Inst) -> BlockCallList {
483 match self[inst].extra {
484 Extra::Targets(targets) => targets,
485 Extra::Switch(info) => self.switches[info.index()].targets,
486 Extra::Asm(info) => self.asms[info.index()].targets,
487 _ => BlockCallList::EMPTY,
488 }
489 }
490
491 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
495 let start = Idx::from_usize(self.value_pool.len());
496 self.value_pool.extend_from_slice(values);
497 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
498 }
499
500 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
507 let range = list.as_usize_range();
508 if range.end == self.value_pool.len() {
509 self.value_pool.push(value);
510 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
511 }
512 let start = self.value_pool.len();
513 self.value_pool.extend_from_within(range);
514 self.value_pool.push(value);
515 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
516 }
517
518 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
523 for value in &mut self.value_pool[list.as_usize_range()] {
524 *value = with(*value);
525 }
526 }
527
528 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
530 let start = Idx::from_usize(self.block_calls.len());
531 self.block_calls.extend_from_slice(calls);
532 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
533 }
534
535 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
537 self.block_calls[at.index()] = call;
538 }
539
540 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
542 let start = Idx::from_usize(self.imms.len());
543 self.imms.extend_from_slice(imms);
544 ImmList::new(start, Idx::from_usize(self.imms.len()))
545 }
546
547 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
549 self.imms.push(imm);
550 Idx::from_usize(self.imms.len() - 1)
551 }
552
553 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
555 let start = Idx::from_usize(self.slots.len());
556 self.slots.extend_from_slice(slots);
557 SlotList::new(start, Idx::from_usize(self.slots.len()))
558 }
559
560 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
562 self.va_objects.push(info);
563 Idx::from_usize(self.va_objects.len() - 1)
564 }
565
566 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
568 self.mem.push(info);
569 Idx::from_usize(self.mem.len() - 1)
570 }
571
572 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
574 let start = Idx::from_usize(self.abis.len());
575 self.abis.extend_from_slice(abis);
576 AbiList::new(start, Idx::from_usize(self.abis.len()))
577 }
578
579 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
581 self.calls.push(info);
582 Idx::from_usize(self.calls.len() - 1)
583 }
584
585 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
587 self.switches.push(info);
588 Idx::from_usize(self.switches.len() - 1)
589 }
590
591 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
593 self.asms.push(info);
594 Idx::from_usize(self.asms.len() - 1)
595 }
596
597 #[must_use]
600 pub fn counts(&self) -> Counts {
601 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
602 }
603
604 #[must_use]
610 pub fn facts(&self, value: Value) -> Facts {
611 match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
612 Ok(at) => self.facts[at].1,
613 Err(_) => Facts::NONE,
614 }
615 }
616
617 pub fn set_facts(&mut self, value: Value, facts: Facts) {
622 let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
623 match (found, facts.is_empty()) {
624 (Ok(at), true) => drop(self.facts.remove(at)),
625 (Ok(at), false) => self.facts[at].1 = facts,
626 (Err(_), true) => {}
627 (Err(at), false) => self.facts.insert(at, (value, facts)),
628 }
629 }
630
631 pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
633 self.facts.iter().copied()
634 }
635
636 fn add_value(&mut self, data: ValueData) -> Value {
637 self.values.push(data);
638 Idx::from_usize(self.values.len() - 1)
639 }
640}
641
642#[derive(Clone, Copy, Debug, PartialEq, Eq)]
644pub struct Counts {
645 pub values: usize,
647 pub insts: usize,
649 pub blocks: usize,
651}
652
653impl Index<Value> for Func {
656 type Output = ValueData;
657
658 fn index(&self, value: Value) -> &ValueData {
659 &self.values[value.index()]
660 }
661}
662
663impl Index<Inst> for Func {
664 type Output = InstData;
665
666 fn index(&self, inst: Inst) -> &InstData {
667 &self.insts[inst.index()]
668 }
669}
670
671impl IndexMut<Inst> for Func {
672 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
673 &mut self.insts[inst.index()]
674 }
675}
676
677impl Index<Block> for Func {
678 type Output = BlockData;
679
680 fn index(&self, block: Block) -> &BlockData {
681 &self.blocks[block.index()]
682 }
683}
684
685impl Index<Sig> for Func {
686 type Output = Signature;
687
688 fn index(&self, sig: Sig) -> &Signature {
689 &self.signatures[sig.index()]
690 }
691}
692
693impl Index<ValueList> for Func {
694 type Output = [Value];
695
696 fn index(&self, list: ValueList) -> &[Value] {
697 &self.value_pool[list.as_usize_range()]
698 }
699}
700
701impl Index<BlockCallList> for Func {
702 type Output = [BlockCall];
703
704 fn index(&self, list: BlockCallList) -> &[BlockCall] {
705 &self.block_calls[list.as_usize_range()]
706 }
707}
708
709impl Index<Idx<BlockCall>> for Func {
710 type Output = BlockCall;
711
712 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
713 &self.block_calls[at.index()]
714 }
715}
716
717impl Index<ImmList> for Func {
718 type Output = [Imm];
719
720 fn index(&self, list: ImmList) -> &[Imm] {
721 &self.imms[list.as_usize_range()]
722 }
723}
724
725impl Index<Idx<Imm>> for Func {
726 type Output = Imm;
727
728 fn index(&self, at: Idx<Imm>) -> &Imm {
729 &self.imms[at.index()]
730 }
731}
732
733impl Index<Idx<MemInfo>> for Func {
734 type Output = MemInfo;
735
736 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
737 &self.mem[at.index()]
738 }
739}
740
741impl Index<AbiList> for Func {
742 type Output = [Abi];
743
744 fn index(&self, list: AbiList) -> &[Abi] {
745 &self.abis[list.as_usize_range()]
746 }
747}
748
749impl Index<SlotList> for Func {
750 type Output = [Slot];
751
752 fn index(&self, list: SlotList) -> &[Slot] {
753 &self.slots[list.as_usize_range()]
754 }
755}
756
757impl Index<Idx<VaInfo>> for Func {
758 type Output = VaInfo;
759
760 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
761 &self.va_objects[at.index()]
762 }
763}
764
765impl Index<Idx<CallInfo>> for Func {
766 type Output = CallInfo;
767
768 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
769 &self.calls[at.index()]
770 }
771}
772
773impl Index<Idx<SwitchInfo>> for Func {
774 type Output = SwitchInfo;
775
776 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
777 &self.switches[at.index()]
778 }
779}
780
781impl Index<Idx<AsmInfo>> for Func {
782 type Output = AsmInfo;
783
784 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
785 &self.asms[at.index()]
786 }
787}
788
789#[derive(Debug)]
796pub struct Builder<'a> {
797 func: &'a mut Func,
798 block: Block,
799 span: Span,
800}
801
802impl<'a> Builder<'a> {
803 pub fn new(func: &'a mut Func, block: Block) -> Self {
805 Self { func, block, span: Span::DUMMY }
806 }
807
808 #[must_use]
810 pub fn at(mut self, span: Span) -> Self {
811 self.span = span;
812 self
813 }
814
815 pub fn set_span(&mut self, span: Span) {
817 self.span = span;
818 }
819
820 pub fn func(&mut self) -> &mut Func {
822 self.func
823 }
824
825 #[must_use]
827 pub fn block(&self) -> Block {
828 self.block
829 }
830
831 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
833 let inst = self.func.create_inst(data, results, self.span);
834 self.func.append_inst(self.block, inst);
835 inst
836 }
837
838 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
844 let inst = self.inst(data, &[ty]);
845 self.func[inst].first_result.expect("one result was asked for")
846 }
847
848 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
854 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
855 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
856 }
857
858 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
860 let imm = self.func.add_imm(Imm::from_bits(bits));
861 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
862 }
863
864 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
866 let ty = self.func[lhs].ty;
867 let args = self.func.push_values(&[lhs, rhs]);
868 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
869 }
870
871 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
873 let args = self.func.push_values(&[arg]);
874 self.value(InstData { args, ..InstData::new(opcode) }, ty)
875 }
876
877 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
879 let ty = self.func[lhs].ty.with_lane(Type::I1);
880 let args = self.func.push_values(&[lhs, rhs]);
881 self.value(
882 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
883 ty,
884 )
885 }
886
887 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
889 let ty = self.func[lhs].ty.with_lane(Type::I1);
890 let args = self.func.push_values(&[lhs, rhs]);
891 self.value(
892 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
893 ty,
894 )
895 }
896
897 pub fn mem_entry(&mut self) -> Value {
901 self.value(InstData::new(Opcode::MemEntry), Type::MEM)
902 }
903
904 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
906 let mem = self.func.add_mem(info);
907 let args = self.func.push_values(&[addr]);
908 self.value(
909 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
910 ty,
911 )
912 }
913
914 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
916 let mem = self.func.add_mem(info);
917 let args = self.func.push_values(&[value, addr]);
918 self.inst(
919 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
920 &[],
921 )
922 }
923
924 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
926 let call = self.block_call(target, args);
927 let targets = self.func.push_block_calls(&[call]);
928 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
929 }
930
931 pub fn block_addr(&mut self, target: Block) -> Value {
937 let call = self.block_call(target, &[]);
938 let targets = self.func.push_block_calls(&[call]);
939 self.value(
940 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
941 Type::PTR,
942 )
943 }
944
945 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
951 let calls: Vec<BlockCall> =
952 targets.iter().map(|&target| self.block_call(target, &[])).collect();
953 let targets = self.func.push_block_calls(&calls);
954 let args = self.func.push_values(&[addr]);
955 self.inst(
956 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
957 &[],
958 )
959 }
960
961 pub fn br_if(
963 &mut self,
964 cond: Value,
965 then_block: Block,
966 then_args: &[Value],
967 else_block: Block,
968 else_args: &[Value],
969 ) -> Inst {
970 let then_call = self.block_call(then_block, then_args);
971 let else_call = self.block_call(else_block, else_args);
972 let targets = self.func.push_block_calls(&[then_call, else_call]);
973 let args = self.func.push_values(&[cond]);
974 self.inst(
975 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
976 &[],
977 )
978 }
979
980 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
987 let ty = self.func[value].ty.lane();
988 let mut calls = vec![self.block_call(default, &[])];
989 let mut values = Vec::with_capacity(cases.len());
990 for &(value, block) in cases {
991 calls.push(self.block_call(block, &[]));
992 values.push(Imm::int(value, ty));
993 }
994 let targets = self.func.push_block_calls(&calls);
995 let cases = self.func.push_imms(&values);
996 let info = self.func.add_switch(SwitchInfo { targets, cases });
997 let args = self.func.push_values(&[value]);
998 self.inst(
999 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1000 &[],
1001 )
1002 }
1003
1004 pub fn ret(&mut self, values: &[Value]) -> Inst {
1006 let args = self.func.push_values(values);
1007 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1008 }
1009
1010 pub fn unreachable(&mut self) -> Inst {
1012 self.inst(InstData::new(Opcode::Unreachable), &[])
1013 }
1014
1015 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1017 self.call_varargs(callee, signature, args, &[])
1018 }
1019
1020 pub fn call_varargs(
1026 &mut self,
1027 callee: Symbol,
1028 signature: Sig,
1029 args: &[Value],
1030 varargs: &[Abi],
1031 ) -> Inst {
1032 let varargs = self.func.push_abis(varargs);
1033 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1034 let returns: Vec<Type> = self.func[signature].return_types().collect();
1035 let args = self.func.push_values(args);
1036 self.inst(
1037 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1038 &returns,
1039 )
1040 }
1041
1042 pub fn inline_asm(
1048 &mut self,
1049 info: AsmInfo,
1050 args: &[Value],
1051 results: &[Type],
1052 flags: Flags,
1053 ) -> Inst {
1054 let info = self.func.add_asm(info);
1055 let args = self.func.push_values(args);
1056 self.inst(
1057 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1058 results,
1059 )
1060 }
1061
1062 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1063 BlockCall { block, args: self.func.push_values(args) }
1064 }
1065}
1066
1067#[cfg(test)]
1068mod tests {
1069 use rucc_base::Interner;
1070
1071 use super::*;
1072 use crate::inst::BlockCallList;
1073 use crate::{MemOrder, Restrict};
1074
1075 fn sum() -> (Func, Block, Block, Block) {
1077 let mut names = Interner::new();
1078 let i32_ = Type::int(32);
1079 let mut func = Func::new(
1080 names.intern("sum"),
1081 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1082 );
1083
1084 let entry = func.create_block();
1085 let n = func.append_param(entry, i32_);
1086 let header = func.create_block();
1087 let acc = func.append_param(header, i32_);
1088 let i = func.append_param(header, i32_);
1089 let exit = func.create_block();
1090 let result = func.append_param(exit, i32_);
1091
1092 let mut b = Builder::new(&mut func, entry);
1093 let zero = b.iconst(i32_, 0);
1094 let cmp = b.icmp(IntPred::Sle, n, zero);
1095 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1096
1097 let mut b = Builder::new(&mut func, header);
1098 let one = b.iconst(i32_, 1);
1099 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1100 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1101 let done = b.icmp(IntPred::Sge, next, n);
1102 b.br_if(done, exit, &[total], header, &[total, next]);
1103
1104 let mut b = Builder::new(&mut func, exit);
1105 b.ret(&[result]);
1106
1107 (func, entry, header, exit)
1108 }
1109
1110 #[test]
1111 fn the_blocks_come_back_in_the_order_they_were_made() {
1112 let (func, entry, header, exit) = sum();
1113 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1114 assert_eq!(func.entry(), Some(entry));
1115 }
1116
1117 #[test]
1118 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1119 let (mut func, entry, header, exit) = sum();
1120 let inside: Vec<Inst> = func.insts(header).collect();
1121 func.remove_block(header);
1122 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1123 assert_eq!(func.entry(), Some(entry));
1124 assert_eq!(func[entry].next, Some(exit));
1125 assert_eq!(func[exit].prev, Some(entry));
1126 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1128 assert!(func.insts(header).next().is_none());
1129 }
1130
1131 #[test]
1132 fn each_block_holds_what_was_appended_to_it() {
1133 let (func, entry, header, exit) = sum();
1134 let opcodes =
1135 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1136 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1137 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1138 assert_eq!(opcodes(exit), ["return"]);
1139 }
1140
1141 #[test]
1142 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1143 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1146 let block = func.create_block();
1147 let plain = func.add_asm(AsmInfo {
1148 template: Symbol::from_raw(0),
1149 constraints: Symbol::from_raw(0),
1150 clobbers: Symbol::from_raw(0),
1151 targets: BlockCallList::EMPTY,
1152 });
1153 let call = BlockCall { block, args: ValueList::EMPTY };
1154 let targets = func.push_block_calls(&[call]);
1155 let labelled = func.add_asm(AsmInfo {
1156 template: Symbol::from_raw(0),
1157 constraints: Symbol::from_raw(0),
1158 clobbers: Symbol::from_raw(0),
1159 targets,
1160 });
1161
1162 let mut make = |extra| {
1163 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1164 func.create_inst(data, &[], Span::DUMMY)
1165 };
1166 let plain = make(Extra::Asm(plain));
1167 let labelled = make(Extra::Asm(labelled));
1168 assert!(!func.is_terminator(plain));
1169 assert!(func.is_terminator(labelled));
1170 }
1171
1172 #[test]
1173 fn every_block_ends_in_its_terminator() {
1174 let (func, entry, header, exit) = sum();
1175 for block in [entry, header, exit] {
1176 let last = func.terminator(block).expect("a terminator");
1177 assert_eq!(Some(last), func.insts(block).last());
1178 }
1179 }
1180
1181 #[test]
1182 fn a_branch_carries_the_arguments_the_block_takes() {
1183 let (func, entry, header, _) = sum();
1184 let br = func.terminator(entry).expect("a terminator");
1185 let calls: Vec<BlockCall> = func.successors(br).collect();
1186 assert_eq!(calls.len(), 2);
1187 assert_eq!(calls[1].block, header);
1189 assert_eq!(func[calls[1].args].len(), 2);
1190 assert_eq!(func[header].params.len(), 2);
1191 assert_eq!(func[calls[0].args].len(), 1);
1192 }
1193
1194 #[test]
1195 fn a_value_knows_what_defined_it() {
1196 let (func, entry, _, _) = sum();
1197 let first = func.insts(entry).next().expect("an instruction");
1198 let value = func[first].first_result.expect("a result");
1199 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1200 assert_eq!(func[value].ty, Type::int(32));
1201
1202 let param = func[entry].params[0];
1203 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1204 }
1205
1206 #[test]
1207 fn a_comparison_produces_one_bit() {
1208 let (func, entry, _, _) = sum();
1209 let cmp = func.insts(entry).nth(1).expect("the comparison");
1210 let value = func[cmp].first_result.expect("a result");
1211 assert_eq!(func[value].ty, Type::I1);
1212 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1213 }
1214
1215 #[test]
1216 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1217 let (func, _, header, _) = sum();
1218 let add = func.insts(header).nth(1).expect("the addition");
1219 assert_eq!(func[add].flags, Flags::NSW);
1220 let cmp = func.insts(header).nth(3).expect("the comparison");
1221 assert_eq!(func[cmp].flags, Flags::NONE);
1222 }
1223
1224 #[test]
1225 fn removing_an_instruction_takes_it_out_of_the_middle() {
1226 let (mut func, _, header, _) = sum();
1227 let add = func.insts(header).nth(1).expect("the addition");
1228 func.remove_inst(add);
1229 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1230 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1231 assert_eq!(func.block_of(add), None);
1232 }
1233
1234 #[test]
1235 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1236 let (mut func, entry, _, _) = sum();
1237 let first = func.insts(entry).next().expect("an instruction");
1238 let last = func.terminator(entry).expect("a terminator");
1239 func.remove_inst(first);
1240 func.remove_inst(last);
1241 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1242 assert_eq!(opcodes, ["icmp"]);
1243 assert_eq!(func[entry].first, func[entry].last);
1244 }
1245
1246 #[test]
1247 fn removing_the_only_instruction_empties_the_block() {
1248 let (mut func, _, _, exit) = sum();
1249 let only = func.insts(exit).next().expect("an instruction");
1250 func.remove_inst(only);
1251 assert_eq!(func.insts(exit).count(), 0);
1252 assert_eq!(func[exit].first, None);
1253 assert_eq!(func[exit].last, None);
1254 }
1255
1256 #[test]
1257 fn inserting_before_puts_it_in_the_right_place() {
1258 let (mut func, entry, _, _) = sum();
1259 let cmp = func.insts(entry).nth(1).expect("the comparison");
1260 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1261 func.insert_before(made, cmp);
1262 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1263 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1264 }
1265
1266 #[test]
1267 fn inserting_before_the_first_makes_it_the_first() {
1268 let (mut func, entry, _, _) = sum();
1269 let first = func.insts(entry).next().expect("an instruction");
1270 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1271 func.insert_before(made, first);
1272 assert_eq!(func.insts(entry).next(), Some(made));
1273 assert_eq!(func[entry].first, Some(made));
1274 }
1275
1276 #[test]
1277 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1278 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1279 let block = func.create_block();
1280 let a = func.append_param(block, Type::int(32));
1281 let b = func.append_param(block, Type::int(32));
1282 let list = func.push_values(&[a]);
1283 let grown = func.append_arg(list, b);
1284 assert_eq!(func[grown], [a, b]);
1285 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1286 }
1287
1288 #[test]
1289 fn a_list_is_copied_when_something_is_behind_it() {
1290 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1291 let block = func.create_block();
1292 let a = func.append_param(block, Type::int(32));
1293 let b = func.append_param(block, Type::int(32));
1294 let list = func.push_values(&[a, a]);
1295 let behind = func.push_values(&[b]);
1296 let grown = func.append_arg(list, b);
1297 assert_eq!(func[grown], [a, a, b]);
1298 assert_eq!(func[list], [a, a], "the old run is still readable");
1299 assert_eq!(func[behind], [b], "and so is what was behind it");
1300 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1301 }
1302
1303 #[test]
1304 fn a_parameter_added_late_is_the_next_one_along() {
1305 let (mut func, entry, header, _) = sum();
1309 let extra = func.append_param(header, Type::int(32));
1310 assert_eq!(func[header].params.len(), 3);
1311 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1312
1313 let br = func.terminator(entry).expect("a terminator");
1314 let call = func.successors(br).nth(1).expect("the branch to the header");
1315 let grown = func.append_arg(call.args, extra);
1316 assert_eq!(func[grown].len(), 3);
1317 }
1318
1319 #[test]
1320 fn a_span_rides_along_with_the_instruction() {
1321 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1322 let block = func.create_block();
1323 let span = Span::new(10, 20);
1324 let mut b = Builder::new(&mut func, block).at(span);
1325 let value = b.iconst(Type::int(32), 7);
1326 let inst = match func[value].def {
1327 Def::Result { inst, .. } => inst,
1328 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1329 };
1330 assert_eq!(func.span(inst), span);
1331 }
1332
1333 #[test]
1334 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1335 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1336 let block = func.create_block();
1337 let addr = func.append_param(block, Type::PTR);
1338 let info = MemInfo {
1339 size: 4,
1340 align: 4,
1341 order: MemOrder::NotAtomic,
1342 tbaa: None,
1343 restrict: Restrict::NONE,
1344 };
1345 let mut b = Builder::new(&mut func, block);
1346 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1347 let store = b.store(value, addr, info, Flags::VOLATILE);
1348 assert_eq!(func[store].results, 0);
1349 assert_eq!(func[store].flags, Flags::VOLATILE);
1350 assert_eq!(func[value].ty, Type::int(32));
1351 }
1352
1353 #[test]
1354 fn a_call_produces_what_its_signature_returns() {
1355 let mut names = Interner::new();
1356 let mut func = Func::new(names.intern("caller"), Signature::new());
1357 let sig = func.add_signature(
1358 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1359 );
1360 let block = func.create_block();
1361 let arg = func.append_param(block, Type::int(32));
1362 let callee = names.intern("callee");
1363 let mut b = Builder::new(&mut func, block);
1364 let call = b.call(callee, sig, &[arg]);
1365 assert_eq!(func[call].results, 1);
1366 let value = func[call].first_result.expect("a result");
1367 assert_eq!(func[value].ty, Type::int(64));
1368 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1369 }
1370
1371 #[test]
1372 fn the_counts_are_what_was_made() {
1373 let (func, _, _, _) = sum();
1374 let counts = func.counts();
1375 assert_eq!(counts.blocks, 3);
1376 assert_eq!(counts.insts, 9);
1377 assert_eq!(counts.values, 4 + 6);
1380 }
1381
1382 #[test]
1383 #[should_panic(expected = "the instruction is in a block")]
1384 fn appending_an_instruction_twice_is_refused() {
1385 let (mut func, entry, _, _) = sum();
1386 let first = func.insts(entry).next().expect("an instruction");
1387 func.append_inst(entry, first);
1388 }
1389
1390 #[test]
1391 #[should_panic(expected = "the instruction is not in a block")]
1392 fn removing_an_instruction_twice_is_refused() {
1393 let (mut func, entry, _, _) = sum();
1394 let first = func.insts(entry).next().expect("an instruction");
1395 func.remove_inst(first);
1396 func.remove_inst(first);
1397 }
1398
1399 fn threaded() -> (Func, Inst, Inst) {
1401 let mut names = Interner::new();
1402 let i32_ = Type::int(32);
1403 let mut func = Func::new(
1404 names.intern("thread"),
1405 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
1406 );
1407 let entry = func.create_block();
1408 let addr = func.append_param(entry, Type::PTR);
1409 let info = MemInfo {
1410 size: 4,
1411 align: 4,
1412 order: MemOrder::NotAtomic,
1413 tbaa: None,
1414 restrict: Restrict::NONE,
1415 };
1416
1417 let mut b = Builder::new(&mut func, entry);
1418 let start = b.mem_entry();
1419 let seven = b.iconst(i32_, 7);
1420 let store = b.store(seven, addr, info, Flags::NONE);
1421 let value = b.load(i32_, addr, info, Flags::NONE);
1422 let Def::Result { inst: load, .. } = func[value].def else {
1423 panic!("the load produced it");
1424 };
1425
1426 let store = func.with_mem(store, start);
1427 let after = func.mem_out(store).expect("a store makes a new version");
1428 let load = func.with_mem(load, after);
1429 (func, store, load)
1430 }
1431
1432 #[test]
1433 fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
1434 let (func, store, load) = threaded();
1435 assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
1436 assert_eq!(func[func[store].args].len(), 3);
1437 assert!(func.carries_mem(store));
1438 assert!(func.carries_mem(load));
1439
1440 assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
1443 assert_eq!(func.mem_in(load), func.mem_out(store));
1444 assert_eq!(func.mem_out(load), None);
1445 }
1446
1447 #[test]
1448 #[should_panic(expected = "this is already on the memory chain")]
1449 fn threading_memory_through_the_same_instruction_twice_is_refused() {
1450 let (mut func, store, _) = threaded();
1451 let start = func.mem_in(store).expect("it was threaded");
1452 func.with_mem(store, start);
1453 }
1454}