1use std::collections::{HashMap, HashSet};
30use std::ops::{Index, IndexMut};
31
32use rucc_base::{Idx, Symbol};
33use rucc_diag::Span;
34use rucc_target::{Isa, Slot};
35
36use crate::inst::{
37 Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, Bulk, CallInfo, Def, Extra,
38 Imm, ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo,
39 VaInfo, Value, ValueData, ValueList,
40};
41use crate::module::{Linkage, Visibility};
42use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, PrefetchHint, RmwOp, Type};
43
44#[derive(Debug)]
46pub struct Func {
47 pub name: Symbol,
49 pub spelled: Option<Symbol>,
62 pub linkage: Linkage,
64 pub visibility: Visibility,
66 pub section: Option<Symbol>,
69 pub align: Option<u32>,
76 pub attrs: Attrs,
79 pub target: Option<Isa>,
87 pub declared: Span,
103 pub named: Span,
112
113 values: Vec<ValueData>,
114 insts: Vec<InstData>,
115 inst_layout: Vec<InstLayout>,
116 inst_spans: Vec<Span>,
117 blocks: Vec<BlockData>,
118
119 value_pool: Vec<Value>,
120 block_calls: Vec<BlockCall>,
121 imms: Vec<Imm>,
122 mem: Vec<MemInfo>,
123 calls: Vec<CallInfo>,
124 abis: Vec<Abi>,
125 switches: Vec<SwitchInfo>,
126 asms: Vec<AsmInfo>,
127 slots: Vec<Slot>,
128 va_objects: Vec<VaInfo>,
129 signatures: Vec<Signature>,
130 facts: Vec<(Value, Facts)>,
131 labels: Vec<(Block, Symbol)>,
132 mem_decls: Vec<(Idx<MemInfo>, u32)>,
133 value_decls: Vec<(Value, u32)>,
134 value_starts: Vec<(Value, Start)>,
135 anchors: HashSet<Inst>,
138 unplaced: HashMap<Inst, Vec<(Value, Start)>>,
141 arg_groups: HashMap<Inst, Vec<u32>>,
149 gone: HashMap<Inst, (Block, Option<Inst>)>,
152
153 first_block: Option<Block>,
154 last_block: Option<Block>,
155}
156
157impl Func {
158 #[must_use]
165 pub fn new(name: Symbol, signature: Signature) -> Self {
166 Self {
167 name,
168 spelled: None,
169 linkage: Linkage::External,
170 visibility: Visibility::Default,
171 section: None,
172 align: None,
173 attrs: Attrs::NONE,
174 target: None,
175 declared: Span::DUMMY,
176 named: Span::DUMMY,
177 values: Vec::new(),
178 insts: Vec::new(),
179 inst_layout: Vec::new(),
180 inst_spans: Vec::new(),
181 blocks: Vec::new(),
182 value_pool: Vec::new(),
183 block_calls: Vec::new(),
184 imms: Vec::new(),
185 mem: Vec::new(),
186 calls: Vec::new(),
187 abis: Vec::new(),
188 switches: Vec::new(),
189 asms: Vec::new(),
190 slots: Vec::new(),
191 va_objects: Vec::new(),
192 signatures: vec![signature],
193 facts: Vec::new(),
194 labels: Vec::new(),
195 mem_decls: Vec::new(),
196 value_decls: Vec::new(),
197 value_starts: Vec::new(),
198 anchors: HashSet::new(),
199 unplaced: HashMap::new(),
200 arg_groups: HashMap::new(),
201 gone: HashMap::new(),
202 first_block: None,
203 last_block: None,
204 }
205 }
206
207 #[must_use]
209 pub fn signature(&self) -> &Signature {
210 &self.signatures[0]
211 }
212
213 pub fn set_signature(&mut self, signature: Signature) {
225 self.signatures[0] = signature;
226 }
227
228 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
230 self.signatures.iter()
231 }
232
233 pub fn add_signature(&mut self, signature: Signature) -> Sig {
235 self.signatures.push(signature);
236 Idx::from_usize(self.signatures.len() - 1)
237 }
238
239 #[must_use]
244 pub fn entry(&self) -> Option<Block> {
245 self.first_block
246 }
247
248 #[must_use]
255 pub fn is_declaration(&self) -> bool {
256 self.first_block.is_none()
257 }
258
259 pub fn create_block(&mut self) -> Block {
263 let block = Idx::from_usize(self.blocks.len());
264 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
265 match self.last_block {
266 Some(last) => self.blocks[last.index()].next = Some(block),
267 None => self.first_block = Some(block),
268 }
269 self.last_block = Some(block);
270 block
271 }
272
273 pub fn remove_block(&mut self, block: Block) {
286 assert!(self.first_block != Some(block), "the entry block is not removable");
287 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
288 match prev {
289 Some(prev) => self.blocks[prev.index()].next = next,
290 None => self.first_block = next,
291 }
292 match next {
293 Some(next) => self.blocks[next.index()].prev = prev,
294 None => self.last_block = prev,
295 }
296 let insts: Vec<Inst> = self.insts(block).collect();
300 for inst in insts {
301 self.inst_layout[inst.index()] = InstLayout::default();
302 }
303 self.blocks[block.index()] = BlockData::default();
304 }
305
306 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
315 let index = u32::try_from(self.blocks[block.index()].params.len())
316 .expect("a block with four billion parameters");
317 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
318 self.blocks[block.index()].params.push(value);
319 value
320 }
321
322 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
334 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
335 let mut dropped = Vec::new();
336 params.retain(|&value| {
337 let kept = keep(value);
338 if !kept {
339 dropped.push(value);
340 }
341 kept
342 });
343 for value in dropped {
347 self.held_from(value, block, None);
348 self.set_facts(value, Facts::NONE);
349 }
350 for (index, &value) in params.iter().enumerate() {
351 let index = u32::try_from(index).expect("a block with four billion parameters");
352 self.values[value.index()].def = Def::Param { block, index };
353 }
354 self.blocks[block.index()].params = params;
355 }
356
357 pub fn retype(&mut self, value: Value, ty: Type) {
369 self.values[value.index()].ty = ty;
370 }
371
372 pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
377 (0..self.values.len()).map(Idx::from_usize)
378 }
379
380 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
382 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
383 }
384
385 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
387 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
388 self.inst_layout[inst.index()].next
389 })
390 }
391
392 pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
398 std::iter::successors(self.blocks[block.index()].last, move |&inst| {
399 self.inst_layout[inst.index()].prev
400 })
401 }
402
403 #[must_use]
405 pub fn terminator(&self, block: Block) -> Option<Inst> {
406 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
407 }
408
409 #[must_use]
415 pub fn is_terminator(&self, inst: Inst) -> bool {
416 let data = &self[inst];
417 match data.extra {
418 Extra::Asm(info) => {
419 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
420 }
421 _ => data.opcode.is_terminator(),
422 }
423 }
424
425 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
436 let inst = Idx::from_usize(self.insts.len());
437 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
438 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
439 for (index, &ty) in results.iter().enumerate() {
440 let index = u8::try_from(index).expect("checked just above");
441 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
442 }
443 self.insts.push(data);
444 self.inst_layout.push(InstLayout::default());
445 self.inst_spans.push(span);
446 inst
447 }
448
449 pub fn drop_results(&mut self, inst: Inst, drop: u8) {
465 let data = &self.insts[inst.index()];
466 assert!(drop <= data.results, "the instruction does not produce that many results");
467 let left = data.results - drop;
468 let first = data.first_result.map_or(0, Idx::raw) + u32::from(drop);
469 let data = &mut self.insts[inst.index()];
470 data.results = left;
471 data.first_result = (left > 0).then(|| Value::new(first));
472 for offset in 0..u32::from(left) {
473 let index = u8::try_from(offset).expect("no more than the count it came from");
474 let value = Value::new(first + offset);
475 self.values[value.index()].def = Def::Result { inst, index };
476 }
477 }
478
479 pub fn append_inst(&mut self, block: Block, inst: Inst) {
486 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
487 let last = self.blocks[block.index()].last;
488 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
489 match last {
490 Some(last) => self.inst_layout[last.index()].next = Some(inst),
491 None => self.blocks[block.index()].first = Some(inst),
492 }
493 self.blocks[block.index()].last = Some(inst);
494 self.placed(inst);
495 }
496
497 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
503 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
504 let at = self.inst_layout[before.index()];
505 let block = at.block.expect("the instruction to insert before is not in a block");
506 self.inst_layout[inst.index()] =
507 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
508 self.inst_layout[before.index()].prev = Some(inst);
509 match at.prev {
510 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
511 None => self.blocks[block.index()].first = Some(inst),
512 }
513 self.placed(inst);
514 }
515
516 pub fn insert_after(&mut self, inst: Inst, after: Inst) {
528 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
529 let at = self.inst_layout[after.index()];
530 let block = at.block.expect("the instruction to insert after is not in a block");
531 assert!(at.next.is_some(), "nothing goes after a terminator");
532 self.inst_layout[inst.index()] =
533 InstLayout { block: Some(block), prev: Some(after), next: at.next };
534 self.inst_layout[after.index()].next = Some(inst);
535 if let Some(next) = at.next {
536 self.inst_layout[next.index()].prev = Some(inst);
537 }
538 self.placed(inst);
539 }
540
541 pub fn remove_inst(&mut self, inst: Inst) {
551 let at = self.inst_layout[inst.index()];
552 let block = at.block.expect("the instruction is not in a block");
553 match at.prev {
554 Some(prev) => self.inst_layout[prev.index()].next = at.next,
555 None => self.blocks[block.index()].first = at.next,
556 }
557 match at.next {
558 Some(next) => self.inst_layout[next.index()].prev = at.prev,
559 None => self.blocks[block.index()].last = at.prev,
560 }
561 self.inst_layout[inst.index()] = InstLayout::default();
562 if self.anchors.contains(&inst) {
567 self.gone.insert(inst, (block, at.prev));
568 self.anchors.extend(at.prev);
569 }
570 let mut made = Vec::new();
577 for value in self.insts[inst.index()].results() {
578 for decl in self.held_from(value, block, at.prev) {
579 made.push((value, Start { decl, block, after: at.prev }));
580 }
581 }
582 if !made.is_empty() {
583 self.unplaced.insert(inst, made);
584 }
585 }
586
587 #[must_use]
590 pub fn is_placed(&self, block: Block) -> bool {
591 let data = &self.blocks[block.index()];
592 self.first_block == Some(block) || data.prev.is_some()
593 }
594
595 #[must_use]
597 pub fn block_of(&self, inst: Inst) -> Option<Block> {
598 self.inst_layout[inst.index()].block
599 }
600
601 #[must_use]
603 pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
604 self.inst_layout[inst.index()].next
605 }
606
607 #[must_use]
609 pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
610 self.inst_layout[inst.index()].prev
611 }
612
613 #[must_use]
616 pub fn unwinds_to_pad(&self, call: Inst) -> bool {
617 self.next_inst(call).is_some_and(|next| self[next].opcode == Opcode::Unwound)
618 }
619
620 #[must_use]
632 pub fn mem_in(&self, inst: Inst) -> Option<Value> {
633 let args = &self[self[inst].args];
634 args.last().copied().filter(|&arg| self[arg].ty.is_mem())
635 }
636
637 #[must_use]
647 pub fn mem_out(&self, inst: Inst) -> Option<Value> {
648 self[inst].results().last().filter(|&result| self[result].ty.is_mem())
649 }
650
651 #[must_use]
661 pub fn bulk(&self, inst: Inst) -> Option<Bulk> {
662 if !matches!(self[inst].opcode, Opcode::Memcpy | Opcode::Memmove | Opcode::Memset) {
663 return None;
664 }
665 let all = &self[self[inst].args];
666 let args = &all[..all.len() - usize::from(self.mem_in(inst).is_some())];
667 let [to, with, rest @ ..] = args else { return None };
668 Some(Bulk { to: *to, with: *with, length: rest.first().copied() })
669 }
670
671 #[must_use]
673 pub fn carries_mem(&self, inst: Inst) -> bool {
674 self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
675 }
676
677 pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
693 assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
694 assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
695 assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
696 let data = self[inst];
697 let mut args = self[data.args].to_vec();
698 args.push(incoming);
699 let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
700 if data.opcode.writes_memory() {
701 results.push(Type::MEM);
702 }
703 let span = self.span(inst);
704 let args = self.push_values(&args);
705 self.create_inst(InstData { args, ..data }, &results, span)
706 }
707
708 pub fn without_mem(&mut self, inst: Inst) -> Inst {
723 assert!(self.carries_mem(inst), "this is not on the memory chain");
724 let data = self[inst];
725 let mut args = self[data.args].to_vec();
726 if self.mem_in(inst).is_some() {
727 args.pop();
728 }
729 let results: Vec<Type> =
730 data.results().map(|result| self[result].ty).filter(|ty| !ty.is_mem()).collect();
731 let span = self.span(inst);
732 let args = self.push_values(&args);
733 self.create_inst(InstData { args, ..data }, &results, span)
734 }
735
736 #[must_use]
738 pub fn span(&self, inst: Inst) -> Span {
739 self.inst_spans[inst.index()]
740 }
741
742 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
747 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
748 }
749
750 #[must_use]
757 pub fn target_list(&self, inst: Inst) -> BlockCallList {
758 match self[inst].extra {
759 Extra::Targets(targets) => targets,
760 Extra::Switch(info) => self.switches[info.index()].targets,
761 Extra::Asm(info) => self.asms[info.index()].targets,
762 _ => BlockCallList::EMPTY,
763 }
764 }
765
766 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
770 let start = Idx::from_usize(self.value_pool.len());
771 self.value_pool.extend_from_slice(values);
772 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
773 }
774
775 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
782 let range = list.as_usize_range();
783 if range.end == self.value_pool.len() {
784 self.value_pool.push(value);
785 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
786 }
787 let start = self.value_pool.len();
788 self.value_pool.extend_from_within(range);
789 self.value_pool.push(value);
790 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
791 }
792
793 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
798 for value in &mut self.value_pool[list.as_usize_range()] {
799 *value = with(*value);
800 }
801 }
802
803 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
805 let start = Idx::from_usize(self.block_calls.len());
806 self.block_calls.extend_from_slice(calls);
807 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
808 }
809
810 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
812 self.block_calls[at.index()] = call;
813 }
814
815 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
817 let start = Idx::from_usize(self.imms.len());
818 self.imms.extend_from_slice(imms);
819 ImmList::new(start, Idx::from_usize(self.imms.len()))
820 }
821
822 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
824 self.imms.push(imm);
825 Idx::from_usize(self.imms.len() - 1)
826 }
827
828 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
830 let start = Idx::from_usize(self.slots.len());
831 self.slots.extend_from_slice(slots);
832 SlotList::new(start, Idx::from_usize(self.slots.len()))
833 }
834
835 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
837 self.va_objects.push(info);
838 Idx::from_usize(self.va_objects.len() - 1)
839 }
840
841 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
843 self.mem.push(info);
844 Idx::from_usize(self.mem.len() - 1)
845 }
846
847 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
849 let start = Idx::from_usize(self.abis.len());
850 self.abis.extend_from_slice(abis);
851 AbiList::new(start, Idx::from_usize(self.abis.len()))
852 }
853
854 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
856 self.calls.push(info);
857 Idx::from_usize(self.calls.len() - 1)
858 }
859
860 pub fn set_arg_groups(&mut self, call: Inst, groups: Vec<u32>) {
862 self.arg_groups.insert(call, groups);
863 }
864
865 #[must_use]
870 pub fn arg_groups(&self, call: Inst) -> Option<&[u32]> {
871 self.arg_groups.get(&call).map(Vec::as_slice)
872 }
873
874 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
876 self.switches.push(info);
877 Idx::from_usize(self.switches.len() - 1)
878 }
879
880 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
882 self.asms.push(info);
883 Idx::from_usize(self.asms.len() - 1)
884 }
885
886 #[must_use]
889 pub fn counts(&self) -> Counts {
890 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
891 }
892
893 #[must_use]
899 pub fn facts(&self, value: Value) -> Facts {
900 match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
901 Ok(at) => self.facts[at].1,
902 Err(_) => Facts::NONE,
903 }
904 }
905
906 pub fn set_facts(&mut self, value: Value, facts: Facts) {
911 let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
912 match (found, facts.is_empty()) {
913 (Ok(at), true) => drop(self.facts.remove(at)),
914 (Ok(at), false) => self.facts[at].1 = facts,
915 (Err(_), true) => {}
916 (Err(at), false) => self.facts.insert(at, (value, facts)),
917 }
918 }
919
920 pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
922 self.facts.iter().copied()
923 }
924
925 pub fn name_block(&mut self, block: Block, name: Symbol) {
939 let found = self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw());
940 if let Err(at) = found {
941 self.labels.insert(at, (block, name));
942 }
943 }
944
945 #[must_use]
947 pub fn block_name(&self, block: Block) -> Option<Symbol> {
948 match self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw()) {
949 Ok(at) => Some(self.labels[at].1),
950 Err(_) => None,
951 }
952 }
953
954 pub fn named_blocks(&self) -> impl Iterator<Item = (Block, Symbol)> + '_ {
956 self.labels.iter().copied()
957 }
958
959 pub fn declare_mem(&mut self, mem: Idx<MemInfo>, decl: u32) {
974 let found = self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw());
975 if let Err(at) = found {
976 self.mem_decls.insert(at, (mem, decl));
977 }
978 }
979
980 #[must_use]
983 pub fn mem_decl(&self, mem: Idx<MemInfo>) -> Option<u32> {
984 match self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw()) {
985 Ok(at) => Some(self.mem_decls[at].1),
986 Err(_) => None,
987 }
988 }
989
990 pub fn declare_value(&mut self, value: Value, decl: u32) {
1007 let key = (value.raw(), decl);
1008 let found = self.value_decls.binary_search_by_key(&key, |&(at, decl)| (at.raw(), decl));
1009 if let Err(at) = found {
1010 self.value_decls.insert(at, (value, decl));
1011 }
1012 }
1013
1014 pub fn value_decls(&self, value: Value) -> impl Iterator<Item = u32> + '_ {
1020 let at = self.value_decls.partition_point(|&(held, _)| held.raw() < value.raw());
1021 self.value_decls[at..]
1022 .iter()
1023 .take_while(move |&&(held, _)| held == value)
1024 .map(|&(_, decl)| decl)
1025 }
1026
1027 pub fn rename_value(&mut self, from: Value, to: Value) {
1040 if from == to {
1041 return;
1042 }
1043 match self.values[from.index()].def {
1046 Def::Result { inst, .. } => {
1047 let at = self.inst_layout[inst.index()];
1048 if let Some(block) = at.block {
1049 self.held_from(from, block, at.prev);
1050 }
1051 }
1052 Def::Param { block, index } => {
1053 let param = usize::try_from(index)
1054 .ok()
1055 .and_then(|index| self.blocks[block.index()].params.get(index).copied());
1056 if param == Some(from) {
1057 self.held_from(from, block, None);
1058 }
1059 }
1060 }
1061 let at = self.value_decls.partition_point(|&(held, _)| held.raw() < from.raw());
1062 let end = at + self.value_decls[at..].iter().take_while(|&&(held, _)| held == from).count();
1063 let moving: Vec<u32> = self.value_decls.drain(at..end).map(|(_, decl)| decl).collect();
1064 for decl in moving {
1065 self.declare_value(to, decl);
1066 }
1067 let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1068 let end =
1069 at + self.value_starts[at..].iter().take_while(|&&(held, _)| held == from).count();
1070 let moving: Vec<Start> = self.value_starts.drain(at..end).map(|(_, start)| start).collect();
1071 for start in moving {
1072 self.declare_value_from(to, start);
1073 }
1074 }
1075
1076 pub fn declare_value_from(&mut self, value: Value, start: Start) {
1089 let at = self.value_starts.partition_point(|&(held, _)| held.raw() <= value.raw());
1090 if !self.value_starts[..at]
1091 .iter()
1092 .rev()
1093 .take_while(|&&(held, _)| held == value)
1094 .any(|&(_, have)| have == start)
1095 {
1096 self.value_starts.insert(at, (value, start));
1097 self.anchors.extend(start.after);
1098 }
1099 }
1100
1101 pub fn value_starts(&self, value: Value) -> impl Iterator<Item = Start> + '_ {
1104 let at = self.value_starts.partition_point(|&(held, _)| held.raw() < value.raw());
1105 self.value_starts[at..]
1106 .iter()
1107 .take_while(move |&&(held, _)| held == value)
1108 .map(|&(_, start)| start)
1109 }
1110
1111 pub fn move_starts(&mut self, from: Value, into: Value, which: &[Start]) {
1119 if from == into {
1120 return;
1121 }
1122 let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1123 let end =
1124 at + self.value_starts[at..].iter().take_while(|&&(held, _)| held == from).count();
1125 let (moving, staying): (Vec<Start>, Vec<Start>) = self
1126 .value_starts
1127 .drain(at..end)
1128 .map(|(_, start)| start)
1129 .partition(|start| which.contains(start));
1130 let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1131 self.value_starts.splice(at..at, staying.into_iter().map(|start| (from, start)));
1132 for start in moving {
1133 self.declare_value_from(into, start);
1134 }
1135 }
1136
1137 fn held_from(&mut self, value: Value, block: Block, after: Option<Inst>) -> Vec<u32> {
1146 let at = self.value_decls.partition_point(|&(held, _)| held.raw() < value.raw());
1147 let end =
1148 at + self.value_decls[at..].iter().take_while(|&&(held, _)| held == value).count();
1149 let moving: Vec<u32> = self.value_decls.drain(at..end).map(|(_, decl)| decl).collect();
1150 for &decl in &moving {
1151 self.declare_value_from(value, Start { decl, block, after });
1152 }
1153 moving
1154 }
1155
1156 fn placed(&mut self, inst: Inst) {
1159 if self.unplaced.is_empty() {
1160 return;
1161 }
1162 let Some(made) = self.unplaced.remove(&inst) else { return };
1163 for (value, start) in made {
1164 let at = self.value_starts.partition_point(|&(held, _)| held.raw() < value.raw());
1165 let found = self.value_starts[at..]
1166 .iter()
1167 .take_while(|&&(held, _)| held == value)
1168 .position(|&(_, have)| have == start);
1169 if let Some(found) = found {
1172 self.value_starts.remove(at + found);
1173 self.declare_value(value, start.decl);
1174 }
1175 }
1176 }
1177
1178 #[must_use]
1187 pub fn start_place(&self, start: Start) -> Option<(Block, Option<Inst>)> {
1188 let (mut block, mut after) = (start.block, start.after);
1189 loop {
1190 let Some(inst) = after else {
1191 return self.is_placed(block).then_some((block, None));
1192 };
1193 if let Some(now) = self.block_of(inst) {
1194 return Some((now, Some(inst)));
1195 }
1196 (block, after) = *self.gone.get(&inst)?;
1197 }
1198 }
1199
1200 pub fn carry_starts(&mut self, from: Block, into: Block, after: Option<Inst>) {
1207 let unplaced = self.unplaced.values_mut().flatten().map(|(_, start)| start);
1208 for start in self.value_starts.iter_mut().map(|(_, start)| start).chain(unplaced) {
1209 if start.block == from && start.after.is_none() {
1210 *start = Start { block: into, after, ..*start };
1211 }
1212 }
1213 for place in self.gone.values_mut() {
1214 if *place == (from, None) {
1215 *place = (into, after);
1216 }
1217 }
1218 self.anchors.extend(after);
1219 }
1220
1221 fn add_value(&mut self, data: ValueData) -> Value {
1222 self.values.push(data);
1223 Idx::from_usize(self.values.len() - 1)
1224 }
1225}
1226
1227#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1234pub struct Start {
1235 pub decl: u32,
1237 pub block: Block,
1239 pub after: Option<Inst>,
1241}
1242
1243#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1245pub struct Counts {
1246 pub values: usize,
1248 pub insts: usize,
1250 pub blocks: usize,
1252}
1253
1254impl Index<Value> for Func {
1257 type Output = ValueData;
1258
1259 fn index(&self, value: Value) -> &ValueData {
1260 &self.values[value.index()]
1261 }
1262}
1263
1264impl Index<Inst> for Func {
1265 type Output = InstData;
1266
1267 fn index(&self, inst: Inst) -> &InstData {
1268 &self.insts[inst.index()]
1269 }
1270}
1271
1272impl IndexMut<Inst> for Func {
1273 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
1274 &mut self.insts[inst.index()]
1275 }
1276}
1277
1278impl Index<Block> for Func {
1279 type Output = BlockData;
1280
1281 fn index(&self, block: Block) -> &BlockData {
1282 &self.blocks[block.index()]
1283 }
1284}
1285
1286impl Index<Sig> for Func {
1287 type Output = Signature;
1288
1289 fn index(&self, sig: Sig) -> &Signature {
1290 &self.signatures[sig.index()]
1291 }
1292}
1293
1294impl Index<ValueList> for Func {
1295 type Output = [Value];
1296
1297 fn index(&self, list: ValueList) -> &[Value] {
1298 &self.value_pool[list.as_usize_range()]
1299 }
1300}
1301
1302impl Index<BlockCallList> for Func {
1303 type Output = [BlockCall];
1304
1305 fn index(&self, list: BlockCallList) -> &[BlockCall] {
1306 &self.block_calls[list.as_usize_range()]
1307 }
1308}
1309
1310impl Index<Idx<BlockCall>> for Func {
1311 type Output = BlockCall;
1312
1313 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
1314 &self.block_calls[at.index()]
1315 }
1316}
1317
1318impl Index<ImmList> for Func {
1319 type Output = [Imm];
1320
1321 fn index(&self, list: ImmList) -> &[Imm] {
1322 &self.imms[list.as_usize_range()]
1323 }
1324}
1325
1326impl Index<Idx<Imm>> for Func {
1327 type Output = Imm;
1328
1329 fn index(&self, at: Idx<Imm>) -> &Imm {
1330 &self.imms[at.index()]
1331 }
1332}
1333
1334impl Index<Idx<MemInfo>> for Func {
1335 type Output = MemInfo;
1336
1337 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
1338 &self.mem[at.index()]
1339 }
1340}
1341
1342impl Index<AbiList> for Func {
1343 type Output = [Abi];
1344
1345 fn index(&self, list: AbiList) -> &[Abi] {
1346 &self.abis[list.as_usize_range()]
1347 }
1348}
1349
1350impl Index<SlotList> for Func {
1351 type Output = [Slot];
1352
1353 fn index(&self, list: SlotList) -> &[Slot] {
1354 &self.slots[list.as_usize_range()]
1355 }
1356}
1357
1358impl Index<Idx<VaInfo>> for Func {
1359 type Output = VaInfo;
1360
1361 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
1362 &self.va_objects[at.index()]
1363 }
1364}
1365
1366impl Index<Idx<CallInfo>> for Func {
1367 type Output = CallInfo;
1368
1369 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
1370 &self.calls[at.index()]
1371 }
1372}
1373
1374impl Index<Idx<SwitchInfo>> for Func {
1375 type Output = SwitchInfo;
1376
1377 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
1378 &self.switches[at.index()]
1379 }
1380}
1381
1382impl Index<Idx<AsmInfo>> for Func {
1383 type Output = AsmInfo;
1384
1385 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
1386 &self.asms[at.index()]
1387 }
1388}
1389
1390#[derive(Debug)]
1397pub struct Builder<'a> {
1398 func: &'a mut Func,
1399 block: Block,
1400 span: Span,
1401}
1402
1403impl<'a> Builder<'a> {
1404 pub fn new(func: &'a mut Func, block: Block) -> Self {
1406 Self { func, block, span: Span::DUMMY }
1407 }
1408
1409 #[must_use]
1411 pub fn at(mut self, span: Span) -> Self {
1412 self.span = span;
1413 self
1414 }
1415
1416 pub fn set_span(&mut self, span: Span) {
1418 self.span = span;
1419 }
1420
1421 pub fn func(&mut self) -> &mut Func {
1423 self.func
1424 }
1425
1426 #[must_use]
1428 pub fn block(&self) -> Block {
1429 self.block
1430 }
1431
1432 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
1434 let inst = self.func.create_inst(data, results, self.span);
1435 self.func.append_inst(self.block, inst);
1436 inst
1437 }
1438
1439 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
1445 let inst = self.inst(data, &[ty]);
1446 self.func[inst].first_result.expect("one result was asked for")
1447 }
1448
1449 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
1455 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
1456 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
1457 }
1458
1459 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
1461 let imm = self.func.add_imm(Imm::from_bits(bits));
1462 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
1463 }
1464
1465 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
1467 let ty = self.func[lhs].ty;
1468 let args = self.func.push_values(&[lhs, rhs]);
1469 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
1470 }
1471
1472 pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
1485 let ty = self.func[lhs].ty;
1486 let args = self.func.push_values(&[lhs, rhs]);
1487 let results = [ty, ty.with_lane(Type::I1)];
1488 let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
1489 let mut answers = self.func[inst].results();
1490 let value = answers.next().expect("two results were asked for");
1491 let wrapped = answers.next().expect("two results were asked for");
1492 (value, wrapped)
1493 }
1494
1495 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
1497 let args = self.func.push_values(&[arg]);
1498 self.value(InstData { args, ..InstData::new(opcode) }, ty)
1499 }
1500
1501 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
1503 let ty = self.func[lhs].ty.with_lane(Type::I1);
1504 let args = self.func.push_values(&[lhs, rhs]);
1505 self.value(
1506 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
1507 ty,
1508 )
1509 }
1510
1511 pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
1517 let ty = self.func[then].ty;
1518 let args = self.func.push_values(&[cond, then, other]);
1519 self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
1520 }
1521
1522 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
1524 let ty = self.func[lhs].ty.with_lane(Type::I1);
1525 let args = self.func.push_values(&[lhs, rhs]);
1526 self.value(
1527 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
1528 ty,
1529 )
1530 }
1531
1532 pub fn mem_entry(&mut self) -> Value {
1536 self.value(InstData::new(Opcode::MemEntry), Type::MEM)
1537 }
1538
1539 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1541 let mem = self.func.add_mem(info);
1542 let args = self.func.push_values(&[addr]);
1543 self.value(
1544 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
1545 ty,
1546 )
1547 }
1548
1549 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1551 let mem = self.func.add_mem(info);
1552 let args = self.func.push_values(&[value, addr]);
1553 self.inst(
1554 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
1555 &[],
1556 )
1557 }
1558
1559 pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1567 let mem = self.func.add_mem(info);
1568 let args = self.func.push_values(&[addr]);
1569 self.value(
1570 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1571 ty,
1572 )
1573 }
1574
1575 pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1577 let mem = self.func.add_mem(info);
1578 let args = self.func.push_values(&[value, addr]);
1579 self.inst(
1580 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1581 &[],
1582 )
1583 }
1584
1585 pub fn cmpxchg(
1592 &mut self,
1593 addr: Value,
1594 expected: Value,
1595 desired: Value,
1596 info: MemInfo,
1597 flags: Flags,
1598 ) -> (Value, Value) {
1599 let ty = self.func[expected].ty;
1600 let mem = self.func.add_mem(info);
1601 let args = self.func.push_values(&[addr, expected, desired]);
1602 let inst = self.inst(
1603 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1604 &[ty, Type::I1],
1605 );
1606 let results: Vec<Value> = self.func[inst].results().collect();
1607 let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1608 (old, exchanged)
1609 }
1610
1611 pub fn atomic_rmw(
1619 &mut self,
1620 op: RmwOp,
1621 addr: Value,
1622 operand: Value,
1623 info: MemInfo,
1624 flags: Flags,
1625 ) -> Value {
1626 let ty = self.func[operand].ty;
1627 let mem = self.func.add_mem(info);
1628 let args = self.func.push_values(&[addr, operand]);
1629 self.value(
1630 InstData {
1631 args,
1632 flags,
1633 extra: Extra::Rmw(op, mem),
1634 ..InstData::new(Opcode::AtomicRmw)
1635 },
1636 ty,
1637 )
1638 }
1639
1640 pub fn fence(&mut self, order: MemOrder) -> Inst {
1642 self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1643 }
1644
1645 pub fn prefetch(&mut self, address: Value, hint: PrefetchHint) -> Inst {
1652 let args = self.func.push_values(&[address]);
1653 self.inst(
1654 InstData { args, extra: Extra::Prefetch(hint), ..InstData::new(Opcode::Prefetch) },
1655 &[],
1656 )
1657 }
1658
1659 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1661 let call = self.block_call(target, args);
1662 let targets = self.func.push_block_calls(&[call]);
1663 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1664 }
1665
1666 pub fn block_addr(&mut self, target: Block) -> Value {
1672 let call = self.block_call(target, &[]);
1673 let targets = self.func.push_block_calls(&[call]);
1674 self.value(
1675 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1676 Type::PTR,
1677 )
1678 }
1679
1680 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1686 let calls: Vec<BlockCall> =
1687 targets.iter().map(|&target| self.block_call(target, &[])).collect();
1688 let targets = self.func.push_block_calls(&calls);
1689 let args = self.func.push_values(&[addr]);
1690 self.inst(
1691 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1692 &[],
1693 )
1694 }
1695
1696 pub fn br_if(
1698 &mut self,
1699 cond: Value,
1700 then_block: Block,
1701 then_args: &[Value],
1702 else_block: Block,
1703 else_args: &[Value],
1704 ) -> Inst {
1705 let then_call = self.block_call(then_block, then_args);
1706 let else_call = self.block_call(else_block, else_args);
1707 let targets = self.func.push_block_calls(&[then_call, else_call]);
1708 let args = self.func.push_values(&[cond]);
1709 self.inst(
1710 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1711 &[],
1712 )
1713 }
1714
1715 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1722 let ty = self.func[value].ty.lane();
1723 let mut calls = vec![self.block_call(default, &[])];
1724 let mut values = Vec::with_capacity(cases.len());
1725 for &(value, block) in cases {
1726 calls.push(self.block_call(block, &[]));
1727 values.push(Imm::int(value, ty));
1728 }
1729 let targets = self.func.push_block_calls(&calls);
1730 let cases = self.func.push_imms(&values);
1731 let info = self.func.add_switch(SwitchInfo { targets, cases });
1732 let args = self.func.push_values(&[value]);
1733 self.inst(
1734 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1735 &[],
1736 )
1737 }
1738
1739 pub fn ret(&mut self, values: &[Value]) -> Inst {
1741 let args = self.func.push_values(values);
1742 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1743 }
1744
1745 pub fn unreachable(&mut self) -> Inst {
1747 self.inst(InstData::new(Opcode::Unreachable), &[])
1748 }
1749
1750 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1752 self.call_varargs(callee, signature, args, &[])
1753 }
1754
1755 pub fn call_varargs(
1761 &mut self,
1762 callee: Symbol,
1763 signature: Sig,
1764 args: &[Value],
1765 varargs: &[Abi],
1766 ) -> Inst {
1767 let varargs = self.func.push_abis(varargs);
1768 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1769 let returns: Vec<Type> = self.func[signature].return_types().collect();
1770 let args = self.func.push_values(args);
1771 self.inst(
1772 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1773 &returns,
1774 )
1775 }
1776
1777 pub fn inline_asm(
1783 &mut self,
1784 info: AsmInfo,
1785 args: &[Value],
1786 results: &[Type],
1787 flags: Flags,
1788 ) -> Inst {
1789 let info = self.func.add_asm(info);
1790 let args = self.func.push_values(args);
1791 self.inst(
1792 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1793 results,
1794 )
1795 }
1796
1797 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1798 BlockCall::new(block, self.func.push_values(args))
1799 }
1800}
1801
1802#[cfg(test)]
1803mod tests {
1804 use rucc_base::Interner;
1805
1806 use super::*;
1807 use crate::inst::BlockCallList;
1808 use crate::{MemOrder, Restrict};
1809
1810 fn sum() -> (Func, Block, Block, Block) {
1812 let mut names = Interner::new();
1813 let i32_ = Type::int(32);
1814 let mut func = Func::new(
1815 names.intern("sum"),
1816 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1817 );
1818
1819 let entry = func.create_block();
1820 let n = func.append_param(entry, i32_);
1821 let header = func.create_block();
1822 let acc = func.append_param(header, i32_);
1823 let i = func.append_param(header, i32_);
1824 let exit = func.create_block();
1825 let result = func.append_param(exit, i32_);
1826
1827 let mut b = Builder::new(&mut func, entry);
1828 let zero = b.iconst(i32_, 0);
1829 let cmp = b.icmp(IntPred::Sle, n, zero);
1830 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1831
1832 let mut b = Builder::new(&mut func, header);
1833 let one = b.iconst(i32_, 1);
1834 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1835 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1836 let done = b.icmp(IntPred::Sge, next, n);
1837 b.br_if(done, exit, &[total], header, &[total, next]);
1838
1839 let mut b = Builder::new(&mut func, exit);
1840 b.ret(&[result]);
1841
1842 (func, entry, header, exit)
1843 }
1844
1845 #[test]
1846 fn the_blocks_come_back_in_the_order_they_were_made() {
1847 let (func, entry, header, exit) = sum();
1848 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1849 assert_eq!(func.entry(), Some(entry));
1850 }
1851
1852 #[test]
1853 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1854 let (mut func, entry, header, exit) = sum();
1855 let inside: Vec<Inst> = func.insts(header).collect();
1856 func.remove_block(header);
1857 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1858 assert_eq!(func.entry(), Some(entry));
1859 assert_eq!(func[entry].next, Some(exit));
1860 assert_eq!(func[exit].prev, Some(entry));
1861 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1863 assert!(func.insts(header).next().is_none());
1864 }
1865
1866 #[test]
1867 fn each_block_holds_what_was_appended_to_it() {
1868 let (func, entry, header, exit) = sum();
1869 let opcodes =
1870 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1871 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1872 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1873 assert_eq!(opcodes(exit), ["return"]);
1874 }
1875
1876 #[test]
1877 fn dropping_the_results_in_front_moves_the_first_one_along_and_renumbers_the_rest() {
1878 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1883 let types = [Type::int(32), Type::int(64), Type::MEM];
1884 let inst = func.create_inst(InstData::new(Opcode::Call), &types, Span::DUMMY);
1885 let before: Vec<Value> = func[inst].results().collect();
1886 func.drop_results(inst, 1);
1887 assert_eq!(func[inst].results().collect::<Vec<_>>(), before[1..]);
1888 assert_eq!(func[before[1]].def, Def::Result { inst, index: 0 });
1889 assert_eq!(func[before[2]].def, Def::Result { inst, index: 1 });
1890 assert_eq!(func.mem_out(inst), Some(before[2]));
1891 }
1892
1893 #[test]
1894 fn dropping_every_result_leaves_an_instruction_that_produces_nothing() {
1895 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1896 let inst = func.create_inst(InstData::new(Opcode::Call), &[Type::int(32)], Span::DUMMY);
1897 func.drop_results(inst, 1);
1898 assert_eq!(func[inst].results().count(), 0);
1899 assert_eq!(func[inst].first_result, None);
1900 }
1901
1902 #[test]
1903 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1904 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1907 let block = func.create_block();
1908 let plain = func.add_asm(AsmInfo {
1909 template: Symbol::from_raw(0),
1910 constraints: Symbol::from_raw(0),
1911 clobbers: Symbol::from_raw(0),
1912 targets: BlockCallList::EMPTY,
1913 });
1914 let call = BlockCall::to(block);
1915 let targets = func.push_block_calls(&[call]);
1916 let labelled = func.add_asm(AsmInfo {
1917 template: Symbol::from_raw(0),
1918 constraints: Symbol::from_raw(0),
1919 clobbers: Symbol::from_raw(0),
1920 targets,
1921 });
1922
1923 let mut make = |extra| {
1924 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1925 func.create_inst(data, &[], Span::DUMMY)
1926 };
1927 let plain = make(Extra::Asm(plain));
1928 let labelled = make(Extra::Asm(labelled));
1929 assert!(!func.is_terminator(plain));
1930 assert!(func.is_terminator(labelled));
1931 }
1932
1933 #[test]
1934 fn every_block_ends_in_its_terminator() {
1935 let (func, entry, header, exit) = sum();
1936 for block in [entry, header, exit] {
1937 let last = func.terminator(block).expect("a terminator");
1938 assert_eq!(Some(last), func.insts(block).last());
1939 }
1940 }
1941
1942 #[test]
1943 fn a_branch_carries_the_arguments_the_block_takes() {
1944 let (func, entry, header, _) = sum();
1945 let br = func.terminator(entry).expect("a terminator");
1946 let calls: Vec<BlockCall> = func.successors(br).collect();
1947 assert_eq!(calls.len(), 2);
1948 assert_eq!(calls[1].block, header);
1950 assert_eq!(func[calls[1].args].len(), 2);
1951 assert_eq!(func[header].params.len(), 2);
1952 assert_eq!(func[calls[0].args].len(), 1);
1953 }
1954
1955 #[test]
1956 fn a_value_knows_what_defined_it() {
1957 let (func, entry, _, _) = sum();
1958 let first = func.insts(entry).next().expect("an instruction");
1959 let value = func[first].first_result.expect("a result");
1960 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1961 assert_eq!(func[value].ty, Type::int(32));
1962
1963 let param = func[entry].params[0];
1964 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1965 }
1966
1967 #[test]
1968 fn a_comparison_produces_one_bit() {
1969 let (func, entry, _, _) = sum();
1970 let cmp = func.insts(entry).nth(1).expect("the comparison");
1971 let value = func[cmp].first_result.expect("a result");
1972 assert_eq!(func[value].ty, Type::I1);
1973 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1974 }
1975
1976 #[test]
1977 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1978 let (func, _, header, _) = sum();
1979 let add = func.insts(header).nth(1).expect("the addition");
1980 assert_eq!(func[add].flags, Flags::NSW);
1981 let cmp = func.insts(header).nth(3).expect("the comparison");
1982 assert_eq!(func[cmp].flags, Flags::NONE);
1983 }
1984
1985 #[test]
1986 fn removing_an_instruction_takes_it_out_of_the_middle() {
1987 let (mut func, _, header, _) = sum();
1988 let add = func.insts(header).nth(1).expect("the addition");
1989 func.remove_inst(add);
1990 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1991 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1992 assert_eq!(func.block_of(add), None);
1993 }
1994
1995 #[test]
1996 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1997 let (mut func, entry, _, _) = sum();
1998 let first = func.insts(entry).next().expect("an instruction");
1999 let last = func.terminator(entry).expect("a terminator");
2000 func.remove_inst(first);
2001 func.remove_inst(last);
2002 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
2003 assert_eq!(opcodes, ["icmp"]);
2004 assert_eq!(func[entry].first, func[entry].last);
2005 }
2006
2007 #[test]
2008 fn removing_the_only_instruction_empties_the_block() {
2009 let (mut func, _, _, exit) = sum();
2010 let only = func.insts(exit).next().expect("an instruction");
2011 func.remove_inst(only);
2012 assert_eq!(func.insts(exit).count(), 0);
2013 assert_eq!(func[exit].first, None);
2014 assert_eq!(func[exit].last, None);
2015 }
2016
2017 #[test]
2018 fn inserting_before_puts_it_in_the_right_place() {
2019 let (mut func, entry, _, _) = sum();
2020 let cmp = func.insts(entry).nth(1).expect("the comparison");
2021 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2022 func.insert_before(made, cmp);
2023 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
2024 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
2025 }
2026
2027 #[test]
2028 fn inserting_before_the_first_makes_it_the_first() {
2029 let (mut func, entry, _, _) = sum();
2030 let first = func.insts(entry).next().expect("an instruction");
2031 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2032 func.insert_before(made, first);
2033 assert_eq!(func.insts(entry).next(), Some(made));
2034 assert_eq!(func[entry].first, Some(made));
2035 }
2036
2037 #[test]
2038 fn inserting_after_puts_it_in_the_right_place() {
2039 let (mut func, entry, _, _) = sum();
2040 let first = func.insts(entry).next().expect("an instruction");
2041 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2042 func.insert_after(made, first);
2043 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
2044 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
2045 assert_eq!(func[entry].first, Some(first));
2046 }
2047
2048 #[test]
2049 #[should_panic(expected = "nothing goes after a terminator")]
2050 fn inserting_after_the_terminator_is_refused() {
2051 let (mut func, entry, _, _) = sum();
2054 let last = func.insts(entry).last().expect("a terminator");
2055 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2056 func.insert_after(made, last);
2057 }
2058
2059 #[test]
2060 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
2061 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2062 let block = func.create_block();
2063 let a = func.append_param(block, Type::int(32));
2064 let b = func.append_param(block, Type::int(32));
2065 let list = func.push_values(&[a]);
2066 let grown = func.append_arg(list, b);
2067 assert_eq!(func[grown], [a, b]);
2068 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
2069 }
2070
2071 #[test]
2072 fn a_list_is_copied_when_something_is_behind_it() {
2073 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2074 let block = func.create_block();
2075 let a = func.append_param(block, Type::int(32));
2076 let b = func.append_param(block, Type::int(32));
2077 let list = func.push_values(&[a, a]);
2078 let behind = func.push_values(&[b]);
2079 let grown = func.append_arg(list, b);
2080 assert_eq!(func[grown], [a, a, b]);
2081 assert_eq!(func[list], [a, a], "the old run is still readable");
2082 assert_eq!(func[behind], [b], "and so is what was behind it");
2083 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
2084 }
2085
2086 #[test]
2087 fn a_parameter_added_late_is_the_next_one_along() {
2088 let (mut func, entry, header, _) = sum();
2092 let extra = func.append_param(header, Type::int(32));
2093 assert_eq!(func[header].params.len(), 3);
2094 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
2095
2096 let br = func.terminator(entry).expect("a terminator");
2097 let call = func.successors(br).nth(1).expect("the branch to the header");
2098 let grown = func.append_arg(call.args, extra);
2099 assert_eq!(func[grown].len(), 3);
2100 }
2101
2102 #[test]
2103 fn a_dropped_parameter_takes_what_was_known_about_it_along() {
2104 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2107 let block = func.create_block();
2108 let kept = func.append_param(block, Type::PTR);
2109 let dropped = func.append_param(block, Type::PTR);
2110 let aligned = Facts { align: Some(4), ..Facts::NONE };
2111 func.set_facts(kept, aligned);
2112 func.set_facts(dropped, aligned);
2113
2114 func.retain_params(block, |value| value == kept);
2115 assert_eq!(func.facts(kept), aligned);
2116 assert_eq!(func.facts(dropped), Facts::NONE);
2117 }
2118
2119 #[test]
2120 fn a_span_rides_along_with_the_instruction() {
2121 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2122 let block = func.create_block();
2123 let span = Span::new(10, 20);
2124 let mut b = Builder::new(&mut func, block).at(span);
2125 let value = b.iconst(Type::int(32), 7);
2126 let inst = match func[value].def {
2127 Def::Result { inst, .. } => inst,
2128 Def::Param { .. } => unreachable!("a constant is not a parameter"),
2129 };
2130 assert_eq!(func.span(inst), span);
2131 }
2132
2133 #[test]
2134 fn a_store_produces_nothing_and_a_load_produces_one_value() {
2135 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2136 let block = func.create_block();
2137 let addr = func.append_param(block, Type::PTR);
2138 let info = MemInfo {
2139 size: 4,
2140 align: 4,
2141 order: MemOrder::NotAtomic,
2142 tbaa: None,
2143 owns: 0,
2144 restrict: Restrict::NONE,
2145 };
2146 let mut b = Builder::new(&mut func, block);
2147 let value = b.load(Type::int(32), addr, info, Flags::NONE);
2148 let store = b.store(value, addr, info, Flags::VOLATILE);
2149 assert_eq!(func[store].results, 0);
2150 assert_eq!(func[store].flags, Flags::VOLATILE);
2151 assert_eq!(func[value].ty, Type::int(32));
2152 }
2153
2154 #[test]
2155 fn memory_remembers_which_declaration_asked_for_it_and_which_did_not() {
2156 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2157 let info = MemInfo {
2158 size: 4,
2159 align: 4,
2160 order: MemOrder::NotAtomic,
2161 tbaa: None,
2162 owns: 0,
2163 restrict: Restrict::NONE,
2164 };
2165 let first = func.add_mem(info);
2166 let second = func.add_mem(info);
2167 let third = func.add_mem(info);
2168
2169 func.declare_mem(third, 7);
2172 func.declare_mem(first, 2);
2173 func.declare_mem(first, 9);
2175
2176 assert_eq!(func.mem_decl(first), Some(2));
2177 assert_eq!(func.mem_decl(third), Some(7));
2178 assert_eq!(func.mem_decl(second), None);
2180 }
2181
2182 #[test]
2188 fn a_value_says_which_declarations_it_is_and_a_rename_carries_them_over() {
2189 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2190 let block = func.create_block();
2191 let first = func.append_param(block, Type::int(32));
2192 let second = func.append_param(block, Type::int(32));
2193 let third = func.append_param(block, Type::int(32));
2194
2195 func.declare_value(third, 7);
2198 func.declare_value(first, 2);
2199 func.declare_value(first, 2);
2201
2202 assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2]);
2203 assert_eq!(func.value_decls(third).collect::<Vec<u32>>(), vec![7]);
2204 assert_eq!(func.value_decls(second).count(), 0);
2206
2207 func.rename_value(third, first);
2211 assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2]);
2212 assert_eq!(
2213 func.value_starts(first).collect::<Vec<Start>>(),
2214 vec![Start { decl: 7, block, after: None }]
2215 );
2216 assert_eq!(func.value_decls(third).count(), 0);
2217
2218 func.rename_value(second, third);
2220 assert_eq!(func.value_decls(third).count(), 0);
2221 }
2222
2223 #[test]
2226 fn a_start_part_of_the_way_through_is_kept_and_a_rename_carries_it_over() {
2227 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2228 let block = func.create_block();
2229 let first = func.append_param(block, Type::int(32));
2230 let second = func.append_param(block, Type::int(32));
2231 let one = Builder::new(&mut func, block).iconst(Type::int(32), 1);
2232 let inst = func.insts(block).next().expect("the constant");
2233
2234 let top = Start { decl: 4, block, after: None };
2235 let later = Start { decl: 4, block, after: Some(inst) };
2236 func.declare_value_from(first, later);
2237 func.declare_value_from(first, top);
2238 func.declare_value_from(first, later);
2240 assert_eq!(func.value_starts(first).collect::<Vec<_>>(), vec![later, top]);
2241 assert_eq!(func.value_starts(one).count(), 0);
2242
2243 func.rename_value(first, second);
2244 assert_eq!(func.value_starts(second).collect::<Vec<_>>(), vec![later, top]);
2245 assert_eq!(func.value_starts(first).count(), 0);
2246 }
2247
2248 fn places(func: &Func, value: Value) -> Vec<Option<(Block, Option<Inst>)>> {
2250 func.value_starts(value).map(|start| func.start_place(start)).collect()
2251 }
2252
2253 #[test]
2256 fn a_start_after_an_instruction_that_is_taken_out_stays_where_it_was() {
2257 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2258 let block = func.create_block();
2259 let value = func.append_param(block, Type::int(32));
2260 let mut build = Builder::new(&mut func, block);
2261 build.iconst(Type::int(32), 1);
2262 build.iconst(Type::int(32), 2);
2263 let [one, two]: [Inst; 2] = func.insts(block).collect::<Vec<_>>().try_into().expect("two");
2264 func.declare_value_from(value, Start { decl: 4, block, after: Some(two) });
2265
2266 func.remove_inst(two);
2267 assert_eq!(places(&func, value), [Some((block, Some(one)))]);
2268 let data = func[one];
2269 let fresh = func.create_inst(data, &[Type::int(32)], Span::DUMMY);
2270 func.insert_before(fresh, one);
2271 func.remove_inst(one);
2272 assert_eq!(places(&func, value), [Some((block, Some(fresh)))]);
2273 func.remove_inst(fresh);
2274 assert_eq!(places(&func, value), [Some((block, None))]);
2275 }
2276
2277 #[test]
2280 fn a_start_after_an_instruction_a_pass_moves_goes_with_it() {
2281 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2282 let top = func.create_block();
2283 let below = func.create_block();
2284 let value = func.append_param(top, Type::int(32));
2285 let mut build = Builder::new(&mut func, below);
2286 build.iconst(Type::int(32), 1);
2287 build.iconst(Type::int(32), 2);
2288 let [one, two]: [Inst; 2] = func.insts(below).collect::<Vec<_>>().try_into().expect("two");
2289 func.declare_value_from(value, Start { decl: 4, block: below, after: Some(two) });
2290
2291 for inst in [one, two] {
2293 func.remove_inst(inst);
2294 func.append_inst(top, inst);
2295 }
2296 func.remove_block(below);
2297 assert_eq!(places(&func, value), [Some((top, Some(two)))]);
2298 }
2299
2300 #[test]
2303 fn a_start_at_the_top_of_a_block_that_is_merged_away_is_carried_over() {
2304 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2305 let top = func.create_block();
2306 let below = func.create_block();
2307 let value = func.append_param(top, Type::int(32));
2308 Builder::new(&mut func, top).iconst(Type::int(32), 1);
2309 Builder::new(&mut func, below).iconst(Type::int(32), 2);
2310 let last = func.insts(top).next();
2311 func.declare_value_from(value, Start { decl: 4, block: below, after: None });
2312
2313 for inst in func.insts(below).collect::<Vec<_>>() {
2314 func.remove_inst(inst);
2315 func.append_inst(top, inst);
2316 }
2317 func.carry_starts(below, top, last);
2318 func.remove_block(below);
2319 assert_eq!(places(&func, value), [Some((top, last))]);
2320 }
2321
2322 #[test]
2325 fn a_name_on_a_value_whose_instruction_goes_becomes_a_start_and_comes_back_if_it_returns() {
2326 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2327 let block = func.create_block();
2328 let mut build = Builder::new(&mut func, block);
2329 let kept = build.iconst(Type::int(32), 1);
2330 let moved = build.iconst(Type::int(32), 2);
2331 let first = func.insts(block).next().expect("one");
2332 let second = func.insts(block).nth(1).expect("two");
2333 func.declare_value(kept, 4);
2334 func.declare_value(moved, 5);
2335
2336 func.remove_inst(first);
2337 assert_eq!(func.value_decls(kept).count(), 0);
2338 assert_eq!(places(&func, kept), [Some((block, None))]);
2339
2340 func.remove_inst(second);
2341 func.append_inst(block, second);
2342 assert_eq!(func.value_decls(moved).collect::<Vec<_>>(), [5]);
2343 assert_eq!(func.value_starts(moved).count(), 0);
2344 }
2345
2346 #[test]
2349 fn a_rename_into_an_earlier_value_starts_the_declaration_where_the_later_one_was() {
2350 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2351 let block = func.create_block();
2352 let mut build = Builder::new(&mut func, block);
2353 let early = build.iconst(Type::int(32), 1);
2354 build.iconst(Type::int(32), 3);
2355 let late = build.iconst(Type::int(32), 1);
2356 let middle = func.insts(block).nth(1).expect("three");
2357 func.declare_value(late, 4);
2358
2359 func.rename_value(late, early);
2360 assert_eq!(func.value_decls(early).count(), 0);
2361 assert_eq!(places(&func, early), [Some((block, Some(middle)))]);
2362 }
2363
2364 #[test]
2366 fn moving_starts_moves_the_ones_asked_for_and_no_others() {
2367 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2368 let block = func.create_block();
2369 let mut build = Builder::new(&mut func, block);
2370 let from = build.iconst(Type::int(32), 1);
2371 let into = build.iconst(Type::int(32), 2);
2372 let first = func.insts(block).next();
2373 let starts: Vec<Start> = (5..8).map(|decl| Start { decl, block, after: first }).collect();
2374 for &start in &starts {
2375 func.declare_value_from(from, start);
2376 }
2377
2378 func.move_starts(from, into, &starts[1..2]);
2379 assert_eq!(func.value_starts(from).collect::<Vec<Start>>(), [starts[0], starts[2]]);
2380 assert_eq!(func.value_starts(into).collect::<Vec<Start>>(), [starts[1]]);
2381 }
2382
2383 #[test]
2384 fn a_call_produces_what_its_signature_returns() {
2385 let mut names = Interner::new();
2386 let mut func = Func::new(names.intern("caller"), Signature::new());
2387 let sig = func.add_signature(
2388 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
2389 );
2390 let block = func.create_block();
2391 let arg = func.append_param(block, Type::int(32));
2392 let callee = names.intern("callee");
2393 let mut b = Builder::new(&mut func, block);
2394 let call = b.call(callee, sig, &[arg]);
2395 assert_eq!(func[call].results, 1);
2396 let value = func[call].first_result.expect("a result");
2397 assert_eq!(func[value].ty, Type::int(64));
2398 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
2399 }
2400
2401 #[test]
2402 fn the_counts_are_what_was_made() {
2403 let (func, _, _, _) = sum();
2404 let counts = func.counts();
2405 assert_eq!(counts.blocks, 3);
2406 assert_eq!(counts.insts, 9);
2407 assert_eq!(counts.values, 4 + 6);
2410 }
2411
2412 #[test]
2413 #[should_panic(expected = "the instruction is in a block")]
2414 fn appending_an_instruction_twice_is_refused() {
2415 let (mut func, entry, _, _) = sum();
2416 let first = func.insts(entry).next().expect("an instruction");
2417 func.append_inst(entry, first);
2418 }
2419
2420 #[test]
2421 #[should_panic(expected = "the instruction is not in a block")]
2422 fn removing_an_instruction_twice_is_refused() {
2423 let (mut func, entry, _, _) = sum();
2424 let first = func.insts(entry).next().expect("an instruction");
2425 func.remove_inst(first);
2426 func.remove_inst(first);
2427 }
2428
2429 fn threaded() -> (Func, Inst, Inst) {
2431 let mut names = Interner::new();
2432 let i32_ = Type::int(32);
2433 let mut func = Func::new(
2434 names.intern("thread"),
2435 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
2436 );
2437 let entry = func.create_block();
2438 let addr = func.append_param(entry, Type::PTR);
2439 let info = MemInfo {
2440 size: 4,
2441 align: 4,
2442 order: MemOrder::NotAtomic,
2443 tbaa: None,
2444 owns: 0,
2445 restrict: Restrict::NONE,
2446 };
2447
2448 let mut b = Builder::new(&mut func, entry);
2449 let start = b.mem_entry();
2450 let seven = b.iconst(i32_, 7);
2451 let store = b.store(seven, addr, info, Flags::NONE);
2452 let value = b.load(i32_, addr, info, Flags::NONE);
2453 let Def::Result { inst: load, .. } = func[value].def else {
2454 panic!("the load produced it");
2455 };
2456
2457 let store = func.with_mem(store, start);
2458 let after = func.mem_out(store).expect("a store makes a new version");
2459 let load = func.with_mem(load, after);
2460 (func, store, load)
2461 }
2462
2463 #[test]
2464 fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
2465 let (func, store, load) = threaded();
2466 assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
2467 assert_eq!(func[func[store].args].len(), 3);
2468 assert!(func.carries_mem(store));
2469 assert!(func.carries_mem(load));
2470
2471 assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
2474 assert_eq!(func.mem_in(load), func.mem_out(store));
2475 assert_eq!(func.mem_out(load), None);
2476 }
2477
2478 #[test]
2479 #[should_panic(expected = "this is already on the memory chain")]
2480 fn threading_memory_through_the_same_instruction_twice_is_refused() {
2481 let (mut func, store, _) = threaded();
2482 let start = func.mem_in(store).expect("it was threaded");
2483 func.with_mem(store, start);
2484 }
2485
2486 fn copies() -> (Func, Inst, Inst) {
2489 let mut names = Interner::new();
2490 let i64_ = Type::int(64);
2491 let mut func = Func::new(
2492 names.intern("copies"),
2493 Signature::new().with_params(&[Type::PTR, Type::PTR, i64_]),
2494 );
2495 let entry = func.create_block();
2496 let to = func.append_param(entry, Type::PTR);
2497 let from = func.append_param(entry, Type::PTR);
2498 let length = func.append_param(entry, i64_);
2499 let info = MemInfo {
2500 size: 16,
2501 align: 4,
2502 order: MemOrder::NotAtomic,
2503 tbaa: None,
2504 owns: 0,
2505 restrict: Restrict::NONE,
2506 };
2507
2508 let mut b = Builder::new(&mut func, entry);
2509 let start = b.mem_entry();
2510 let mem = b.func().add_mem(info);
2511 let args = b.func().push_values(&[to, from]);
2512 let fixed =
2513 b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2514 let mem = b.func().add_mem(MemInfo { size: 0, ..info });
2515 let args = b.func().push_values(&[to, from, length]);
2516 let computed =
2517 b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2518 b.ret(&[]);
2519
2520 let fixed = func.with_mem(fixed, start);
2521 let after = func.mem_out(fixed).expect("a copy makes a new version");
2522 let computed = func.with_mem(computed, after);
2523 (func, fixed, computed)
2524 }
2525
2526 #[test]
2527 fn a_bulk_copy_hands_back_its_length_where_it_has_one_and_nothing_where_the_payload_has_it() {
2528 let (func, fixed, computed) = copies();
2529 let params = &func[func.entry().expect("an entry")].params;
2530 let [to, from, length] = params[..] else { panic!("three of them were appended") };
2531
2532 let bulk = func.bulk(fixed).expect("a memcpy is one");
2533 assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, None));
2534
2535 let bulk = func.bulk(computed).expect("a memcpy is one");
2536 assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, Some(length)));
2537 }
2538
2539 #[test]
2540 fn an_instruction_that_is_not_a_bulk_operation_is_not_taken_apart_as_one() {
2541 let (func, store, load) = threaded();
2542 assert_eq!(func.bulk(store), None);
2543 assert_eq!(func.bulk(load), None);
2544 }
2545}