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 add_signature(&mut self, signature: Signature) -> Sig {
117 self.signatures.push(signature);
118 Idx::from_usize(self.signatures.len() - 1)
119 }
120
121 #[must_use]
126 pub fn entry(&self) -> Option<Block> {
127 self.first_block
128 }
129
130 #[must_use]
137 pub fn is_declaration(&self) -> bool {
138 self.first_block.is_none()
139 }
140
141 pub fn create_block(&mut self) -> Block {
145 let block = Idx::from_usize(self.blocks.len());
146 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
147 match self.last_block {
148 Some(last) => self.blocks[last.index()].next = Some(block),
149 None => self.first_block = Some(block),
150 }
151 self.last_block = Some(block);
152 block
153 }
154
155 pub fn remove_block(&mut self, block: Block) {
168 assert!(self.first_block != Some(block), "the entry block is not removable");
169 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
170 match prev {
171 Some(prev) => self.blocks[prev.index()].next = next,
172 None => self.first_block = next,
173 }
174 match next {
175 Some(next) => self.blocks[next.index()].prev = prev,
176 None => self.last_block = prev,
177 }
178 let insts: Vec<Inst> = self.insts(block).collect();
182 for inst in insts {
183 self.inst_layout[inst.index()] = InstLayout::default();
184 }
185 self.blocks[block.index()] = BlockData::default();
186 }
187
188 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
197 let index = u32::try_from(self.blocks[block.index()].params.len())
198 .expect("a block with four billion parameters");
199 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
200 self.blocks[block.index()].params.push(value);
201 value
202 }
203
204 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
216 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
217 params.retain(|&value| keep(value));
218 for (index, &value) in params.iter().enumerate() {
219 let index = u32::try_from(index).expect("a block with four billion parameters");
220 self.values[value.index()].def = Def::Param { block, index };
221 }
222 self.blocks[block.index()].params = params;
223 }
224
225 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
227 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
228 }
229
230 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
232 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
233 self.inst_layout[inst.index()].next
234 })
235 }
236
237 #[must_use]
239 pub fn terminator(&self, block: Block) -> Option<Inst> {
240 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
241 }
242
243 #[must_use]
249 pub fn is_terminator(&self, inst: Inst) -> bool {
250 let data = &self[inst];
251 match data.extra {
252 Extra::Asm(info) => {
253 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
254 }
255 _ => data.opcode.is_terminator(),
256 }
257 }
258
259 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
270 let inst = Idx::from_usize(self.insts.len());
271 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
272 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
273 for (index, &ty) in results.iter().enumerate() {
274 let index = u8::try_from(index).expect("checked just above");
275 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
276 }
277 self.insts.push(data);
278 self.inst_layout.push(InstLayout::default());
279 self.inst_spans.push(span);
280 inst
281 }
282
283 pub fn append_inst(&mut self, block: Block, inst: Inst) {
290 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
291 let last = self.blocks[block.index()].last;
292 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
293 match last {
294 Some(last) => self.inst_layout[last.index()].next = Some(inst),
295 None => self.blocks[block.index()].first = Some(inst),
296 }
297 self.blocks[block.index()].last = Some(inst);
298 }
299
300 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
306 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
307 let at = self.inst_layout[before.index()];
308 let block = at.block.expect("the instruction to insert before is not in a block");
309 self.inst_layout[inst.index()] =
310 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
311 self.inst_layout[before.index()].prev = Some(inst);
312 match at.prev {
313 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
314 None => self.blocks[block.index()].first = Some(inst),
315 }
316 }
317
318 pub fn remove_inst(&mut self, inst: Inst) {
328 let at = self.inst_layout[inst.index()];
329 let block = at.block.expect("the instruction is not in a block");
330 match at.prev {
331 Some(prev) => self.inst_layout[prev.index()].next = at.next,
332 None => self.blocks[block.index()].first = at.next,
333 }
334 match at.next {
335 Some(next) => self.inst_layout[next.index()].prev = at.prev,
336 None => self.blocks[block.index()].last = at.prev,
337 }
338 self.inst_layout[inst.index()] = InstLayout::default();
339 }
340
341 #[must_use]
343 pub fn block_of(&self, inst: Inst) -> Option<Block> {
344 self.inst_layout[inst.index()].block
345 }
346
347 #[must_use]
349 pub fn span(&self, inst: Inst) -> Span {
350 self.inst_spans[inst.index()]
351 }
352
353 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
358 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
359 }
360
361 #[must_use]
368 pub fn target_list(&self, inst: Inst) -> BlockCallList {
369 match self[inst].extra {
370 Extra::Targets(targets) => targets,
371 Extra::Switch(info) => self.switches[info.index()].targets,
372 Extra::Asm(info) => self.asms[info.index()].targets,
373 _ => BlockCallList::EMPTY,
374 }
375 }
376
377 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
381 let start = Idx::from_usize(self.value_pool.len());
382 self.value_pool.extend_from_slice(values);
383 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
384 }
385
386 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
393 let range = list.as_usize_range();
394 if range.end == self.value_pool.len() {
395 self.value_pool.push(value);
396 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
397 }
398 let start = self.value_pool.len();
399 self.value_pool.extend_from_within(range);
400 self.value_pool.push(value);
401 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
402 }
403
404 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
409 for value in &mut self.value_pool[list.as_usize_range()] {
410 *value = with(*value);
411 }
412 }
413
414 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
416 let start = Idx::from_usize(self.block_calls.len());
417 self.block_calls.extend_from_slice(calls);
418 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
419 }
420
421 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
423 self.block_calls[at.index()] = call;
424 }
425
426 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
428 let start = Idx::from_usize(self.imms.len());
429 self.imms.extend_from_slice(imms);
430 ImmList::new(start, Idx::from_usize(self.imms.len()))
431 }
432
433 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
435 self.imms.push(imm);
436 Idx::from_usize(self.imms.len() - 1)
437 }
438
439 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
441 self.mem.push(info);
442 Idx::from_usize(self.mem.len() - 1)
443 }
444
445 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
447 self.calls.push(info);
448 Idx::from_usize(self.calls.len() - 1)
449 }
450
451 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
453 self.switches.push(info);
454 Idx::from_usize(self.switches.len() - 1)
455 }
456
457 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
459 self.asms.push(info);
460 Idx::from_usize(self.asms.len() - 1)
461 }
462
463 #[must_use]
466 pub fn counts(&self) -> Counts {
467 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
468 }
469
470 fn add_value(&mut self, data: ValueData) -> Value {
471 self.values.push(data);
472 Idx::from_usize(self.values.len() - 1)
473 }
474}
475
476#[derive(Clone, Copy, Debug, PartialEq, Eq)]
478pub struct Counts {
479 pub values: usize,
481 pub insts: usize,
483 pub blocks: usize,
485}
486
487impl Index<Value> for Func {
490 type Output = ValueData;
491
492 fn index(&self, value: Value) -> &ValueData {
493 &self.values[value.index()]
494 }
495}
496
497impl Index<Inst> for Func {
498 type Output = InstData;
499
500 fn index(&self, inst: Inst) -> &InstData {
501 &self.insts[inst.index()]
502 }
503}
504
505impl IndexMut<Inst> for Func {
506 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
507 &mut self.insts[inst.index()]
508 }
509}
510
511impl Index<Block> for Func {
512 type Output = BlockData;
513
514 fn index(&self, block: Block) -> &BlockData {
515 &self.blocks[block.index()]
516 }
517}
518
519impl Index<Sig> for Func {
520 type Output = Signature;
521
522 fn index(&self, sig: Sig) -> &Signature {
523 &self.signatures[sig.index()]
524 }
525}
526
527impl Index<ValueList> for Func {
528 type Output = [Value];
529
530 fn index(&self, list: ValueList) -> &[Value] {
531 &self.value_pool[list.as_usize_range()]
532 }
533}
534
535impl Index<BlockCallList> for Func {
536 type Output = [BlockCall];
537
538 fn index(&self, list: BlockCallList) -> &[BlockCall] {
539 &self.block_calls[list.as_usize_range()]
540 }
541}
542
543impl Index<Idx<BlockCall>> for Func {
544 type Output = BlockCall;
545
546 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
547 &self.block_calls[at.index()]
548 }
549}
550
551impl Index<ImmList> for Func {
552 type Output = [Imm];
553
554 fn index(&self, list: ImmList) -> &[Imm] {
555 &self.imms[list.as_usize_range()]
556 }
557}
558
559impl Index<Idx<Imm>> for Func {
560 type Output = Imm;
561
562 fn index(&self, at: Idx<Imm>) -> &Imm {
563 &self.imms[at.index()]
564 }
565}
566
567impl Index<Idx<MemInfo>> for Func {
568 type Output = MemInfo;
569
570 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
571 &self.mem[at.index()]
572 }
573}
574
575impl Index<Idx<CallInfo>> for Func {
576 type Output = CallInfo;
577
578 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
579 &self.calls[at.index()]
580 }
581}
582
583impl Index<Idx<SwitchInfo>> for Func {
584 type Output = SwitchInfo;
585
586 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
587 &self.switches[at.index()]
588 }
589}
590
591impl Index<Idx<AsmInfo>> for Func {
592 type Output = AsmInfo;
593
594 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
595 &self.asms[at.index()]
596 }
597}
598
599#[derive(Debug)]
606pub struct Builder<'a> {
607 func: &'a mut Func,
608 block: Block,
609 span: Span,
610}
611
612impl<'a> Builder<'a> {
613 pub fn new(func: &'a mut Func, block: Block) -> Self {
615 Self { func, block, span: Span::DUMMY }
616 }
617
618 #[must_use]
620 pub fn at(mut self, span: Span) -> Self {
621 self.span = span;
622 self
623 }
624
625 pub fn set_span(&mut self, span: Span) {
627 self.span = span;
628 }
629
630 pub fn func(&mut self) -> &mut Func {
632 self.func
633 }
634
635 #[must_use]
637 pub fn block(&self) -> Block {
638 self.block
639 }
640
641 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
643 let inst = self.func.create_inst(data, results, self.span);
644 self.func.append_inst(self.block, inst);
645 inst
646 }
647
648 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
654 let inst = self.inst(data, &[ty]);
655 self.func[inst].first_result.expect("one result was asked for")
656 }
657
658 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
664 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
665 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
666 }
667
668 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
670 let imm = self.func.add_imm(Imm::from_bits(bits));
671 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
672 }
673
674 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
676 let ty = self.func[lhs].ty;
677 let args = self.func.push_values(&[lhs, rhs]);
678 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
679 }
680
681 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
683 let args = self.func.push_values(&[arg]);
684 self.value(InstData { args, ..InstData::new(opcode) }, ty)
685 }
686
687 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
689 let ty = self.func[lhs].ty.with_lane(Type::I1);
690 let args = self.func.push_values(&[lhs, rhs]);
691 self.value(
692 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
693 ty,
694 )
695 }
696
697 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
699 let ty = self.func[lhs].ty.with_lane(Type::I1);
700 let args = self.func.push_values(&[lhs, rhs]);
701 self.value(
702 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
703 ty,
704 )
705 }
706
707 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
709 let mem = self.func.add_mem(info);
710 let args = self.func.push_values(&[addr]);
711 self.value(
712 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
713 ty,
714 )
715 }
716
717 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
719 let mem = self.func.add_mem(info);
720 let args = self.func.push_values(&[value, addr]);
721 self.inst(
722 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
723 &[],
724 )
725 }
726
727 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
729 let call = self.block_call(target, args);
730 let targets = self.func.push_block_calls(&[call]);
731 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
732 }
733
734 pub fn br_if(
736 &mut self,
737 cond: Value,
738 then_block: Block,
739 then_args: &[Value],
740 else_block: Block,
741 else_args: &[Value],
742 ) -> Inst {
743 let then_call = self.block_call(then_block, then_args);
744 let else_call = self.block_call(else_block, else_args);
745 let targets = self.func.push_block_calls(&[then_call, else_call]);
746 let args = self.func.push_values(&[cond]);
747 self.inst(
748 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
749 &[],
750 )
751 }
752
753 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
760 let ty = self.func[value].ty.lane();
761 let mut calls = vec![self.block_call(default, &[])];
762 let mut values = Vec::with_capacity(cases.len());
763 for &(value, block) in cases {
764 calls.push(self.block_call(block, &[]));
765 values.push(Imm::int(value, ty));
766 }
767 let targets = self.func.push_block_calls(&calls);
768 let cases = self.func.push_imms(&values);
769 let info = self.func.add_switch(SwitchInfo { targets, cases });
770 let args = self.func.push_values(&[value]);
771 self.inst(
772 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
773 &[],
774 )
775 }
776
777 pub fn ret(&mut self, values: &[Value]) -> Inst {
779 let args = self.func.push_values(values);
780 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
781 }
782
783 pub fn unreachable(&mut self) -> Inst {
785 self.inst(InstData::new(Opcode::Unreachable), &[])
786 }
787
788 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
790 let info = self.func.add_call(CallInfo { callee: Some(callee), signature });
791 let returns = self.func[signature].returns.clone();
792 let args = self.func.push_values(args);
793 self.inst(
794 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
795 &returns,
796 )
797 }
798
799 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
800 BlockCall { block, args: self.func.push_values(args) }
801 }
802}
803
804#[cfg(test)]
805mod tests {
806 use rucc_base::Interner;
807
808 use super::*;
809 use crate::MemOrder;
810 use crate::inst::BlockCallList;
811
812 fn sum() -> (Func, Block, Block, Block) {
814 let mut names = Interner::new();
815 let i32_ = Type::int(32);
816 let mut func = Func::new(
817 names.intern("sum"),
818 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
819 );
820
821 let entry = func.create_block();
822 let n = func.append_param(entry, i32_);
823 let header = func.create_block();
824 let acc = func.append_param(header, i32_);
825 let i = func.append_param(header, i32_);
826 let exit = func.create_block();
827 let result = func.append_param(exit, i32_);
828
829 let mut b = Builder::new(&mut func, entry);
830 let zero = b.iconst(i32_, 0);
831 let cmp = b.icmp(IntPred::Sle, n, zero);
832 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
833
834 let mut b = Builder::new(&mut func, header);
835 let one = b.iconst(i32_, 1);
836 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
837 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
838 let done = b.icmp(IntPred::Sge, next, n);
839 b.br_if(done, exit, &[total], header, &[total, next]);
840
841 let mut b = Builder::new(&mut func, exit);
842 b.ret(&[result]);
843
844 (func, entry, header, exit)
845 }
846
847 #[test]
848 fn the_blocks_come_back_in_the_order_they_were_made() {
849 let (func, entry, header, exit) = sum();
850 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
851 assert_eq!(func.entry(), Some(entry));
852 }
853
854 #[test]
855 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
856 let (mut func, entry, header, exit) = sum();
857 let inside: Vec<Inst> = func.insts(header).collect();
858 func.remove_block(header);
859 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
860 assert_eq!(func.entry(), Some(entry));
861 assert_eq!(func[entry].next, Some(exit));
862 assert_eq!(func[exit].prev, Some(entry));
863 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
865 assert!(func.insts(header).next().is_none());
866 }
867
868 #[test]
869 fn each_block_holds_what_was_appended_to_it() {
870 let (func, entry, header, exit) = sum();
871 let opcodes =
872 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
873 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
874 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
875 assert_eq!(opcodes(exit), ["return"]);
876 }
877
878 #[test]
879 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
880 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
883 let block = func.create_block();
884 let plain = func.add_asm(AsmInfo {
885 template: Symbol::from_raw(0),
886 constraints: Symbol::from_raw(0),
887 clobbers: Symbol::from_raw(0),
888 targets: BlockCallList::EMPTY,
889 });
890 let call = BlockCall { block, args: ValueList::EMPTY };
891 let targets = func.push_block_calls(&[call]);
892 let labelled = func.add_asm(AsmInfo {
893 template: Symbol::from_raw(0),
894 constraints: Symbol::from_raw(0),
895 clobbers: Symbol::from_raw(0),
896 targets,
897 });
898
899 let mut make = |extra| {
900 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
901 func.create_inst(data, &[], Span::DUMMY)
902 };
903 let plain = make(Extra::Asm(plain));
904 let labelled = make(Extra::Asm(labelled));
905 assert!(!func.is_terminator(plain));
906 assert!(func.is_terminator(labelled));
907 }
908
909 #[test]
910 fn every_block_ends_in_its_terminator() {
911 let (func, entry, header, exit) = sum();
912 for block in [entry, header, exit] {
913 let last = func.terminator(block).expect("a terminator");
914 assert_eq!(Some(last), func.insts(block).last());
915 }
916 }
917
918 #[test]
919 fn a_branch_carries_the_arguments_the_block_takes() {
920 let (func, entry, header, _) = sum();
921 let br = func.terminator(entry).expect("a terminator");
922 let calls: Vec<BlockCall> = func.successors(br).collect();
923 assert_eq!(calls.len(), 2);
924 assert_eq!(calls[1].block, header);
926 assert_eq!(func[calls[1].args].len(), 2);
927 assert_eq!(func[header].params.len(), 2);
928 assert_eq!(func[calls[0].args].len(), 1);
929 }
930
931 #[test]
932 fn a_value_knows_what_defined_it() {
933 let (func, entry, _, _) = sum();
934 let first = func.insts(entry).next().expect("an instruction");
935 let value = func[first].first_result.expect("a result");
936 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
937 assert_eq!(func[value].ty, Type::int(32));
938
939 let param = func[entry].params[0];
940 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
941 }
942
943 #[test]
944 fn a_comparison_produces_one_bit() {
945 let (func, entry, _, _) = sum();
946 let cmp = func.insts(entry).nth(1).expect("the comparison");
947 let value = func[cmp].first_result.expect("a result");
948 assert_eq!(func[value].ty, Type::I1);
949 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
950 }
951
952 #[test]
953 fn flags_ride_along_on_the_instruction_that_was_given_them() {
954 let (func, _, header, _) = sum();
955 let add = func.insts(header).nth(1).expect("the addition");
956 assert_eq!(func[add].flags, Flags::NSW);
957 let cmp = func.insts(header).nth(3).expect("the comparison");
958 assert_eq!(func[cmp].flags, Flags::NONE);
959 }
960
961 #[test]
962 fn removing_an_instruction_takes_it_out_of_the_middle() {
963 let (mut func, _, header, _) = sum();
964 let add = func.insts(header).nth(1).expect("the addition");
965 func.remove_inst(add);
966 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
967 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
968 assert_eq!(func.block_of(add), None);
969 }
970
971 #[test]
972 fn removing_the_first_and_the_last_keeps_the_ends_right() {
973 let (mut func, entry, _, _) = sum();
974 let first = func.insts(entry).next().expect("an instruction");
975 let last = func.terminator(entry).expect("a terminator");
976 func.remove_inst(first);
977 func.remove_inst(last);
978 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
979 assert_eq!(opcodes, ["icmp"]);
980 assert_eq!(func[entry].first, func[entry].last);
981 }
982
983 #[test]
984 fn removing_the_only_instruction_empties_the_block() {
985 let (mut func, _, _, exit) = sum();
986 let only = func.insts(exit).next().expect("an instruction");
987 func.remove_inst(only);
988 assert_eq!(func.insts(exit).count(), 0);
989 assert_eq!(func[exit].first, None);
990 assert_eq!(func[exit].last, None);
991 }
992
993 #[test]
994 fn inserting_before_puts_it_in_the_right_place() {
995 let (mut func, entry, _, _) = sum();
996 let cmp = func.insts(entry).nth(1).expect("the comparison");
997 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
998 func.insert_before(made, cmp);
999 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1000 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1001 }
1002
1003 #[test]
1004 fn inserting_before_the_first_makes_it_the_first() {
1005 let (mut func, entry, _, _) = sum();
1006 let first = func.insts(entry).next().expect("an instruction");
1007 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1008 func.insert_before(made, first);
1009 assert_eq!(func.insts(entry).next(), Some(made));
1010 assert_eq!(func[entry].first, Some(made));
1011 }
1012
1013 #[test]
1014 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1015 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1016 let block = func.create_block();
1017 let a = func.append_param(block, Type::int(32));
1018 let b = func.append_param(block, Type::int(32));
1019 let list = func.push_values(&[a]);
1020 let grown = func.append_arg(list, b);
1021 assert_eq!(func[grown], [a, b]);
1022 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1023 }
1024
1025 #[test]
1026 fn a_list_is_copied_when_something_is_behind_it() {
1027 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1028 let block = func.create_block();
1029 let a = func.append_param(block, Type::int(32));
1030 let b = func.append_param(block, Type::int(32));
1031 let list = func.push_values(&[a, a]);
1032 let behind = func.push_values(&[b]);
1033 let grown = func.append_arg(list, b);
1034 assert_eq!(func[grown], [a, a, b]);
1035 assert_eq!(func[list], [a, a], "the old run is still readable");
1036 assert_eq!(func[behind], [b], "and so is what was behind it");
1037 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1038 }
1039
1040 #[test]
1041 fn a_parameter_added_late_is_the_next_one_along() {
1042 let (mut func, entry, header, _) = sum();
1046 let extra = func.append_param(header, Type::int(32));
1047 assert_eq!(func[header].params.len(), 3);
1048 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1049
1050 let br = func.terminator(entry).expect("a terminator");
1051 let call = func.successors(br).nth(1).expect("the branch to the header");
1052 let grown = func.append_arg(call.args, extra);
1053 assert_eq!(func[grown].len(), 3);
1054 }
1055
1056 #[test]
1057 fn a_span_rides_along_with_the_instruction() {
1058 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1059 let block = func.create_block();
1060 let span = Span::new(10, 20);
1061 let mut b = Builder::new(&mut func, block).at(span);
1062 let value = b.iconst(Type::int(32), 7);
1063 let inst = match func[value].def {
1064 Def::Result { inst, .. } => inst,
1065 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1066 };
1067 assert_eq!(func.span(inst), span);
1068 }
1069
1070 #[test]
1071 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1072 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1073 let block = func.create_block();
1074 let addr = func.append_param(block, Type::PTR);
1075 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1076 let mut b = Builder::new(&mut func, block);
1077 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1078 let store = b.store(value, addr, info, Flags::VOLATILE);
1079 assert_eq!(func[store].results, 0);
1080 assert_eq!(func[store].flags, Flags::VOLATILE);
1081 assert_eq!(func[value].ty, Type::int(32));
1082 }
1083
1084 #[test]
1085 fn a_call_produces_what_its_signature_returns() {
1086 let mut names = Interner::new();
1087 let mut func = Func::new(names.intern("caller"), Signature::new());
1088 let sig = func.add_signature(
1089 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1090 );
1091 let block = func.create_block();
1092 let arg = func.append_param(block, Type::int(32));
1093 let callee = names.intern("callee");
1094 let mut b = Builder::new(&mut func, block);
1095 let call = b.call(callee, sig, &[arg]);
1096 assert_eq!(func[call].results, 1);
1097 let value = func[call].first_result.expect("a result");
1098 assert_eq!(func[value].ty, Type::int(64));
1099 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1100 }
1101
1102 #[test]
1103 fn the_counts_are_what_was_made() {
1104 let (func, _, _, _) = sum();
1105 let counts = func.counts();
1106 assert_eq!(counts.blocks, 3);
1107 assert_eq!(counts.insts, 9);
1108 assert_eq!(counts.values, 4 + 6);
1111 }
1112
1113 #[test]
1114 #[should_panic(expected = "the instruction is in a block")]
1115 fn appending_an_instruction_twice_is_refused() {
1116 let (mut func, entry, _, _) = sum();
1117 let first = func.insts(entry).next().expect("an instruction");
1118 func.append_inst(entry, first);
1119 }
1120
1121 #[test]
1122 #[should_panic(expected = "the instruction is not in a block")]
1123 fn removing_an_instruction_twice_is_refused() {
1124 let (mut func, entry, _, _) = sum();
1125 let first = func.insts(entry).next().expect("an instruction");
1126 func.remove_inst(first);
1127 func.remove_inst(first);
1128 }
1129}