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, Bulk, CallInfo, Def, Extra,
37 Imm, ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo,
38 VaInfo, Value, ValueData, ValueList,
39};
40use crate::module::{Linkage, Visibility};
41use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, PrefetchHint, RmwOp, Type};
42
43#[derive(Debug)]
45pub struct Func {
46 pub name: Symbol,
48 pub spelled: Option<Symbol>,
61 pub linkage: Linkage,
63 pub visibility: Visibility,
65 pub section: Option<Symbol>,
68 pub align: Option<u32>,
75 pub attrs: Attrs,
78 pub declared: Span,
94
95 values: Vec<ValueData>,
96 insts: Vec<InstData>,
97 inst_layout: Vec<InstLayout>,
98 inst_spans: Vec<Span>,
99 blocks: Vec<BlockData>,
100
101 value_pool: Vec<Value>,
102 block_calls: Vec<BlockCall>,
103 imms: Vec<Imm>,
104 mem: Vec<MemInfo>,
105 calls: Vec<CallInfo>,
106 abis: Vec<Abi>,
107 switches: Vec<SwitchInfo>,
108 asms: Vec<AsmInfo>,
109 slots: Vec<Slot>,
110 va_objects: Vec<VaInfo>,
111 signatures: Vec<Signature>,
112 facts: Vec<(Value, Facts)>,
113 labels: Vec<(Block, Symbol)>,
114 mem_decls: Vec<(Idx<MemInfo>, u32)>,
115 value_decls: Vec<(Value, u32)>,
116
117 first_block: Option<Block>,
118 last_block: Option<Block>,
119}
120
121impl Func {
122 #[must_use]
129 pub fn new(name: Symbol, signature: Signature) -> Self {
130 Self {
131 name,
132 spelled: None,
133 linkage: Linkage::External,
134 visibility: Visibility::Default,
135 section: None,
136 align: None,
137 attrs: Attrs::NONE,
138 declared: Span::DUMMY,
139 values: Vec::new(),
140 insts: Vec::new(),
141 inst_layout: Vec::new(),
142 inst_spans: Vec::new(),
143 blocks: Vec::new(),
144 value_pool: Vec::new(),
145 block_calls: Vec::new(),
146 imms: Vec::new(),
147 mem: Vec::new(),
148 calls: Vec::new(),
149 abis: Vec::new(),
150 switches: Vec::new(),
151 asms: Vec::new(),
152 slots: Vec::new(),
153 va_objects: Vec::new(),
154 signatures: vec![signature],
155 facts: Vec::new(),
156 labels: Vec::new(),
157 mem_decls: Vec::new(),
158 value_decls: Vec::new(),
159 first_block: None,
160 last_block: None,
161 }
162 }
163
164 #[must_use]
166 pub fn signature(&self) -> &Signature {
167 &self.signatures[0]
168 }
169
170 pub fn set_signature(&mut self, signature: Signature) {
182 self.signatures[0] = signature;
183 }
184
185 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
187 self.signatures.iter()
188 }
189
190 pub fn add_signature(&mut self, signature: Signature) -> Sig {
192 self.signatures.push(signature);
193 Idx::from_usize(self.signatures.len() - 1)
194 }
195
196 #[must_use]
201 pub fn entry(&self) -> Option<Block> {
202 self.first_block
203 }
204
205 #[must_use]
212 pub fn is_declaration(&self) -> bool {
213 self.first_block.is_none()
214 }
215
216 pub fn create_block(&mut self) -> Block {
220 let block = Idx::from_usize(self.blocks.len());
221 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
222 match self.last_block {
223 Some(last) => self.blocks[last.index()].next = Some(block),
224 None => self.first_block = Some(block),
225 }
226 self.last_block = Some(block);
227 block
228 }
229
230 pub fn remove_block(&mut self, block: Block) {
243 assert!(self.first_block != Some(block), "the entry block is not removable");
244 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
245 match prev {
246 Some(prev) => self.blocks[prev.index()].next = next,
247 None => self.first_block = next,
248 }
249 match next {
250 Some(next) => self.blocks[next.index()].prev = prev,
251 None => self.last_block = prev,
252 }
253 let insts: Vec<Inst> = self.insts(block).collect();
257 for inst in insts {
258 self.inst_layout[inst.index()] = InstLayout::default();
259 }
260 self.blocks[block.index()] = BlockData::default();
261 }
262
263 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
272 let index = u32::try_from(self.blocks[block.index()].params.len())
273 .expect("a block with four billion parameters");
274 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
275 self.blocks[block.index()].params.push(value);
276 value
277 }
278
279 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
291 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
292 params.retain(|&value| keep(value));
293 for (index, &value) in params.iter().enumerate() {
294 let index = u32::try_from(index).expect("a block with four billion parameters");
295 self.values[value.index()].def = Def::Param { block, index };
296 }
297 self.blocks[block.index()].params = params;
298 }
299
300 pub fn retype(&mut self, value: Value, ty: Type) {
312 self.values[value.index()].ty = ty;
313 }
314
315 pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
320 (0..self.values.len()).map(Idx::from_usize)
321 }
322
323 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
325 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
326 }
327
328 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
330 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
331 self.inst_layout[inst.index()].next
332 })
333 }
334
335 pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
341 std::iter::successors(self.blocks[block.index()].last, move |&inst| {
342 self.inst_layout[inst.index()].prev
343 })
344 }
345
346 #[must_use]
348 pub fn terminator(&self, block: Block) -> Option<Inst> {
349 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
350 }
351
352 #[must_use]
358 pub fn is_terminator(&self, inst: Inst) -> bool {
359 let data = &self[inst];
360 match data.extra {
361 Extra::Asm(info) => {
362 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
363 }
364 _ => data.opcode.is_terminator(),
365 }
366 }
367
368 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
379 let inst = Idx::from_usize(self.insts.len());
380 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
381 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
382 for (index, &ty) in results.iter().enumerate() {
383 let index = u8::try_from(index).expect("checked just above");
384 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
385 }
386 self.insts.push(data);
387 self.inst_layout.push(InstLayout::default());
388 self.inst_spans.push(span);
389 inst
390 }
391
392 pub fn drop_results(&mut self, inst: Inst, drop: u8) {
408 let data = &self.insts[inst.index()];
409 assert!(drop <= data.results, "the instruction does not produce that many results");
410 let left = data.results - drop;
411 let first = data.first_result.map_or(0, Idx::raw) + u32::from(drop);
412 let data = &mut self.insts[inst.index()];
413 data.results = left;
414 data.first_result = (left > 0).then(|| Value::new(first));
415 for offset in 0..u32::from(left) {
416 let index = u8::try_from(offset).expect("no more than the count it came from");
417 let value = Value::new(first + offset);
418 self.values[value.index()].def = Def::Result { inst, index };
419 }
420 }
421
422 pub fn append_inst(&mut self, block: Block, inst: Inst) {
429 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
430 let last = self.blocks[block.index()].last;
431 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
432 match last {
433 Some(last) => self.inst_layout[last.index()].next = Some(inst),
434 None => self.blocks[block.index()].first = Some(inst),
435 }
436 self.blocks[block.index()].last = Some(inst);
437 }
438
439 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
445 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
446 let at = self.inst_layout[before.index()];
447 let block = at.block.expect("the instruction to insert before is not in a block");
448 self.inst_layout[inst.index()] =
449 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
450 self.inst_layout[before.index()].prev = Some(inst);
451 match at.prev {
452 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
453 None => self.blocks[block.index()].first = Some(inst),
454 }
455 }
456
457 pub fn insert_after(&mut self, inst: Inst, after: Inst) {
469 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
470 let at = self.inst_layout[after.index()];
471 let block = at.block.expect("the instruction to insert after is not in a block");
472 assert!(at.next.is_some(), "nothing goes after a terminator");
473 self.inst_layout[inst.index()] =
474 InstLayout { block: Some(block), prev: Some(after), next: at.next };
475 self.inst_layout[after.index()].next = Some(inst);
476 if let Some(next) = at.next {
477 self.inst_layout[next.index()].prev = Some(inst);
478 }
479 }
480
481 pub fn remove_inst(&mut self, inst: Inst) {
491 let at = self.inst_layout[inst.index()];
492 let block = at.block.expect("the instruction is not in a block");
493 match at.prev {
494 Some(prev) => self.inst_layout[prev.index()].next = at.next,
495 None => self.blocks[block.index()].first = at.next,
496 }
497 match at.next {
498 Some(next) => self.inst_layout[next.index()].prev = at.prev,
499 None => self.blocks[block.index()].last = at.prev,
500 }
501 self.inst_layout[inst.index()] = InstLayout::default();
502 }
503
504 #[must_use]
506 pub fn block_of(&self, inst: Inst) -> Option<Block> {
507 self.inst_layout[inst.index()].block
508 }
509
510 #[must_use]
522 pub fn mem_in(&self, inst: Inst) -> Option<Value> {
523 let args = &self[self[inst].args];
524 args.last().copied().filter(|&arg| self[arg].ty.is_mem())
525 }
526
527 #[must_use]
537 pub fn mem_out(&self, inst: Inst) -> Option<Value> {
538 self[inst].results().last().filter(|&result| self[result].ty.is_mem())
539 }
540
541 #[must_use]
551 pub fn bulk(&self, inst: Inst) -> Option<Bulk> {
552 if !matches!(self[inst].opcode, Opcode::Memcpy | Opcode::Memmove | Opcode::Memset) {
553 return None;
554 }
555 let all = &self[self[inst].args];
556 let args = &all[..all.len() - usize::from(self.mem_in(inst).is_some())];
557 let [to, with, rest @ ..] = args else { return None };
558 Some(Bulk { to: *to, with: *with, length: rest.first().copied() })
559 }
560
561 #[must_use]
563 pub fn carries_mem(&self, inst: Inst) -> bool {
564 self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
565 }
566
567 pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
583 assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
584 assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
585 assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
586 let data = self[inst];
587 let mut args = self[data.args].to_vec();
588 args.push(incoming);
589 let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
590 if data.opcode.writes_memory() {
591 results.push(Type::MEM);
592 }
593 let span = self.span(inst);
594 let args = self.push_values(&args);
595 self.create_inst(InstData { args, ..data }, &results, span)
596 }
597
598 pub fn without_mem(&mut self, inst: Inst) -> Inst {
613 assert!(self.carries_mem(inst), "this is not on the memory chain");
614 let data = self[inst];
615 let mut args = self[data.args].to_vec();
616 if self.mem_in(inst).is_some() {
617 args.pop();
618 }
619 let results: Vec<Type> =
620 data.results().map(|result| self[result].ty).filter(|ty| !ty.is_mem()).collect();
621 let span = self.span(inst);
622 let args = self.push_values(&args);
623 self.create_inst(InstData { args, ..data }, &results, span)
624 }
625
626 #[must_use]
628 pub fn span(&self, inst: Inst) -> Span {
629 self.inst_spans[inst.index()]
630 }
631
632 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
637 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
638 }
639
640 #[must_use]
647 pub fn target_list(&self, inst: Inst) -> BlockCallList {
648 match self[inst].extra {
649 Extra::Targets(targets) => targets,
650 Extra::Switch(info) => self.switches[info.index()].targets,
651 Extra::Asm(info) => self.asms[info.index()].targets,
652 _ => BlockCallList::EMPTY,
653 }
654 }
655
656 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
660 let start = Idx::from_usize(self.value_pool.len());
661 self.value_pool.extend_from_slice(values);
662 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
663 }
664
665 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
672 let range = list.as_usize_range();
673 if range.end == self.value_pool.len() {
674 self.value_pool.push(value);
675 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
676 }
677 let start = self.value_pool.len();
678 self.value_pool.extend_from_within(range);
679 self.value_pool.push(value);
680 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
681 }
682
683 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
688 for value in &mut self.value_pool[list.as_usize_range()] {
689 *value = with(*value);
690 }
691 }
692
693 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
695 let start = Idx::from_usize(self.block_calls.len());
696 self.block_calls.extend_from_slice(calls);
697 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
698 }
699
700 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
702 self.block_calls[at.index()] = call;
703 }
704
705 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
707 let start = Idx::from_usize(self.imms.len());
708 self.imms.extend_from_slice(imms);
709 ImmList::new(start, Idx::from_usize(self.imms.len()))
710 }
711
712 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
714 self.imms.push(imm);
715 Idx::from_usize(self.imms.len() - 1)
716 }
717
718 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
720 let start = Idx::from_usize(self.slots.len());
721 self.slots.extend_from_slice(slots);
722 SlotList::new(start, Idx::from_usize(self.slots.len()))
723 }
724
725 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
727 self.va_objects.push(info);
728 Idx::from_usize(self.va_objects.len() - 1)
729 }
730
731 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
733 self.mem.push(info);
734 Idx::from_usize(self.mem.len() - 1)
735 }
736
737 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
739 let start = Idx::from_usize(self.abis.len());
740 self.abis.extend_from_slice(abis);
741 AbiList::new(start, Idx::from_usize(self.abis.len()))
742 }
743
744 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
746 self.calls.push(info);
747 Idx::from_usize(self.calls.len() - 1)
748 }
749
750 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
752 self.switches.push(info);
753 Idx::from_usize(self.switches.len() - 1)
754 }
755
756 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
758 self.asms.push(info);
759 Idx::from_usize(self.asms.len() - 1)
760 }
761
762 #[must_use]
765 pub fn counts(&self) -> Counts {
766 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
767 }
768
769 #[must_use]
775 pub fn facts(&self, value: Value) -> Facts {
776 match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
777 Ok(at) => self.facts[at].1,
778 Err(_) => Facts::NONE,
779 }
780 }
781
782 pub fn set_facts(&mut self, value: Value, facts: Facts) {
787 let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
788 match (found, facts.is_empty()) {
789 (Ok(at), true) => drop(self.facts.remove(at)),
790 (Ok(at), false) => self.facts[at].1 = facts,
791 (Err(_), true) => {}
792 (Err(at), false) => self.facts.insert(at, (value, facts)),
793 }
794 }
795
796 pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
798 self.facts.iter().copied()
799 }
800
801 pub fn name_block(&mut self, block: Block, name: Symbol) {
815 let found = self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw());
816 if let Err(at) = found {
817 self.labels.insert(at, (block, name));
818 }
819 }
820
821 #[must_use]
823 pub fn block_name(&self, block: Block) -> Option<Symbol> {
824 match self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw()) {
825 Ok(at) => Some(self.labels[at].1),
826 Err(_) => None,
827 }
828 }
829
830 pub fn named_blocks(&self) -> impl Iterator<Item = (Block, Symbol)> + '_ {
832 self.labels.iter().copied()
833 }
834
835 pub fn declare_mem(&mut self, mem: Idx<MemInfo>, decl: u32) {
850 let found = self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw());
851 if let Err(at) = found {
852 self.mem_decls.insert(at, (mem, decl));
853 }
854 }
855
856 #[must_use]
859 pub fn mem_decl(&self, mem: Idx<MemInfo>) -> Option<u32> {
860 match self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw()) {
861 Ok(at) => Some(self.mem_decls[at].1),
862 Err(_) => None,
863 }
864 }
865
866 pub fn declare_value(&mut self, value: Value, decl: u32) {
883 let key = (value.raw(), decl);
884 let found = self.value_decls.binary_search_by_key(&key, |&(at, decl)| (at.raw(), decl));
885 if let Err(at) = found {
886 self.value_decls.insert(at, (value, decl));
887 }
888 }
889
890 pub fn value_decls(&self, value: Value) -> impl Iterator<Item = u32> + '_ {
896 let at = self.value_decls.partition_point(|&(held, _)| held.raw() < value.raw());
897 self.value_decls[at..]
898 .iter()
899 .take_while(move |&&(held, _)| held == value)
900 .map(|&(_, decl)| decl)
901 }
902
903 pub fn rename_value(&mut self, from: Value, to: Value) {
913 if from == to {
914 return;
915 }
916 let at = self.value_decls.partition_point(|&(held, _)| held.raw() < from.raw());
917 let end = at + self.value_decls[at..].iter().take_while(|&&(held, _)| held == from).count();
918 let moving: Vec<u32> = self.value_decls.drain(at..end).map(|(_, decl)| decl).collect();
919 for decl in moving {
920 self.declare_value(to, decl);
921 }
922 }
923
924 fn add_value(&mut self, data: ValueData) -> Value {
925 self.values.push(data);
926 Idx::from_usize(self.values.len() - 1)
927 }
928}
929
930#[derive(Clone, Copy, Debug, PartialEq, Eq)]
932pub struct Counts {
933 pub values: usize,
935 pub insts: usize,
937 pub blocks: usize,
939}
940
941impl Index<Value> for Func {
944 type Output = ValueData;
945
946 fn index(&self, value: Value) -> &ValueData {
947 &self.values[value.index()]
948 }
949}
950
951impl Index<Inst> for Func {
952 type Output = InstData;
953
954 fn index(&self, inst: Inst) -> &InstData {
955 &self.insts[inst.index()]
956 }
957}
958
959impl IndexMut<Inst> for Func {
960 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
961 &mut self.insts[inst.index()]
962 }
963}
964
965impl Index<Block> for Func {
966 type Output = BlockData;
967
968 fn index(&self, block: Block) -> &BlockData {
969 &self.blocks[block.index()]
970 }
971}
972
973impl Index<Sig> for Func {
974 type Output = Signature;
975
976 fn index(&self, sig: Sig) -> &Signature {
977 &self.signatures[sig.index()]
978 }
979}
980
981impl Index<ValueList> for Func {
982 type Output = [Value];
983
984 fn index(&self, list: ValueList) -> &[Value] {
985 &self.value_pool[list.as_usize_range()]
986 }
987}
988
989impl Index<BlockCallList> for Func {
990 type Output = [BlockCall];
991
992 fn index(&self, list: BlockCallList) -> &[BlockCall] {
993 &self.block_calls[list.as_usize_range()]
994 }
995}
996
997impl Index<Idx<BlockCall>> for Func {
998 type Output = BlockCall;
999
1000 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
1001 &self.block_calls[at.index()]
1002 }
1003}
1004
1005impl Index<ImmList> for Func {
1006 type Output = [Imm];
1007
1008 fn index(&self, list: ImmList) -> &[Imm] {
1009 &self.imms[list.as_usize_range()]
1010 }
1011}
1012
1013impl Index<Idx<Imm>> for Func {
1014 type Output = Imm;
1015
1016 fn index(&self, at: Idx<Imm>) -> &Imm {
1017 &self.imms[at.index()]
1018 }
1019}
1020
1021impl Index<Idx<MemInfo>> for Func {
1022 type Output = MemInfo;
1023
1024 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
1025 &self.mem[at.index()]
1026 }
1027}
1028
1029impl Index<AbiList> for Func {
1030 type Output = [Abi];
1031
1032 fn index(&self, list: AbiList) -> &[Abi] {
1033 &self.abis[list.as_usize_range()]
1034 }
1035}
1036
1037impl Index<SlotList> for Func {
1038 type Output = [Slot];
1039
1040 fn index(&self, list: SlotList) -> &[Slot] {
1041 &self.slots[list.as_usize_range()]
1042 }
1043}
1044
1045impl Index<Idx<VaInfo>> for Func {
1046 type Output = VaInfo;
1047
1048 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
1049 &self.va_objects[at.index()]
1050 }
1051}
1052
1053impl Index<Idx<CallInfo>> for Func {
1054 type Output = CallInfo;
1055
1056 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
1057 &self.calls[at.index()]
1058 }
1059}
1060
1061impl Index<Idx<SwitchInfo>> for Func {
1062 type Output = SwitchInfo;
1063
1064 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
1065 &self.switches[at.index()]
1066 }
1067}
1068
1069impl Index<Idx<AsmInfo>> for Func {
1070 type Output = AsmInfo;
1071
1072 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
1073 &self.asms[at.index()]
1074 }
1075}
1076
1077#[derive(Debug)]
1084pub struct Builder<'a> {
1085 func: &'a mut Func,
1086 block: Block,
1087 span: Span,
1088}
1089
1090impl<'a> Builder<'a> {
1091 pub fn new(func: &'a mut Func, block: Block) -> Self {
1093 Self { func, block, span: Span::DUMMY }
1094 }
1095
1096 #[must_use]
1098 pub fn at(mut self, span: Span) -> Self {
1099 self.span = span;
1100 self
1101 }
1102
1103 pub fn set_span(&mut self, span: Span) {
1105 self.span = span;
1106 }
1107
1108 pub fn func(&mut self) -> &mut Func {
1110 self.func
1111 }
1112
1113 #[must_use]
1115 pub fn block(&self) -> Block {
1116 self.block
1117 }
1118
1119 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
1121 let inst = self.func.create_inst(data, results, self.span);
1122 self.func.append_inst(self.block, inst);
1123 inst
1124 }
1125
1126 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
1132 let inst = self.inst(data, &[ty]);
1133 self.func[inst].first_result.expect("one result was asked for")
1134 }
1135
1136 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
1142 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
1143 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
1144 }
1145
1146 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
1148 let imm = self.func.add_imm(Imm::from_bits(bits));
1149 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
1150 }
1151
1152 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
1154 let ty = self.func[lhs].ty;
1155 let args = self.func.push_values(&[lhs, rhs]);
1156 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
1157 }
1158
1159 pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
1172 let ty = self.func[lhs].ty;
1173 let args = self.func.push_values(&[lhs, rhs]);
1174 let results = [ty, ty.with_lane(Type::I1)];
1175 let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
1176 let mut answers = self.func[inst].results();
1177 let value = answers.next().expect("two results were asked for");
1178 let wrapped = answers.next().expect("two results were asked for");
1179 (value, wrapped)
1180 }
1181
1182 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
1184 let args = self.func.push_values(&[arg]);
1185 self.value(InstData { args, ..InstData::new(opcode) }, ty)
1186 }
1187
1188 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
1190 let ty = self.func[lhs].ty.with_lane(Type::I1);
1191 let args = self.func.push_values(&[lhs, rhs]);
1192 self.value(
1193 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
1194 ty,
1195 )
1196 }
1197
1198 pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
1204 let ty = self.func[then].ty;
1205 let args = self.func.push_values(&[cond, then, other]);
1206 self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
1207 }
1208
1209 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
1211 let ty = self.func[lhs].ty.with_lane(Type::I1);
1212 let args = self.func.push_values(&[lhs, rhs]);
1213 self.value(
1214 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
1215 ty,
1216 )
1217 }
1218
1219 pub fn mem_entry(&mut self) -> Value {
1223 self.value(InstData::new(Opcode::MemEntry), Type::MEM)
1224 }
1225
1226 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1228 let mem = self.func.add_mem(info);
1229 let args = self.func.push_values(&[addr]);
1230 self.value(
1231 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
1232 ty,
1233 )
1234 }
1235
1236 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1238 let mem = self.func.add_mem(info);
1239 let args = self.func.push_values(&[value, addr]);
1240 self.inst(
1241 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
1242 &[],
1243 )
1244 }
1245
1246 pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1254 let mem = self.func.add_mem(info);
1255 let args = self.func.push_values(&[addr]);
1256 self.value(
1257 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1258 ty,
1259 )
1260 }
1261
1262 pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1264 let mem = self.func.add_mem(info);
1265 let args = self.func.push_values(&[value, addr]);
1266 self.inst(
1267 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1268 &[],
1269 )
1270 }
1271
1272 pub fn cmpxchg(
1279 &mut self,
1280 addr: Value,
1281 expected: Value,
1282 desired: Value,
1283 info: MemInfo,
1284 flags: Flags,
1285 ) -> (Value, Value) {
1286 let ty = self.func[expected].ty;
1287 let mem = self.func.add_mem(info);
1288 let args = self.func.push_values(&[addr, expected, desired]);
1289 let inst = self.inst(
1290 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1291 &[ty, Type::I1],
1292 );
1293 let results: Vec<Value> = self.func[inst].results().collect();
1294 let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1295 (old, exchanged)
1296 }
1297
1298 pub fn atomic_rmw(
1306 &mut self,
1307 op: RmwOp,
1308 addr: Value,
1309 operand: Value,
1310 info: MemInfo,
1311 flags: Flags,
1312 ) -> Value {
1313 let ty = self.func[operand].ty;
1314 let mem = self.func.add_mem(info);
1315 let args = self.func.push_values(&[addr, operand]);
1316 self.value(
1317 InstData {
1318 args,
1319 flags,
1320 extra: Extra::Rmw(op, mem),
1321 ..InstData::new(Opcode::AtomicRmw)
1322 },
1323 ty,
1324 )
1325 }
1326
1327 pub fn fence(&mut self, order: MemOrder) -> Inst {
1329 self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1330 }
1331
1332 pub fn prefetch(&mut self, address: Value, hint: PrefetchHint) -> Inst {
1339 let args = self.func.push_values(&[address]);
1340 self.inst(
1341 InstData { args, extra: Extra::Prefetch(hint), ..InstData::new(Opcode::Prefetch) },
1342 &[],
1343 )
1344 }
1345
1346 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1348 let call = self.block_call(target, args);
1349 let targets = self.func.push_block_calls(&[call]);
1350 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1351 }
1352
1353 pub fn block_addr(&mut self, target: Block) -> Value {
1359 let call = self.block_call(target, &[]);
1360 let targets = self.func.push_block_calls(&[call]);
1361 self.value(
1362 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1363 Type::PTR,
1364 )
1365 }
1366
1367 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1373 let calls: Vec<BlockCall> =
1374 targets.iter().map(|&target| self.block_call(target, &[])).collect();
1375 let targets = self.func.push_block_calls(&calls);
1376 let args = self.func.push_values(&[addr]);
1377 self.inst(
1378 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1379 &[],
1380 )
1381 }
1382
1383 pub fn br_if(
1385 &mut self,
1386 cond: Value,
1387 then_block: Block,
1388 then_args: &[Value],
1389 else_block: Block,
1390 else_args: &[Value],
1391 ) -> Inst {
1392 let then_call = self.block_call(then_block, then_args);
1393 let else_call = self.block_call(else_block, else_args);
1394 let targets = self.func.push_block_calls(&[then_call, else_call]);
1395 let args = self.func.push_values(&[cond]);
1396 self.inst(
1397 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1398 &[],
1399 )
1400 }
1401
1402 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1409 let ty = self.func[value].ty.lane();
1410 let mut calls = vec![self.block_call(default, &[])];
1411 let mut values = Vec::with_capacity(cases.len());
1412 for &(value, block) in cases {
1413 calls.push(self.block_call(block, &[]));
1414 values.push(Imm::int(value, ty));
1415 }
1416 let targets = self.func.push_block_calls(&calls);
1417 let cases = self.func.push_imms(&values);
1418 let info = self.func.add_switch(SwitchInfo { targets, cases });
1419 let args = self.func.push_values(&[value]);
1420 self.inst(
1421 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1422 &[],
1423 )
1424 }
1425
1426 pub fn ret(&mut self, values: &[Value]) -> Inst {
1428 let args = self.func.push_values(values);
1429 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1430 }
1431
1432 pub fn unreachable(&mut self) -> Inst {
1434 self.inst(InstData::new(Opcode::Unreachable), &[])
1435 }
1436
1437 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1439 self.call_varargs(callee, signature, args, &[])
1440 }
1441
1442 pub fn call_varargs(
1448 &mut self,
1449 callee: Symbol,
1450 signature: Sig,
1451 args: &[Value],
1452 varargs: &[Abi],
1453 ) -> Inst {
1454 let varargs = self.func.push_abis(varargs);
1455 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1456 let returns: Vec<Type> = self.func[signature].return_types().collect();
1457 let args = self.func.push_values(args);
1458 self.inst(
1459 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1460 &returns,
1461 )
1462 }
1463
1464 pub fn inline_asm(
1470 &mut self,
1471 info: AsmInfo,
1472 args: &[Value],
1473 results: &[Type],
1474 flags: Flags,
1475 ) -> Inst {
1476 let info = self.func.add_asm(info);
1477 let args = self.func.push_values(args);
1478 self.inst(
1479 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1480 results,
1481 )
1482 }
1483
1484 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1485 BlockCall::new(block, self.func.push_values(args))
1486 }
1487}
1488
1489#[cfg(test)]
1490mod tests {
1491 use rucc_base::Interner;
1492
1493 use super::*;
1494 use crate::inst::BlockCallList;
1495 use crate::{MemOrder, Restrict};
1496
1497 fn sum() -> (Func, Block, Block, Block) {
1499 let mut names = Interner::new();
1500 let i32_ = Type::int(32);
1501 let mut func = Func::new(
1502 names.intern("sum"),
1503 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1504 );
1505
1506 let entry = func.create_block();
1507 let n = func.append_param(entry, i32_);
1508 let header = func.create_block();
1509 let acc = func.append_param(header, i32_);
1510 let i = func.append_param(header, i32_);
1511 let exit = func.create_block();
1512 let result = func.append_param(exit, i32_);
1513
1514 let mut b = Builder::new(&mut func, entry);
1515 let zero = b.iconst(i32_, 0);
1516 let cmp = b.icmp(IntPred::Sle, n, zero);
1517 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1518
1519 let mut b = Builder::new(&mut func, header);
1520 let one = b.iconst(i32_, 1);
1521 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1522 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1523 let done = b.icmp(IntPred::Sge, next, n);
1524 b.br_if(done, exit, &[total], header, &[total, next]);
1525
1526 let mut b = Builder::new(&mut func, exit);
1527 b.ret(&[result]);
1528
1529 (func, entry, header, exit)
1530 }
1531
1532 #[test]
1533 fn the_blocks_come_back_in_the_order_they_were_made() {
1534 let (func, entry, header, exit) = sum();
1535 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1536 assert_eq!(func.entry(), Some(entry));
1537 }
1538
1539 #[test]
1540 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1541 let (mut func, entry, header, exit) = sum();
1542 let inside: Vec<Inst> = func.insts(header).collect();
1543 func.remove_block(header);
1544 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1545 assert_eq!(func.entry(), Some(entry));
1546 assert_eq!(func[entry].next, Some(exit));
1547 assert_eq!(func[exit].prev, Some(entry));
1548 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1550 assert!(func.insts(header).next().is_none());
1551 }
1552
1553 #[test]
1554 fn each_block_holds_what_was_appended_to_it() {
1555 let (func, entry, header, exit) = sum();
1556 let opcodes =
1557 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1558 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1559 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1560 assert_eq!(opcodes(exit), ["return"]);
1561 }
1562
1563 #[test]
1564 fn dropping_the_results_in_front_moves_the_first_one_along_and_renumbers_the_rest() {
1565 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1570 let types = [Type::int(32), Type::int(64), Type::MEM];
1571 let inst = func.create_inst(InstData::new(Opcode::Call), &types, Span::DUMMY);
1572 let before: Vec<Value> = func[inst].results().collect();
1573 func.drop_results(inst, 1);
1574 assert_eq!(func[inst].results().collect::<Vec<_>>(), before[1..]);
1575 assert_eq!(func[before[1]].def, Def::Result { inst, index: 0 });
1576 assert_eq!(func[before[2]].def, Def::Result { inst, index: 1 });
1577 assert_eq!(func.mem_out(inst), Some(before[2]));
1578 }
1579
1580 #[test]
1581 fn dropping_every_result_leaves_an_instruction_that_produces_nothing() {
1582 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1583 let inst = func.create_inst(InstData::new(Opcode::Call), &[Type::int(32)], Span::DUMMY);
1584 func.drop_results(inst, 1);
1585 assert_eq!(func[inst].results().count(), 0);
1586 assert_eq!(func[inst].first_result, None);
1587 }
1588
1589 #[test]
1590 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1591 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1594 let block = func.create_block();
1595 let plain = func.add_asm(AsmInfo {
1596 template: Symbol::from_raw(0),
1597 constraints: Symbol::from_raw(0),
1598 clobbers: Symbol::from_raw(0),
1599 targets: BlockCallList::EMPTY,
1600 });
1601 let call = BlockCall::to(block);
1602 let targets = func.push_block_calls(&[call]);
1603 let labelled = func.add_asm(AsmInfo {
1604 template: Symbol::from_raw(0),
1605 constraints: Symbol::from_raw(0),
1606 clobbers: Symbol::from_raw(0),
1607 targets,
1608 });
1609
1610 let mut make = |extra| {
1611 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1612 func.create_inst(data, &[], Span::DUMMY)
1613 };
1614 let plain = make(Extra::Asm(plain));
1615 let labelled = make(Extra::Asm(labelled));
1616 assert!(!func.is_terminator(plain));
1617 assert!(func.is_terminator(labelled));
1618 }
1619
1620 #[test]
1621 fn every_block_ends_in_its_terminator() {
1622 let (func, entry, header, exit) = sum();
1623 for block in [entry, header, exit] {
1624 let last = func.terminator(block).expect("a terminator");
1625 assert_eq!(Some(last), func.insts(block).last());
1626 }
1627 }
1628
1629 #[test]
1630 fn a_branch_carries_the_arguments_the_block_takes() {
1631 let (func, entry, header, _) = sum();
1632 let br = func.terminator(entry).expect("a terminator");
1633 let calls: Vec<BlockCall> = func.successors(br).collect();
1634 assert_eq!(calls.len(), 2);
1635 assert_eq!(calls[1].block, header);
1637 assert_eq!(func[calls[1].args].len(), 2);
1638 assert_eq!(func[header].params.len(), 2);
1639 assert_eq!(func[calls[0].args].len(), 1);
1640 }
1641
1642 #[test]
1643 fn a_value_knows_what_defined_it() {
1644 let (func, entry, _, _) = sum();
1645 let first = func.insts(entry).next().expect("an instruction");
1646 let value = func[first].first_result.expect("a result");
1647 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1648 assert_eq!(func[value].ty, Type::int(32));
1649
1650 let param = func[entry].params[0];
1651 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1652 }
1653
1654 #[test]
1655 fn a_comparison_produces_one_bit() {
1656 let (func, entry, _, _) = sum();
1657 let cmp = func.insts(entry).nth(1).expect("the comparison");
1658 let value = func[cmp].first_result.expect("a result");
1659 assert_eq!(func[value].ty, Type::I1);
1660 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1661 }
1662
1663 #[test]
1664 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1665 let (func, _, header, _) = sum();
1666 let add = func.insts(header).nth(1).expect("the addition");
1667 assert_eq!(func[add].flags, Flags::NSW);
1668 let cmp = func.insts(header).nth(3).expect("the comparison");
1669 assert_eq!(func[cmp].flags, Flags::NONE);
1670 }
1671
1672 #[test]
1673 fn removing_an_instruction_takes_it_out_of_the_middle() {
1674 let (mut func, _, header, _) = sum();
1675 let add = func.insts(header).nth(1).expect("the addition");
1676 func.remove_inst(add);
1677 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1678 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1679 assert_eq!(func.block_of(add), None);
1680 }
1681
1682 #[test]
1683 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1684 let (mut func, entry, _, _) = sum();
1685 let first = func.insts(entry).next().expect("an instruction");
1686 let last = func.terminator(entry).expect("a terminator");
1687 func.remove_inst(first);
1688 func.remove_inst(last);
1689 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1690 assert_eq!(opcodes, ["icmp"]);
1691 assert_eq!(func[entry].first, func[entry].last);
1692 }
1693
1694 #[test]
1695 fn removing_the_only_instruction_empties_the_block() {
1696 let (mut func, _, _, exit) = sum();
1697 let only = func.insts(exit).next().expect("an instruction");
1698 func.remove_inst(only);
1699 assert_eq!(func.insts(exit).count(), 0);
1700 assert_eq!(func[exit].first, None);
1701 assert_eq!(func[exit].last, None);
1702 }
1703
1704 #[test]
1705 fn inserting_before_puts_it_in_the_right_place() {
1706 let (mut func, entry, _, _) = sum();
1707 let cmp = func.insts(entry).nth(1).expect("the comparison");
1708 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1709 func.insert_before(made, cmp);
1710 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1711 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1712 }
1713
1714 #[test]
1715 fn inserting_before_the_first_makes_it_the_first() {
1716 let (mut func, entry, _, _) = sum();
1717 let first = func.insts(entry).next().expect("an instruction");
1718 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1719 func.insert_before(made, first);
1720 assert_eq!(func.insts(entry).next(), Some(made));
1721 assert_eq!(func[entry].first, Some(made));
1722 }
1723
1724 #[test]
1725 fn inserting_after_puts_it_in_the_right_place() {
1726 let (mut func, entry, _, _) = sum();
1727 let first = func.insts(entry).next().expect("an instruction");
1728 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1729 func.insert_after(made, first);
1730 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1731 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1732 assert_eq!(func[entry].first, Some(first));
1733 }
1734
1735 #[test]
1736 #[should_panic(expected = "nothing goes after a terminator")]
1737 fn inserting_after_the_terminator_is_refused() {
1738 let (mut func, entry, _, _) = sum();
1741 let last = func.insts(entry).last().expect("a terminator");
1742 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1743 func.insert_after(made, last);
1744 }
1745
1746 #[test]
1747 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1748 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1749 let block = func.create_block();
1750 let a = func.append_param(block, Type::int(32));
1751 let b = func.append_param(block, Type::int(32));
1752 let list = func.push_values(&[a]);
1753 let grown = func.append_arg(list, b);
1754 assert_eq!(func[grown], [a, b]);
1755 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1756 }
1757
1758 #[test]
1759 fn a_list_is_copied_when_something_is_behind_it() {
1760 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1761 let block = func.create_block();
1762 let a = func.append_param(block, Type::int(32));
1763 let b = func.append_param(block, Type::int(32));
1764 let list = func.push_values(&[a, a]);
1765 let behind = func.push_values(&[b]);
1766 let grown = func.append_arg(list, b);
1767 assert_eq!(func[grown], [a, a, b]);
1768 assert_eq!(func[list], [a, a], "the old run is still readable");
1769 assert_eq!(func[behind], [b], "and so is what was behind it");
1770 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1771 }
1772
1773 #[test]
1774 fn a_parameter_added_late_is_the_next_one_along() {
1775 let (mut func, entry, header, _) = sum();
1779 let extra = func.append_param(header, Type::int(32));
1780 assert_eq!(func[header].params.len(), 3);
1781 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1782
1783 let br = func.terminator(entry).expect("a terminator");
1784 let call = func.successors(br).nth(1).expect("the branch to the header");
1785 let grown = func.append_arg(call.args, extra);
1786 assert_eq!(func[grown].len(), 3);
1787 }
1788
1789 #[test]
1790 fn a_span_rides_along_with_the_instruction() {
1791 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1792 let block = func.create_block();
1793 let span = Span::new(10, 20);
1794 let mut b = Builder::new(&mut func, block).at(span);
1795 let value = b.iconst(Type::int(32), 7);
1796 let inst = match func[value].def {
1797 Def::Result { inst, .. } => inst,
1798 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1799 };
1800 assert_eq!(func.span(inst), span);
1801 }
1802
1803 #[test]
1804 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1805 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1806 let block = func.create_block();
1807 let addr = func.append_param(block, Type::PTR);
1808 let info = MemInfo {
1809 size: 4,
1810 align: 4,
1811 order: MemOrder::NotAtomic,
1812 tbaa: None,
1813 owns: 0,
1814 restrict: Restrict::NONE,
1815 };
1816 let mut b = Builder::new(&mut func, block);
1817 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1818 let store = b.store(value, addr, info, Flags::VOLATILE);
1819 assert_eq!(func[store].results, 0);
1820 assert_eq!(func[store].flags, Flags::VOLATILE);
1821 assert_eq!(func[value].ty, Type::int(32));
1822 }
1823
1824 #[test]
1825 fn memory_remembers_which_declaration_asked_for_it_and_which_did_not() {
1826 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1827 let info = MemInfo {
1828 size: 4,
1829 align: 4,
1830 order: MemOrder::NotAtomic,
1831 tbaa: None,
1832 owns: 0,
1833 restrict: Restrict::NONE,
1834 };
1835 let first = func.add_mem(info);
1836 let second = func.add_mem(info);
1837 let third = func.add_mem(info);
1838
1839 func.declare_mem(third, 7);
1842 func.declare_mem(first, 2);
1843 func.declare_mem(first, 9);
1845
1846 assert_eq!(func.mem_decl(first), Some(2));
1847 assert_eq!(func.mem_decl(third), Some(7));
1848 assert_eq!(func.mem_decl(second), None);
1850 }
1851
1852 #[test]
1858 fn a_value_says_which_declarations_it_is_and_a_rename_carries_them_over() {
1859 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1860 let block = func.create_block();
1861 let first = func.append_param(block, Type::int(32));
1862 let second = func.append_param(block, Type::int(32));
1863 let third = func.append_param(block, Type::int(32));
1864
1865 func.declare_value(third, 7);
1868 func.declare_value(first, 2);
1869 func.declare_value(first, 2);
1871
1872 assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2]);
1873 assert_eq!(func.value_decls(third).collect::<Vec<u32>>(), vec![7]);
1874 assert_eq!(func.value_decls(second).count(), 0);
1876
1877 func.rename_value(third, first);
1880 assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2, 7]);
1881 assert_eq!(func.value_decls(third).count(), 0);
1882
1883 func.rename_value(second, third);
1885 assert_eq!(func.value_decls(third).count(), 0);
1886 }
1887
1888 #[test]
1889 fn a_call_produces_what_its_signature_returns() {
1890 let mut names = Interner::new();
1891 let mut func = Func::new(names.intern("caller"), Signature::new());
1892 let sig = func.add_signature(
1893 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1894 );
1895 let block = func.create_block();
1896 let arg = func.append_param(block, Type::int(32));
1897 let callee = names.intern("callee");
1898 let mut b = Builder::new(&mut func, block);
1899 let call = b.call(callee, sig, &[arg]);
1900 assert_eq!(func[call].results, 1);
1901 let value = func[call].first_result.expect("a result");
1902 assert_eq!(func[value].ty, Type::int(64));
1903 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1904 }
1905
1906 #[test]
1907 fn the_counts_are_what_was_made() {
1908 let (func, _, _, _) = sum();
1909 let counts = func.counts();
1910 assert_eq!(counts.blocks, 3);
1911 assert_eq!(counts.insts, 9);
1912 assert_eq!(counts.values, 4 + 6);
1915 }
1916
1917 #[test]
1918 #[should_panic(expected = "the instruction is in a block")]
1919 fn appending_an_instruction_twice_is_refused() {
1920 let (mut func, entry, _, _) = sum();
1921 let first = func.insts(entry).next().expect("an instruction");
1922 func.append_inst(entry, first);
1923 }
1924
1925 #[test]
1926 #[should_panic(expected = "the instruction is not in a block")]
1927 fn removing_an_instruction_twice_is_refused() {
1928 let (mut func, entry, _, _) = sum();
1929 let first = func.insts(entry).next().expect("an instruction");
1930 func.remove_inst(first);
1931 func.remove_inst(first);
1932 }
1933
1934 fn threaded() -> (Func, Inst, Inst) {
1936 let mut names = Interner::new();
1937 let i32_ = Type::int(32);
1938 let mut func = Func::new(
1939 names.intern("thread"),
1940 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
1941 );
1942 let entry = func.create_block();
1943 let addr = func.append_param(entry, Type::PTR);
1944 let info = MemInfo {
1945 size: 4,
1946 align: 4,
1947 order: MemOrder::NotAtomic,
1948 tbaa: None,
1949 owns: 0,
1950 restrict: Restrict::NONE,
1951 };
1952
1953 let mut b = Builder::new(&mut func, entry);
1954 let start = b.mem_entry();
1955 let seven = b.iconst(i32_, 7);
1956 let store = b.store(seven, addr, info, Flags::NONE);
1957 let value = b.load(i32_, addr, info, Flags::NONE);
1958 let Def::Result { inst: load, .. } = func[value].def else {
1959 panic!("the load produced it");
1960 };
1961
1962 let store = func.with_mem(store, start);
1963 let after = func.mem_out(store).expect("a store makes a new version");
1964 let load = func.with_mem(load, after);
1965 (func, store, load)
1966 }
1967
1968 #[test]
1969 fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
1970 let (func, store, load) = threaded();
1971 assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
1972 assert_eq!(func[func[store].args].len(), 3);
1973 assert!(func.carries_mem(store));
1974 assert!(func.carries_mem(load));
1975
1976 assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
1979 assert_eq!(func.mem_in(load), func.mem_out(store));
1980 assert_eq!(func.mem_out(load), None);
1981 }
1982
1983 #[test]
1984 #[should_panic(expected = "this is already on the memory chain")]
1985 fn threading_memory_through_the_same_instruction_twice_is_refused() {
1986 let (mut func, store, _) = threaded();
1987 let start = func.mem_in(store).expect("it was threaded");
1988 func.with_mem(store, start);
1989 }
1990
1991 fn copies() -> (Func, Inst, Inst) {
1994 let mut names = Interner::new();
1995 let i64_ = Type::int(64);
1996 let mut func = Func::new(
1997 names.intern("copies"),
1998 Signature::new().with_params(&[Type::PTR, Type::PTR, i64_]),
1999 );
2000 let entry = func.create_block();
2001 let to = func.append_param(entry, Type::PTR);
2002 let from = func.append_param(entry, Type::PTR);
2003 let length = func.append_param(entry, i64_);
2004 let info = MemInfo {
2005 size: 16,
2006 align: 4,
2007 order: MemOrder::NotAtomic,
2008 tbaa: None,
2009 owns: 0,
2010 restrict: Restrict::NONE,
2011 };
2012
2013 let mut b = Builder::new(&mut func, entry);
2014 let start = b.mem_entry();
2015 let mem = b.func().add_mem(info);
2016 let args = b.func().push_values(&[to, from]);
2017 let fixed =
2018 b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2019 let mem = b.func().add_mem(MemInfo { size: 0, ..info });
2020 let args = b.func().push_values(&[to, from, length]);
2021 let computed =
2022 b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2023 b.ret(&[]);
2024
2025 let fixed = func.with_mem(fixed, start);
2026 let after = func.mem_out(fixed).expect("a copy makes a new version");
2027 let computed = func.with_mem(computed, after);
2028 (func, fixed, computed)
2029 }
2030
2031 #[test]
2032 fn a_bulk_copy_hands_back_its_length_where_it_has_one_and_nothing_where_the_payload_has_it() {
2033 let (func, fixed, computed) = copies();
2034 let params = &func[func.entry().expect("an entry")].params;
2035 let [to, from, length] = params[..] else { panic!("three of them were appended") };
2036
2037 let bulk = func.bulk(fixed).expect("a memcpy is one");
2038 assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, None));
2039
2040 let bulk = func.bulk(computed).expect("a memcpy is one");
2041 assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, Some(length)));
2042 }
2043
2044 #[test]
2045 fn an_instruction_that_is_not_a_bulk_operation_is_not_taken_apart_as_one() {
2046 let (func, store, load) = threaded();
2047 assert_eq!(func.bulk(store), None);
2048 assert_eq!(func.bulk(load), None);
2049 }
2050}