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 br_if(
741 &mut self,
742 cond: Value,
743 then_block: Block,
744 then_args: &[Value],
745 else_block: Block,
746 else_args: &[Value],
747 ) -> Inst {
748 let then_call = self.block_call(then_block, then_args);
749 let else_call = self.block_call(else_block, else_args);
750 let targets = self.func.push_block_calls(&[then_call, else_call]);
751 let args = self.func.push_values(&[cond]);
752 self.inst(
753 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
754 &[],
755 )
756 }
757
758 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
765 let ty = self.func[value].ty.lane();
766 let mut calls = vec![self.block_call(default, &[])];
767 let mut values = Vec::with_capacity(cases.len());
768 for &(value, block) in cases {
769 calls.push(self.block_call(block, &[]));
770 values.push(Imm::int(value, ty));
771 }
772 let targets = self.func.push_block_calls(&calls);
773 let cases = self.func.push_imms(&values);
774 let info = self.func.add_switch(SwitchInfo { targets, cases });
775 let args = self.func.push_values(&[value]);
776 self.inst(
777 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
778 &[],
779 )
780 }
781
782 pub fn ret(&mut self, values: &[Value]) -> Inst {
784 let args = self.func.push_values(values);
785 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
786 }
787
788 pub fn unreachable(&mut self) -> Inst {
790 self.inst(InstData::new(Opcode::Unreachable), &[])
791 }
792
793 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
795 let info = self.func.add_call(CallInfo { callee: Some(callee), signature });
796 let returns: Vec<Type> = self.func[signature].return_types().collect();
797 let args = self.func.push_values(args);
798 self.inst(
799 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
800 &returns,
801 )
802 }
803
804 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
805 BlockCall { block, args: self.func.push_values(args) }
806 }
807}
808
809#[cfg(test)]
810mod tests {
811 use rucc_base::Interner;
812
813 use super::*;
814 use crate::MemOrder;
815 use crate::inst::BlockCallList;
816
817 fn sum() -> (Func, Block, Block, Block) {
819 let mut names = Interner::new();
820 let i32_ = Type::int(32);
821 let mut func = Func::new(
822 names.intern("sum"),
823 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
824 );
825
826 let entry = func.create_block();
827 let n = func.append_param(entry, i32_);
828 let header = func.create_block();
829 let acc = func.append_param(header, i32_);
830 let i = func.append_param(header, i32_);
831 let exit = func.create_block();
832 let result = func.append_param(exit, i32_);
833
834 let mut b = Builder::new(&mut func, entry);
835 let zero = b.iconst(i32_, 0);
836 let cmp = b.icmp(IntPred::Sle, n, zero);
837 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
838
839 let mut b = Builder::new(&mut func, header);
840 let one = b.iconst(i32_, 1);
841 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
842 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
843 let done = b.icmp(IntPred::Sge, next, n);
844 b.br_if(done, exit, &[total], header, &[total, next]);
845
846 let mut b = Builder::new(&mut func, exit);
847 b.ret(&[result]);
848
849 (func, entry, header, exit)
850 }
851
852 #[test]
853 fn the_blocks_come_back_in_the_order_they_were_made() {
854 let (func, entry, header, exit) = sum();
855 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
856 assert_eq!(func.entry(), Some(entry));
857 }
858
859 #[test]
860 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
861 let (mut func, entry, header, exit) = sum();
862 let inside: Vec<Inst> = func.insts(header).collect();
863 func.remove_block(header);
864 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
865 assert_eq!(func.entry(), Some(entry));
866 assert_eq!(func[entry].next, Some(exit));
867 assert_eq!(func[exit].prev, Some(entry));
868 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
870 assert!(func.insts(header).next().is_none());
871 }
872
873 #[test]
874 fn each_block_holds_what_was_appended_to_it() {
875 let (func, entry, header, exit) = sum();
876 let opcodes =
877 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
878 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
879 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
880 assert_eq!(opcodes(exit), ["return"]);
881 }
882
883 #[test]
884 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
885 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
888 let block = func.create_block();
889 let plain = func.add_asm(AsmInfo {
890 template: Symbol::from_raw(0),
891 constraints: Symbol::from_raw(0),
892 clobbers: Symbol::from_raw(0),
893 targets: BlockCallList::EMPTY,
894 });
895 let call = BlockCall { block, args: ValueList::EMPTY };
896 let targets = func.push_block_calls(&[call]);
897 let labelled = func.add_asm(AsmInfo {
898 template: Symbol::from_raw(0),
899 constraints: Symbol::from_raw(0),
900 clobbers: Symbol::from_raw(0),
901 targets,
902 });
903
904 let mut make = |extra| {
905 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
906 func.create_inst(data, &[], Span::DUMMY)
907 };
908 let plain = make(Extra::Asm(plain));
909 let labelled = make(Extra::Asm(labelled));
910 assert!(!func.is_terminator(plain));
911 assert!(func.is_terminator(labelled));
912 }
913
914 #[test]
915 fn every_block_ends_in_its_terminator() {
916 let (func, entry, header, exit) = sum();
917 for block in [entry, header, exit] {
918 let last = func.terminator(block).expect("a terminator");
919 assert_eq!(Some(last), func.insts(block).last());
920 }
921 }
922
923 #[test]
924 fn a_branch_carries_the_arguments_the_block_takes() {
925 let (func, entry, header, _) = sum();
926 let br = func.terminator(entry).expect("a terminator");
927 let calls: Vec<BlockCall> = func.successors(br).collect();
928 assert_eq!(calls.len(), 2);
929 assert_eq!(calls[1].block, header);
931 assert_eq!(func[calls[1].args].len(), 2);
932 assert_eq!(func[header].params.len(), 2);
933 assert_eq!(func[calls[0].args].len(), 1);
934 }
935
936 #[test]
937 fn a_value_knows_what_defined_it() {
938 let (func, entry, _, _) = sum();
939 let first = func.insts(entry).next().expect("an instruction");
940 let value = func[first].first_result.expect("a result");
941 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
942 assert_eq!(func[value].ty, Type::int(32));
943
944 let param = func[entry].params[0];
945 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
946 }
947
948 #[test]
949 fn a_comparison_produces_one_bit() {
950 let (func, entry, _, _) = sum();
951 let cmp = func.insts(entry).nth(1).expect("the comparison");
952 let value = func[cmp].first_result.expect("a result");
953 assert_eq!(func[value].ty, Type::I1);
954 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
955 }
956
957 #[test]
958 fn flags_ride_along_on_the_instruction_that_was_given_them() {
959 let (func, _, header, _) = sum();
960 let add = func.insts(header).nth(1).expect("the addition");
961 assert_eq!(func[add].flags, Flags::NSW);
962 let cmp = func.insts(header).nth(3).expect("the comparison");
963 assert_eq!(func[cmp].flags, Flags::NONE);
964 }
965
966 #[test]
967 fn removing_an_instruction_takes_it_out_of_the_middle() {
968 let (mut func, _, header, _) = sum();
969 let add = func.insts(header).nth(1).expect("the addition");
970 func.remove_inst(add);
971 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
972 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
973 assert_eq!(func.block_of(add), None);
974 }
975
976 #[test]
977 fn removing_the_first_and_the_last_keeps_the_ends_right() {
978 let (mut func, entry, _, _) = sum();
979 let first = func.insts(entry).next().expect("an instruction");
980 let last = func.terminator(entry).expect("a terminator");
981 func.remove_inst(first);
982 func.remove_inst(last);
983 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
984 assert_eq!(opcodes, ["icmp"]);
985 assert_eq!(func[entry].first, func[entry].last);
986 }
987
988 #[test]
989 fn removing_the_only_instruction_empties_the_block() {
990 let (mut func, _, _, exit) = sum();
991 let only = func.insts(exit).next().expect("an instruction");
992 func.remove_inst(only);
993 assert_eq!(func.insts(exit).count(), 0);
994 assert_eq!(func[exit].first, None);
995 assert_eq!(func[exit].last, None);
996 }
997
998 #[test]
999 fn inserting_before_puts_it_in_the_right_place() {
1000 let (mut func, entry, _, _) = sum();
1001 let cmp = func.insts(entry).nth(1).expect("the comparison");
1002 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1003 func.insert_before(made, cmp);
1004 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1005 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1006 }
1007
1008 #[test]
1009 fn inserting_before_the_first_makes_it_the_first() {
1010 let (mut func, entry, _, _) = sum();
1011 let first = func.insts(entry).next().expect("an instruction");
1012 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1013 func.insert_before(made, first);
1014 assert_eq!(func.insts(entry).next(), Some(made));
1015 assert_eq!(func[entry].first, Some(made));
1016 }
1017
1018 #[test]
1019 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1020 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1021 let block = func.create_block();
1022 let a = func.append_param(block, Type::int(32));
1023 let b = func.append_param(block, Type::int(32));
1024 let list = func.push_values(&[a]);
1025 let grown = func.append_arg(list, b);
1026 assert_eq!(func[grown], [a, b]);
1027 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1028 }
1029
1030 #[test]
1031 fn a_list_is_copied_when_something_is_behind_it() {
1032 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1033 let block = func.create_block();
1034 let a = func.append_param(block, Type::int(32));
1035 let b = func.append_param(block, Type::int(32));
1036 let list = func.push_values(&[a, a]);
1037 let behind = func.push_values(&[b]);
1038 let grown = func.append_arg(list, b);
1039 assert_eq!(func[grown], [a, a, b]);
1040 assert_eq!(func[list], [a, a], "the old run is still readable");
1041 assert_eq!(func[behind], [b], "and so is what was behind it");
1042 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1043 }
1044
1045 #[test]
1046 fn a_parameter_added_late_is_the_next_one_along() {
1047 let (mut func, entry, header, _) = sum();
1051 let extra = func.append_param(header, Type::int(32));
1052 assert_eq!(func[header].params.len(), 3);
1053 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1054
1055 let br = func.terminator(entry).expect("a terminator");
1056 let call = func.successors(br).nth(1).expect("the branch to the header");
1057 let grown = func.append_arg(call.args, extra);
1058 assert_eq!(func[grown].len(), 3);
1059 }
1060
1061 #[test]
1062 fn a_span_rides_along_with_the_instruction() {
1063 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1064 let block = func.create_block();
1065 let span = Span::new(10, 20);
1066 let mut b = Builder::new(&mut func, block).at(span);
1067 let value = b.iconst(Type::int(32), 7);
1068 let inst = match func[value].def {
1069 Def::Result { inst, .. } => inst,
1070 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1071 };
1072 assert_eq!(func.span(inst), span);
1073 }
1074
1075 #[test]
1076 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1077 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1078 let block = func.create_block();
1079 let addr = func.append_param(block, Type::PTR);
1080 let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1081 let mut b = Builder::new(&mut func, block);
1082 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1083 let store = b.store(value, addr, info, Flags::VOLATILE);
1084 assert_eq!(func[store].results, 0);
1085 assert_eq!(func[store].flags, Flags::VOLATILE);
1086 assert_eq!(func[value].ty, Type::int(32));
1087 }
1088
1089 #[test]
1090 fn a_call_produces_what_its_signature_returns() {
1091 let mut names = Interner::new();
1092 let mut func = Func::new(names.intern("caller"), Signature::new());
1093 let sig = func.add_signature(
1094 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1095 );
1096 let block = func.create_block();
1097 let arg = func.append_param(block, Type::int(32));
1098 let callee = names.intern("callee");
1099 let mut b = Builder::new(&mut func, block);
1100 let call = b.call(callee, sig, &[arg]);
1101 assert_eq!(func[call].results, 1);
1102 let value = func[call].first_result.expect("a result");
1103 assert_eq!(func[value].ty, Type::int(64));
1104 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1105 }
1106
1107 #[test]
1108 fn the_counts_are_what_was_made() {
1109 let (func, _, _, _) = sum();
1110 let counts = func.counts();
1111 assert_eq!(counts.blocks, 3);
1112 assert_eq!(counts.insts, 9);
1113 assert_eq!(counts.values, 4 + 6);
1116 }
1117
1118 #[test]
1119 #[should_panic(expected = "the instruction is in a block")]
1120 fn appending_an_instruction_twice_is_refused() {
1121 let (mut func, entry, _, _) = sum();
1122 let first = func.insts(entry).next().expect("an instruction");
1123 func.append_inst(entry, first);
1124 }
1125
1126 #[test]
1127 #[should_panic(expected = "the instruction is not in a block")]
1128 fn removing_an_instruction_twice_is_refused() {
1129 let (mut func, entry, _, _) = sum();
1130 let first = func.insts(entry).next().expect("an instruction");
1131 func.remove_inst(first);
1132 func.remove_inst(first);
1133 }
1134}