1use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33
34use crate::inst::{
35 Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
36 ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SwitchInfo, Value, ValueData,
37 ValueList,
38};
39use crate::module::{Linkage, Visibility};
40use crate::{Attrs, Flags, FloatPred, IntPred, Opcode, Type};
41
42#[derive(Debug)]
44pub struct Func {
45 pub name: Symbol,
47 pub linkage: Linkage,
49 pub visibility: Visibility,
51 pub section: Option<Symbol>,
54 pub attrs: Attrs,
57
58 values: Vec<ValueData>,
59 insts: Vec<InstData>,
60 inst_layout: Vec<InstLayout>,
61 inst_spans: Vec<Span>,
62 blocks: Vec<BlockData>,
63
64 value_pool: Vec<Value>,
65 block_calls: Vec<BlockCall>,
66 imms: Vec<Imm>,
67 mem: Vec<MemInfo>,
68 calls: Vec<CallInfo>,
69 abis: Vec<Abi>,
70 switches: Vec<SwitchInfo>,
71 asms: Vec<AsmInfo>,
72 signatures: Vec<Signature>,
73
74 first_block: Option<Block>,
75 last_block: Option<Block>,
76}
77
78impl Func {
79 #[must_use]
86 pub fn new(name: Symbol, signature: Signature) -> Self {
87 Self {
88 name,
89 linkage: Linkage::External,
90 visibility: Visibility::Default,
91 section: None,
92 attrs: Attrs::NONE,
93 values: Vec::new(),
94 insts: Vec::new(),
95 inst_layout: Vec::new(),
96 inst_spans: Vec::new(),
97 blocks: Vec::new(),
98 value_pool: Vec::new(),
99 block_calls: Vec::new(),
100 imms: Vec::new(),
101 mem: Vec::new(),
102 calls: Vec::new(),
103 abis: Vec::new(),
104 switches: Vec::new(),
105 asms: Vec::new(),
106 signatures: vec![signature],
107 first_block: None,
108 last_block: None,
109 }
110 }
111
112 #[must_use]
114 pub fn signature(&self) -> &Signature {
115 &self.signatures[0]
116 }
117
118 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
120 self.signatures.iter()
121 }
122
123 pub fn add_signature(&mut self, signature: Signature) -> Sig {
125 self.signatures.push(signature);
126 Idx::from_usize(self.signatures.len() - 1)
127 }
128
129 #[must_use]
134 pub fn entry(&self) -> Option<Block> {
135 self.first_block
136 }
137
138 #[must_use]
145 pub fn is_declaration(&self) -> bool {
146 self.first_block.is_none()
147 }
148
149 pub fn create_block(&mut self) -> Block {
153 let block = Idx::from_usize(self.blocks.len());
154 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
155 match self.last_block {
156 Some(last) => self.blocks[last.index()].next = Some(block),
157 None => self.first_block = Some(block),
158 }
159 self.last_block = Some(block);
160 block
161 }
162
163 pub fn remove_block(&mut self, block: Block) {
176 assert!(self.first_block != Some(block), "the entry block is not removable");
177 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
178 match prev {
179 Some(prev) => self.blocks[prev.index()].next = next,
180 None => self.first_block = next,
181 }
182 match next {
183 Some(next) => self.blocks[next.index()].prev = prev,
184 None => self.last_block = prev,
185 }
186 let insts: Vec<Inst> = self.insts(block).collect();
190 for inst in insts {
191 self.inst_layout[inst.index()] = InstLayout::default();
192 }
193 self.blocks[block.index()] = BlockData::default();
194 }
195
196 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
205 let index = u32::try_from(self.blocks[block.index()].params.len())
206 .expect("a block with four billion parameters");
207 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
208 self.blocks[block.index()].params.push(value);
209 value
210 }
211
212 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
224 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
225 params.retain(|&value| keep(value));
226 for (index, &value) in params.iter().enumerate() {
227 let index = u32::try_from(index).expect("a block with four billion parameters");
228 self.values[value.index()].def = Def::Param { block, index };
229 }
230 self.blocks[block.index()].params = params;
231 }
232
233 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
235 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
236 }
237
238 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
240 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
241 self.inst_layout[inst.index()].next
242 })
243 }
244
245 #[must_use]
247 pub fn terminator(&self, block: Block) -> Option<Inst> {
248 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
249 }
250
251 #[must_use]
257 pub fn is_terminator(&self, inst: Inst) -> bool {
258 let data = &self[inst];
259 match data.extra {
260 Extra::Asm(info) => {
261 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
262 }
263 _ => data.opcode.is_terminator(),
264 }
265 }
266
267 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
278 let inst = Idx::from_usize(self.insts.len());
279 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
280 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
281 for (index, &ty) in results.iter().enumerate() {
282 let index = u8::try_from(index).expect("checked just above");
283 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
284 }
285 self.insts.push(data);
286 self.inst_layout.push(InstLayout::default());
287 self.inst_spans.push(span);
288 inst
289 }
290
291 pub fn append_inst(&mut self, block: Block, inst: Inst) {
298 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
299 let last = self.blocks[block.index()].last;
300 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
301 match last {
302 Some(last) => self.inst_layout[last.index()].next = Some(inst),
303 None => self.blocks[block.index()].first = Some(inst),
304 }
305 self.blocks[block.index()].last = Some(inst);
306 }
307
308 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
314 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
315 let at = self.inst_layout[before.index()];
316 let block = at.block.expect("the instruction to insert before is not in a block");
317 self.inst_layout[inst.index()] =
318 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
319 self.inst_layout[before.index()].prev = Some(inst);
320 match at.prev {
321 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
322 None => self.blocks[block.index()].first = Some(inst),
323 }
324 }
325
326 pub fn remove_inst(&mut self, inst: Inst) {
336 let at = self.inst_layout[inst.index()];
337 let block = at.block.expect("the instruction is not in a block");
338 match at.prev {
339 Some(prev) => self.inst_layout[prev.index()].next = at.next,
340 None => self.blocks[block.index()].first = at.next,
341 }
342 match at.next {
343 Some(next) => self.inst_layout[next.index()].prev = at.prev,
344 None => self.blocks[block.index()].last = at.prev,
345 }
346 self.inst_layout[inst.index()] = InstLayout::default();
347 }
348
349 #[must_use]
351 pub fn block_of(&self, inst: Inst) -> Option<Block> {
352 self.inst_layout[inst.index()].block
353 }
354
355 #[must_use]
357 pub fn span(&self, inst: Inst) -> Span {
358 self.inst_spans[inst.index()]
359 }
360
361 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
366 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
367 }
368
369 #[must_use]
376 pub fn target_list(&self, inst: Inst) -> BlockCallList {
377 match self[inst].extra {
378 Extra::Targets(targets) => targets,
379 Extra::Switch(info) => self.switches[info.index()].targets,
380 Extra::Asm(info) => self.asms[info.index()].targets,
381 _ => BlockCallList::EMPTY,
382 }
383 }
384
385 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
389 let start = Idx::from_usize(self.value_pool.len());
390 self.value_pool.extend_from_slice(values);
391 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
392 }
393
394 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
401 let range = list.as_usize_range();
402 if range.end == self.value_pool.len() {
403 self.value_pool.push(value);
404 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
405 }
406 let start = self.value_pool.len();
407 self.value_pool.extend_from_within(range);
408 self.value_pool.push(value);
409 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
410 }
411
412 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
417 for value in &mut self.value_pool[list.as_usize_range()] {
418 *value = with(*value);
419 }
420 }
421
422 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
424 let start = Idx::from_usize(self.block_calls.len());
425 self.block_calls.extend_from_slice(calls);
426 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
427 }
428
429 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
431 self.block_calls[at.index()] = call;
432 }
433
434 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
436 let start = Idx::from_usize(self.imms.len());
437 self.imms.extend_from_slice(imms);
438 ImmList::new(start, Idx::from_usize(self.imms.len()))
439 }
440
441 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
443 self.imms.push(imm);
444 Idx::from_usize(self.imms.len() - 1)
445 }
446
447 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
449 self.mem.push(info);
450 Idx::from_usize(self.mem.len() - 1)
451 }
452
453 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
455 let start = Idx::from_usize(self.abis.len());
456 self.abis.extend_from_slice(abis);
457 AbiList::new(start, Idx::from_usize(self.abis.len()))
458 }
459
460 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
462 self.calls.push(info);
463 Idx::from_usize(self.calls.len() - 1)
464 }
465
466 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
468 self.switches.push(info);
469 Idx::from_usize(self.switches.len() - 1)
470 }
471
472 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
474 self.asms.push(info);
475 Idx::from_usize(self.asms.len() - 1)
476 }
477
478 #[must_use]
481 pub fn counts(&self) -> Counts {
482 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
483 }
484
485 fn add_value(&mut self, data: ValueData) -> Value {
486 self.values.push(data);
487 Idx::from_usize(self.values.len() - 1)
488 }
489}
490
491#[derive(Clone, Copy, Debug, PartialEq, Eq)]
493pub struct Counts {
494 pub values: usize,
496 pub insts: usize,
498 pub blocks: usize,
500}
501
502impl Index<Value> for Func {
505 type Output = ValueData;
506
507 fn index(&self, value: Value) -> &ValueData {
508 &self.values[value.index()]
509 }
510}
511
512impl Index<Inst> for Func {
513 type Output = InstData;
514
515 fn index(&self, inst: Inst) -> &InstData {
516 &self.insts[inst.index()]
517 }
518}
519
520impl IndexMut<Inst> for Func {
521 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
522 &mut self.insts[inst.index()]
523 }
524}
525
526impl Index<Block> for Func {
527 type Output = BlockData;
528
529 fn index(&self, block: Block) -> &BlockData {
530 &self.blocks[block.index()]
531 }
532}
533
534impl Index<Sig> for Func {
535 type Output = Signature;
536
537 fn index(&self, sig: Sig) -> &Signature {
538 &self.signatures[sig.index()]
539 }
540}
541
542impl Index<ValueList> for Func {
543 type Output = [Value];
544
545 fn index(&self, list: ValueList) -> &[Value] {
546 &self.value_pool[list.as_usize_range()]
547 }
548}
549
550impl Index<BlockCallList> for Func {
551 type Output = [BlockCall];
552
553 fn index(&self, list: BlockCallList) -> &[BlockCall] {
554 &self.block_calls[list.as_usize_range()]
555 }
556}
557
558impl Index<Idx<BlockCall>> for Func {
559 type Output = BlockCall;
560
561 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
562 &self.block_calls[at.index()]
563 }
564}
565
566impl Index<ImmList> for Func {
567 type Output = [Imm];
568
569 fn index(&self, list: ImmList) -> &[Imm] {
570 &self.imms[list.as_usize_range()]
571 }
572}
573
574impl Index<Idx<Imm>> for Func {
575 type Output = Imm;
576
577 fn index(&self, at: Idx<Imm>) -> &Imm {
578 &self.imms[at.index()]
579 }
580}
581
582impl Index<Idx<MemInfo>> for Func {
583 type Output = MemInfo;
584
585 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
586 &self.mem[at.index()]
587 }
588}
589
590impl Index<AbiList> for Func {
591 type Output = [Abi];
592
593 fn index(&self, list: AbiList) -> &[Abi] {
594 &self.abis[list.as_usize_range()]
595 }
596}
597
598impl Index<Idx<CallInfo>> for Func {
599 type Output = CallInfo;
600
601 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
602 &self.calls[at.index()]
603 }
604}
605
606impl Index<Idx<SwitchInfo>> for Func {
607 type Output = SwitchInfo;
608
609 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
610 &self.switches[at.index()]
611 }
612}
613
614impl Index<Idx<AsmInfo>> for Func {
615 type Output = AsmInfo;
616
617 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
618 &self.asms[at.index()]
619 }
620}
621
622#[derive(Debug)]
629pub struct Builder<'a> {
630 func: &'a mut Func,
631 block: Block,
632 span: Span,
633}
634
635impl<'a> Builder<'a> {
636 pub fn new(func: &'a mut Func, block: Block) -> Self {
638 Self { func, block, span: Span::DUMMY }
639 }
640
641 #[must_use]
643 pub fn at(mut self, span: Span) -> Self {
644 self.span = span;
645 self
646 }
647
648 pub fn set_span(&mut self, span: Span) {
650 self.span = span;
651 }
652
653 pub fn func(&mut self) -> &mut Func {
655 self.func
656 }
657
658 #[must_use]
660 pub fn block(&self) -> Block {
661 self.block
662 }
663
664 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
666 let inst = self.func.create_inst(data, results, self.span);
667 self.func.append_inst(self.block, inst);
668 inst
669 }
670
671 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
677 let inst = self.inst(data, &[ty]);
678 self.func[inst].first_result.expect("one result was asked for")
679 }
680
681 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
687 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
688 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
689 }
690
691 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
693 let imm = self.func.add_imm(Imm::from_bits(bits));
694 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
695 }
696
697 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
699 let ty = self.func[lhs].ty;
700 let args = self.func.push_values(&[lhs, rhs]);
701 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
702 }
703
704 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
706 let args = self.func.push_values(&[arg]);
707 self.value(InstData { args, ..InstData::new(opcode) }, ty)
708 }
709
710 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
712 let ty = self.func[lhs].ty.with_lane(Type::I1);
713 let args = self.func.push_values(&[lhs, rhs]);
714 self.value(
715 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
716 ty,
717 )
718 }
719
720 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
722 let ty = self.func[lhs].ty.with_lane(Type::I1);
723 let args = self.func.push_values(&[lhs, rhs]);
724 self.value(
725 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
726 ty,
727 )
728 }
729
730 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
732 let mem = self.func.add_mem(info);
733 let args = self.func.push_values(&[addr]);
734 self.value(
735 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
736 ty,
737 )
738 }
739
740 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
742 let mem = self.func.add_mem(info);
743 let args = self.func.push_values(&[value, addr]);
744 self.inst(
745 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
746 &[],
747 )
748 }
749
750 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
752 let call = self.block_call(target, args);
753 let targets = self.func.push_block_calls(&[call]);
754 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
755 }
756
757 pub fn block_addr(&mut self, target: Block) -> Value {
763 let call = self.block_call(target, &[]);
764 let targets = self.func.push_block_calls(&[call]);
765 self.value(
766 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
767 Type::PTR,
768 )
769 }
770
771 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
777 let calls: Vec<BlockCall> =
778 targets.iter().map(|&target| self.block_call(target, &[])).collect();
779 let targets = self.func.push_block_calls(&calls);
780 let args = self.func.push_values(&[addr]);
781 self.inst(
782 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
783 &[],
784 )
785 }
786
787 pub fn br_if(
789 &mut self,
790 cond: Value,
791 then_block: Block,
792 then_args: &[Value],
793 else_block: Block,
794 else_args: &[Value],
795 ) -> Inst {
796 let then_call = self.block_call(then_block, then_args);
797 let else_call = self.block_call(else_block, else_args);
798 let targets = self.func.push_block_calls(&[then_call, else_call]);
799 let args = self.func.push_values(&[cond]);
800 self.inst(
801 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
802 &[],
803 )
804 }
805
806 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
813 let ty = self.func[value].ty.lane();
814 let mut calls = vec![self.block_call(default, &[])];
815 let mut values = Vec::with_capacity(cases.len());
816 for &(value, block) in cases {
817 calls.push(self.block_call(block, &[]));
818 values.push(Imm::int(value, ty));
819 }
820 let targets = self.func.push_block_calls(&calls);
821 let cases = self.func.push_imms(&values);
822 let info = self.func.add_switch(SwitchInfo { targets, cases });
823 let args = self.func.push_values(&[value]);
824 self.inst(
825 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
826 &[],
827 )
828 }
829
830 pub fn ret(&mut self, values: &[Value]) -> Inst {
832 let args = self.func.push_values(values);
833 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
834 }
835
836 pub fn unreachable(&mut self) -> Inst {
838 self.inst(InstData::new(Opcode::Unreachable), &[])
839 }
840
841 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
843 self.call_varargs(callee, signature, args, &[])
844 }
845
846 pub fn call_varargs(
852 &mut self,
853 callee: Symbol,
854 signature: Sig,
855 args: &[Value],
856 varargs: &[Abi],
857 ) -> Inst {
858 let varargs = self.func.push_abis(varargs);
859 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
860 let returns: Vec<Type> = self.func[signature].return_types().collect();
861 let args = self.func.push_values(args);
862 self.inst(
863 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
864 &returns,
865 )
866 }
867
868 pub fn inline_asm(
874 &mut self,
875 info: AsmInfo,
876 args: &[Value],
877 results: &[Type],
878 flags: Flags,
879 ) -> Inst {
880 let info = self.func.add_asm(info);
881 let args = self.func.push_values(args);
882 self.inst(
883 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
884 results,
885 )
886 }
887
888 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
889 BlockCall { block, args: self.func.push_values(args) }
890 }
891}
892
893#[cfg(test)]
894mod tests {
895 use rucc_base::Interner;
896
897 use super::*;
898 use crate::MemOrder;
899 use crate::inst::BlockCallList;
900
901 fn sum() -> (Func, Block, Block, Block) {
903 let mut names = Interner::new();
904 let i32_ = Type::int(32);
905 let mut func = Func::new(
906 names.intern("sum"),
907 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
908 );
909
910 let entry = func.create_block();
911 let n = func.append_param(entry, i32_);
912 let header = func.create_block();
913 let acc = func.append_param(header, i32_);
914 let i = func.append_param(header, i32_);
915 let exit = func.create_block();
916 let result = func.append_param(exit, i32_);
917
918 let mut b = Builder::new(&mut func, entry);
919 let zero = b.iconst(i32_, 0);
920 let cmp = b.icmp(IntPred::Sle, n, zero);
921 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
922
923 let mut b = Builder::new(&mut func, header);
924 let one = b.iconst(i32_, 1);
925 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
926 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
927 let done = b.icmp(IntPred::Sge, next, n);
928 b.br_if(done, exit, &[total], header, &[total, next]);
929
930 let mut b = Builder::new(&mut func, exit);
931 b.ret(&[result]);
932
933 (func, entry, header, exit)
934 }
935
936 #[test]
937 fn the_blocks_come_back_in_the_order_they_were_made() {
938 let (func, entry, header, exit) = sum();
939 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
940 assert_eq!(func.entry(), Some(entry));
941 }
942
943 #[test]
944 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
945 let (mut func, entry, header, exit) = sum();
946 let inside: Vec<Inst> = func.insts(header).collect();
947 func.remove_block(header);
948 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
949 assert_eq!(func.entry(), Some(entry));
950 assert_eq!(func[entry].next, Some(exit));
951 assert_eq!(func[exit].prev, Some(entry));
952 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
954 assert!(func.insts(header).next().is_none());
955 }
956
957 #[test]
958 fn each_block_holds_what_was_appended_to_it() {
959 let (func, entry, header, exit) = sum();
960 let opcodes =
961 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
962 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
963 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
964 assert_eq!(opcodes(exit), ["return"]);
965 }
966
967 #[test]
968 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
969 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
972 let block = func.create_block();
973 let plain = func.add_asm(AsmInfo {
974 template: Symbol::from_raw(0),
975 constraints: Symbol::from_raw(0),
976 clobbers: Symbol::from_raw(0),
977 targets: BlockCallList::EMPTY,
978 });
979 let call = BlockCall { block, args: ValueList::EMPTY };
980 let targets = func.push_block_calls(&[call]);
981 let labelled = func.add_asm(AsmInfo {
982 template: Symbol::from_raw(0),
983 constraints: Symbol::from_raw(0),
984 clobbers: Symbol::from_raw(0),
985 targets,
986 });
987
988 let mut make = |extra| {
989 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
990 func.create_inst(data, &[], Span::DUMMY)
991 };
992 let plain = make(Extra::Asm(plain));
993 let labelled = make(Extra::Asm(labelled));
994 assert!(!func.is_terminator(plain));
995 assert!(func.is_terminator(labelled));
996 }
997
998 #[test]
999 fn every_block_ends_in_its_terminator() {
1000 let (func, entry, header, exit) = sum();
1001 for block in [entry, header, exit] {
1002 let last = func.terminator(block).expect("a terminator");
1003 assert_eq!(Some(last), func.insts(block).last());
1004 }
1005 }
1006
1007 #[test]
1008 fn a_branch_carries_the_arguments_the_block_takes() {
1009 let (func, entry, header, _) = sum();
1010 let br = func.terminator(entry).expect("a terminator");
1011 let calls: Vec<BlockCall> = func.successors(br).collect();
1012 assert_eq!(calls.len(), 2);
1013 assert_eq!(calls[1].block, header);
1015 assert_eq!(func[calls[1].args].len(), 2);
1016 assert_eq!(func[header].params.len(), 2);
1017 assert_eq!(func[calls[0].args].len(), 1);
1018 }
1019
1020 #[test]
1021 fn a_value_knows_what_defined_it() {
1022 let (func, entry, _, _) = sum();
1023 let first = func.insts(entry).next().expect("an instruction");
1024 let value = func[first].first_result.expect("a result");
1025 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1026 assert_eq!(func[value].ty, Type::int(32));
1027
1028 let param = func[entry].params[0];
1029 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1030 }
1031
1032 #[test]
1033 fn a_comparison_produces_one_bit() {
1034 let (func, entry, _, _) = sum();
1035 let cmp = func.insts(entry).nth(1).expect("the comparison");
1036 let value = func[cmp].first_result.expect("a result");
1037 assert_eq!(func[value].ty, Type::I1);
1038 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1039 }
1040
1041 #[test]
1042 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1043 let (func, _, header, _) = sum();
1044 let add = func.insts(header).nth(1).expect("the addition");
1045 assert_eq!(func[add].flags, Flags::NSW);
1046 let cmp = func.insts(header).nth(3).expect("the comparison");
1047 assert_eq!(func[cmp].flags, Flags::NONE);
1048 }
1049
1050 #[test]
1051 fn removing_an_instruction_takes_it_out_of_the_middle() {
1052 let (mut func, _, header, _) = sum();
1053 let add = func.insts(header).nth(1).expect("the addition");
1054 func.remove_inst(add);
1055 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1056 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1057 assert_eq!(func.block_of(add), None);
1058 }
1059
1060 #[test]
1061 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1062 let (mut func, entry, _, _) = sum();
1063 let first = func.insts(entry).next().expect("an instruction");
1064 let last = func.terminator(entry).expect("a terminator");
1065 func.remove_inst(first);
1066 func.remove_inst(last);
1067 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1068 assert_eq!(opcodes, ["icmp"]);
1069 assert_eq!(func[entry].first, func[entry].last);
1070 }
1071
1072 #[test]
1073 fn removing_the_only_instruction_empties_the_block() {
1074 let (mut func, _, _, exit) = sum();
1075 let only = func.insts(exit).next().expect("an instruction");
1076 func.remove_inst(only);
1077 assert_eq!(func.insts(exit).count(), 0);
1078 assert_eq!(func[exit].first, None);
1079 assert_eq!(func[exit].last, None);
1080 }
1081
1082 #[test]
1083 fn inserting_before_puts_it_in_the_right_place() {
1084 let (mut func, entry, _, _) = sum();
1085 let cmp = func.insts(entry).nth(1).expect("the comparison");
1086 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1087 func.insert_before(made, cmp);
1088 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1089 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1090 }
1091
1092 #[test]
1093 fn inserting_before_the_first_makes_it_the_first() {
1094 let (mut func, entry, _, _) = sum();
1095 let first = func.insts(entry).next().expect("an instruction");
1096 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1097 func.insert_before(made, first);
1098 assert_eq!(func.insts(entry).next(), Some(made));
1099 assert_eq!(func[entry].first, Some(made));
1100 }
1101
1102 #[test]
1103 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1104 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1105 let block = func.create_block();
1106 let a = func.append_param(block, Type::int(32));
1107 let b = func.append_param(block, Type::int(32));
1108 let list = func.push_values(&[a]);
1109 let grown = func.append_arg(list, b);
1110 assert_eq!(func[grown], [a, b]);
1111 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1112 }
1113
1114 #[test]
1115 fn a_list_is_copied_when_something_is_behind_it() {
1116 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1117 let block = func.create_block();
1118 let a = func.append_param(block, Type::int(32));
1119 let b = func.append_param(block, Type::int(32));
1120 let list = func.push_values(&[a, a]);
1121 let behind = func.push_values(&[b]);
1122 let grown = func.append_arg(list, b);
1123 assert_eq!(func[grown], [a, a, b]);
1124 assert_eq!(func[list], [a, a], "the old run is still readable");
1125 assert_eq!(func[behind], [b], "and so is what was behind it");
1126 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1127 }
1128
1129 #[test]
1130 fn a_parameter_added_late_is_the_next_one_along() {
1131 let (mut func, entry, header, _) = sum();
1135 let extra = func.append_param(header, Type::int(32));
1136 assert_eq!(func[header].params.len(), 3);
1137 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1138
1139 let br = func.terminator(entry).expect("a terminator");
1140 let call = func.successors(br).nth(1).expect("the branch to the header");
1141 let grown = func.append_arg(call.args, extra);
1142 assert_eq!(func[grown].len(), 3);
1143 }
1144
1145 #[test]
1146 fn a_span_rides_along_with_the_instruction() {
1147 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1148 let block = func.create_block();
1149 let span = Span::new(10, 20);
1150 let mut b = Builder::new(&mut func, block).at(span);
1151 let value = b.iconst(Type::int(32), 7);
1152 let inst = match func[value].def {
1153 Def::Result { inst, .. } => inst,
1154 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1155 };
1156 assert_eq!(func.span(inst), span);
1157 }
1158
1159 #[test]
1160 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1161 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1162 let block = func.create_block();
1163 let addr = func.append_param(block, Type::PTR);
1164 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1165 let mut b = Builder::new(&mut func, block);
1166 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1167 let store = b.store(value, addr, info, Flags::VOLATILE);
1168 assert_eq!(func[store].results, 0);
1169 assert_eq!(func[store].flags, Flags::VOLATILE);
1170 assert_eq!(func[value].ty, Type::int(32));
1171 }
1172
1173 #[test]
1174 fn a_call_produces_what_its_signature_returns() {
1175 let mut names = Interner::new();
1176 let mut func = Func::new(names.intern("caller"), Signature::new());
1177 let sig = func.add_signature(
1178 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1179 );
1180 let block = func.create_block();
1181 let arg = func.append_param(block, Type::int(32));
1182 let callee = names.intern("callee");
1183 let mut b = Builder::new(&mut func, block);
1184 let call = b.call(callee, sig, &[arg]);
1185 assert_eq!(func[call].results, 1);
1186 let value = func[call].first_result.expect("a result");
1187 assert_eq!(func[value].ty, Type::int(64));
1188 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1189 }
1190
1191 #[test]
1192 fn the_counts_are_what_was_made() {
1193 let (func, _, _, _) = sum();
1194 let counts = func.counts();
1195 assert_eq!(counts.blocks, 3);
1196 assert_eq!(counts.insts, 9);
1197 assert_eq!(counts.values, 4 + 6);
1200 }
1201
1202 #[test]
1203 #[should_panic(expected = "the instruction is in a block")]
1204 fn appending_an_instruction_twice_is_refused() {
1205 let (mut func, entry, _, _) = sum();
1206 let first = func.insts(entry).next().expect("an instruction");
1207 func.append_inst(entry, first);
1208 }
1209
1210 #[test]
1211 #[should_panic(expected = "the instruction is not in a block")]
1212 fn removing_an_instruction_twice_is_refused() {
1213 let (mut func, entry, _, _) = sum();
1214 let first = func.insts(entry).next().expect("an instruction");
1215 func.remove_inst(first);
1216 func.remove_inst(first);
1217 }
1218}