1use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33use rucc_target::Slot;
34
35use crate::inst::{
36 Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
37 ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo, VaInfo,
38 Value, ValueData, ValueList,
39};
40use crate::module::{Linkage, Visibility};
41use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, RmwOp, Type};
42
43#[derive(Debug)]
45pub struct Func {
46 pub name: Symbol,
48 pub linkage: Linkage,
50 pub visibility: Visibility,
52 pub section: Option<Symbol>,
55 pub align: Option<u32>,
62 pub attrs: Attrs,
65
66 values: Vec<ValueData>,
67 insts: Vec<InstData>,
68 inst_layout: Vec<InstLayout>,
69 inst_spans: Vec<Span>,
70 blocks: Vec<BlockData>,
71
72 value_pool: Vec<Value>,
73 block_calls: Vec<BlockCall>,
74 imms: Vec<Imm>,
75 mem: Vec<MemInfo>,
76 calls: Vec<CallInfo>,
77 abis: Vec<Abi>,
78 switches: Vec<SwitchInfo>,
79 asms: Vec<AsmInfo>,
80 slots: Vec<Slot>,
81 va_objects: Vec<VaInfo>,
82 signatures: Vec<Signature>,
83 facts: Vec<(Value, Facts)>,
84
85 first_block: Option<Block>,
86 last_block: Option<Block>,
87}
88
89impl Func {
90 #[must_use]
97 pub fn new(name: Symbol, signature: Signature) -> Self {
98 Self {
99 name,
100 linkage: Linkage::External,
101 visibility: Visibility::Default,
102 section: None,
103 align: None,
104 attrs: Attrs::NONE,
105 values: Vec::new(),
106 insts: Vec::new(),
107 inst_layout: Vec::new(),
108 inst_spans: Vec::new(),
109 blocks: Vec::new(),
110 value_pool: Vec::new(),
111 block_calls: Vec::new(),
112 imms: Vec::new(),
113 mem: Vec::new(),
114 calls: Vec::new(),
115 abis: Vec::new(),
116 switches: Vec::new(),
117 asms: Vec::new(),
118 slots: Vec::new(),
119 va_objects: Vec::new(),
120 signatures: vec![signature],
121 facts: Vec::new(),
122 first_block: None,
123 last_block: None,
124 }
125 }
126
127 #[must_use]
129 pub fn signature(&self) -> &Signature {
130 &self.signatures[0]
131 }
132
133 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
135 self.signatures.iter()
136 }
137
138 pub fn add_signature(&mut self, signature: Signature) -> Sig {
140 self.signatures.push(signature);
141 Idx::from_usize(self.signatures.len() - 1)
142 }
143
144 #[must_use]
149 pub fn entry(&self) -> Option<Block> {
150 self.first_block
151 }
152
153 #[must_use]
160 pub fn is_declaration(&self) -> bool {
161 self.first_block.is_none()
162 }
163
164 pub fn create_block(&mut self) -> Block {
168 let block = Idx::from_usize(self.blocks.len());
169 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
170 match self.last_block {
171 Some(last) => self.blocks[last.index()].next = Some(block),
172 None => self.first_block = Some(block),
173 }
174 self.last_block = Some(block);
175 block
176 }
177
178 pub fn remove_block(&mut self, block: Block) {
191 assert!(self.first_block != Some(block), "the entry block is not removable");
192 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
193 match prev {
194 Some(prev) => self.blocks[prev.index()].next = next,
195 None => self.first_block = next,
196 }
197 match next {
198 Some(next) => self.blocks[next.index()].prev = prev,
199 None => self.last_block = prev,
200 }
201 let insts: Vec<Inst> = self.insts(block).collect();
205 for inst in insts {
206 self.inst_layout[inst.index()] = InstLayout::default();
207 }
208 self.blocks[block.index()] = BlockData::default();
209 }
210
211 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
220 let index = u32::try_from(self.blocks[block.index()].params.len())
221 .expect("a block with four billion parameters");
222 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
223 self.blocks[block.index()].params.push(value);
224 value
225 }
226
227 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
239 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
240 params.retain(|&value| keep(value));
241 for (index, &value) in params.iter().enumerate() {
242 let index = u32::try_from(index).expect("a block with four billion parameters");
243 self.values[value.index()].def = Def::Param { block, index };
244 }
245 self.blocks[block.index()].params = params;
246 }
247
248 pub fn retype(&mut self, value: Value, ty: Type) {
260 self.values[value.index()].ty = ty;
261 }
262
263 pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
268 (0..self.values.len()).map(Idx::from_usize)
269 }
270
271 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
273 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
274 }
275
276 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
278 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
279 self.inst_layout[inst.index()].next
280 })
281 }
282
283 pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
289 std::iter::successors(self.blocks[block.index()].last, move |&inst| {
290 self.inst_layout[inst.index()].prev
291 })
292 }
293
294 #[must_use]
296 pub fn terminator(&self, block: Block) -> Option<Inst> {
297 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
298 }
299
300 #[must_use]
306 pub fn is_terminator(&self, inst: Inst) -> bool {
307 let data = &self[inst];
308 match data.extra {
309 Extra::Asm(info) => {
310 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
311 }
312 _ => data.opcode.is_terminator(),
313 }
314 }
315
316 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
327 let inst = Idx::from_usize(self.insts.len());
328 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
329 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
330 for (index, &ty) in results.iter().enumerate() {
331 let index = u8::try_from(index).expect("checked just above");
332 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
333 }
334 self.insts.push(data);
335 self.inst_layout.push(InstLayout::default());
336 self.inst_spans.push(span);
337 inst
338 }
339
340 pub fn append_inst(&mut self, block: Block, inst: Inst) {
347 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
348 let last = self.blocks[block.index()].last;
349 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
350 match last {
351 Some(last) => self.inst_layout[last.index()].next = Some(inst),
352 None => self.blocks[block.index()].first = Some(inst),
353 }
354 self.blocks[block.index()].last = Some(inst);
355 }
356
357 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
363 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
364 let at = self.inst_layout[before.index()];
365 let block = at.block.expect("the instruction to insert before is not in a block");
366 self.inst_layout[inst.index()] =
367 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
368 self.inst_layout[before.index()].prev = Some(inst);
369 match at.prev {
370 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
371 None => self.blocks[block.index()].first = Some(inst),
372 }
373 }
374
375 pub fn insert_after(&mut self, inst: Inst, after: Inst) {
387 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
388 let at = self.inst_layout[after.index()];
389 let block = at.block.expect("the instruction to insert after is not in a block");
390 assert!(at.next.is_some(), "nothing goes after a terminator");
391 self.inst_layout[inst.index()] =
392 InstLayout { block: Some(block), prev: Some(after), next: at.next };
393 self.inst_layout[after.index()].next = Some(inst);
394 if let Some(next) = at.next {
395 self.inst_layout[next.index()].prev = Some(inst);
396 }
397 }
398
399 pub fn remove_inst(&mut self, inst: Inst) {
409 let at = self.inst_layout[inst.index()];
410 let block = at.block.expect("the instruction is not in a block");
411 match at.prev {
412 Some(prev) => self.inst_layout[prev.index()].next = at.next,
413 None => self.blocks[block.index()].first = at.next,
414 }
415 match at.next {
416 Some(next) => self.inst_layout[next.index()].prev = at.prev,
417 None => self.blocks[block.index()].last = at.prev,
418 }
419 self.inst_layout[inst.index()] = InstLayout::default();
420 }
421
422 #[must_use]
424 pub fn block_of(&self, inst: Inst) -> Option<Block> {
425 self.inst_layout[inst.index()].block
426 }
427
428 #[must_use]
440 pub fn mem_in(&self, inst: Inst) -> Option<Value> {
441 let args = &self[self[inst].args];
442 args.last().copied().filter(|&arg| self[arg].ty.is_mem())
443 }
444
445 #[must_use]
455 pub fn mem_out(&self, inst: Inst) -> Option<Value> {
456 self[inst].results().last().filter(|&result| self[result].ty.is_mem())
457 }
458
459 #[must_use]
461 pub fn carries_mem(&self, inst: Inst) -> bool {
462 self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
463 }
464
465 pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
481 assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
482 assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
483 assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
484 let data = self[inst];
485 let mut args = self[data.args].to_vec();
486 args.push(incoming);
487 let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
488 if data.opcode.writes_memory() {
489 results.push(Type::MEM);
490 }
491 let span = self.span(inst);
492 let args = self.push_values(&args);
493 self.create_inst(InstData { args, ..data }, &results, span)
494 }
495
496 #[must_use]
498 pub fn span(&self, inst: Inst) -> Span {
499 self.inst_spans[inst.index()]
500 }
501
502 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
507 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
508 }
509
510 #[must_use]
517 pub fn target_list(&self, inst: Inst) -> BlockCallList {
518 match self[inst].extra {
519 Extra::Targets(targets) => targets,
520 Extra::Switch(info) => self.switches[info.index()].targets,
521 Extra::Asm(info) => self.asms[info.index()].targets,
522 _ => BlockCallList::EMPTY,
523 }
524 }
525
526 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
530 let start = Idx::from_usize(self.value_pool.len());
531 self.value_pool.extend_from_slice(values);
532 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
533 }
534
535 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
542 let range = list.as_usize_range();
543 if range.end == self.value_pool.len() {
544 self.value_pool.push(value);
545 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
546 }
547 let start = self.value_pool.len();
548 self.value_pool.extend_from_within(range);
549 self.value_pool.push(value);
550 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
551 }
552
553 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
558 for value in &mut self.value_pool[list.as_usize_range()] {
559 *value = with(*value);
560 }
561 }
562
563 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
565 let start = Idx::from_usize(self.block_calls.len());
566 self.block_calls.extend_from_slice(calls);
567 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
568 }
569
570 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
572 self.block_calls[at.index()] = call;
573 }
574
575 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
577 let start = Idx::from_usize(self.imms.len());
578 self.imms.extend_from_slice(imms);
579 ImmList::new(start, Idx::from_usize(self.imms.len()))
580 }
581
582 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
584 self.imms.push(imm);
585 Idx::from_usize(self.imms.len() - 1)
586 }
587
588 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
590 let start = Idx::from_usize(self.slots.len());
591 self.slots.extend_from_slice(slots);
592 SlotList::new(start, Idx::from_usize(self.slots.len()))
593 }
594
595 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
597 self.va_objects.push(info);
598 Idx::from_usize(self.va_objects.len() - 1)
599 }
600
601 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
603 self.mem.push(info);
604 Idx::from_usize(self.mem.len() - 1)
605 }
606
607 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
609 let start = Idx::from_usize(self.abis.len());
610 self.abis.extend_from_slice(abis);
611 AbiList::new(start, Idx::from_usize(self.abis.len()))
612 }
613
614 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
616 self.calls.push(info);
617 Idx::from_usize(self.calls.len() - 1)
618 }
619
620 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
622 self.switches.push(info);
623 Idx::from_usize(self.switches.len() - 1)
624 }
625
626 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
628 self.asms.push(info);
629 Idx::from_usize(self.asms.len() - 1)
630 }
631
632 #[must_use]
635 pub fn counts(&self) -> Counts {
636 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
637 }
638
639 #[must_use]
645 pub fn facts(&self, value: Value) -> Facts {
646 match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
647 Ok(at) => self.facts[at].1,
648 Err(_) => Facts::NONE,
649 }
650 }
651
652 pub fn set_facts(&mut self, value: Value, facts: Facts) {
657 let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
658 match (found, facts.is_empty()) {
659 (Ok(at), true) => drop(self.facts.remove(at)),
660 (Ok(at), false) => self.facts[at].1 = facts,
661 (Err(_), true) => {}
662 (Err(at), false) => self.facts.insert(at, (value, facts)),
663 }
664 }
665
666 pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
668 self.facts.iter().copied()
669 }
670
671 fn add_value(&mut self, data: ValueData) -> Value {
672 self.values.push(data);
673 Idx::from_usize(self.values.len() - 1)
674 }
675}
676
677#[derive(Clone, Copy, Debug, PartialEq, Eq)]
679pub struct Counts {
680 pub values: usize,
682 pub insts: usize,
684 pub blocks: usize,
686}
687
688impl Index<Value> for Func {
691 type Output = ValueData;
692
693 fn index(&self, value: Value) -> &ValueData {
694 &self.values[value.index()]
695 }
696}
697
698impl Index<Inst> for Func {
699 type Output = InstData;
700
701 fn index(&self, inst: Inst) -> &InstData {
702 &self.insts[inst.index()]
703 }
704}
705
706impl IndexMut<Inst> for Func {
707 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
708 &mut self.insts[inst.index()]
709 }
710}
711
712impl Index<Block> for Func {
713 type Output = BlockData;
714
715 fn index(&self, block: Block) -> &BlockData {
716 &self.blocks[block.index()]
717 }
718}
719
720impl Index<Sig> for Func {
721 type Output = Signature;
722
723 fn index(&self, sig: Sig) -> &Signature {
724 &self.signatures[sig.index()]
725 }
726}
727
728impl Index<ValueList> for Func {
729 type Output = [Value];
730
731 fn index(&self, list: ValueList) -> &[Value] {
732 &self.value_pool[list.as_usize_range()]
733 }
734}
735
736impl Index<BlockCallList> for Func {
737 type Output = [BlockCall];
738
739 fn index(&self, list: BlockCallList) -> &[BlockCall] {
740 &self.block_calls[list.as_usize_range()]
741 }
742}
743
744impl Index<Idx<BlockCall>> for Func {
745 type Output = BlockCall;
746
747 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
748 &self.block_calls[at.index()]
749 }
750}
751
752impl Index<ImmList> for Func {
753 type Output = [Imm];
754
755 fn index(&self, list: ImmList) -> &[Imm] {
756 &self.imms[list.as_usize_range()]
757 }
758}
759
760impl Index<Idx<Imm>> for Func {
761 type Output = Imm;
762
763 fn index(&self, at: Idx<Imm>) -> &Imm {
764 &self.imms[at.index()]
765 }
766}
767
768impl Index<Idx<MemInfo>> for Func {
769 type Output = MemInfo;
770
771 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
772 &self.mem[at.index()]
773 }
774}
775
776impl Index<AbiList> for Func {
777 type Output = [Abi];
778
779 fn index(&self, list: AbiList) -> &[Abi] {
780 &self.abis[list.as_usize_range()]
781 }
782}
783
784impl Index<SlotList> for Func {
785 type Output = [Slot];
786
787 fn index(&self, list: SlotList) -> &[Slot] {
788 &self.slots[list.as_usize_range()]
789 }
790}
791
792impl Index<Idx<VaInfo>> for Func {
793 type Output = VaInfo;
794
795 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
796 &self.va_objects[at.index()]
797 }
798}
799
800impl Index<Idx<CallInfo>> for Func {
801 type Output = CallInfo;
802
803 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
804 &self.calls[at.index()]
805 }
806}
807
808impl Index<Idx<SwitchInfo>> for Func {
809 type Output = SwitchInfo;
810
811 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
812 &self.switches[at.index()]
813 }
814}
815
816impl Index<Idx<AsmInfo>> for Func {
817 type Output = AsmInfo;
818
819 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
820 &self.asms[at.index()]
821 }
822}
823
824#[derive(Debug)]
831pub struct Builder<'a> {
832 func: &'a mut Func,
833 block: Block,
834 span: Span,
835}
836
837impl<'a> Builder<'a> {
838 pub fn new(func: &'a mut Func, block: Block) -> Self {
840 Self { func, block, span: Span::DUMMY }
841 }
842
843 #[must_use]
845 pub fn at(mut self, span: Span) -> Self {
846 self.span = span;
847 self
848 }
849
850 pub fn set_span(&mut self, span: Span) {
852 self.span = span;
853 }
854
855 pub fn func(&mut self) -> &mut Func {
857 self.func
858 }
859
860 #[must_use]
862 pub fn block(&self) -> Block {
863 self.block
864 }
865
866 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
868 let inst = self.func.create_inst(data, results, self.span);
869 self.func.append_inst(self.block, inst);
870 inst
871 }
872
873 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
879 let inst = self.inst(data, &[ty]);
880 self.func[inst].first_result.expect("one result was asked for")
881 }
882
883 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
889 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
890 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
891 }
892
893 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
895 let imm = self.func.add_imm(Imm::from_bits(bits));
896 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
897 }
898
899 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
901 let ty = self.func[lhs].ty;
902 let args = self.func.push_values(&[lhs, rhs]);
903 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
904 }
905
906 pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
919 let ty = self.func[lhs].ty;
920 let args = self.func.push_values(&[lhs, rhs]);
921 let results = [ty, ty.with_lane(Type::I1)];
922 let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
923 let mut answers = self.func[inst].results();
924 let value = answers.next().expect("two results were asked for");
925 let wrapped = answers.next().expect("two results were asked for");
926 (value, wrapped)
927 }
928
929 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
931 let args = self.func.push_values(&[arg]);
932 self.value(InstData { args, ..InstData::new(opcode) }, ty)
933 }
934
935 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
937 let ty = self.func[lhs].ty.with_lane(Type::I1);
938 let args = self.func.push_values(&[lhs, rhs]);
939 self.value(
940 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
941 ty,
942 )
943 }
944
945 pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
951 let ty = self.func[then].ty;
952 let args = self.func.push_values(&[cond, then, other]);
953 self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
954 }
955
956 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
958 let ty = self.func[lhs].ty.with_lane(Type::I1);
959 let args = self.func.push_values(&[lhs, rhs]);
960 self.value(
961 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
962 ty,
963 )
964 }
965
966 pub fn mem_entry(&mut self) -> Value {
970 self.value(InstData::new(Opcode::MemEntry), Type::MEM)
971 }
972
973 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
975 let mem = self.func.add_mem(info);
976 let args = self.func.push_values(&[addr]);
977 self.value(
978 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
979 ty,
980 )
981 }
982
983 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
985 let mem = self.func.add_mem(info);
986 let args = self.func.push_values(&[value, addr]);
987 self.inst(
988 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
989 &[],
990 )
991 }
992
993 pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1001 let mem = self.func.add_mem(info);
1002 let args = self.func.push_values(&[addr]);
1003 self.value(
1004 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1005 ty,
1006 )
1007 }
1008
1009 pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1011 let mem = self.func.add_mem(info);
1012 let args = self.func.push_values(&[value, addr]);
1013 self.inst(
1014 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1015 &[],
1016 )
1017 }
1018
1019 pub fn cmpxchg(
1026 &mut self,
1027 addr: Value,
1028 expected: Value,
1029 desired: Value,
1030 info: MemInfo,
1031 flags: Flags,
1032 ) -> (Value, Value) {
1033 let ty = self.func[expected].ty;
1034 let mem = self.func.add_mem(info);
1035 let args = self.func.push_values(&[addr, expected, desired]);
1036 let inst = self.inst(
1037 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1038 &[ty, Type::I1],
1039 );
1040 let results: Vec<Value> = self.func[inst].results().collect();
1041 let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1042 (old, exchanged)
1043 }
1044
1045 pub fn atomic_rmw(
1053 &mut self,
1054 op: RmwOp,
1055 addr: Value,
1056 operand: Value,
1057 info: MemInfo,
1058 flags: Flags,
1059 ) -> Value {
1060 let ty = self.func[operand].ty;
1061 let mem = self.func.add_mem(info);
1062 let args = self.func.push_values(&[addr, operand]);
1063 self.value(
1064 InstData {
1065 args,
1066 flags,
1067 extra: Extra::Rmw(op, mem),
1068 ..InstData::new(Opcode::AtomicRmw)
1069 },
1070 ty,
1071 )
1072 }
1073
1074 pub fn fence(&mut self, order: MemOrder) -> Inst {
1076 self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1077 }
1078
1079 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1081 let call = self.block_call(target, args);
1082 let targets = self.func.push_block_calls(&[call]);
1083 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1084 }
1085
1086 pub fn block_addr(&mut self, target: Block) -> Value {
1092 let call = self.block_call(target, &[]);
1093 let targets = self.func.push_block_calls(&[call]);
1094 self.value(
1095 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1096 Type::PTR,
1097 )
1098 }
1099
1100 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1106 let calls: Vec<BlockCall> =
1107 targets.iter().map(|&target| self.block_call(target, &[])).collect();
1108 let targets = self.func.push_block_calls(&calls);
1109 let args = self.func.push_values(&[addr]);
1110 self.inst(
1111 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1112 &[],
1113 )
1114 }
1115
1116 pub fn br_if(
1118 &mut self,
1119 cond: Value,
1120 then_block: Block,
1121 then_args: &[Value],
1122 else_block: Block,
1123 else_args: &[Value],
1124 ) -> Inst {
1125 let then_call = self.block_call(then_block, then_args);
1126 let else_call = self.block_call(else_block, else_args);
1127 let targets = self.func.push_block_calls(&[then_call, else_call]);
1128 let args = self.func.push_values(&[cond]);
1129 self.inst(
1130 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1131 &[],
1132 )
1133 }
1134
1135 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1142 let ty = self.func[value].ty.lane();
1143 let mut calls = vec![self.block_call(default, &[])];
1144 let mut values = Vec::with_capacity(cases.len());
1145 for &(value, block) in cases {
1146 calls.push(self.block_call(block, &[]));
1147 values.push(Imm::int(value, ty));
1148 }
1149 let targets = self.func.push_block_calls(&calls);
1150 let cases = self.func.push_imms(&values);
1151 let info = self.func.add_switch(SwitchInfo { targets, cases });
1152 let args = self.func.push_values(&[value]);
1153 self.inst(
1154 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1155 &[],
1156 )
1157 }
1158
1159 pub fn ret(&mut self, values: &[Value]) -> Inst {
1161 let args = self.func.push_values(values);
1162 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1163 }
1164
1165 pub fn unreachable(&mut self) -> Inst {
1167 self.inst(InstData::new(Opcode::Unreachable), &[])
1168 }
1169
1170 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1172 self.call_varargs(callee, signature, args, &[])
1173 }
1174
1175 pub fn call_varargs(
1181 &mut self,
1182 callee: Symbol,
1183 signature: Sig,
1184 args: &[Value],
1185 varargs: &[Abi],
1186 ) -> Inst {
1187 let varargs = self.func.push_abis(varargs);
1188 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1189 let returns: Vec<Type> = self.func[signature].return_types().collect();
1190 let args = self.func.push_values(args);
1191 self.inst(
1192 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1193 &returns,
1194 )
1195 }
1196
1197 pub fn inline_asm(
1203 &mut self,
1204 info: AsmInfo,
1205 args: &[Value],
1206 results: &[Type],
1207 flags: Flags,
1208 ) -> Inst {
1209 let info = self.func.add_asm(info);
1210 let args = self.func.push_values(args);
1211 self.inst(
1212 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1213 results,
1214 )
1215 }
1216
1217 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1218 BlockCall { block, args: self.func.push_values(args) }
1219 }
1220}
1221
1222#[cfg(test)]
1223mod tests {
1224 use rucc_base::Interner;
1225
1226 use super::*;
1227 use crate::inst::BlockCallList;
1228 use crate::{MemOrder, Restrict};
1229
1230 fn sum() -> (Func, Block, Block, Block) {
1232 let mut names = Interner::new();
1233 let i32_ = Type::int(32);
1234 let mut func = Func::new(
1235 names.intern("sum"),
1236 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1237 );
1238
1239 let entry = func.create_block();
1240 let n = func.append_param(entry, i32_);
1241 let header = func.create_block();
1242 let acc = func.append_param(header, i32_);
1243 let i = func.append_param(header, i32_);
1244 let exit = func.create_block();
1245 let result = func.append_param(exit, i32_);
1246
1247 let mut b = Builder::new(&mut func, entry);
1248 let zero = b.iconst(i32_, 0);
1249 let cmp = b.icmp(IntPred::Sle, n, zero);
1250 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1251
1252 let mut b = Builder::new(&mut func, header);
1253 let one = b.iconst(i32_, 1);
1254 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1255 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1256 let done = b.icmp(IntPred::Sge, next, n);
1257 b.br_if(done, exit, &[total], header, &[total, next]);
1258
1259 let mut b = Builder::new(&mut func, exit);
1260 b.ret(&[result]);
1261
1262 (func, entry, header, exit)
1263 }
1264
1265 #[test]
1266 fn the_blocks_come_back_in_the_order_they_were_made() {
1267 let (func, entry, header, exit) = sum();
1268 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1269 assert_eq!(func.entry(), Some(entry));
1270 }
1271
1272 #[test]
1273 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1274 let (mut func, entry, header, exit) = sum();
1275 let inside: Vec<Inst> = func.insts(header).collect();
1276 func.remove_block(header);
1277 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1278 assert_eq!(func.entry(), Some(entry));
1279 assert_eq!(func[entry].next, Some(exit));
1280 assert_eq!(func[exit].prev, Some(entry));
1281 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1283 assert!(func.insts(header).next().is_none());
1284 }
1285
1286 #[test]
1287 fn each_block_holds_what_was_appended_to_it() {
1288 let (func, entry, header, exit) = sum();
1289 let opcodes =
1290 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1291 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1292 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1293 assert_eq!(opcodes(exit), ["return"]);
1294 }
1295
1296 #[test]
1297 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1298 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1301 let block = func.create_block();
1302 let plain = func.add_asm(AsmInfo {
1303 template: Symbol::from_raw(0),
1304 constraints: Symbol::from_raw(0),
1305 clobbers: Symbol::from_raw(0),
1306 targets: BlockCallList::EMPTY,
1307 });
1308 let call = BlockCall { block, args: ValueList::EMPTY };
1309 let targets = func.push_block_calls(&[call]);
1310 let labelled = func.add_asm(AsmInfo {
1311 template: Symbol::from_raw(0),
1312 constraints: Symbol::from_raw(0),
1313 clobbers: Symbol::from_raw(0),
1314 targets,
1315 });
1316
1317 let mut make = |extra| {
1318 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1319 func.create_inst(data, &[], Span::DUMMY)
1320 };
1321 let plain = make(Extra::Asm(plain));
1322 let labelled = make(Extra::Asm(labelled));
1323 assert!(!func.is_terminator(plain));
1324 assert!(func.is_terminator(labelled));
1325 }
1326
1327 #[test]
1328 fn every_block_ends_in_its_terminator() {
1329 let (func, entry, header, exit) = sum();
1330 for block in [entry, header, exit] {
1331 let last = func.terminator(block).expect("a terminator");
1332 assert_eq!(Some(last), func.insts(block).last());
1333 }
1334 }
1335
1336 #[test]
1337 fn a_branch_carries_the_arguments_the_block_takes() {
1338 let (func, entry, header, _) = sum();
1339 let br = func.terminator(entry).expect("a terminator");
1340 let calls: Vec<BlockCall> = func.successors(br).collect();
1341 assert_eq!(calls.len(), 2);
1342 assert_eq!(calls[1].block, header);
1344 assert_eq!(func[calls[1].args].len(), 2);
1345 assert_eq!(func[header].params.len(), 2);
1346 assert_eq!(func[calls[0].args].len(), 1);
1347 }
1348
1349 #[test]
1350 fn a_value_knows_what_defined_it() {
1351 let (func, entry, _, _) = sum();
1352 let first = func.insts(entry).next().expect("an instruction");
1353 let value = func[first].first_result.expect("a result");
1354 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1355 assert_eq!(func[value].ty, Type::int(32));
1356
1357 let param = func[entry].params[0];
1358 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1359 }
1360
1361 #[test]
1362 fn a_comparison_produces_one_bit() {
1363 let (func, entry, _, _) = sum();
1364 let cmp = func.insts(entry).nth(1).expect("the comparison");
1365 let value = func[cmp].first_result.expect("a result");
1366 assert_eq!(func[value].ty, Type::I1);
1367 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1368 }
1369
1370 #[test]
1371 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1372 let (func, _, header, _) = sum();
1373 let add = func.insts(header).nth(1).expect("the addition");
1374 assert_eq!(func[add].flags, Flags::NSW);
1375 let cmp = func.insts(header).nth(3).expect("the comparison");
1376 assert_eq!(func[cmp].flags, Flags::NONE);
1377 }
1378
1379 #[test]
1380 fn removing_an_instruction_takes_it_out_of_the_middle() {
1381 let (mut func, _, header, _) = sum();
1382 let add = func.insts(header).nth(1).expect("the addition");
1383 func.remove_inst(add);
1384 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1385 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1386 assert_eq!(func.block_of(add), None);
1387 }
1388
1389 #[test]
1390 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1391 let (mut func, entry, _, _) = sum();
1392 let first = func.insts(entry).next().expect("an instruction");
1393 let last = func.terminator(entry).expect("a terminator");
1394 func.remove_inst(first);
1395 func.remove_inst(last);
1396 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1397 assert_eq!(opcodes, ["icmp"]);
1398 assert_eq!(func[entry].first, func[entry].last);
1399 }
1400
1401 #[test]
1402 fn removing_the_only_instruction_empties_the_block() {
1403 let (mut func, _, _, exit) = sum();
1404 let only = func.insts(exit).next().expect("an instruction");
1405 func.remove_inst(only);
1406 assert_eq!(func.insts(exit).count(), 0);
1407 assert_eq!(func[exit].first, None);
1408 assert_eq!(func[exit].last, None);
1409 }
1410
1411 #[test]
1412 fn inserting_before_puts_it_in_the_right_place() {
1413 let (mut func, entry, _, _) = sum();
1414 let cmp = func.insts(entry).nth(1).expect("the comparison");
1415 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1416 func.insert_before(made, cmp);
1417 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1418 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1419 }
1420
1421 #[test]
1422 fn inserting_before_the_first_makes_it_the_first() {
1423 let (mut func, entry, _, _) = sum();
1424 let first = func.insts(entry).next().expect("an instruction");
1425 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1426 func.insert_before(made, first);
1427 assert_eq!(func.insts(entry).next(), Some(made));
1428 assert_eq!(func[entry].first, Some(made));
1429 }
1430
1431 #[test]
1432 fn inserting_after_puts_it_in_the_right_place() {
1433 let (mut func, entry, _, _) = sum();
1434 let first = func.insts(entry).next().expect("an instruction");
1435 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1436 func.insert_after(made, first);
1437 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1438 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1439 assert_eq!(func[entry].first, Some(first));
1440 }
1441
1442 #[test]
1443 #[should_panic(expected = "nothing goes after a terminator")]
1444 fn inserting_after_the_terminator_is_refused() {
1445 let (mut func, entry, _, _) = sum();
1448 let last = func.insts(entry).last().expect("a terminator");
1449 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1450 func.insert_after(made, last);
1451 }
1452
1453 #[test]
1454 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1455 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1456 let block = func.create_block();
1457 let a = func.append_param(block, Type::int(32));
1458 let b = func.append_param(block, Type::int(32));
1459 let list = func.push_values(&[a]);
1460 let grown = func.append_arg(list, b);
1461 assert_eq!(func[grown], [a, b]);
1462 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1463 }
1464
1465 #[test]
1466 fn a_list_is_copied_when_something_is_behind_it() {
1467 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1468 let block = func.create_block();
1469 let a = func.append_param(block, Type::int(32));
1470 let b = func.append_param(block, Type::int(32));
1471 let list = func.push_values(&[a, a]);
1472 let behind = func.push_values(&[b]);
1473 let grown = func.append_arg(list, b);
1474 assert_eq!(func[grown], [a, a, b]);
1475 assert_eq!(func[list], [a, a], "the old run is still readable");
1476 assert_eq!(func[behind], [b], "and so is what was behind it");
1477 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1478 }
1479
1480 #[test]
1481 fn a_parameter_added_late_is_the_next_one_along() {
1482 let (mut func, entry, header, _) = sum();
1486 let extra = func.append_param(header, Type::int(32));
1487 assert_eq!(func[header].params.len(), 3);
1488 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1489
1490 let br = func.terminator(entry).expect("a terminator");
1491 let call = func.successors(br).nth(1).expect("the branch to the header");
1492 let grown = func.append_arg(call.args, extra);
1493 assert_eq!(func[grown].len(), 3);
1494 }
1495
1496 #[test]
1497 fn a_span_rides_along_with_the_instruction() {
1498 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1499 let block = func.create_block();
1500 let span = Span::new(10, 20);
1501 let mut b = Builder::new(&mut func, block).at(span);
1502 let value = b.iconst(Type::int(32), 7);
1503 let inst = match func[value].def {
1504 Def::Result { inst, .. } => inst,
1505 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1506 };
1507 assert_eq!(func.span(inst), span);
1508 }
1509
1510 #[test]
1511 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1512 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1513 let block = func.create_block();
1514 let addr = func.append_param(block, Type::PTR);
1515 let info = MemInfo {
1516 size: 4,
1517 align: 4,
1518 order: MemOrder::NotAtomic,
1519 tbaa: None,
1520 restrict: Restrict::NONE,
1521 };
1522 let mut b = Builder::new(&mut func, block);
1523 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1524 let store = b.store(value, addr, info, Flags::VOLATILE);
1525 assert_eq!(func[store].results, 0);
1526 assert_eq!(func[store].flags, Flags::VOLATILE);
1527 assert_eq!(func[value].ty, Type::int(32));
1528 }
1529
1530 #[test]
1531 fn a_call_produces_what_its_signature_returns() {
1532 let mut names = Interner::new();
1533 let mut func = Func::new(names.intern("caller"), Signature::new());
1534 let sig = func.add_signature(
1535 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1536 );
1537 let block = func.create_block();
1538 let arg = func.append_param(block, Type::int(32));
1539 let callee = names.intern("callee");
1540 let mut b = Builder::new(&mut func, block);
1541 let call = b.call(callee, sig, &[arg]);
1542 assert_eq!(func[call].results, 1);
1543 let value = func[call].first_result.expect("a result");
1544 assert_eq!(func[value].ty, Type::int(64));
1545 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1546 }
1547
1548 #[test]
1549 fn the_counts_are_what_was_made() {
1550 let (func, _, _, _) = sum();
1551 let counts = func.counts();
1552 assert_eq!(counts.blocks, 3);
1553 assert_eq!(counts.insts, 9);
1554 assert_eq!(counts.values, 4 + 6);
1557 }
1558
1559 #[test]
1560 #[should_panic(expected = "the instruction is in a block")]
1561 fn appending_an_instruction_twice_is_refused() {
1562 let (mut func, entry, _, _) = sum();
1563 let first = func.insts(entry).next().expect("an instruction");
1564 func.append_inst(entry, first);
1565 }
1566
1567 #[test]
1568 #[should_panic(expected = "the instruction is not in a block")]
1569 fn removing_an_instruction_twice_is_refused() {
1570 let (mut func, entry, _, _) = sum();
1571 let first = func.insts(entry).next().expect("an instruction");
1572 func.remove_inst(first);
1573 func.remove_inst(first);
1574 }
1575
1576 fn threaded() -> (Func, Inst, Inst) {
1578 let mut names = Interner::new();
1579 let i32_ = Type::int(32);
1580 let mut func = Func::new(
1581 names.intern("thread"),
1582 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
1583 );
1584 let entry = func.create_block();
1585 let addr = func.append_param(entry, Type::PTR);
1586 let info = MemInfo {
1587 size: 4,
1588 align: 4,
1589 order: MemOrder::NotAtomic,
1590 tbaa: None,
1591 restrict: Restrict::NONE,
1592 };
1593
1594 let mut b = Builder::new(&mut func, entry);
1595 let start = b.mem_entry();
1596 let seven = b.iconst(i32_, 7);
1597 let store = b.store(seven, addr, info, Flags::NONE);
1598 let value = b.load(i32_, addr, info, Flags::NONE);
1599 let Def::Result { inst: load, .. } = func[value].def else {
1600 panic!("the load produced it");
1601 };
1602
1603 let store = func.with_mem(store, start);
1604 let after = func.mem_out(store).expect("a store makes a new version");
1605 let load = func.with_mem(load, after);
1606 (func, store, load)
1607 }
1608
1609 #[test]
1610 fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
1611 let (func, store, load) = threaded();
1612 assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
1613 assert_eq!(func[func[store].args].len(), 3);
1614 assert!(func.carries_mem(store));
1615 assert!(func.carries_mem(load));
1616
1617 assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
1620 assert_eq!(func.mem_in(load), func.mem_out(store));
1621 assert_eq!(func.mem_out(load), None);
1622 }
1623
1624 #[test]
1625 #[should_panic(expected = "this is already on the memory chain")]
1626 fn threading_memory_through_the_same_instruction_twice_is_refused() {
1627 let (mut func, store, _) = threaded();
1628 let start = func.mem_in(store).expect("it was threaded");
1629 func.with_mem(store, start);
1630 }
1631}