1use crate::Variable;
11use alloc::{vec, vec::Vec};
12use core::mem;
13use cranelift_codegen::cursor::{Cursor, FuncCursor};
14use cranelift_codegen::entity::{EntityList, EntitySet, ListPool, SecondaryMap};
15use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128};
16use cranelift_codegen::ir::types::{F16, F32, F64, F128, I64, I128};
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 stack_map_vars: EntitySet<Variable>,
42
43 stack_map_values: EntitySet<Value>,
45
46 ssa_blocks: SecondaryMap<Block, SSABlockData>,
49
50 calls: Vec<Call>,
52 results: Vec<Value>,
54
55 side_effects: SideEffects,
57
58 visited: EntitySet<Block>,
60
61 variable_pool: ListPool<Variable>,
63
64 inst_pool: ListPool<Inst>,
66}
67
68#[derive(Default)]
70pub struct SideEffects {
71 pub instructions_added_to_blocks: Vec<Block>,
76}
77
78impl SideEffects {
79 fn is_empty(&self) -> bool {
80 let Self {
81 instructions_added_to_blocks,
82 } = self;
83 instructions_added_to_blocks.is_empty()
84 }
85}
86
87#[derive(Clone)]
88enum Sealed {
89 No {
90 undef_variables: EntityList<Variable>,
92 },
93 Yes,
94}
95
96impl Default for Sealed {
97 fn default() -> Self {
98 Sealed::No {
99 undef_variables: EntityList::new(),
100 }
101 }
102}
103
104#[derive(Clone, Default)]
105struct SSABlockData {
106 predecessors: EntityList<Inst>,
108 sealed: Sealed,
110 single_predecessor: PackedOption<Block>,
112}
113
114impl SSABuilder {
115 pub fn clear(&mut self) {
118 self.variables.clear();
119 self.stack_map_vars.clear();
120 self.stack_map_values.clear();
121 self.ssa_blocks.clear();
122 self.variable_pool.clear();
123 self.inst_pool.clear();
124 debug_assert!(self.calls.is_empty());
125 debug_assert!(self.results.is_empty());
126 debug_assert!(self.side_effects.is_empty());
127 }
128
129 pub fn is_empty(&self) -> bool {
131 self.variables.is_empty()
132 && self.stack_map_vars.is_empty()
133 && self.stack_map_values.is_empty()
134 && self.ssa_blocks.is_empty()
135 && self.calls.is_empty()
136 && self.results.is_empty()
137 && self.side_effects.is_empty()
138 }
139}
140
141enum Call {
143 UseVar(Inst),
144 FinishPredecessorsLookup(Value, Block),
145}
146
147fn emit_zero(ty: Type, mut cur: FuncCursor) -> Value {
149 match ty {
150 I128 => {
151 let zero = cur.ins().iconst(I64, 0);
152 cur.ins().uextend(I128, zero)
153 }
154 ty if ty.is_int() => cur.ins().iconst(ty, 0),
155 F16 => cur.ins().f16const(Ieee16::with_bits(0)),
156 F32 => cur.ins().f32const(Ieee32::with_bits(0)),
157 F64 => cur.ins().f64const(Ieee64::with_bits(0)),
158 F128 => {
159 let zero = cur.func.dfg.constants.insert(Ieee128::with_bits(0).into());
160 cur.ins().f128const(zero)
161 }
162 ty if ty.is_vector() => match ty.lane_type() {
163 scalar_ty if scalar_ty.is_int() => {
164 let zero = cur
165 .func
166 .dfg
167 .constants
168 .insert(vec![0; ty.bytes().try_into().unwrap()].into());
169 cur.ins().vconst(ty, zero)
170 }
171 F16 => {
172 let scalar = cur.ins().f16const(Ieee16::with_bits(0));
173 cur.ins().splat(ty, scalar)
174 }
175 F32 => {
176 let scalar = cur.ins().f32const(Ieee32::with_bits(0));
177 cur.ins().splat(ty, scalar)
178 }
179 F64 => {
180 let scalar = cur.ins().f64const(Ieee64::with_bits(0));
181 cur.ins().splat(ty, scalar)
182 }
183 F128 => {
184 let zero = cur.func.dfg.constants.insert(Ieee128::with_bits(0).into());
185 let scalar = cur.ins().f128const(zero);
186 cur.ins().splat(ty, scalar)
187 }
188 _ => panic!("unimplemented scalar type: {ty:?}"),
189 },
190 ty => panic!("unimplemented type: {ty:?}"),
191 }
192}
193
194impl SSABuilder {
214 pub fn def_var(&mut self, var: Variable, val: Value, block: Block) {
218 self.variables[var][block] = PackedOption::from(val);
219 self.record_stack_map_binding(var, val);
220 }
221
222 pub fn mark_var_needs_stack_map(&mut self, var: Variable) {
224 debug_assert!(
225 self.variables[var].values().all(|v| v.is_none()),
226 "declare_var_needs_stack_map({var:?}) must be called before any \
227 definition of the variable; otherwise earlier definitions are \
228 silently omitted from stack maps"
229 );
230 self.stack_map_vars.insert(var);
231 }
232
233 pub fn stack_map_values(&self) -> &EntitySet<Value> {
235 &self.stack_map_values
236 }
237
238 pub fn stack_map_values_mut(&mut self) -> &mut EntitySet<Value> {
240 &mut self.stack_map_values
241 }
242
243 fn record_stack_map_binding(&mut self, var: Variable, val: Value) {
245 if self.stack_map_vars.contains(var) {
246 log::trace!("recording stack-map binding {var:?} -> {val:?}");
247 self.stack_map_values.insert(val);
248 }
249 }
250
251 pub fn use_var(
259 &mut self,
260 func: &mut Function,
261 var: Variable,
262 ty: Type,
263 block: Block,
264 ) -> (Value, SideEffects) {
265 debug_assert!(self.calls.is_empty());
266 debug_assert!(self.results.is_empty());
267 debug_assert!(self.side_effects.is_empty());
268
269 self.use_var_nonlocal(func, var, ty, block);
271 let value = self.run_state_machine(func, var, ty);
272
273 let side_effects = mem::take(&mut self.side_effects);
274 (value, side_effects)
275 }
276
277 fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block) {
281 if let Some(val) = self.variables[var][block].expand() {
284 self.results.push(val);
285 return;
286 }
287
288 let (val, from) = self.find_var(func, var, ty, block);
292
293 debug_assert!(!self.stack_map_vars.contains(var) || self.stack_map_values.contains(val));
312 let var_defs = &mut self.variables[var];
313 while block != from {
314 debug_assert!(var_defs[block].is_none());
315 var_defs[block] = PackedOption::from(val);
316 block = self.ssa_blocks[block].single_predecessor.unwrap();
317 }
318 }
319
320 fn find_var(
344 &mut self,
345 func: &mut Function,
346 var: Variable,
347 ty: Type,
348 mut block: Block,
349 ) -> (Value, Block) {
350 self.visited.clear();
352 let var_defs = &mut self.variables[var];
353 while let Some(pred) = self.ssa_blocks[block].single_predecessor.expand() {
354 if !self.visited.insert(block) {
355 break;
356 }
357 block = pred;
358 if let Some(val) = var_defs[block].expand() {
359 self.results.push(val);
360 return (val, block);
361 }
362 }
363
364 let val = func.dfg.append_block_param(block, ty);
367 var_defs[block] = PackedOption::from(val);
368 self.record_stack_map_binding(var, val);
369
370 match &mut self.ssa_blocks[block].sealed {
376 Sealed::Yes => self.begin_predecessors_lookup(val, block),
379 Sealed::No { undef_variables } => {
380 undef_variables.push(var, &mut self.variable_pool);
381 self.results.push(val);
382 }
383 }
384 (val, block)
385 }
386
387 pub fn declare_block(&mut self, block: Block) {
391 let _ = &mut self.ssa_blocks[block];
395 }
396
397 pub fn declare_block_predecessor(&mut self, block: Block, inst: Inst) {
407 debug_assert!(!self.is_sealed(block));
408 self.ssa_blocks[block]
409 .predecessors
410 .push(inst, &mut self.inst_pool);
411 }
412
413 pub fn remove_block_predecessor(&mut self, block: Block, inst: Inst) {
418 debug_assert!(!self.is_sealed(block));
419 let data = &mut self.ssa_blocks[block];
420 let pred = data
421 .predecessors
422 .as_slice(&self.inst_pool)
423 .iter()
424 .position(|&branch| branch == inst)
425 .expect("the predecessor you are trying to remove is not declared");
426 data.predecessors.swap_remove(pred, &mut self.inst_pool);
427 }
428
429 pub fn seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects {
437 debug_assert!(
438 !self.is_sealed(block),
439 "Attempting to seal {block} which is already sealed."
440 );
441 self.seal_one_block(block, func);
442 mem::take(&mut self.side_effects)
443 }
444
445 pub fn seal_all_blocks(&mut self, func: &mut Function) -> SideEffects {
452 for block in self.ssa_blocks.keys() {
456 self.seal_one_block(block, func);
457 }
458 mem::take(&mut self.side_effects)
459 }
460
461 fn seal_one_block(&mut self, block: Block, func: &mut Function) {
463 let mut undef_variables =
466 match mem::replace(&mut self.ssa_blocks[block].sealed, Sealed::Yes) {
467 Sealed::No { undef_variables } => undef_variables,
468 Sealed::Yes => return,
469 };
470 let ssa_params = undef_variables.len(&self.variable_pool);
471
472 let predecessors = self.predecessors(block);
473 if predecessors.len() == 1 {
474 let pred = func.layout.inst_block(predecessors[0]).unwrap();
475 self.ssa_blocks[block].single_predecessor = PackedOption::from(pred);
476 }
477
478 for idx in 0..ssa_params {
482 let var = undef_variables.get(idx, &self.variable_pool).unwrap();
483
484 let block_params = func.dfg.block_params(block);
489
490 let val = block_params[block_params.len() - (ssa_params - idx)];
495
496 debug_assert!(self.calls.is_empty());
497 debug_assert!(self.results.is_empty());
498 self.begin_predecessors_lookup(val, block);
501 self.run_state_machine(func, var, func.dfg.value_type(val));
502 }
503
504 undef_variables.clear(&mut self.variable_pool);
505 }
506
507 fn begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block) {
522 self.calls
523 .push(Call::FinishPredecessorsLookup(sentinel, dest_block));
524 self.calls.extend(
526 self.ssa_blocks[dest_block]
527 .predecessors
528 .as_slice(&self.inst_pool)
529 .iter()
530 .rev()
531 .copied()
532 .map(Call::UseVar),
533 );
534 }
535
536 fn finish_predecessors_lookup(
539 &mut self,
540 func: &mut Function,
541 sentinel: Value,
542 dest_block: Block,
543 ) -> Value {
544 let num_predecessors = self.predecessors(dest_block).len();
551 let results = self.results.drain(self.results.len() - num_predecessors..);
553
554 let pred_val = {
555 let mut iter = results
556 .as_slice()
557 .iter()
558 .map(|&val| func.dfg.resolve_aliases(val))
559 .filter(|&val| val != sentinel);
560 if let Some(val) = iter.next() {
561 if iter.all(|other| other == val) {
564 Some(val)
565 } else {
566 None
567 }
568 } else {
569 if !func.layout.is_block_inserted(dest_block) {
573 func.layout.append_block(dest_block);
574 }
575 self.side_effects
576 .instructions_added_to_blocks
577 .push(dest_block);
578 let zero = emit_zero(
579 func.dfg.value_type(sentinel),
580 FuncCursor::new(func).at_first_insertion_point(dest_block),
581 );
582 Some(zero)
583 }
584 };
585
586 if let Some(pred_val) = pred_val {
587 func.dfg.remove_block_param(sentinel);
592 func.dfg.change_to_alias(sentinel, pred_val);
593 pred_val
594 } else {
595 let mut preds = self.ssa_blocks[dest_block].predecessors;
598 let dfg = &mut func.stencil.dfg;
599 for (idx, &val) in results.as_slice().iter().enumerate() {
600 let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
601 let branch = *pred;
602
603 let dests = dfg.insts[branch]
604 .branch_destination_mut(&mut dfg.jump_tables, &mut dfg.exception_tables);
605 assert!(
606 !dests.is_empty(),
607 "you have declared a non-branch instruction as a predecessor to a block!"
608 );
609 for block in dests {
610 if block.block(&dfg.value_lists) == dest_block {
611 block.append_argument(val, &mut dfg.value_lists);
612 }
613 }
614 }
615 sentinel
616 }
617 }
618
619 fn predecessors(&self, block: Block) -> &[Inst] {
621 self.ssa_blocks[block]
622 .predecessors
623 .as_slice(&self.inst_pool)
624 }
625
626 pub fn has_any_predecessors(&self, block: Block) -> bool {
628 !self.predecessors(block).is_empty()
629 }
630
631 pub fn is_sealed(&self, block: Block) -> bool {
633 matches!(self.ssa_blocks[block].sealed, Sealed::Yes)
634 }
635
636 fn run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value {
642 while let Some(call) = self.calls.pop() {
644 match call {
645 Call::UseVar(branch) => {
646 let block = func.layout.inst_block(branch).unwrap();
647 self.use_var_nonlocal(func, var, ty, block);
648 }
649 Call::FinishPredecessorsLookup(sentinel, dest_block) => {
650 let val = self.finish_predecessors_lookup(func, sentinel, dest_block);
651 self.results.push(val);
652 }
653 }
654 }
655 debug_assert_eq!(self.results.len(), 1);
656 self.results.pop().unwrap()
657 }
658}
659
660#[cfg(test)]
661mod tests {
662 use crate::Variable;
663 use crate::ssa::SSABuilder;
664 use cranelift_codegen::cursor::{Cursor, FuncCursor};
665 use cranelift_codegen::entity::EntityRef;
666 use cranelift_codegen::ir;
667 use cranelift_codegen::ir::types::*;
668 use cranelift_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode};
669 use cranelift_codegen::settings;
670 use cranelift_codegen::verify_function;
671
672 #[test]
673 fn simple_block() {
674 let mut func = Function::new();
675 let mut ssa = SSABuilder::default();
676 let block0 = func.dfg.make_block();
677 ssa.declare_block(block0);
685 let x_var = Variable::new(0);
686 let x_ssa = {
687 let mut cur = FuncCursor::new(&mut func);
688 cur.insert_block(block0);
689 cur.ins().iconst(I32, 1)
690 };
691 ssa.def_var(x_var, x_ssa, block0);
692 let y_var = Variable::new(1);
693 let y_ssa = {
694 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
695 cur.ins().iconst(I32, 2)
696 };
697 ssa.def_var(y_var, y_ssa, block0);
698 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
699 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
700
701 let z_var = Variable::new(2);
702 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
703 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
704 let z1_ssa = {
705 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
706 cur.ins().iadd(x_use1, y_use1)
707 };
708 ssa.def_var(z_var, z1_ssa, block0);
709 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
710
711 let x_use2 = ssa.use_var(&mut func, x_var, I32, block0).0;
712 let z_use1 = ssa.use_var(&mut func, z_var, I32, block0).0;
713 let z2_ssa = {
714 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
715 cur.ins().iadd(x_use2, z_use1)
716 };
717 ssa.def_var(z_var, z2_ssa, block0);
718 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z2_ssa);
719 }
720
721 #[test]
722 fn sequence_of_blocks() {
723 let mut func = Function::new();
724 let mut ssa = SSABuilder::default();
725 let block0 = func.dfg.make_block();
726 let block1 = func.dfg.make_block();
727 let block2 = func.dfg.make_block();
728 {
740 let mut cur = FuncCursor::new(&mut func);
741 cur.insert_block(block0);
742 cur.insert_block(block1);
743 cur.insert_block(block2);
744 }
745
746 ssa.declare_block(block0);
748 ssa.seal_block(block0, &mut func);
749 let x_var = Variable::new(0);
750 let x_ssa = {
751 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
752 cur.ins().iconst(I32, 1)
753 };
754 ssa.def_var(x_var, x_ssa, block0);
755 let y_var = Variable::new(1);
756 let y_ssa = {
757 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
758 cur.ins().iconst(I32, 2)
759 };
760 ssa.def_var(y_var, y_ssa, block0);
761 let z_var = Variable::new(2);
762 let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
763 let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
764 let z1_ssa = {
765 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
766 cur.ins().iadd(x_use1, y_use1)
767 };
768 ssa.def_var(z_var, z1_ssa, block0);
769 let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0;
770 let brif_block0_block2_block1: Inst = {
771 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
772 cur.ins().brif(y_use2, block2, &[], block1, &[])
773 };
774
775 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
776 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
777 assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
778
779 ssa.declare_block(block1);
781 ssa.declare_block_predecessor(block1, brif_block0_block2_block1);
782 ssa.seal_block(block1, &mut func);
783
784 let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0;
785 let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0;
786 let z2_ssa = {
787 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
788 cur.ins().iadd(x_use2, z_use1)
789 };
790 ssa.def_var(z_var, z2_ssa, block1);
791 let jump_block1_block2: Inst = {
792 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
793 cur.ins().jump(block2, &[])
794 };
795
796 assert_eq!(x_use2, x_ssa);
797 assert_eq!(z_use1, z1_ssa);
798 assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa);
799
800 ssa.declare_block(block2);
802 ssa.declare_block_predecessor(block2, brif_block0_block2_block1);
803 ssa.declare_block_predecessor(block2, jump_block1_block2);
804 ssa.seal_block(block2, &mut func);
805 let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0;
806 let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0;
807 let y2_ssa = {
808 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
809 cur.ins().iadd(x_use3, y_use3)
810 };
811 ssa.def_var(y_var, y2_ssa, block2);
812
813 assert_eq!(x_ssa, x_use3);
814 assert_eq!(y_ssa, y_use3);
815 match func.dfg.insts[brif_block0_block2_block1] {
816 ir::InstructionData::Brif {
817 blocks: [block_then, block_else],
818 ..
819 } => {
820 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
821 assert_eq!(block_then.args(&func.dfg.value_lists).len(), 0);
822 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
823 assert_eq!(block_else.args(&func.dfg.value_lists).len(), 0);
824 }
825 _ => assert!(false),
826 };
827 match func.dfg.insts[brif_block0_block2_block1] {
828 ir::InstructionData::Brif {
829 blocks: [block_then, block_else],
830 ..
831 } => {
832 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
833 assert_eq!(block_then.args(&func.dfg.value_lists).len(), 0);
834 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
835 assert_eq!(block_else.args(&func.dfg.value_lists).len(), 0);
836 }
837 _ => assert!(false),
838 };
839 match func.dfg.insts[jump_block1_block2] {
840 ir::InstructionData::Jump {
841 destination: dest, ..
842 } => {
843 assert_eq!(dest.block(&func.dfg.value_lists), block2);
844 assert_eq!(dest.args(&func.dfg.value_lists).len(), 0);
845 }
846 _ => assert!(false),
847 };
848 }
849
850 #[test]
851 fn program_with_loop() {
852 let mut func = Function::new();
853 let mut ssa = SSABuilder::default();
854 let block0 = func.dfg.make_block();
855 let block1 = func.dfg.make_block();
856 let block2 = func.dfg.make_block();
857 let block3 = func.dfg.make_block();
858 {
859 let mut cur = FuncCursor::new(&mut func);
860 cur.insert_block(block0);
861 cur.insert_block(block1);
862 cur.insert_block(block2);
863 cur.insert_block(block3);
864 }
865 ssa.declare_block(block0);
883 ssa.seal_block(block0, &mut func);
884 let x_var = Variable::new(0);
885 let x1 = {
886 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
887 cur.ins().iconst(I32, 1)
888 };
889 ssa.def_var(x_var, x1, block0);
890 let y_var = Variable::new(1);
891 let y1 = {
892 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
893 cur.ins().iconst(I32, 2)
894 };
895 ssa.def_var(y_var, y1, block0);
896 let z_var = Variable::new(2);
897 let x2 = ssa.use_var(&mut func, x_var, I32, block0).0;
898 let y2 = ssa.use_var(&mut func, y_var, I32, block0).0;
899 let z1 = {
900 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
901 cur.ins().iadd(x2, y2)
902 };
903 ssa.def_var(z_var, z1, block0);
904 let jump_block0_block1 = {
905 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
906 cur.ins().jump(block1, &[])
907 };
908 assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1);
909 assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1);
910 assert_eq!(x2, x1);
911 assert_eq!(y2, y1);
912
913 ssa.declare_block(block1);
915 ssa.declare_block_predecessor(block1, jump_block0_block1);
916 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
917 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
918 let z3 = {
919 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
920 cur.ins().iadd(z2, y3)
921 };
922 ssa.def_var(z_var, z3, block1);
923 let y4 = ssa.use_var(&mut func, y_var, I32, block1).0;
924 assert_eq!(y4, y3);
925 let brif_block1_block3_block2 = {
926 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
927 cur.ins().brif(y4, block3, &[], block2, &[])
928 };
929
930 ssa.declare_block(block2);
932 ssa.declare_block_predecessor(block2, brif_block1_block3_block2);
933 ssa.seal_block(block2, &mut func);
934 let z4 = ssa.use_var(&mut func, z_var, I32, block2).0;
935 assert_eq!(z4, z3);
936 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
937 let z5 = {
938 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
939 cur.ins().isub(z4, x3)
940 };
941 ssa.def_var(z_var, z5, block2);
942 let y5 = ssa.use_var(&mut func, y_var, I32, block2).0;
943 assert_eq!(y5, y3);
944 {
945 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
946 cur.ins().return_(&[y5])
947 };
948
949 ssa.declare_block(block3);
951 ssa.declare_block_predecessor(block3, brif_block1_block3_block2);
952 ssa.seal_block(block3, &mut func);
953 let y6 = ssa.use_var(&mut func, y_var, I32, block3).0;
954 assert_eq!(y6, y3);
955 let x4 = ssa.use_var(&mut func, x_var, I32, block3).0;
956 assert_eq!(x4, x3);
957 let y7 = {
958 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
959 cur.ins().isub(y6, x4)
960 };
961 ssa.def_var(y_var, y7, block3);
962 let jump_block3_block1 = {
963 let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
964 cur.ins().jump(block1, &[])
965 };
966
967 ssa.declare_block_predecessor(block1, jump_block3_block1);
969 ssa.seal_block(block1, &mut func);
970 assert_eq!(func.dfg.block_params(block1)[0], z2);
971 assert_eq!(func.dfg.block_params(block1)[1], y3);
972 assert_eq!(func.dfg.resolve_aliases(x3), x1);
973 }
974
975 #[test]
976 fn br_table_with_args() {
977 let mut func = Function::new();
994 let mut ssa = SSABuilder::default();
995 let block0 = func.dfg.make_block();
996 let block1 = func.dfg.make_block();
997 let block2 = func.dfg.make_block();
998 {
999 let mut cur = FuncCursor::new(&mut func);
1000 cur.insert_block(block0);
1001 cur.insert_block(block1);
1002 cur.insert_block(block2);
1003 }
1004
1005 let x1 = {
1007 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1008 cur.ins().iconst(I32, 1)
1009 };
1010 ssa.declare_block(block0);
1011 ssa.seal_block(block0, &mut func);
1012 let x_var = Variable::new(0);
1013 ssa.def_var(x_var, x1, block0);
1014 ssa.use_var(&mut func, x_var, I32, block0).0;
1015 let br_table = {
1016 let jump_table = JumpTableData::new(
1017 func.dfg.block_call(block2, &[]),
1018 &[
1019 func.dfg.block_call(block2, &[]),
1020 func.dfg.block_call(block1, &[]),
1021 ],
1022 );
1023 let jt = func.create_jump_table(jump_table);
1024 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1025 cur.ins().br_table(x1, jt)
1026 };
1027
1028 ssa.declare_block(block1);
1030 ssa.declare_block_predecessor(block1, br_table);
1031 ssa.seal_block(block1, &mut func);
1032 let x2 = {
1033 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1034 cur.ins().iconst(I32, 2)
1035 };
1036 ssa.def_var(x_var, x2, block1);
1037 let jump_block1_block2 = {
1038 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1039 cur.ins().jump(block2, &[])
1040 };
1041
1042 ssa.declare_block(block2);
1044 ssa.declare_block_predecessor(block2, jump_block1_block2);
1045 ssa.declare_block_predecessor(block2, br_table);
1046 ssa.seal_block(block2, &mut func);
1047 let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
1048 let x4 = {
1049 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1050 cur.ins().iadd_imm_s(x3, 1)
1051 };
1052 ssa.def_var(x_var, x4, block2);
1053 {
1054 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1055 cur.ins().return_(&[])
1056 };
1057
1058 let flags = settings::Flags::new(settings::builder());
1059 match verify_function(&func, &flags) {
1060 Ok(()) => {}
1061 Err(_errors) => {
1062 #[cfg(feature = "std")]
1063 panic!("{}", _errors);
1064 #[cfg(not(feature = "std"))]
1065 panic!("function failed to verify");
1066 }
1067 }
1068 }
1069
1070 #[test]
1071 fn undef_values_reordering() {
1072 let mut func = Function::new();
1084 let mut ssa = SSABuilder::default();
1085 let block0 = func.dfg.make_block();
1086 let block1 = func.dfg.make_block();
1087 {
1088 let mut cur = FuncCursor::new(&mut func);
1089 cur.insert_block(block0);
1090 cur.insert_block(block1);
1091 }
1092
1093 ssa.declare_block(block0);
1095 let x_var = Variable::new(0);
1096 ssa.seal_block(block0, &mut func);
1097 let x1 = {
1098 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1099 cur.ins().iconst(I32, 0)
1100 };
1101 ssa.def_var(x_var, x1, block0);
1102 let y_var = Variable::new(1);
1103 let y1 = {
1104 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1105 cur.ins().iconst(I32, 1)
1106 };
1107 ssa.def_var(y_var, y1, block0);
1108 let z_var = Variable::new(2);
1109 let z1 = {
1110 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1111 cur.ins().iconst(I32, 2)
1112 };
1113 ssa.def_var(z_var, z1, block0);
1114 let jump_block0_block1 = {
1115 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1116 cur.ins().jump(block1, &[])
1117 };
1118
1119 ssa.declare_block(block1);
1121 ssa.declare_block_predecessor(block1, jump_block0_block1);
1122 let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
1123 assert_eq!(func.dfg.block_params(block1)[0], z2);
1124 let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
1125 assert_eq!(func.dfg.block_params(block1)[1], x2);
1126 let x3 = {
1127 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1128 cur.ins().iadd(x2, z2)
1129 };
1130 ssa.def_var(x_var, x3, block1);
1131 let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
1132 let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
1133 assert_eq!(func.dfg.block_params(block1)[2], y3);
1134 let y4 = {
1135 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1136 cur.ins().isub(y3, x4)
1137 };
1138 ssa.def_var(y_var, y4, block1);
1139 let jump_block1_block1 = {
1140 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1141 cur.ins().jump(block1, &[])
1142 };
1143 ssa.declare_block_predecessor(block1, jump_block1_block1);
1144 ssa.seal_block(block1, &mut func);
1145 assert_eq!(func.dfg.block_params(block1)[1], y3);
1148 assert_eq!(func.dfg.block_params(block1)[0], x2);
1149 }
1150
1151 #[test]
1152 fn undef() {
1153 let mut func = Function::new();
1155 let mut ssa = SSABuilder::default();
1156 let block0 = func.dfg.make_block();
1157 ssa.declare_block(block0);
1158 ssa.seal_block(block0, &mut func);
1159 let i32_var = Variable::new(0);
1160 let f32_var = Variable::new(1);
1161 let f64_var = Variable::new(2);
1162 let i8_var = Variable::new(3);
1163 let f32x4_var = Variable::new(4);
1164 ssa.use_var(&mut func, i32_var, I32, block0);
1165 ssa.use_var(&mut func, f32_var, F32, block0);
1166 ssa.use_var(&mut func, f64_var, F64, block0);
1167 ssa.use_var(&mut func, i8_var, I8, block0);
1168 ssa.use_var(&mut func, f32x4_var, F32X4, block0);
1169 assert_eq!(func.dfg.num_block_params(block0), 0);
1170 }
1171
1172 #[test]
1173 fn undef_in_entry() {
1174 let mut func = Function::new();
1177 let mut ssa = SSABuilder::default();
1178 let block0 = func.dfg.make_block();
1179 ssa.declare_block(block0);
1180 ssa.seal_block(block0, &mut func);
1181 let x_var = Variable::new(0);
1182 assert_eq!(func.dfg.num_block_params(block0), 0);
1183 ssa.use_var(&mut func, x_var, I32, block0);
1184 assert_eq!(func.dfg.num_block_params(block0), 0);
1185 assert_eq!(
1186 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1187 Opcode::Iconst
1188 );
1189 }
1190
1191 #[test]
1192 fn undef_in_entry_sealed_after() {
1193 let mut func = Function::new();
1197 let mut ssa = SSABuilder::default();
1198 let block0 = func.dfg.make_block();
1199 ssa.declare_block(block0);
1200 let x_var = Variable::new(0);
1201 assert_eq!(func.dfg.num_block_params(block0), 0);
1202 ssa.use_var(&mut func, x_var, I32, block0);
1203 assert_eq!(func.dfg.num_block_params(block0), 1);
1204 ssa.seal_block(block0, &mut func);
1205 assert_eq!(func.dfg.num_block_params(block0), 0);
1206 assert_eq!(
1207 func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1208 Opcode::Iconst
1209 );
1210 }
1211
1212 #[test]
1213 fn unreachable_use() {
1214 let mut func = Function::new();
1220 let mut ssa = SSABuilder::default();
1221 let block0 = func.dfg.make_block();
1222 let block1 = func.dfg.make_block();
1223 {
1224 let mut cur = FuncCursor::new(&mut func);
1225 cur.insert_block(block0);
1226 cur.insert_block(block1);
1227 }
1228
1229 ssa.declare_block(block0);
1231 ssa.seal_block(block0, &mut func);
1232 {
1233 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1234 cur.ins().return_(&[]);
1235 }
1236
1237 ssa.declare_block(block1);
1239 {
1240 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1241 let x_var = Variable::new(0);
1242 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1243 let brif = cur.ins().brif(x_val, block1, &[], block1, &[]);
1244 ssa.declare_block_predecessor(block1, brif);
1245 }
1246 ssa.seal_block(block1, &mut func);
1247
1248 let flags = settings::Flags::new(settings::builder());
1249 match verify_function(&func, &flags) {
1250 Ok(()) => {}
1251 Err(_errors) => {
1252 #[cfg(feature = "std")]
1253 panic!("{}", _errors);
1254 #[cfg(not(feature = "std"))]
1255 panic!("function failed to verify");
1256 }
1257 }
1258 }
1259
1260 #[test]
1261 fn unreachable_use_with_multiple_preds() {
1262 let mut func = Function::new();
1270 let mut ssa = SSABuilder::default();
1271 let block0 = func.dfg.make_block();
1272 let block1 = func.dfg.make_block();
1273 let block2 = func.dfg.make_block();
1274 {
1275 let mut cur = FuncCursor::new(&mut func);
1276 cur.insert_block(block0);
1277 cur.insert_block(block1);
1278 cur.insert_block(block2);
1279 }
1280
1281 ssa.declare_block(block0);
1283 ssa.seal_block(block0, &mut func);
1284 {
1285 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1286 cur.ins().return_(&[]);
1287 }
1288
1289 ssa.declare_block(block1);
1291 let brif = {
1292 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1293 let x_var = Variable::new(0);
1294 let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1295 cur.ins().brif(x_val, block2, &[], block1, &[])
1296 };
1297
1298 ssa.declare_block(block2);
1300 ssa.declare_block_predecessor(block1, brif);
1301 ssa.declare_block_predecessor(block2, brif);
1302 ssa.seal_block(block2, &mut func);
1303 let jump_block2_block1 = {
1304 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1305 cur.ins().jump(block1, &[])
1306 };
1307
1308 ssa.declare_block_predecessor(block1, jump_block2_block1);
1310 ssa.seal_block(block1, &mut func);
1311 let flags = settings::Flags::new(settings::builder());
1312 match verify_function(&func, &flags) {
1313 Ok(()) => {}
1314 Err(_errors) => {
1315 #[cfg(feature = "std")]
1316 panic!("{}", _errors);
1317 #[cfg(not(feature = "std"))]
1318 panic!("function failed to verify");
1319 }
1320 }
1321 }
1322
1323 #[test]
1324 fn reassign_with_predecessor_loop_hangs() {
1325 let mut func = Function::new();
1337 let mut ssa = SSABuilder::default();
1338 let block0 = func.dfg.make_block();
1339 let block1 = func.dfg.make_block();
1340 let block2 = func.dfg.make_block();
1341 let var0 = Variable::new(0);
1342
1343 {
1344 let mut cur = FuncCursor::new(&mut func);
1345 for block in [block0, block1, block2] {
1346 cur.insert_block(block);
1347 ssa.declare_block(block);
1348 }
1349 }
1350
1351 {
1353 let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1354
1355 let var0_iconst = cur.ins().iconst(I32, 0);
1356 ssa.def_var(var0, var0_iconst, block0);
1357
1358 cur.ins().return_(&[]);
1359 }
1360
1361 {
1363 let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1364
1365 let jump = cur.ins().jump(block2, &[]);
1366 ssa.declare_block_predecessor(block2, jump);
1367 }
1368
1369 {
1371 let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1372
1373 let _ = ssa.use_var(&mut cur.func, var0, I32, block2).0;
1374 let var0_iconst = cur.ins().iconst(I32, 1);
1375 ssa.def_var(var0, var0_iconst, block2);
1376
1377 let jump = cur.ins().jump(block1, &[]);
1378 ssa.declare_block_predecessor(block1, jump);
1379 }
1380
1381 ssa.seal_all_blocks(&mut func);
1383 }
1384}