1use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33
34use crate::inst::{
35 AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm, ImmList, Inst,
36 InstData, InstLayout, MemInfo, Sig, Signature, SwitchInfo, Value, ValueData, ValueList,
37};
38use crate::module::{Linkage, Visibility};
39use crate::{Attrs, Flags, FloatPred, IntPred, Opcode, Type};
40
41#[derive(Debug)]
43pub struct Func {
44 pub name: Symbol,
46 pub linkage: Linkage,
48 pub visibility: Visibility,
50 pub section: Option<Symbol>,
53 pub attrs: Attrs,
56
57 values: Vec<ValueData>,
58 insts: Vec<InstData>,
59 inst_layout: Vec<InstLayout>,
60 inst_spans: Vec<Span>,
61 blocks: Vec<BlockData>,
62
63 value_pool: Vec<Value>,
64 block_calls: Vec<BlockCall>,
65 imms: Vec<Imm>,
66 mem: Vec<MemInfo>,
67 calls: Vec<CallInfo>,
68 switches: Vec<SwitchInfo>,
69 asms: Vec<AsmInfo>,
70 signatures: Vec<Signature>,
71
72 first_block: Option<Block>,
73 last_block: Option<Block>,
74}
75
76impl Func {
77 #[must_use]
84 pub fn new(name: Symbol, signature: Signature) -> Self {
85 Self {
86 name,
87 linkage: Linkage::External,
88 visibility: Visibility::Default,
89 section: None,
90 attrs: Attrs::NONE,
91 values: Vec::new(),
92 insts: Vec::new(),
93 inst_layout: Vec::new(),
94 inst_spans: Vec::new(),
95 blocks: Vec::new(),
96 value_pool: Vec::new(),
97 block_calls: Vec::new(),
98 imms: Vec::new(),
99 mem: Vec::new(),
100 calls: Vec::new(),
101 switches: Vec::new(),
102 asms: Vec::new(),
103 signatures: vec![signature],
104 first_block: None,
105 last_block: None,
106 }
107 }
108
109 #[must_use]
111 pub fn signature(&self) -> &Signature {
112 &self.signatures[0]
113 }
114
115 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
117 self.signatures.iter()
118 }
119
120 pub fn add_signature(&mut self, signature: Signature) -> Sig {
122 self.signatures.push(signature);
123 Idx::from_usize(self.signatures.len() - 1)
124 }
125
126 #[must_use]
131 pub fn entry(&self) -> Option<Block> {
132 self.first_block
133 }
134
135 #[must_use]
142 pub fn is_declaration(&self) -> bool {
143 self.first_block.is_none()
144 }
145
146 pub fn create_block(&mut self) -> Block {
150 let block = Idx::from_usize(self.blocks.len());
151 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
152 match self.last_block {
153 Some(last) => self.blocks[last.index()].next = Some(block),
154 None => self.first_block = Some(block),
155 }
156 self.last_block = Some(block);
157 block
158 }
159
160 pub fn remove_block(&mut self, block: Block) {
173 assert!(self.first_block != Some(block), "the entry block is not removable");
174 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
175 match prev {
176 Some(prev) => self.blocks[prev.index()].next = next,
177 None => self.first_block = next,
178 }
179 match next {
180 Some(next) => self.blocks[next.index()].prev = prev,
181 None => self.last_block = prev,
182 }
183 let insts: Vec<Inst> = self.insts(block).collect();
187 for inst in insts {
188 self.inst_layout[inst.index()] = InstLayout::default();
189 }
190 self.blocks[block.index()] = BlockData::default();
191 }
192
193 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
202 let index = u32::try_from(self.blocks[block.index()].params.len())
203 .expect("a block with four billion parameters");
204 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
205 self.blocks[block.index()].params.push(value);
206 value
207 }
208
209 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
221 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
222 params.retain(|&value| keep(value));
223 for (index, &value) in params.iter().enumerate() {
224 let index = u32::try_from(index).expect("a block with four billion parameters");
225 self.values[value.index()].def = Def::Param { block, index };
226 }
227 self.blocks[block.index()].params = params;
228 }
229
230 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
232 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
233 }
234
235 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
237 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
238 self.inst_layout[inst.index()].next
239 })
240 }
241
242 #[must_use]
244 pub fn terminator(&self, block: Block) -> Option<Inst> {
245 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
246 }
247
248 #[must_use]
254 pub fn is_terminator(&self, inst: Inst) -> bool {
255 let data = &self[inst];
256 match data.extra {
257 Extra::Asm(info) => {
258 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
259 }
260 _ => data.opcode.is_terminator(),
261 }
262 }
263
264 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
275 let inst = Idx::from_usize(self.insts.len());
276 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
277 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
278 for (index, &ty) in results.iter().enumerate() {
279 let index = u8::try_from(index).expect("checked just above");
280 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
281 }
282 self.insts.push(data);
283 self.inst_layout.push(InstLayout::default());
284 self.inst_spans.push(span);
285 inst
286 }
287
288 pub fn append_inst(&mut self, block: Block, inst: Inst) {
295 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
296 let last = self.blocks[block.index()].last;
297 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
298 match last {
299 Some(last) => self.inst_layout[last.index()].next = Some(inst),
300 None => self.blocks[block.index()].first = Some(inst),
301 }
302 self.blocks[block.index()].last = Some(inst);
303 }
304
305 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
311 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
312 let at = self.inst_layout[before.index()];
313 let block = at.block.expect("the instruction to insert before is not in a block");
314 self.inst_layout[inst.index()] =
315 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
316 self.inst_layout[before.index()].prev = Some(inst);
317 match at.prev {
318 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
319 None => self.blocks[block.index()].first = Some(inst),
320 }
321 }
322
323 pub fn remove_inst(&mut self, inst: Inst) {
333 let at = self.inst_layout[inst.index()];
334 let block = at.block.expect("the instruction is not in a block");
335 match at.prev {
336 Some(prev) => self.inst_layout[prev.index()].next = at.next,
337 None => self.blocks[block.index()].first = at.next,
338 }
339 match at.next {
340 Some(next) => self.inst_layout[next.index()].prev = at.prev,
341 None => self.blocks[block.index()].last = at.prev,
342 }
343 self.inst_layout[inst.index()] = InstLayout::default();
344 }
345
346 #[must_use]
348 pub fn block_of(&self, inst: Inst) -> Option<Block> {
349 self.inst_layout[inst.index()].block
350 }
351
352 #[must_use]
354 pub fn span(&self, inst: Inst) -> Span {
355 self.inst_spans[inst.index()]
356 }
357
358 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
363 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
364 }
365
366 #[must_use]
373 pub fn target_list(&self, inst: Inst) -> BlockCallList {
374 match self[inst].extra {
375 Extra::Targets(targets) => targets,
376 Extra::Switch(info) => self.switches[info.index()].targets,
377 Extra::Asm(info) => self.asms[info.index()].targets,
378 _ => BlockCallList::EMPTY,
379 }
380 }
381
382 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
386 let start = Idx::from_usize(self.value_pool.len());
387 self.value_pool.extend_from_slice(values);
388 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
389 }
390
391 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
398 let range = list.as_usize_range();
399 if range.end == self.value_pool.len() {
400 self.value_pool.push(value);
401 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
402 }
403 let start = self.value_pool.len();
404 self.value_pool.extend_from_within(range);
405 self.value_pool.push(value);
406 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
407 }
408
409 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
414 for value in &mut self.value_pool[list.as_usize_range()] {
415 *value = with(*value);
416 }
417 }
418
419 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
421 let start = Idx::from_usize(self.block_calls.len());
422 self.block_calls.extend_from_slice(calls);
423 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
424 }
425
426 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
428 self.block_calls[at.index()] = call;
429 }
430
431 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
433 let start = Idx::from_usize(self.imms.len());
434 self.imms.extend_from_slice(imms);
435 ImmList::new(start, Idx::from_usize(self.imms.len()))
436 }
437
438 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
440 self.imms.push(imm);
441 Idx::from_usize(self.imms.len() - 1)
442 }
443
444 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
446 self.mem.push(info);
447 Idx::from_usize(self.mem.len() - 1)
448 }
449
450 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
452 self.calls.push(info);
453 Idx::from_usize(self.calls.len() - 1)
454 }
455
456 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
458 self.switches.push(info);
459 Idx::from_usize(self.switches.len() - 1)
460 }
461
462 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
464 self.asms.push(info);
465 Idx::from_usize(self.asms.len() - 1)
466 }
467
468 #[must_use]
471 pub fn counts(&self) -> Counts {
472 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
473 }
474
475 fn add_value(&mut self, data: ValueData) -> Value {
476 self.values.push(data);
477 Idx::from_usize(self.values.len() - 1)
478 }
479}
480
481#[derive(Clone, Copy, Debug, PartialEq, Eq)]
483pub struct Counts {
484 pub values: usize,
486 pub insts: usize,
488 pub blocks: usize,
490}
491
492impl Index<Value> for Func {
495 type Output = ValueData;
496
497 fn index(&self, value: Value) -> &ValueData {
498 &self.values[value.index()]
499 }
500}
501
502impl Index<Inst> for Func {
503 type Output = InstData;
504
505 fn index(&self, inst: Inst) -> &InstData {
506 &self.insts[inst.index()]
507 }
508}
509
510impl IndexMut<Inst> for Func {
511 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
512 &mut self.insts[inst.index()]
513 }
514}
515
516impl Index<Block> for Func {
517 type Output = BlockData;
518
519 fn index(&self, block: Block) -> &BlockData {
520 &self.blocks[block.index()]
521 }
522}
523
524impl Index<Sig> for Func {
525 type Output = Signature;
526
527 fn index(&self, sig: Sig) -> &Signature {
528 &self.signatures[sig.index()]
529 }
530}
531
532impl Index<ValueList> for Func {
533 type Output = [Value];
534
535 fn index(&self, list: ValueList) -> &[Value] {
536 &self.value_pool[list.as_usize_range()]
537 }
538}
539
540impl Index<BlockCallList> for Func {
541 type Output = [BlockCall];
542
543 fn index(&self, list: BlockCallList) -> &[BlockCall] {
544 &self.block_calls[list.as_usize_range()]
545 }
546}
547
548impl Index<Idx<BlockCall>> for Func {
549 type Output = BlockCall;
550
551 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
552 &self.block_calls[at.index()]
553 }
554}
555
556impl Index<ImmList> for Func {
557 type Output = [Imm];
558
559 fn index(&self, list: ImmList) -> &[Imm] {
560 &self.imms[list.as_usize_range()]
561 }
562}
563
564impl Index<Idx<Imm>> for Func {
565 type Output = Imm;
566
567 fn index(&self, at: Idx<Imm>) -> &Imm {
568 &self.imms[at.index()]
569 }
570}
571
572impl Index<Idx<MemInfo>> for Func {
573 type Output = MemInfo;
574
575 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
576 &self.mem[at.index()]
577 }
578}
579
580impl Index<Idx<CallInfo>> for Func {
581 type Output = CallInfo;
582
583 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
584 &self.calls[at.index()]
585 }
586}
587
588impl Index<Idx<SwitchInfo>> for Func {
589 type Output = SwitchInfo;
590
591 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
592 &self.switches[at.index()]
593 }
594}
595
596impl Index<Idx<AsmInfo>> for Func {
597 type Output = AsmInfo;
598
599 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
600 &self.asms[at.index()]
601 }
602}
603
604#[derive(Debug)]
611pub struct Builder<'a> {
612 func: &'a mut Func,
613 block: Block,
614 span: Span,
615}
616
617impl<'a> Builder<'a> {
618 pub fn new(func: &'a mut Func, block: Block) -> Self {
620 Self { func, block, span: Span::DUMMY }
621 }
622
623 #[must_use]
625 pub fn at(mut self, span: Span) -> Self {
626 self.span = span;
627 self
628 }
629
630 pub fn set_span(&mut self, span: Span) {
632 self.span = span;
633 }
634
635 pub fn func(&mut self) -> &mut Func {
637 self.func
638 }
639
640 #[must_use]
642 pub fn block(&self) -> Block {
643 self.block
644 }
645
646 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
648 let inst = self.func.create_inst(data, results, self.span);
649 self.func.append_inst(self.block, inst);
650 inst
651 }
652
653 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
659 let inst = self.inst(data, &[ty]);
660 self.func[inst].first_result.expect("one result was asked for")
661 }
662
663 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
669 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
670 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
671 }
672
673 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
675 let imm = self.func.add_imm(Imm::from_bits(bits));
676 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
677 }
678
679 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
681 let ty = self.func[lhs].ty;
682 let args = self.func.push_values(&[lhs, rhs]);
683 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
684 }
685
686 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
688 let args = self.func.push_values(&[arg]);
689 self.value(InstData { args, ..InstData::new(opcode) }, ty)
690 }
691
692 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
694 let ty = self.func[lhs].ty.with_lane(Type::I1);
695 let args = self.func.push_values(&[lhs, rhs]);
696 self.value(
697 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
698 ty,
699 )
700 }
701
702 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
704 let ty = self.func[lhs].ty.with_lane(Type::I1);
705 let args = self.func.push_values(&[lhs, rhs]);
706 self.value(
707 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
708 ty,
709 )
710 }
711
712 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
714 let mem = self.func.add_mem(info);
715 let args = self.func.push_values(&[addr]);
716 self.value(
717 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
718 ty,
719 )
720 }
721
722 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
724 let mem = self.func.add_mem(info);
725 let args = self.func.push_values(&[value, addr]);
726 self.inst(
727 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
728 &[],
729 )
730 }
731
732 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
734 let call = self.block_call(target, args);
735 let targets = self.func.push_block_calls(&[call]);
736 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
737 }
738
739 pub fn block_addr(&mut self, target: Block) -> Value {
745 let call = self.block_call(target, &[]);
746 let targets = self.func.push_block_calls(&[call]);
747 self.value(
748 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
749 Type::PTR,
750 )
751 }
752
753 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
759 let calls: Vec<BlockCall> =
760 targets.iter().map(|&target| self.block_call(target, &[])).collect();
761 let targets = self.func.push_block_calls(&calls);
762 let args = self.func.push_values(&[addr]);
763 self.inst(
764 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
765 &[],
766 )
767 }
768
769 pub fn br_if(
771 &mut self,
772 cond: Value,
773 then_block: Block,
774 then_args: &[Value],
775 else_block: Block,
776 else_args: &[Value],
777 ) -> Inst {
778 let then_call = self.block_call(then_block, then_args);
779 let else_call = self.block_call(else_block, else_args);
780 let targets = self.func.push_block_calls(&[then_call, else_call]);
781 let args = self.func.push_values(&[cond]);
782 self.inst(
783 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
784 &[],
785 )
786 }
787
788 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
795 let ty = self.func[value].ty.lane();
796 let mut calls = vec![self.block_call(default, &[])];
797 let mut values = Vec::with_capacity(cases.len());
798 for &(value, block) in cases {
799 calls.push(self.block_call(block, &[]));
800 values.push(Imm::int(value, ty));
801 }
802 let targets = self.func.push_block_calls(&calls);
803 let cases = self.func.push_imms(&values);
804 let info = self.func.add_switch(SwitchInfo { targets, cases });
805 let args = self.func.push_values(&[value]);
806 self.inst(
807 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
808 &[],
809 )
810 }
811
812 pub fn ret(&mut self, values: &[Value]) -> Inst {
814 let args = self.func.push_values(values);
815 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
816 }
817
818 pub fn unreachable(&mut self) -> Inst {
820 self.inst(InstData::new(Opcode::Unreachable), &[])
821 }
822
823 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
825 let info = self.func.add_call(CallInfo { callee: Some(callee), signature });
826 let returns: Vec<Type> = self.func[signature].return_types().collect();
827 let args = self.func.push_values(args);
828 self.inst(
829 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
830 &returns,
831 )
832 }
833
834 pub fn inline_asm(
840 &mut self,
841 info: AsmInfo,
842 args: &[Value],
843 results: &[Type],
844 flags: Flags,
845 ) -> Inst {
846 let info = self.func.add_asm(info);
847 let args = self.func.push_values(args);
848 self.inst(
849 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
850 results,
851 )
852 }
853
854 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
855 BlockCall { block, args: self.func.push_values(args) }
856 }
857}
858
859#[cfg(test)]
860mod tests {
861 use rucc_base::Interner;
862
863 use super::*;
864 use crate::MemOrder;
865 use crate::inst::BlockCallList;
866
867 fn sum() -> (Func, Block, Block, Block) {
869 let mut names = Interner::new();
870 let i32_ = Type::int(32);
871 let mut func = Func::new(
872 names.intern("sum"),
873 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
874 );
875
876 let entry = func.create_block();
877 let n = func.append_param(entry, i32_);
878 let header = func.create_block();
879 let acc = func.append_param(header, i32_);
880 let i = func.append_param(header, i32_);
881 let exit = func.create_block();
882 let result = func.append_param(exit, i32_);
883
884 let mut b = Builder::new(&mut func, entry);
885 let zero = b.iconst(i32_, 0);
886 let cmp = b.icmp(IntPred::Sle, n, zero);
887 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
888
889 let mut b = Builder::new(&mut func, header);
890 let one = b.iconst(i32_, 1);
891 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
892 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
893 let done = b.icmp(IntPred::Sge, next, n);
894 b.br_if(done, exit, &[total], header, &[total, next]);
895
896 let mut b = Builder::new(&mut func, exit);
897 b.ret(&[result]);
898
899 (func, entry, header, exit)
900 }
901
902 #[test]
903 fn the_blocks_come_back_in_the_order_they_were_made() {
904 let (func, entry, header, exit) = sum();
905 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
906 assert_eq!(func.entry(), Some(entry));
907 }
908
909 #[test]
910 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
911 let (mut func, entry, header, exit) = sum();
912 let inside: Vec<Inst> = func.insts(header).collect();
913 func.remove_block(header);
914 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
915 assert_eq!(func.entry(), Some(entry));
916 assert_eq!(func[entry].next, Some(exit));
917 assert_eq!(func[exit].prev, Some(entry));
918 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
920 assert!(func.insts(header).next().is_none());
921 }
922
923 #[test]
924 fn each_block_holds_what_was_appended_to_it() {
925 let (func, entry, header, exit) = sum();
926 let opcodes =
927 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
928 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
929 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
930 assert_eq!(opcodes(exit), ["return"]);
931 }
932
933 #[test]
934 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
935 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
938 let block = func.create_block();
939 let plain = func.add_asm(AsmInfo {
940 template: Symbol::from_raw(0),
941 constraints: Symbol::from_raw(0),
942 clobbers: Symbol::from_raw(0),
943 targets: BlockCallList::EMPTY,
944 });
945 let call = BlockCall { block, args: ValueList::EMPTY };
946 let targets = func.push_block_calls(&[call]);
947 let labelled = func.add_asm(AsmInfo {
948 template: Symbol::from_raw(0),
949 constraints: Symbol::from_raw(0),
950 clobbers: Symbol::from_raw(0),
951 targets,
952 });
953
954 let mut make = |extra| {
955 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
956 func.create_inst(data, &[], Span::DUMMY)
957 };
958 let plain = make(Extra::Asm(plain));
959 let labelled = make(Extra::Asm(labelled));
960 assert!(!func.is_terminator(plain));
961 assert!(func.is_terminator(labelled));
962 }
963
964 #[test]
965 fn every_block_ends_in_its_terminator() {
966 let (func, entry, header, exit) = sum();
967 for block in [entry, header, exit] {
968 let last = func.terminator(block).expect("a terminator");
969 assert_eq!(Some(last), func.insts(block).last());
970 }
971 }
972
973 #[test]
974 fn a_branch_carries_the_arguments_the_block_takes() {
975 let (func, entry, header, _) = sum();
976 let br = func.terminator(entry).expect("a terminator");
977 let calls: Vec<BlockCall> = func.successors(br).collect();
978 assert_eq!(calls.len(), 2);
979 assert_eq!(calls[1].block, header);
981 assert_eq!(func[calls[1].args].len(), 2);
982 assert_eq!(func[header].params.len(), 2);
983 assert_eq!(func[calls[0].args].len(), 1);
984 }
985
986 #[test]
987 fn a_value_knows_what_defined_it() {
988 let (func, entry, _, _) = sum();
989 let first = func.insts(entry).next().expect("an instruction");
990 let value = func[first].first_result.expect("a result");
991 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
992 assert_eq!(func[value].ty, Type::int(32));
993
994 let param = func[entry].params[0];
995 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
996 }
997
998 #[test]
999 fn a_comparison_produces_one_bit() {
1000 let (func, entry, _, _) = sum();
1001 let cmp = func.insts(entry).nth(1).expect("the comparison");
1002 let value = func[cmp].first_result.expect("a result");
1003 assert_eq!(func[value].ty, Type::I1);
1004 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1005 }
1006
1007 #[test]
1008 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1009 let (func, _, header, _) = sum();
1010 let add = func.insts(header).nth(1).expect("the addition");
1011 assert_eq!(func[add].flags, Flags::NSW);
1012 let cmp = func.insts(header).nth(3).expect("the comparison");
1013 assert_eq!(func[cmp].flags, Flags::NONE);
1014 }
1015
1016 #[test]
1017 fn removing_an_instruction_takes_it_out_of_the_middle() {
1018 let (mut func, _, header, _) = sum();
1019 let add = func.insts(header).nth(1).expect("the addition");
1020 func.remove_inst(add);
1021 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1022 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1023 assert_eq!(func.block_of(add), None);
1024 }
1025
1026 #[test]
1027 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1028 let (mut func, entry, _, _) = sum();
1029 let first = func.insts(entry).next().expect("an instruction");
1030 let last = func.terminator(entry).expect("a terminator");
1031 func.remove_inst(first);
1032 func.remove_inst(last);
1033 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1034 assert_eq!(opcodes, ["icmp"]);
1035 assert_eq!(func[entry].first, func[entry].last);
1036 }
1037
1038 #[test]
1039 fn removing_the_only_instruction_empties_the_block() {
1040 let (mut func, _, _, exit) = sum();
1041 let only = func.insts(exit).next().expect("an instruction");
1042 func.remove_inst(only);
1043 assert_eq!(func.insts(exit).count(), 0);
1044 assert_eq!(func[exit].first, None);
1045 assert_eq!(func[exit].last, None);
1046 }
1047
1048 #[test]
1049 fn inserting_before_puts_it_in_the_right_place() {
1050 let (mut func, entry, _, _) = sum();
1051 let cmp = func.insts(entry).nth(1).expect("the comparison");
1052 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1053 func.insert_before(made, cmp);
1054 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1055 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1056 }
1057
1058 #[test]
1059 fn inserting_before_the_first_makes_it_the_first() {
1060 let (mut func, entry, _, _) = sum();
1061 let first = func.insts(entry).next().expect("an instruction");
1062 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1063 func.insert_before(made, first);
1064 assert_eq!(func.insts(entry).next(), Some(made));
1065 assert_eq!(func[entry].first, Some(made));
1066 }
1067
1068 #[test]
1069 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1070 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1071 let block = func.create_block();
1072 let a = func.append_param(block, Type::int(32));
1073 let b = func.append_param(block, Type::int(32));
1074 let list = func.push_values(&[a]);
1075 let grown = func.append_arg(list, b);
1076 assert_eq!(func[grown], [a, b]);
1077 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1078 }
1079
1080 #[test]
1081 fn a_list_is_copied_when_something_is_behind_it() {
1082 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1083 let block = func.create_block();
1084 let a = func.append_param(block, Type::int(32));
1085 let b = func.append_param(block, Type::int(32));
1086 let list = func.push_values(&[a, a]);
1087 let behind = func.push_values(&[b]);
1088 let grown = func.append_arg(list, b);
1089 assert_eq!(func[grown], [a, a, b]);
1090 assert_eq!(func[list], [a, a], "the old run is still readable");
1091 assert_eq!(func[behind], [b], "and so is what was behind it");
1092 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1093 }
1094
1095 #[test]
1096 fn a_parameter_added_late_is_the_next_one_along() {
1097 let (mut func, entry, header, _) = sum();
1101 let extra = func.append_param(header, Type::int(32));
1102 assert_eq!(func[header].params.len(), 3);
1103 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1104
1105 let br = func.terminator(entry).expect("a terminator");
1106 let call = func.successors(br).nth(1).expect("the branch to the header");
1107 let grown = func.append_arg(call.args, extra);
1108 assert_eq!(func[grown].len(), 3);
1109 }
1110
1111 #[test]
1112 fn a_span_rides_along_with_the_instruction() {
1113 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1114 let block = func.create_block();
1115 let span = Span::new(10, 20);
1116 let mut b = Builder::new(&mut func, block).at(span);
1117 let value = b.iconst(Type::int(32), 7);
1118 let inst = match func[value].def {
1119 Def::Result { inst, .. } => inst,
1120 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1121 };
1122 assert_eq!(func.span(inst), span);
1123 }
1124
1125 #[test]
1126 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1127 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1128 let block = func.create_block();
1129 let addr = func.append_param(block, Type::PTR);
1130 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1131 let mut b = Builder::new(&mut func, block);
1132 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1133 let store = b.store(value, addr, info, Flags::VOLATILE);
1134 assert_eq!(func[store].results, 0);
1135 assert_eq!(func[store].flags, Flags::VOLATILE);
1136 assert_eq!(func[value].ty, Type::int(32));
1137 }
1138
1139 #[test]
1140 fn a_call_produces_what_its_signature_returns() {
1141 let mut names = Interner::new();
1142 let mut func = Func::new(names.intern("caller"), Signature::new());
1143 let sig = func.add_signature(
1144 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1145 );
1146 let block = func.create_block();
1147 let arg = func.append_param(block, Type::int(32));
1148 let callee = names.intern("callee");
1149 let mut b = Builder::new(&mut func, block);
1150 let call = b.call(callee, sig, &[arg]);
1151 assert_eq!(func[call].results, 1);
1152 let value = func[call].first_result.expect("a result");
1153 assert_eq!(func[value].ty, Type::int(64));
1154 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1155 }
1156
1157 #[test]
1158 fn the_counts_are_what_was_made() {
1159 let (func, _, _, _) = sum();
1160 let counts = func.counts();
1161 assert_eq!(counts.blocks, 3);
1162 assert_eq!(counts.insts, 9);
1163 assert_eq!(counts.values, 4 + 6);
1166 }
1167
1168 #[test]
1169 #[should_panic(expected = "the instruction is in a block")]
1170 fn appending_an_instruction_twice_is_refused() {
1171 let (mut func, entry, _, _) = sum();
1172 let first = func.insts(entry).next().expect("an instruction");
1173 func.append_inst(entry, first);
1174 }
1175
1176 #[test]
1177 #[should_panic(expected = "the instruction is not in a block")]
1178 fn removing_an_instruction_twice_is_refused() {
1179 let (mut func, entry, _, _) = sum();
1180 let first = func.insts(entry).next().expect("an instruction");
1181 func.remove_inst(first);
1182 func.remove_inst(first);
1183 }
1184}