1use crate::Variable;
11use alloc::vec::Vec;
12use core::convert::TryInto;
13use core::mem;
14use cranelift_codegen::cursor::{Cursor, FuncCursor};
15use cranelift_codegen::entity::{EntityList, EntitySet, ListPool, SecondaryMap};
16use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
17use cranelift_codegen::ir::types::{F32, F64, I128, I64};
18use cranelift_codegen::ir::{Block, Function, Inst, InstBuilder, Type, Value};
19use cranelift_codegen::packed_option::PackedOption;
20
21#[derive(Default)]
35pub struct SSABuilder {
36 variables: SecondaryMap<Variable, SecondaryMap<Block, PackedOption<Value>>>,
40
41 ssa_blocks: SecondaryMap<Block, SSABlockData>,
44
45 calls: Vec<Call>,
47 results: Vec<Value>,
49
50 side_effects: SideEffects,
52
53 visited: EntitySet<Block>,
55
56 variable_pool: ListPool<Variable>,
58
59 inst_pool: ListPool<Inst>,
61}
62
63#[derive(Default)]
65pub struct SideEffects {
66 pub instructions_added_to_blocks: Vec<Block>,
71}
72
73impl SideEffects {
74 fn is_empty(&self) -> bool {
75 self.instructions_added_to_blocks.is_empty()
76 }
77}
78
79#[derive(Clone)]
80enum Sealed {
81 No {
82 undef_variables: EntityList<Variable>,
84 },
85 Yes,
86}
87
88impl Default for Sealed {
89 fn default() -> Self {
90 Sealed::No {
91 undef_variables: EntityList::new(),
92 }
93 }
94}
95
96#[derive(Clone, Default)]
97struct SSABlockData {
98 predecessors: EntityList<Inst>,
100 sealed: Sealed,
102 single_predecessor: PackedOption<Block>,
104}
105
106impl SSABuilder {
107 pub fn clear(&mut self) {
110 self.variables.clear();
111 self.ssa_blocks.clear();
112 self.variable_pool.clear();
113 self.inst_pool.clear();
114 debug_assert!(self.calls.is_empty());
115 debug_assert!(self.results.is_empty());
116 debug_assert!(self.side_effects.is_empty());
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.variables.is_empty()
122 && self.ssa_blocks.is_empty()
123 && self.calls.is_empty()
124 && self.results.is_empty()
125 && self.side_effects.is_empty()
126 }
127}
128
129enum Call {
131 UseVar(Inst),
132 FinishPredecessorsLookup(Value, Block),
133}
134
135fn emit_zero(ty: Type, mut cur: FuncCursor) -> Value {
137 if ty == I128 {
138 let zero = cur.ins().iconst(I64, 0);
139 cur.ins().uextend(I128, zero)
140 } else if ty.is_int() {
141 cur.ins().iconst(ty, 0)
142 } else if ty == F32 {
143 cur.ins().f32const(Ieee32::with_bits(0))
144 } else if ty == F64 {
145 cur.ins().f64const(Ieee64::with_bits(0))
146 } else if ty.is_ref() {
147 cur.ins().null(ty)
148 } else if ty.is_vector() {
149 let scalar_ty = ty.lane_type();
150 if scalar_ty.is_int() {
151 let zero = cur.func.dfg.constants.insert(
152 core::iter::repeat(0)
153 .take(ty.bytes().try_into().unwrap())
154 .collect(),
155 );
156 cur.ins().vconst(ty, zero)
157 } else if scalar_ty == F32 {
158 let scalar = cur.ins().f32const(Ieee32::with_bits(0));
159 cur.ins().splat(ty, scalar)
160 } else if scalar_ty == F64 {
161 let scalar = cur.ins().f64const(Ieee64::with_bits(0));
162 cur.ins().splat(ty, scalar)
163 } else {
164 panic!("unimplemented scalar type: {:?}", ty)
165 }
166 } else {
167 panic!("unimplemented type: {:?}", ty)
168 }
169}
170
171impl SSABuilder {
191 pub fn def_var(&mut self, var: Variable, val: Value, block: Block) {
195 self.variables[var][block] = PackedOption::from(val);
196 }
197
198 pub fn use_var(
206 &mut self,
207 func: &mut Function,
208 var: Variable,
209 ty: Type,
210 block: Block,
211 ) -> (Value, SideEffects) {
212 debug_assert!(self.calls.is_empty());
213 debug_assert!(self.results.is_empty());
214 debug_assert!(self.side_effects.is_empty());
215
216 self.use_var_nonlocal(func, var, ty, block);
218 let value = self.run_state_machine(func, var, ty);
219
220 let side_effects = mem::take(&mut self.side_effects);
221 (value, side_effects)
222 }
223
224 fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block) {
228 if let Some(val) = self.variables[var][block].expand() {
231 self.results.push(val);
232 return;
233 }
234
235 let (val, from) = self.find_var(func, var, ty, block);
239
240 let var_defs = &mut self.variables[var];
259 while block != from {
260 debug_assert!(var_defs[block].is_none());
261 var_defs[block] = PackedOption::from(val);
262 block = self.ssa_blocks[block].single_predecessor.unwrap();
263 }
264 }
265
266 fn find_var(
290 &mut self,
291 func: &mut Function,
292 var: Variable,
293 ty: Type,
294 mut block: Block,
295 ) -> (Value, Block) {
296 self.visited.clear();
298 let var_defs = &mut self.variables[var];
299 while let Some(pred) = self.ssa_blocks[block].single_predecessor.expand() {
300 if !self.visited.insert(block) {
301 break;
302 }
303 block = pred;
304 if let Some(val) = var_defs[block].expand() {
305 self.results.push(val);
306 return (val, block);
307 }
308 }
309
310 let val = func.dfg.append_block_param(block, ty);
313 var_defs[block] = PackedOption::from(val);
314
315 match &mut self.ssa_blocks[block].sealed {
321 Sealed::Yes => self.begin_predecessors_lookup(val, block),
324 Sealed::No { undef_variables } => {
325 undef_variables.push(var, &mut self.variable_pool);
326 self.results.push(val);
327 }
328 }
329 (val, block)
330 }
331
332 pub fn declare_block(&mut self, block: Block) {
336 let _ = &mut self.ssa_blocks[block];
340 }
341
342 pub fn declare_block_predecessor(&mut self, block: Block, inst: Inst) {
352 debug_assert!(!self.is_sealed(block));
353 self.ssa_blocks[block]
354 .predecessors
355 .push(inst, &mut self.inst_pool);
356 }
357
358 pub fn remove_block_predecessor(&mut self, block: Block, inst: Inst) {
363 debug_assert!(!self.is_sealed(block));
364 let data = &mut self.ssa_blocks[block];
365 let pred = data
366 .predecessors
367 .as_slice(&self.inst_pool)
368 .iter()
369 .position(|&branch| branch == inst)
370 .expect("the predecessor you are trying to remove is not declared");
371 data.predecessors.swap_remove(pred, &mut self.inst_pool);
372 }
373
374 pub fn seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects {
382 debug_assert!(
383 !self.is_sealed(block),
384 "Attempting to seal {} which is already sealed.",
385 block
386 );
387 self.seal_one_block(block, func);
388 mem::take(&mut self.side_effects)
389 }
390
391 pub fn seal_all_blocks(&mut self, func: &mut Function) -> SideEffects {
398 for block in self.ssa_blocks.keys() {
402 self.seal_one_block(block, func);
403 }
404 mem::take(&mut self.side_effects)
405 }
406
407 fn seal_one_block(&mut self, block: Block, func: &mut Function) {
409 let mut undef_variables =
412 match mem::replace(&mut self.ssa_blocks[block].sealed, Sealed::Yes) {
413 Sealed::No { undef_variables } => undef_variables,
414 Sealed::Yes => return,
415 };
416 let ssa_params = undef_variables.len(&self.variable_pool);
417
418 let predecessors = self.predecessors(block);
419 if predecessors.len() == 1 {
420 let pred = func.layout.inst_block(predecessors[0]).unwrap();
421 self.ssa_blocks[block].single_predecessor = PackedOption::from(pred);
422 }
423
424 for idx in 0..ssa_params {
428 let var = undef_variables.get(idx, &self.variable_pool).unwrap();
429
430 let block_params = func.dfg.block_params(block);
435
436 let val = block_params[block_params.len() - (ssa_params - idx)];
441
442 debug_assert!(self.calls.is_empty());
443 debug_assert!(self.results.is_empty());
444 self.begin_predecessors_lookup(val, block);
447 self.run_state_machine(func, var, func.dfg.value_type(val));
448 }
449
450 undef_variables.clear(&mut self.variable_pool);
451 }
452
453 fn begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block) {
468 self.calls
469 .push(Call::FinishPredecessorsLookup(sentinel, dest_block));
470 self.calls.extend(
472 self.ssa_blocks[dest_block]
473 .predecessors
474 .as_slice(&self.inst_pool)
475 .iter()
476 .rev()
477 .copied()
478 .map(Call::UseVar),
479 );
480 }
481
482 fn finish_predecessors_lookup(
485 &mut self,
486 func: &mut Function,
487 sentinel: Value,
488 dest_block: Block,
489 ) -> Value {
490 let num_predecessors = self.predecessors(dest_block).len();
497 let results = self.results.drain(self.results.len() - num_predecessors..);
499
500 let pred_val = {
501 let mut iter = results
502 .as_slice()
503 .iter()
504 .map(|&val| func.dfg.resolve_aliases(val))
505 .filter(|&val| val != sentinel);
506 if let Some(val) = iter.next() {
507 if iter.all(|other| other == val) {
510 Some(val)
511 } else {
512 None
513 }
514 } else {
515 if !func.layout.is_block_inserted(dest_block) {
519 func.layout.append_block(dest_block);
520 }
521 self.side_effects
522 .instructions_added_to_blocks
523 .push(dest_block);
524 let zero = emit_zero(
525 func.dfg.value_type(sentinel),
526 FuncCursor::new(func).at_first_insertion_point(dest_block),
527 );
528 Some(zero)
529 }
530 };
531
532 if let Some(pred_val) = pred_val {
533 func.dfg.remove_block_param(sentinel);
538 func.dfg.change_to_alias(sentinel, pred_val);
539 pred_val
540 } else {
541 let mut preds = self.ssa_blocks[dest_block].predecessors;
544 let dfg = &mut func.stencil.dfg;
545 for (idx, &val) in results.as_slice().iter().enumerate() {
546 let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
547 let branch = *pred;
548
549 let dests = dfg.insts[branch].branch_destination_mut(&mut dfg.jump_tables);
550 assert!(
551 !dests.is_empty(),
552 "you have declared a non-branch instruction as a predecessor to a block!"
553 );
554 for block in dests {
555 if block.block(&dfg.value_lists) == dest_block {
556 block.append_argument(val, &mut dfg.value_lists);
557 }
558 }
559 }
560 sentinel
561 }
562 }
563
564 fn predecessors(&self, block: Block) -> &[Inst] {
566 self.ssa_blocks[block]
567 .predecessors
568 .as_slice(&self.inst_pool)
569 }
570
571 pub fn has_any_predecessors(&self, block: Block) -> bool {
573 !self.predecessors(block).is_empty()
574 }
575
576 pub fn is_sealed(&self, block: Block) -> bool {
578 matches!(self.ssa_blocks[block].sealed, Sealed::Yes)
579 }
580
581 fn run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value {
587 while let Some(call) = self.calls.pop() {
589 match call {
590 Call::UseVar(branch) => {
591 let block = func.layout.inst_block(branch).unwrap();
592 self.use_var_nonlocal(func, var, ty, block);
593 }
594 Call::FinishPredecessorsLookup(sentinel, dest_block) => {
595 let val = self.finish_predecessors_lookup(func, sentinel, dest_block);
596 self.results.push(val);
597 }
598 }
599 }
600 debug_assert_eq!(self.results.len(), 1);
601 self.results.pop().unwrap()
602 }
603}
604
605#[cfg(test)]
606mod tests {
607 use crate::ssa::SSABuilder;
608 use crate::Variable;
609 use cranelift_codegen::cursor::{Cursor, FuncCursor};
610 use cranelift_codegen::entity::EntityRef;
611 use cranelift_codegen::ir;
612 use cranelift_codegen::ir::types::*;
613 use cranelift_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode};
614 use cranelift_codegen::settings;
615 use cranelift_codegen::verify_function;
616
617 #[test]
618 fn simple_block() {
619 let mut func = Function::new();
620 let mut ssa = SSABuilder::default();
621 let block0 = func.dfg.make_block();
622 ssa.declare_block(block0);
630 let x_var = Variable::new(0);
631 let x_ssa = {
632 let mut cur = FuncCursor::new(&mut func);
633 cur.insert_block(block0);
634 cur.ins().iconst(I32, 1)
635 };
636 ssa.def_var(x_var, x_ssa, block0);
637 let y_var = Variable::new(1);
638 let y_ssa = {
639 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
640 cur.ins().iconst(I32, 2)
641 };
642 ssa.def_var(y_var, y_ssa, block0);
643 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
644 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
645
646 let z_var = Variable::new(2);
647 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
648 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
649 let z1_ssa = {
650 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
651 cur.ins().iadd(x_use1, y_use1)
652 };
653 ssa.def_var(z_var, z1_ssa, block0);
654 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
655
656 let x_use2 = ssa.use_var(&mut func, x_var, I32, block0).0;
657 let z_use1 = ssa.use_var(&mut func, z_var, I32, block0).0;
658 let z2_ssa = {
659 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
660 cur.ins().iadd(x_use2, z_use1)
661 };
662 ssa.def_var(z_var, z2_ssa, block0);
663 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z2_ssa);
664 }
665
666 #[test]
667 fn sequence_of_blocks() {
668 let mut func = Function::new();
669 let mut ssa = SSABuilder::default();
670 let block0 = func.dfg.make_block();
671 let block1 = func.dfg.make_block();
672 let block2 = func.dfg.make_block();
673 {
685 let mut cur = FuncCursor::new(&mut func);
686 cur.insert_block(block0);
687 cur.insert_block(block1);
688 cur.insert_block(block2);
689 }
690
691 ssa.declare_block(block0);
693 ssa.seal_block(block0, &mut func);
694 let x_var = Variable::new(0);
695 let x_ssa = {
696 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
697 cur.ins().iconst(I32, 1)
698 };
699 ssa.def_var(x_var, x_ssa, block0);
700 let y_var = Variable::new(1);
701 let y_ssa = {
702 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
703 cur.ins().iconst(I32, 2)
704 };
705 ssa.def_var(y_var, y_ssa, block0);
706 let z_var = Variable::new(2);
707 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
708 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
709 let z1_ssa = {
710 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
711 cur.ins().iadd(x_use1, y_use1)
712 };
713 ssa.def_var(z_var, z1_ssa, block0);
714 let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0;
715 let brif_block0_block2_block1: Inst = {
716 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
717 cur.ins().brif(y_use2, block2, &[], block1, &[])
718 };
719
720 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
721 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
722 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
723
724 ssa.declare_block(block1);
726 ssa.declare_block_predecessor(block1, brif_block0_block2_block1);
727 ssa.seal_block(block1, &mut func);
728
729 let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0;
730 let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0;
731 let z2_ssa = {
732 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
733 cur.ins().iadd(x_use2, z_use1)
734 };
735 ssa.def_var(z_var, z2_ssa, block1);
736 let jump_block1_block2: Inst = {
737 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
738 cur.ins().jump(block2, &[])
739 };
740
741 assert_eq!(x_use2, x_ssa);
742 assert_eq!(z_use1, z1_ssa);
743 assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa);
744
745 ssa.declare_block(block2);
747 ssa.declare_block_predecessor(block2, brif_block0_block2_block1);
748 ssa.declare_block_predecessor(block2, jump_block1_block2);
749 ssa.seal_block(block2, &mut func);
750 let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0;
751 let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0;
752 let y2_ssa = {
753 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
754 cur.ins().iadd(x_use3, y_use3)
755 };
756 ssa.def_var(y_var, y2_ssa, block2);
757
758 assert_eq!(x_ssa, x_use3);
759 assert_eq!(y_ssa, y_use3);
760 match func.dfg.insts[brif_block0_block2_block1] {
761 ir::InstructionData::Brif {
762 blocks: [block_then, block_else],
763 ..
764 } => {
765 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
766 assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0);
767 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
768 assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0);
769 }
770 _ => assert!(false),
771 };
772 match func.dfg.insts[brif_block0_block2_block1] {
773 ir::InstructionData::Brif {
774 blocks: [block_then, block_else],
775 ..
776 } => {
777 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
778 assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0);
779 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
780 assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0);
781 }
782 _ => assert!(false),
783 };
784 match func.dfg.insts[jump_block1_block2] {
785 ir::InstructionData::Jump {
786 destination: dest, ..
787 } => {
788 assert_eq!(dest.block(&func.dfg.value_lists), block2);
789 assert_eq!(dest.args_slice(&func.dfg.value_lists).len(), 0);
790 }
791 _ => assert!(false),
792 };
793 }
794
795 #[test]
796 fn program_with_loop() {
797 let mut func = Function::new();
798 let mut ssa = SSABuilder::default();
799 let block0 = func.dfg.make_block();
800 let block1 = func.dfg.make_block();
801 let block2 = func.dfg.make_block();
802 let block3 = func.dfg.make_block();
803 {
804 let mut cur = FuncCursor::new(&mut func);
805 cur.insert_block(block0);
806 cur.insert_block(block1);
807 cur.insert_block(block2);
808 cur.insert_block(block3);
809 }
810 ssa.declare_block(block0);
828 ssa.seal_block(block0, &mut func);
829 let x_var = Variable::new(0);
830 let x1 = {
831 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
832 cur.ins().iconst(I32, 1)
833 };
834 ssa.def_var(x_var, x1, block0);
835 let y_var = Variable::new(1);
836 let y1 = {
837 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
838 cur.ins().iconst(I32, 2)
839 };
840 ssa.def_var(y_var, y1, block0);
841 let z_var = Variable::new(2);
842 let x2 = ssa.use_var(&mut func, x_var, I32, block0).0;
843 let y2 = ssa.use_var(&mut func, y_var, I32, block0).0;
844 let z1 = {
845 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
846 cur.ins().iadd(x2, y2)
847 };
848 ssa.def_var(z_var, z1, block0);
849 let jump_block0_block1 = {
850 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
851 cur.ins().jump(block1, &[])
852 };
853 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1);
854 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1);
855 assert_eq!(x2, x1);
856 assert_eq!(y2, y1);
857
858 ssa.declare_block(block1);
860 ssa.declare_block_predecessor(block1, jump_block0_block1);
861 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
862 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
863 let z3 = {
864 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
865 cur.ins().iadd(z2, y3)
866 };
867 ssa.def_var(z_var, z3, block1);
868 let y4 = ssa.use_var(&mut func, y_var, I32, block1).0;
869 assert_eq!(y4, y3);
870 let brif_block1_block3_block2 = {
871 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
872 cur.ins().brif(y4, block3, &[], block2, &[])
873 };
874
875 ssa.declare_block(block2);
877 ssa.declare_block_predecessor(block2, brif_block1_block3_block2);
878 ssa.seal_block(block2, &mut func);
879 let z4 = ssa.use_var(&mut func, z_var, I32, block2).0;
880 assert_eq!(z4, z3);
881 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
882 let z5 = {
883 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
884 cur.ins().isub(z4, x3)
885 };
886 ssa.def_var(z_var, z5, block2);
887 let y5 = ssa.use_var(&mut func, y_var, I32, block2).0;
888 assert_eq!(y5, y3);
889 {
890 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
891 cur.ins().return_(&[y5])
892 };
893
894 ssa.declare_block(block3);
896 ssa.declare_block_predecessor(block3, brif_block1_block3_block2);
897 ssa.seal_block(block3, &mut func);
898 let y6 = ssa.use_var(&mut func, y_var, I32, block3).0;
899 assert_eq!(y6, y3);
900 let x4 = ssa.use_var(&mut func, x_var, I32, block3).0;
901 assert_eq!(x4, x3);
902 let y7 = {
903 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
904 cur.ins().isub(y6, x4)
905 };
906 ssa.def_var(y_var, y7, block3);
907 let jump_block3_block1 = {
908 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
909 cur.ins().jump(block1, &[])
910 };
911
912 ssa.declare_block_predecessor(block1, jump_block3_block1);
914 ssa.seal_block(block1, &mut func);
915 assert_eq!(func.dfg.block_params(block1)[0], z2);
916 assert_eq!(func.dfg.block_params(block1)[1], y3);
917 assert_eq!(func.dfg.resolve_aliases(x3), x1);
918 }
919
920 #[test]
921 fn br_table_with_args() {
922 let mut func = Function::new();
939 let mut ssa = SSABuilder::default();
940 let block0 = func.dfg.make_block();
941 let block1 = func.dfg.make_block();
942 let block2 = func.dfg.make_block();
943 {
944 let mut cur = FuncCursor::new(&mut func);
945 cur.insert_block(block0);
946 cur.insert_block(block1);
947 cur.insert_block(block2);
948 }
949
950 let x1 = {
952 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
953 cur.ins().iconst(I32, 1)
954 };
955 ssa.declare_block(block0);
956 ssa.seal_block(block0, &mut func);
957 let x_var = Variable::new(0);
958 ssa.def_var(x_var, x1, block0);
959 ssa.use_var(&mut func, x_var, I32, block0).0;
960 let br_table = {
961 let jump_table = JumpTableData::new(
962 func.dfg.block_call(block2, &[]),
963 &[
964 func.dfg.block_call(block2, &[]),
965 func.dfg.block_call(block1, &[]),
966 ],
967 );
968 let jt = func.create_jump_table(jump_table);
969 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
970 cur.ins().br_table(x1, jt)
971 };
972
973 ssa.declare_block(block1);
975 ssa.declare_block_predecessor(block1, br_table);
976 ssa.seal_block(block1, &mut func);
977 let x2 = {
978 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
979 cur.ins().iconst(I32, 2)
980 };
981 ssa.def_var(x_var, x2, block1);
982 let jump_block1_block2 = {
983 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
984 cur.ins().jump(block2, &[])
985 };
986
987 ssa.declare_block(block2);
989 ssa.declare_block_predecessor(block2, jump_block1_block2);
990 ssa.declare_block_predecessor(block2, br_table);
991 ssa.seal_block(block2, &mut func);
992 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
993 let x4 = {
994 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
995 cur.ins().iadd_imm(x3, 1)
996 };
997 ssa.def_var(x_var, x4, block2);
998 {
999 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1000 cur.ins().return_(&[])
1001 };
1002
1003 let flags = settings::Flags::new(settings::builder());
1004 match verify_function(&func, &flags) {
1005 Ok(()) => {}
1006 Err(_errors) => {
1007 #[cfg(feature = "std")]
1008 panic!("{}", _errors);
1009 #[cfg(not(feature = "std"))]
1010 panic!("function failed to verify");
1011 }
1012 }
1013 }
1014
1015 #[test]
1016 fn undef_values_reordering() {
1017 let mut func = Function::new();
1029 let mut ssa = SSABuilder::default();
1030 let block0 = func.dfg.make_block();
1031 let block1 = func.dfg.make_block();
1032 {
1033 let mut cur = FuncCursor::new(&mut func);
1034 cur.insert_block(block0);
1035 cur.insert_block(block1);
1036 }
1037
1038 ssa.declare_block(block0);
1040 let x_var = Variable::new(0);
1041 ssa.seal_block(block0, &mut func);
1042 let x1 = {
1043 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1044 cur.ins().iconst(I32, 0)
1045 };
1046 ssa.def_var(x_var, x1, block0);
1047 let y_var = Variable::new(1);
1048 let y1 = {
1049 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1050 cur.ins().iconst(I32, 1)
1051 };
1052 ssa.def_var(y_var, y1, block0);
1053 let z_var = Variable::new(2);
1054 let z1 = {
1055 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1056 cur.ins().iconst(I32, 2)
1057 };
1058 ssa.def_var(z_var, z1, block0);
1059 let jump_block0_block1 = {
1060 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1061 cur.ins().jump(block1, &[])
1062 };
1063
1064 ssa.declare_block(block1);
1066 ssa.declare_block_predecessor(block1, jump_block0_block1);
1067 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
1068 assert_eq!(func.dfg.block_params(block1)[0], z2);
1069 let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
1070 assert_eq!(func.dfg.block_params(block1)[1], x2);
1071 let x3 = {
1072 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1073 cur.ins().iadd(x2, z2)
1074 };
1075 ssa.def_var(x_var, x3, block1);
1076 let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
1077 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
1078 assert_eq!(func.dfg.block_params(block1)[2], y3);
1079 let y4 = {
1080 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1081 cur.ins().isub(y3, x4)
1082 };
1083 ssa.def_var(y_var, y4, block1);
1084 let jump_block1_block1 = {
1085 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1086 cur.ins().jump(block1, &[])
1087 };
1088 ssa.declare_block_predecessor(block1, jump_block1_block1);
1089 ssa.seal_block(block1, &mut func);
1090 assert_eq!(func.dfg.block_params(block1)[1], y3);
1093 assert_eq!(func.dfg.block_params(block1)[0], x2);
1094 }
1095
1096 #[test]
1097 fn undef() {
1098 let mut func = Function::new();
1100 let mut ssa = SSABuilder::default();
1101 let block0 = func.dfg.make_block();
1102 ssa.declare_block(block0);
1103 ssa.seal_block(block0, &mut func);
1104 let i32_var = Variable::new(0);
1105 let f32_var = Variable::new(1);
1106 let f64_var = Variable::new(2);
1107 let i8_var = Variable::new(3);
1108 let f32x4_var = Variable::new(4);
1109 ssa.use_var(&mut func, i32_var, I32, block0);
1110 ssa.use_var(&mut func, f32_var, F32, block0);
1111 ssa.use_var(&mut func, f64_var, F64, block0);
1112 ssa.use_var(&mut func, i8_var, I8, block0);
1113 ssa.use_var(&mut func, f32x4_var, F32X4, block0);
1114 assert_eq!(func.dfg.num_block_params(block0), 0);
1115 }
1116
1117 #[test]
1118 fn undef_in_entry() {
1119 let mut func = Function::new();
1122 let mut ssa = SSABuilder::default();
1123 let block0 = func.dfg.make_block();
1124 ssa.declare_block(block0);
1125 ssa.seal_block(block0, &mut func);
1126 let x_var = Variable::new(0);
1127 assert_eq!(func.dfg.num_block_params(block0), 0);
1128 ssa.use_var(&mut func, x_var, I32, block0);
1129 assert_eq!(func.dfg.num_block_params(block0), 0);
1130 assert_eq!(
1131 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1132 Opcode::Iconst
1133 );
1134 }
1135
1136 #[test]
1137 fn undef_in_entry_sealed_after() {
1138 let mut func = Function::new();
1142 let mut ssa = SSABuilder::default();
1143 let block0 = func.dfg.make_block();
1144 ssa.declare_block(block0);
1145 let x_var = Variable::new(0);
1146 assert_eq!(func.dfg.num_block_params(block0), 0);
1147 ssa.use_var(&mut func, x_var, I32, block0);
1148 assert_eq!(func.dfg.num_block_params(block0), 1);
1149 ssa.seal_block(block0, &mut func);
1150 assert_eq!(func.dfg.num_block_params(block0), 0);
1151 assert_eq!(
1152 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1153 Opcode::Iconst
1154 );
1155 }
1156
1157 #[test]
1158 fn unreachable_use() {
1159 let mut func = Function::new();
1165 let mut ssa = SSABuilder::default();
1166 let block0 = func.dfg.make_block();
1167 let block1 = func.dfg.make_block();
1168 {
1169 let mut cur = FuncCursor::new(&mut func);
1170 cur.insert_block(block0);
1171 cur.insert_block(block1);
1172 }
1173
1174 ssa.declare_block(block0);
1176 ssa.seal_block(block0, &mut func);
1177 {
1178 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1179 cur.ins().return_(&[]);
1180 }
1181
1182 ssa.declare_block(block1);
1184 {
1185 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1186 let x_var = Variable::new(0);
1187 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1188 let brif = cur.ins().brif(x_val, block1, &[], block1, &[]);
1189 ssa.declare_block_predecessor(block1, brif);
1190 }
1191 ssa.seal_block(block1, &mut func);
1192
1193 let flags = settings::Flags::new(settings::builder());
1194 match verify_function(&func, &flags) {
1195 Ok(()) => {}
1196 Err(_errors) => {
1197 #[cfg(feature = "std")]
1198 panic!("{}", _errors);
1199 #[cfg(not(feature = "std"))]
1200 panic!("function failed to verify");
1201 }
1202 }
1203 }
1204
1205 #[test]
1206 fn unreachable_use_with_multiple_preds() {
1207 let mut func = Function::new();
1215 let mut ssa = SSABuilder::default();
1216 let block0 = func.dfg.make_block();
1217 let block1 = func.dfg.make_block();
1218 let block2 = func.dfg.make_block();
1219 {
1220 let mut cur = FuncCursor::new(&mut func);
1221 cur.insert_block(block0);
1222 cur.insert_block(block1);
1223 cur.insert_block(block2);
1224 }
1225
1226 ssa.declare_block(block0);
1228 ssa.seal_block(block0, &mut func);
1229 {
1230 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1231 cur.ins().return_(&[]);
1232 }
1233
1234 ssa.declare_block(block1);
1236 let brif = {
1237 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1238 let x_var = Variable::new(0);
1239 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1240 cur.ins().brif(x_val, block2, &[], block1, &[])
1241 };
1242
1243 ssa.declare_block(block2);
1245 ssa.declare_block_predecessor(block1, brif);
1246 ssa.declare_block_predecessor(block2, brif);
1247 ssa.seal_block(block2, &mut func);
1248 let jump_block2_block1 = {
1249 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1250 cur.ins().jump(block1, &[])
1251 };
1252
1253 ssa.declare_block_predecessor(block1, jump_block2_block1);
1255 ssa.seal_block(block1, &mut func);
1256 let flags = settings::Flags::new(settings::builder());
1257 match verify_function(&func, &flags) {
1258 Ok(()) => {}
1259 Err(_errors) => {
1260 #[cfg(feature = "std")]
1261 panic!("{}", _errors);
1262 #[cfg(not(feature = "std"))]
1263 panic!("function failed to verify");
1264 }
1265 }
1266 }
1267
1268 #[test]
1269 fn reassign_with_predecessor_loop_hangs() {
1270 let mut func = Function::new();
1282 let mut ssa = SSABuilder::default();
1283 let block0 = func.dfg.make_block();
1284 let block1 = func.dfg.make_block();
1285 let block2 = func.dfg.make_block();
1286 let var0 = Variable::new(0);
1287
1288 {
1289 let mut cur = FuncCursor::new(&mut func);
1290 for block in [block0, block1, block2] {
1291 cur.insert_block(block);
1292 ssa.declare_block(block);
1293 }
1294 }
1295
1296 {
1298 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1299
1300 let var0_iconst = cur.ins().iconst(I32, 0);
1301 ssa.def_var(var0, var0_iconst, block0);
1302
1303 cur.ins().return_(&[]);
1304 }
1305
1306 {
1308 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1309
1310 let jump = cur.ins().jump(block2, &[]);
1311 ssa.declare_block_predecessor(block2, jump);
1312 }
1313
1314 {
1316 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1317
1318 let _ = ssa.use_var(&mut cur.func, var0, I32, block2).0;
1319 let var0_iconst = cur.ins().iconst(I32, 1);
1320 ssa.def_var(var0, var0_iconst, block2);
1321
1322 let jump = cur.ins().jump(block1, &[]);
1323 ssa.declare_block_predecessor(block1, jump);
1324 }
1325
1326 ssa.seal_all_blocks(&mut func);
1328 }
1329}