1use crate::Variable;
11use alloc::vec::Vec;
12use core::mem;
13use cranelift_codegen::cursor::{Cursor, FuncCursor};
14use cranelift_codegen::entity::{EntityList, EntitySet, ListPool, SecondaryMap};
15use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
16use cranelift_codegen::ir::types::{F32, F64, I128, I64};
17use cranelift_codegen::ir::{Block, Function, Inst, InstBuilder, Type, Value};
18use cranelift_codegen::packed_option::PackedOption;
19
20#[derive(Default)]
34pub struct SSABuilder {
35 variables: SecondaryMap<Variable, SecondaryMap<Block, PackedOption<Value>>>,
39
40 ssa_blocks: SecondaryMap<Block, SSABlockData>,
43
44 calls: Vec<Call>,
46 results: Vec<Value>,
48
49 side_effects: SideEffects,
51
52 visited: EntitySet<Block>,
54
55 variable_pool: ListPool<Variable>,
57
58 inst_pool: ListPool<Inst>,
60}
61
62#[derive(Default)]
64pub struct SideEffects {
65 pub instructions_added_to_blocks: Vec<Block>,
70}
71
72impl SideEffects {
73 fn is_empty(&self) -> bool {
74 self.instructions_added_to_blocks.is_empty()
75 }
76}
77
78#[derive(Clone)]
79enum Sealed {
80 No {
81 undef_variables: EntityList<Variable>,
83 },
84 Yes,
85}
86
87impl Default for Sealed {
88 fn default() -> Self {
89 Sealed::No {
90 undef_variables: EntityList::new(),
91 }
92 }
93}
94
95#[derive(Clone, Default)]
96struct SSABlockData {
97 predecessors: EntityList<Inst>,
99 sealed: Sealed,
101 single_predecessor: PackedOption<Block>,
103}
104
105impl SSABuilder {
106 pub fn clear(&mut self) {
109 self.variables.clear();
110 self.ssa_blocks.clear();
111 self.variable_pool.clear();
112 self.inst_pool.clear();
113 debug_assert!(self.calls.is_empty());
114 debug_assert!(self.results.is_empty());
115 debug_assert!(self.side_effects.is_empty());
116 }
117
118 pub fn is_empty(&self) -> bool {
120 self.variables.is_empty()
121 && self.ssa_blocks.is_empty()
122 && self.calls.is_empty()
123 && self.results.is_empty()
124 && self.side_effects.is_empty()
125 }
126}
127
128enum Call {
130 UseVar(Inst),
131 FinishPredecessorsLookup(Value, Block),
132}
133
134fn emit_zero(ty: Type, mut cur: FuncCursor) -> Value {
136 if ty == I128 {
137 let zero = cur.ins().iconst(I64, 0);
138 cur.ins().uextend(I128, zero)
139 } else if ty.is_int() {
140 cur.ins().iconst(ty, 0)
141 } else if ty == F32 {
142 cur.ins().f32const(Ieee32::with_bits(0))
143 } else if ty == F64 {
144 cur.ins().f64const(Ieee64::with_bits(0))
145 } else if ty.is_vector() {
146 let scalar_ty = ty.lane_type();
147 if scalar_ty.is_int() {
148 let zero = cur.func.dfg.constants.insert(
149 core::iter::repeat(0)
150 .take(ty.bytes().try_into().unwrap())
151 .collect(),
152 );
153 cur.ins().vconst(ty, zero)
154 } else if scalar_ty == F32 {
155 let scalar = cur.ins().f32const(Ieee32::with_bits(0));
156 cur.ins().splat(ty, scalar)
157 } else if scalar_ty == F64 {
158 let scalar = cur.ins().f64const(Ieee64::with_bits(0));
159 cur.ins().splat(ty, scalar)
160 } else {
161 panic!("unimplemented scalar type: {ty:?}")
162 }
163 } else {
164 panic!("unimplemented type: {ty:?}")
165 }
166}
167
168impl SSABuilder {
188 pub fn def_var(&mut self, var: Variable, val: Value, block: Block) {
192 self.variables[var][block] = PackedOption::from(val);
193 }
194
195 pub fn use_var(
203 &mut self,
204 func: &mut Function,
205 var: Variable,
206 ty: Type,
207 block: Block,
208 ) -> (Value, SideEffects) {
209 debug_assert!(self.calls.is_empty());
210 debug_assert!(self.results.is_empty());
211 debug_assert!(self.side_effects.is_empty());
212
213 self.use_var_nonlocal(func, var, ty, block);
215 let value = self.run_state_machine(func, var, ty);
216
217 let side_effects = mem::take(&mut self.side_effects);
218 (value, side_effects)
219 }
220
221 fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block) {
225 if let Some(val) = self.variables[var][block].expand() {
228 self.results.push(val);
229 return;
230 }
231
232 let (val, from) = self.find_var(func, var, ty, block);
236
237 let var_defs = &mut self.variables[var];
256 while block != from {
257 debug_assert!(var_defs[block].is_none());
258 var_defs[block] = PackedOption::from(val);
259 block = self.ssa_blocks[block].single_predecessor.unwrap();
260 }
261 }
262
263 fn find_var(
287 &mut self,
288 func: &mut Function,
289 var: Variable,
290 ty: Type,
291 mut block: Block,
292 ) -> (Value, Block) {
293 self.visited.clear();
295 let var_defs = &mut self.variables[var];
296 while let Some(pred) = self.ssa_blocks[block].single_predecessor.expand() {
297 if !self.visited.insert(block) {
298 break;
299 }
300 block = pred;
301 if let Some(val) = var_defs[block].expand() {
302 self.results.push(val);
303 return (val, block);
304 }
305 }
306
307 let val = func.dfg.append_block_param(block, ty);
310 var_defs[block] = PackedOption::from(val);
311
312 match &mut self.ssa_blocks[block].sealed {
318 Sealed::Yes => self.begin_predecessors_lookup(val, block),
321 Sealed::No { undef_variables } => {
322 undef_variables.push(var, &mut self.variable_pool);
323 self.results.push(val);
324 }
325 }
326 (val, block)
327 }
328
329 pub fn declare_block(&mut self, block: Block) {
333 let _ = &mut self.ssa_blocks[block];
337 }
338
339 pub fn declare_block_predecessor(&mut self, block: Block, inst: Inst) {
349 debug_assert!(!self.is_sealed(block));
350 self.ssa_blocks[block]
351 .predecessors
352 .push(inst, &mut self.inst_pool);
353 }
354
355 pub fn remove_block_predecessor(&mut self, block: Block, inst: Inst) {
360 debug_assert!(!self.is_sealed(block));
361 let data = &mut self.ssa_blocks[block];
362 let pred = data
363 .predecessors
364 .as_slice(&self.inst_pool)
365 .iter()
366 .position(|&branch| branch == inst)
367 .expect("the predecessor you are trying to remove is not declared");
368 data.predecessors.swap_remove(pred, &mut self.inst_pool);
369 }
370
371 pub fn seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects {
379 debug_assert!(
380 !self.is_sealed(block),
381 "Attempting to seal {block} which is already sealed."
382 );
383 self.seal_one_block(block, func);
384 mem::take(&mut self.side_effects)
385 }
386
387 pub fn seal_all_blocks(&mut self, func: &mut Function) -> SideEffects {
394 for block in self.ssa_blocks.keys() {
398 self.seal_one_block(block, func);
399 }
400 mem::take(&mut self.side_effects)
401 }
402
403 fn seal_one_block(&mut self, block: Block, func: &mut Function) {
405 let mut undef_variables =
408 match mem::replace(&mut self.ssa_blocks[block].sealed, Sealed::Yes) {
409 Sealed::No { undef_variables } => undef_variables,
410 Sealed::Yes => return,
411 };
412 let ssa_params = undef_variables.len(&self.variable_pool);
413
414 let predecessors = self.predecessors(block);
415 if predecessors.len() == 1 {
416 let pred = func.layout.inst_block(predecessors[0]).unwrap();
417 self.ssa_blocks[block].single_predecessor = PackedOption::from(pred);
418 }
419
420 for idx in 0..ssa_params {
424 let var = undef_variables.get(idx, &self.variable_pool).unwrap();
425
426 let block_params = func.dfg.block_params(block);
431
432 let val = block_params[block_params.len() - (ssa_params - idx)];
437
438 debug_assert!(self.calls.is_empty());
439 debug_assert!(self.results.is_empty());
440 self.begin_predecessors_lookup(val, block);
443 self.run_state_machine(func, var, func.dfg.value_type(val));
444 }
445
446 undef_variables.clear(&mut self.variable_pool);
447 }
448
449 fn begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block) {
464 self.calls
465 .push(Call::FinishPredecessorsLookup(sentinel, dest_block));
466 self.calls.extend(
468 self.ssa_blocks[dest_block]
469 .predecessors
470 .as_slice(&self.inst_pool)
471 .iter()
472 .rev()
473 .copied()
474 .map(Call::UseVar),
475 );
476 }
477
478 fn finish_predecessors_lookup(
481 &mut self,
482 func: &mut Function,
483 sentinel: Value,
484 dest_block: Block,
485 ) -> Value {
486 let num_predecessors = self.predecessors(dest_block).len();
493 let results = self.results.drain(self.results.len() - num_predecessors..);
495
496 let pred_val = {
497 let mut iter = results
498 .as_slice()
499 .iter()
500 .map(|&val| func.dfg.resolve_aliases(val))
501 .filter(|&val| val != sentinel);
502 if let Some(val) = iter.next() {
503 if iter.all(|other| other == val) {
506 Some(val)
507 } else {
508 None
509 }
510 } else {
511 if !func.layout.is_block_inserted(dest_block) {
515 func.layout.append_block(dest_block);
516 }
517 self.side_effects
518 .instructions_added_to_blocks
519 .push(dest_block);
520 let zero = emit_zero(
521 func.dfg.value_type(sentinel),
522 FuncCursor::new(func).at_first_insertion_point(dest_block),
523 );
524 Some(zero)
525 }
526 };
527
528 if let Some(pred_val) = pred_val {
529 func.dfg.remove_block_param(sentinel);
534 func.dfg.change_to_alias(sentinel, pred_val);
535 pred_val
536 } else {
537 let mut preds = self.ssa_blocks[dest_block].predecessors;
540 let dfg = &mut func.stencil.dfg;
541 for (idx, &val) in results.as_slice().iter().enumerate() {
542 let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
543 let branch = *pred;
544
545 let dests = dfg.insts[branch].branch_destination_mut(&mut dfg.jump_tables);
546 assert!(
547 !dests.is_empty(),
548 "you have declared a non-branch instruction as a predecessor to a block!"
549 );
550 for block in dests {
551 if block.block(&dfg.value_lists) == dest_block {
552 block.append_argument(val, &mut dfg.value_lists);
553 }
554 }
555 }
556 sentinel
557 }
558 }
559
560 fn predecessors(&self, block: Block) -> &[Inst] {
562 self.ssa_blocks[block]
563 .predecessors
564 .as_slice(&self.inst_pool)
565 }
566
567 pub fn has_any_predecessors(&self, block: Block) -> bool {
569 !self.predecessors(block).is_empty()
570 }
571
572 pub fn is_sealed(&self, block: Block) -> bool {
574 matches!(self.ssa_blocks[block].sealed, Sealed::Yes)
575 }
576
577 fn run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value {
583 while let Some(call) = self.calls.pop() {
585 match call {
586 Call::UseVar(branch) => {
587 let block = func.layout.inst_block(branch).unwrap();
588 self.use_var_nonlocal(func, var, ty, block);
589 }
590 Call::FinishPredecessorsLookup(sentinel, dest_block) => {
591 let val = self.finish_predecessors_lookup(func, sentinel, dest_block);
592 self.results.push(val);
593 }
594 }
595 }
596 debug_assert_eq!(self.results.len(), 1);
597 self.results.pop().unwrap()
598 }
599}
600
601#[cfg(test)]
602mod tests {
603 use crate::ssa::SSABuilder;
604 use crate::Variable;
605 use cranelift_codegen::cursor::{Cursor, FuncCursor};
606 use cranelift_codegen::entity::EntityRef;
607 use cranelift_codegen::ir;
608 use cranelift_codegen::ir::types::*;
609 use cranelift_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode};
610 use cranelift_codegen::settings;
611 use cranelift_codegen::verify_function;
612
613 #[test]
614 fn simple_block() {
615 let mut func = Function::new();
616 let mut ssa = SSABuilder::default();
617 let block0 = func.dfg.make_block();
618 ssa.declare_block(block0);
626 let x_var = Variable::new(0);
627 let x_ssa = {
628 let mut cur = FuncCursor::new(&mut func);
629 cur.insert_block(block0);
630 cur.ins().iconst(I32, 1)
631 };
632 ssa.def_var(x_var, x_ssa, block0);
633 let y_var = Variable::new(1);
634 let y_ssa = {
635 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
636 cur.ins().iconst(I32, 2)
637 };
638 ssa.def_var(y_var, y_ssa, block0);
639 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
640 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
641
642 let z_var = Variable::new(2);
643 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
644 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
645 let z1_ssa = {
646 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
647 cur.ins().iadd(x_use1, y_use1)
648 };
649 ssa.def_var(z_var, z1_ssa, block0);
650 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
651
652 let x_use2 = ssa.use_var(&mut func, x_var, I32, block0).0;
653 let z_use1 = ssa.use_var(&mut func, z_var, I32, block0).0;
654 let z2_ssa = {
655 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
656 cur.ins().iadd(x_use2, z_use1)
657 };
658 ssa.def_var(z_var, z2_ssa, block0);
659 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z2_ssa);
660 }
661
662 #[test]
663 fn sequence_of_blocks() {
664 let mut func = Function::new();
665 let mut ssa = SSABuilder::default();
666 let block0 = func.dfg.make_block();
667 let block1 = func.dfg.make_block();
668 let block2 = func.dfg.make_block();
669 {
681 let mut cur = FuncCursor::new(&mut func);
682 cur.insert_block(block0);
683 cur.insert_block(block1);
684 cur.insert_block(block2);
685 }
686
687 ssa.declare_block(block0);
689 ssa.seal_block(block0, &mut func);
690 let x_var = Variable::new(0);
691 let x_ssa = {
692 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
693 cur.ins().iconst(I32, 1)
694 };
695 ssa.def_var(x_var, x_ssa, block0);
696 let y_var = Variable::new(1);
697 let y_ssa = {
698 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
699 cur.ins().iconst(I32, 2)
700 };
701 ssa.def_var(y_var, y_ssa, block0);
702 let z_var = Variable::new(2);
703 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
704 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
705 let z1_ssa = {
706 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
707 cur.ins().iadd(x_use1, y_use1)
708 };
709 ssa.def_var(z_var, z1_ssa, block0);
710 let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0;
711 let brif_block0_block2_block1: Inst = {
712 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
713 cur.ins().brif(y_use2, block2, &[], block1, &[])
714 };
715
716 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
717 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
718 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
719
720 ssa.declare_block(block1);
722 ssa.declare_block_predecessor(block1, brif_block0_block2_block1);
723 ssa.seal_block(block1, &mut func);
724
725 let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0;
726 let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0;
727 let z2_ssa = {
728 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
729 cur.ins().iadd(x_use2, z_use1)
730 };
731 ssa.def_var(z_var, z2_ssa, block1);
732 let jump_block1_block2: Inst = {
733 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
734 cur.ins().jump(block2, &[])
735 };
736
737 assert_eq!(x_use2, x_ssa);
738 assert_eq!(z_use1, z1_ssa);
739 assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa);
740
741 ssa.declare_block(block2);
743 ssa.declare_block_predecessor(block2, brif_block0_block2_block1);
744 ssa.declare_block_predecessor(block2, jump_block1_block2);
745 ssa.seal_block(block2, &mut func);
746 let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0;
747 let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0;
748 let y2_ssa = {
749 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
750 cur.ins().iadd(x_use3, y_use3)
751 };
752 ssa.def_var(y_var, y2_ssa, block2);
753
754 assert_eq!(x_ssa, x_use3);
755 assert_eq!(y_ssa, y_use3);
756 match func.dfg.insts[brif_block0_block2_block1] {
757 ir::InstructionData::Brif {
758 blocks: [block_then, block_else],
759 ..
760 } => {
761 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
762 assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0);
763 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
764 assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0);
765 }
766 _ => assert!(false),
767 };
768 match func.dfg.insts[brif_block0_block2_block1] {
769 ir::InstructionData::Brif {
770 blocks: [block_then, block_else],
771 ..
772 } => {
773 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
774 assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0);
775 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
776 assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0);
777 }
778 _ => assert!(false),
779 };
780 match func.dfg.insts[jump_block1_block2] {
781 ir::InstructionData::Jump {
782 destination: dest, ..
783 } => {
784 assert_eq!(dest.block(&func.dfg.value_lists), block2);
785 assert_eq!(dest.args_slice(&func.dfg.value_lists).len(), 0);
786 }
787 _ => assert!(false),
788 };
789 }
790
791 #[test]
792 fn program_with_loop() {
793 let mut func = Function::new();
794 let mut ssa = SSABuilder::default();
795 let block0 = func.dfg.make_block();
796 let block1 = func.dfg.make_block();
797 let block2 = func.dfg.make_block();
798 let block3 = func.dfg.make_block();
799 {
800 let mut cur = FuncCursor::new(&mut func);
801 cur.insert_block(block0);
802 cur.insert_block(block1);
803 cur.insert_block(block2);
804 cur.insert_block(block3);
805 }
806 ssa.declare_block(block0);
824 ssa.seal_block(block0, &mut func);
825 let x_var = Variable::new(0);
826 let x1 = {
827 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
828 cur.ins().iconst(I32, 1)
829 };
830 ssa.def_var(x_var, x1, block0);
831 let y_var = Variable::new(1);
832 let y1 = {
833 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
834 cur.ins().iconst(I32, 2)
835 };
836 ssa.def_var(y_var, y1, block0);
837 let z_var = Variable::new(2);
838 let x2 = ssa.use_var(&mut func, x_var, I32, block0).0;
839 let y2 = ssa.use_var(&mut func, y_var, I32, block0).0;
840 let z1 = {
841 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
842 cur.ins().iadd(x2, y2)
843 };
844 ssa.def_var(z_var, z1, block0);
845 let jump_block0_block1 = {
846 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
847 cur.ins().jump(block1, &[])
848 };
849 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1);
850 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1);
851 assert_eq!(x2, x1);
852 assert_eq!(y2, y1);
853
854 ssa.declare_block(block1);
856 ssa.declare_block_predecessor(block1, jump_block0_block1);
857 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
858 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
859 let z3 = {
860 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
861 cur.ins().iadd(z2, y3)
862 };
863 ssa.def_var(z_var, z3, block1);
864 let y4 = ssa.use_var(&mut func, y_var, I32, block1).0;
865 assert_eq!(y4, y3);
866 let brif_block1_block3_block2 = {
867 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
868 cur.ins().brif(y4, block3, &[], block2, &[])
869 };
870
871 ssa.declare_block(block2);
873 ssa.declare_block_predecessor(block2, brif_block1_block3_block2);
874 ssa.seal_block(block2, &mut func);
875 let z4 = ssa.use_var(&mut func, z_var, I32, block2).0;
876 assert_eq!(z4, z3);
877 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
878 let z5 = {
879 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
880 cur.ins().isub(z4, x3)
881 };
882 ssa.def_var(z_var, z5, block2);
883 let y5 = ssa.use_var(&mut func, y_var, I32, block2).0;
884 assert_eq!(y5, y3);
885 {
886 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
887 cur.ins().return_(&[y5])
888 };
889
890 ssa.declare_block(block3);
892 ssa.declare_block_predecessor(block3, brif_block1_block3_block2);
893 ssa.seal_block(block3, &mut func);
894 let y6 = ssa.use_var(&mut func, y_var, I32, block3).0;
895 assert_eq!(y6, y3);
896 let x4 = ssa.use_var(&mut func, x_var, I32, block3).0;
897 assert_eq!(x4, x3);
898 let y7 = {
899 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
900 cur.ins().isub(y6, x4)
901 };
902 ssa.def_var(y_var, y7, block3);
903 let jump_block3_block1 = {
904 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
905 cur.ins().jump(block1, &[])
906 };
907
908 ssa.declare_block_predecessor(block1, jump_block3_block1);
910 ssa.seal_block(block1, &mut func);
911 assert_eq!(func.dfg.block_params(block1)[0], z2);
912 assert_eq!(func.dfg.block_params(block1)[1], y3);
913 assert_eq!(func.dfg.resolve_aliases(x3), x1);
914 }
915
916 #[test]
917 fn br_table_with_args() {
918 let mut func = Function::new();
935 let mut ssa = SSABuilder::default();
936 let block0 = func.dfg.make_block();
937 let block1 = func.dfg.make_block();
938 let block2 = func.dfg.make_block();
939 {
940 let mut cur = FuncCursor::new(&mut func);
941 cur.insert_block(block0);
942 cur.insert_block(block1);
943 cur.insert_block(block2);
944 }
945
946 let x1 = {
948 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
949 cur.ins().iconst(I32, 1)
950 };
951 ssa.declare_block(block0);
952 ssa.seal_block(block0, &mut func);
953 let x_var = Variable::new(0);
954 ssa.def_var(x_var, x1, block0);
955 ssa.use_var(&mut func, x_var, I32, block0).0;
956 let br_table = {
957 let jump_table = JumpTableData::new(
958 func.dfg.block_call(block2, &[]),
959 &[
960 func.dfg.block_call(block2, &[]),
961 func.dfg.block_call(block1, &[]),
962 ],
963 );
964 let jt = func.create_jump_table(jump_table);
965 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
966 cur.ins().br_table(x1, jt)
967 };
968
969 ssa.declare_block(block1);
971 ssa.declare_block_predecessor(block1, br_table);
972 ssa.seal_block(block1, &mut func);
973 let x2 = {
974 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
975 cur.ins().iconst(I32, 2)
976 };
977 ssa.def_var(x_var, x2, block1);
978 let jump_block1_block2 = {
979 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
980 cur.ins().jump(block2, &[])
981 };
982
983 ssa.declare_block(block2);
985 ssa.declare_block_predecessor(block2, jump_block1_block2);
986 ssa.declare_block_predecessor(block2, br_table);
987 ssa.seal_block(block2, &mut func);
988 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
989 let x4 = {
990 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
991 cur.ins().iadd_imm(x3, 1)
992 };
993 ssa.def_var(x_var, x4, block2);
994 {
995 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
996 cur.ins().return_(&[])
997 };
998
999 let flags = settings::Flags::new(settings::builder());
1000 match verify_function(&func, &flags) {
1001 Ok(()) => {}
1002 Err(_errors) => {
1003 #[cfg(feature = "std")]
1004 panic!("{}", _errors);
1005 #[cfg(not(feature = "std"))]
1006 panic!("function failed to verify");
1007 }
1008 }
1009 }
1010
1011 #[test]
1012 fn undef_values_reordering() {
1013 let mut func = Function::new();
1025 let mut ssa = SSABuilder::default();
1026 let block0 = func.dfg.make_block();
1027 let block1 = func.dfg.make_block();
1028 {
1029 let mut cur = FuncCursor::new(&mut func);
1030 cur.insert_block(block0);
1031 cur.insert_block(block1);
1032 }
1033
1034 ssa.declare_block(block0);
1036 let x_var = Variable::new(0);
1037 ssa.seal_block(block0, &mut func);
1038 let x1 = {
1039 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1040 cur.ins().iconst(I32, 0)
1041 };
1042 ssa.def_var(x_var, x1, block0);
1043 let y_var = Variable::new(1);
1044 let y1 = {
1045 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1046 cur.ins().iconst(I32, 1)
1047 };
1048 ssa.def_var(y_var, y1, block0);
1049 let z_var = Variable::new(2);
1050 let z1 = {
1051 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1052 cur.ins().iconst(I32, 2)
1053 };
1054 ssa.def_var(z_var, z1, block0);
1055 let jump_block0_block1 = {
1056 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1057 cur.ins().jump(block1, &[])
1058 };
1059
1060 ssa.declare_block(block1);
1062 ssa.declare_block_predecessor(block1, jump_block0_block1);
1063 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
1064 assert_eq!(func.dfg.block_params(block1)[0], z2);
1065 let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
1066 assert_eq!(func.dfg.block_params(block1)[1], x2);
1067 let x3 = {
1068 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1069 cur.ins().iadd(x2, z2)
1070 };
1071 ssa.def_var(x_var, x3, block1);
1072 let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
1073 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
1074 assert_eq!(func.dfg.block_params(block1)[2], y3);
1075 let y4 = {
1076 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1077 cur.ins().isub(y3, x4)
1078 };
1079 ssa.def_var(y_var, y4, block1);
1080 let jump_block1_block1 = {
1081 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1082 cur.ins().jump(block1, &[])
1083 };
1084 ssa.declare_block_predecessor(block1, jump_block1_block1);
1085 ssa.seal_block(block1, &mut func);
1086 assert_eq!(func.dfg.block_params(block1)[1], y3);
1089 assert_eq!(func.dfg.block_params(block1)[0], x2);
1090 }
1091
1092 #[test]
1093 fn undef() {
1094 let mut func = Function::new();
1096 let mut ssa = SSABuilder::default();
1097 let block0 = func.dfg.make_block();
1098 ssa.declare_block(block0);
1099 ssa.seal_block(block0, &mut func);
1100 let i32_var = Variable::new(0);
1101 let f32_var = Variable::new(1);
1102 let f64_var = Variable::new(2);
1103 let i8_var = Variable::new(3);
1104 let f32x4_var = Variable::new(4);
1105 ssa.use_var(&mut func, i32_var, I32, block0);
1106 ssa.use_var(&mut func, f32_var, F32, block0);
1107 ssa.use_var(&mut func, f64_var, F64, block0);
1108 ssa.use_var(&mut func, i8_var, I8, block0);
1109 ssa.use_var(&mut func, f32x4_var, F32X4, block0);
1110 assert_eq!(func.dfg.num_block_params(block0), 0);
1111 }
1112
1113 #[test]
1114 fn undef_in_entry() {
1115 let mut func = Function::new();
1118 let mut ssa = SSABuilder::default();
1119 let block0 = func.dfg.make_block();
1120 ssa.declare_block(block0);
1121 ssa.seal_block(block0, &mut func);
1122 let x_var = Variable::new(0);
1123 assert_eq!(func.dfg.num_block_params(block0), 0);
1124 ssa.use_var(&mut func, x_var, I32, block0);
1125 assert_eq!(func.dfg.num_block_params(block0), 0);
1126 assert_eq!(
1127 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1128 Opcode::Iconst
1129 );
1130 }
1131
1132 #[test]
1133 fn undef_in_entry_sealed_after() {
1134 let mut func = Function::new();
1138 let mut ssa = SSABuilder::default();
1139 let block0 = func.dfg.make_block();
1140 ssa.declare_block(block0);
1141 let x_var = Variable::new(0);
1142 assert_eq!(func.dfg.num_block_params(block0), 0);
1143 ssa.use_var(&mut func, x_var, I32, block0);
1144 assert_eq!(func.dfg.num_block_params(block0), 1);
1145 ssa.seal_block(block0, &mut func);
1146 assert_eq!(func.dfg.num_block_params(block0), 0);
1147 assert_eq!(
1148 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1149 Opcode::Iconst
1150 );
1151 }
1152
1153 #[test]
1154 fn unreachable_use() {
1155 let mut func = Function::new();
1161 let mut ssa = SSABuilder::default();
1162 let block0 = func.dfg.make_block();
1163 let block1 = func.dfg.make_block();
1164 {
1165 let mut cur = FuncCursor::new(&mut func);
1166 cur.insert_block(block0);
1167 cur.insert_block(block1);
1168 }
1169
1170 ssa.declare_block(block0);
1172 ssa.seal_block(block0, &mut func);
1173 {
1174 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1175 cur.ins().return_(&[]);
1176 }
1177
1178 ssa.declare_block(block1);
1180 {
1181 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1182 let x_var = Variable::new(0);
1183 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1184 let brif = cur.ins().brif(x_val, block1, &[], block1, &[]);
1185 ssa.declare_block_predecessor(block1, brif);
1186 }
1187 ssa.seal_block(block1, &mut func);
1188
1189 let flags = settings::Flags::new(settings::builder());
1190 match verify_function(&func, &flags) {
1191 Ok(()) => {}
1192 Err(_errors) => {
1193 #[cfg(feature = "std")]
1194 panic!("{}", _errors);
1195 #[cfg(not(feature = "std"))]
1196 panic!("function failed to verify");
1197 }
1198 }
1199 }
1200
1201 #[test]
1202 fn unreachable_use_with_multiple_preds() {
1203 let mut func = Function::new();
1211 let mut ssa = SSABuilder::default();
1212 let block0 = func.dfg.make_block();
1213 let block1 = func.dfg.make_block();
1214 let block2 = func.dfg.make_block();
1215 {
1216 let mut cur = FuncCursor::new(&mut func);
1217 cur.insert_block(block0);
1218 cur.insert_block(block1);
1219 cur.insert_block(block2);
1220 }
1221
1222 ssa.declare_block(block0);
1224 ssa.seal_block(block0, &mut func);
1225 {
1226 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1227 cur.ins().return_(&[]);
1228 }
1229
1230 ssa.declare_block(block1);
1232 let brif = {
1233 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1234 let x_var = Variable::new(0);
1235 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1236 cur.ins().brif(x_val, block2, &[], block1, &[])
1237 };
1238
1239 ssa.declare_block(block2);
1241 ssa.declare_block_predecessor(block1, brif);
1242 ssa.declare_block_predecessor(block2, brif);
1243 ssa.seal_block(block2, &mut func);
1244 let jump_block2_block1 = {
1245 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1246 cur.ins().jump(block1, &[])
1247 };
1248
1249 ssa.declare_block_predecessor(block1, jump_block2_block1);
1251 ssa.seal_block(block1, &mut func);
1252 let flags = settings::Flags::new(settings::builder());
1253 match verify_function(&func, &flags) {
1254 Ok(()) => {}
1255 Err(_errors) => {
1256 #[cfg(feature = "std")]
1257 panic!("{}", _errors);
1258 #[cfg(not(feature = "std"))]
1259 panic!("function failed to verify");
1260 }
1261 }
1262 }
1263
1264 #[test]
1265 fn reassign_with_predecessor_loop_hangs() {
1266 let mut func = Function::new();
1278 let mut ssa = SSABuilder::default();
1279 let block0 = func.dfg.make_block();
1280 let block1 = func.dfg.make_block();
1281 let block2 = func.dfg.make_block();
1282 let var0 = Variable::new(0);
1283
1284 {
1285 let mut cur = FuncCursor::new(&mut func);
1286 for block in [block0, block1, block2] {
1287 cur.insert_block(block);
1288 ssa.declare_block(block);
1289 }
1290 }
1291
1292 {
1294 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1295
1296 let var0_iconst = cur.ins().iconst(I32, 0);
1297 ssa.def_var(var0, var0_iconst, block0);
1298
1299 cur.ins().return_(&[]);
1300 }
1301
1302 {
1304 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1305
1306 let jump = cur.ins().jump(block2, &[]);
1307 ssa.declare_block_predecessor(block2, jump);
1308 }
1309
1310 {
1312 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1313
1314 let _ = ssa.use_var(&mut cur.func, var0, I32, block2).0;
1315 let var0_iconst = cur.ins().iconst(I32, 1);
1316 ssa.def_var(var0, var0_iconst, block2);
1317
1318 let jump = cur.ins().jump(block1, &[]);
1319 ssa.declare_block_predecessor(block1, jump);
1320 }
1321
1322 ssa.seal_all_blocks(&mut func);
1324 }
1325}