1 //! A SSA-building API that handles incomplete CFGs.
2 //!
3 //! The algorithm is based upon Braun M., Buchwald S., Hack S., Leißa R., Mallon C.,
4 //! Zwinkau A. (2013) Simple and Efficient Construction of Static Single Assignment Form.
5 //! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013.
6 //! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg
7 //!
8 //! <https://link.springer.com/content/pdf/10.1007/978-3-642-37051-9_6.pdf>
9 
10 use crate::Variable;
11 use alloc::vec::Vec;
12 use core::mem;
13 use cranelift_codegen::cursor::{Cursor, FuncCursor};
14 use cranelift_codegen::entity::{EntityList, EntitySet, ListPool, SecondaryMap};
15 use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128};
16 use cranelift_codegen::ir::types::{F16, F32, F64, F128, I64, I128};
17 use cranelift_codegen::ir::{Block, Function, Inst, InstBuilder, Type, Value};
18 use cranelift_codegen::packed_option::PackedOption;
19 
20 /// Structure containing the data relevant the construction of SSA for a given function.
21 ///
22 /// The parameter struct [`Variable`] corresponds to the way variables are represented in the
23 /// non-SSA language you're translating from.
24 ///
25 /// The SSA building relies on information about the variables used and defined.
26 ///
27 /// This SSA building module allows you to def and use variables on the fly while you are
28 /// constructing the CFG, no need for a separate SSA pass after the CFG is completed.
29 ///
30 /// A basic block is said _filled_ if all the instruction that it contains have been translated,
31 /// and it is said _sealed_ if all of its predecessors have been declared. Only filled predecessors
32 /// can be declared.
33 #[derive(Default)]
34 pub struct SSABuilder {
35     // TODO: Consider a sparse representation rather than SecondaryMap-of-SecondaryMap.
36     /// Records for every variable and for every relevant block, the last definition of
37     /// the variable in the block.
38     variables: SecondaryMap<Variable, SecondaryMap<Block, PackedOption<Value>>>,
39 
40     /// Records the position of the basic blocks and the list of values used but not defined in the
41     /// block.
42     ssa_blocks: SecondaryMap<Block, SSABlockData>,
43 
44     /// Call stack for use in the `use_var`/`predecessors_lookup` state machine.
45     calls: Vec<Call>,
46     /// Result stack for use in the `use_var`/`predecessors_lookup` state machine.
47     results: Vec<Value>,
48 
49     /// Side effects accumulated in the `use_var`/`predecessors_lookup` state machine.
50     side_effects: SideEffects,
51 
52     /// Reused storage for cycle-detection.
53     visited: EntitySet<Block>,
54 
55     /// Storage for pending variable definitions.
56     variable_pool: ListPool<Variable>,
57 
58     /// Storage for predecessor definitions.
59     inst_pool: ListPool<Inst>,
60 }
61 
62 /// Side effects of a `use_var` or a `seal_block` method call.
63 #[derive(Default)]
64 pub struct SideEffects {
65     /// When a variable is used but has never been defined before (this happens in the case of
66     /// unreachable code), a placeholder `iconst` or `fconst` value is added to the right `Block`.
67     /// This field signals if it is the case and return the `Block` to which the initialization has
68     /// been added.
69     pub instructions_added_to_blocks: Vec<Block>,
70 }
71 
72 impl SideEffects {
is_empty(&self) -> bool73     fn is_empty(&self) -> bool {
74         let Self {
75             instructions_added_to_blocks,
76         } = self;
77         instructions_added_to_blocks.is_empty()
78     }
79 }
80 
81 #[derive(Clone)]
82 enum Sealed {
83     No {
84         // List of current Block arguments for which an earlier def has not been found yet.
85         undef_variables: EntityList<Variable>,
86     },
87     Yes,
88 }
89 
90 impl Default for Sealed {
default() -> Self91     fn default() -> Self {
92         Sealed::No {
93             undef_variables: EntityList::new(),
94         }
95     }
96 }
97 
98 #[derive(Clone, Default)]
99 struct SSABlockData {
100     // The predecessors of the Block with the block and branch instruction.
101     predecessors: EntityList<Inst>,
102     // A block is sealed if all of its predecessors have been declared.
103     sealed: Sealed,
104     // If this block is sealed and it has exactly one predecessor, this is that predecessor.
105     single_predecessor: PackedOption<Block>,
106 }
107 
108 impl SSABuilder {
109     /// Clears a `SSABuilder` from all its data, letting it in a pristine state without
110     /// deallocating memory.
clear(&mut self)111     pub fn clear(&mut self) {
112         self.variables.clear();
113         self.ssa_blocks.clear();
114         self.variable_pool.clear();
115         self.inst_pool.clear();
116         debug_assert!(self.calls.is_empty());
117         debug_assert!(self.results.is_empty());
118         debug_assert!(self.side_effects.is_empty());
119     }
120 
121     /// Tests whether an `SSABuilder` is in a cleared state.
is_empty(&self) -> bool122     pub fn is_empty(&self) -> bool {
123         self.variables.is_empty()
124             && self.ssa_blocks.is_empty()
125             && self.calls.is_empty()
126             && self.results.is_empty()
127             && self.side_effects.is_empty()
128     }
129 }
130 
131 /// States for the `use_var`/`predecessors_lookup` state machine.
132 enum Call {
133     UseVar(Inst),
134     FinishPredecessorsLookup(Value, Block),
135 }
136 
137 /// Emit instructions to produce a zero value in the given type.
emit_zero(ty: Type, mut cur: FuncCursor) -> Value138 fn emit_zero(ty: Type, mut cur: FuncCursor) -> Value {
139     match ty {
140         I128 => {
141             let zero = cur.ins().iconst(I64, 0);
142             cur.ins().uextend(I128, zero)
143         }
144         ty if ty.is_int() => cur.ins().iconst(ty, 0),
145         F16 => cur.ins().f16const(Ieee16::with_bits(0)),
146         F32 => cur.ins().f32const(Ieee32::with_bits(0)),
147         F64 => cur.ins().f64const(Ieee64::with_bits(0)),
148         F128 => {
149             let zero = cur.func.dfg.constants.insert(Ieee128::with_bits(0).into());
150             cur.ins().f128const(zero)
151         }
152         ty if ty.is_vector() => match ty.lane_type() {
153             scalar_ty if scalar_ty.is_int() => {
154                 let zero = cur
155                     .func
156                     .dfg
157                     .constants
158                     .insert(vec![0; ty.bytes().try_into().unwrap()].into());
159                 cur.ins().vconst(ty, zero)
160             }
161             F16 => {
162                 let scalar = cur.ins().f16const(Ieee16::with_bits(0));
163                 cur.ins().splat(ty, scalar)
164             }
165             F32 => {
166                 let scalar = cur.ins().f32const(Ieee32::with_bits(0));
167                 cur.ins().splat(ty, scalar)
168             }
169             F64 => {
170                 let scalar = cur.ins().f64const(Ieee64::with_bits(0));
171                 cur.ins().splat(ty, scalar)
172             }
173             F128 => {
174                 let zero = cur.func.dfg.constants.insert(Ieee128::with_bits(0).into());
175                 let scalar = cur.ins().f128const(zero);
176                 cur.ins().splat(ty, scalar)
177             }
178             _ => panic!("unimplemented scalar type: {ty:?}"),
179         },
180         ty => panic!("unimplemented type: {ty:?}"),
181     }
182 }
183 
184 /// The following methods are the API of the SSA builder. Here is how it should be used when
185 /// translating to Cranelift IR:
186 ///
187 /// - for each basic block, create a corresponding data for SSA construction with `declare_block`;
188 ///
189 /// - while traversing a basic block and translating instruction, use `def_var` and `use_var`
190 ///   to record definitions and uses of variables, these methods will give you the corresponding
191 ///   SSA values;
192 ///
193 /// - when all the instructions in a basic block have translated, the block is said _filled_ and
194 ///   only then you can add it as a predecessor to other blocks with `declare_block_predecessor`;
195 ///
196 /// - when you have constructed all the predecessor to a basic block,
197 ///   call `seal_block` on it with the `Function` that you are building.
198 ///
199 /// This API will give you the correct SSA values to use as arguments of your instructions,
200 /// as well as modify the jump instruction and `Block` parameters to account for the SSA
201 /// Phi functions.
202 ///
203 impl SSABuilder {
204     /// Get all of the values associated with the given variable that we have
205     /// inserted in the function thus far.
values_for_var(&self, var: Variable) -> impl Iterator<Item = Value> + '_206     pub fn values_for_var(&self, var: Variable) -> impl Iterator<Item = Value> + '_ {
207         self.variables[var].values().filter_map(|v| v.expand())
208     }
209 
210     /// Declares a new definition of a variable in a given basic block.
211     /// The SSA value is passed as an argument because it should be created with
212     /// `ir::DataFlowGraph::append_result`.
def_var(&mut self, var: Variable, val: Value, block: Block)213     pub fn def_var(&mut self, var: Variable, val: Value, block: Block) {
214         self.variables[var][block] = PackedOption::from(val);
215     }
216 
217     /// Declares a use of a variable in a given basic block. Returns the SSA value corresponding
218     /// to the current SSA definition of this variable and a list of newly created Blocks that
219     /// are the results of critical edge splitting for `br_table` with arguments.
220     ///
221     /// If the variable has never been defined in this blocks or recursively in its predecessors,
222     /// this method will silently create an initializer with `iconst` or `fconst`. You are
223     /// responsible for making sure that you initialize your variables.
use_var( &mut self, func: &mut Function, var: Variable, ty: Type, block: Block, ) -> (Value, SideEffects)224     pub fn use_var(
225         &mut self,
226         func: &mut Function,
227         var: Variable,
228         ty: Type,
229         block: Block,
230     ) -> (Value, SideEffects) {
231         debug_assert!(self.calls.is_empty());
232         debug_assert!(self.results.is_empty());
233         debug_assert!(self.side_effects.is_empty());
234 
235         // Prepare the 'calls' and 'results' stacks for the state machine.
236         self.use_var_nonlocal(func, var, ty, block);
237         let value = self.run_state_machine(func, var, ty);
238 
239         let side_effects = mem::take(&mut self.side_effects);
240         (value, side_effects)
241     }
242 
243     /// Resolve the minimal SSA Value of `var` in `block` by traversing predecessors.
244     ///
245     /// This function sets up state for `run_state_machine()` but does not execute it.
use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block)246     fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block) {
247         // First, try Local Value Numbering (Algorithm 1 in the paper).
248         // If the variable already has a known Value in this block, use that.
249         if let Some(val) = self.variables[var][block].expand() {
250             self.results.push(val);
251             return;
252         }
253 
254         // Otherwise, use Global Value Numbering (Algorithm 2 in the paper).
255         // This resolves the Value with respect to its predecessors.
256         // Find the most recent definition of `var`, and the block the definition comes from.
257         let (val, from) = self.find_var(func, var, ty, block);
258 
259         // The `from` block returned from `find_var` is guaranteed to be on the path we follow by
260         // traversing only single-predecessor edges. It might be equal to `block` if there is no
261         // such path, but in that case `find_var` ensures that the variable is defined in this block
262         // by a new block parameter. It also might be somewhere in a cycle, but even then this loop
263         // will terminate the first time it encounters that block, rather than continuing around the
264         // cycle forever.
265         //
266         // Why is it okay to copy the definition to all intervening blocks? For the initial block,
267         // this may not be the final definition of this variable within this block, but if we've
268         // gotten here then we know there is no earlier definition in the block already.
269         //
270         // For the remaining blocks: Recall that a block is only allowed to be set as a predecessor
271         // after all its instructions have already been filled in, so when we follow a predecessor
272         // edge to a block, we know there will never be any more local variable definitions added to
273         // that block. We also know that `find_var` didn't find a definition for this variable in
274         // any of the blocks before `from`.
275         //
276         // So in either case there is no definition in these blocks yet and we can blindly set one.
277         let var_defs = &mut self.variables[var];
278         while block != from {
279             debug_assert!(var_defs[block].is_none());
280             var_defs[block] = PackedOption::from(val);
281             block = self.ssa_blocks[block].single_predecessor.unwrap();
282         }
283     }
284 
285     /// Find the most recent definition of this variable, returning both the definition and the
286     /// block in which it was found. If we can't find a definition that's provably the right one for
287     /// all paths to the current block, then append a block parameter to some block and use that as
288     /// the definition. Either way, also arrange that the definition will be on the `results` stack
289     /// when `run_state_machine` is done processing the current step.
290     ///
291     /// If a block has exactly one predecessor, and the block is sealed so we know its predecessors
292     /// will never change, then its definition for this variable is the same as the definition from
293     /// that one predecessor. In this case it's easy to see that no block parameter is necessary,
294     /// but we need to look at the predecessor to see if a block parameter might be needed there.
295     /// That holds transitively across any chain of sealed blocks with exactly one predecessor each.
296     ///
297     /// This runs into a problem, though, if such a chain has a cycle: Blindly following a cyclic
298     /// chain that never defines this variable would lead to an infinite loop in the compiler. It
299     /// doesn't really matter what code we generate in that case. Since each block in the cycle has
300     /// exactly one predecessor, there's no way to enter the cycle from the function's entry block;
301     /// and since all blocks in the cycle are sealed, the entire cycle is permanently dead code. But
302     /// we still have to prevent the possibility of an infinite loop.
303     ///
304     /// To break cycles, we can pick any block within the cycle as the one where we'll add a block
305     /// parameter. It's convenient to pick the block at which we entered the cycle, because that's
306     /// the first place where we can detect that we just followed a cycle. Adding a block parameter
307     /// gives us a definition we can reuse throughout the rest of the cycle.
find_var( &mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block, ) -> (Value, Block)308     fn find_var(
309         &mut self,
310         func: &mut Function,
311         var: Variable,
312         ty: Type,
313         mut block: Block,
314     ) -> (Value, Block) {
315         // Try to find an existing definition along single-predecessor edges first.
316         self.visited.clear();
317         let var_defs = &mut self.variables[var];
318         while let Some(pred) = self.ssa_blocks[block].single_predecessor.expand() {
319             if !self.visited.insert(block) {
320                 break;
321             }
322             block = pred;
323             if let Some(val) = var_defs[block].expand() {
324                 self.results.push(val);
325                 return (val, block);
326             }
327         }
328 
329         // We've promised to return the most recent block where `var` was defined, but we didn't
330         // find a usable definition. So create one.
331         let val = func.dfg.append_block_param(block, ty);
332         var_defs[block] = PackedOption::from(val);
333 
334         // Now every predecessor needs to pass its definition of this variable to the newly added
335         // block parameter. To do that we have to "recursively" call `use_var`, but there are two
336         // problems with doing that. First, we need to keep a fixed bound on stack depth, so we
337         // can't actually recurse; instead we defer to `run_state_machine`. Second, if we don't
338         // know all our predecessors yet, we have to defer this work until the block gets sealed.
339         match &mut self.ssa_blocks[block].sealed {
340             // Once all the `calls` added here complete, this leaves either `val` or an equivalent
341             // definition on the `results` stack.
342             Sealed::Yes => self.begin_predecessors_lookup(val, block),
343             Sealed::No { undef_variables } => {
344                 undef_variables.push(var, &mut self.variable_pool);
345                 self.results.push(val);
346             }
347         }
348         (val, block)
349     }
350 
351     /// Declares a new basic block to construct corresponding data for SSA construction.
352     /// No predecessors are declared here and the block is not sealed.
353     /// Predecessors have to be added with `declare_block_predecessor`.
declare_block(&mut self, block: Block)354     pub fn declare_block(&mut self, block: Block) {
355         // Ensure the block exists so seal_all_blocks will see it even if no predecessors or
356         // variables get declared for this block. But don't assign anything to it:
357         // SecondaryMap automatically sets all blocks to `default()`.
358         let _ = &mut self.ssa_blocks[block];
359     }
360 
361     /// Declares a new predecessor for a `Block` and record the branch instruction
362     /// of the predecessor that leads to it.
363     ///
364     /// The precedent `Block` must be filled before added as predecessor.
365     /// Note that you must provide no jump arguments to the branch
366     /// instruction when you create it since `SSABuilder` will fill them for you.
367     ///
368     /// Callers are expected to avoid adding the same predecessor more than once in the case
369     /// of a jump table.
declare_block_predecessor(&mut self, block: Block, inst: Inst)370     pub fn declare_block_predecessor(&mut self, block: Block, inst: Inst) {
371         debug_assert!(!self.is_sealed(block));
372         self.ssa_blocks[block]
373             .predecessors
374             .push(inst, &mut self.inst_pool);
375     }
376 
377     /// Remove a previously declared Block predecessor by giving a reference to the jump
378     /// instruction. Returns the basic block containing the instruction.
379     ///
380     /// Note: use only when you know what you are doing, this might break the SSA building problem
remove_block_predecessor(&mut self, block: Block, inst: Inst)381     pub fn remove_block_predecessor(&mut self, block: Block, inst: Inst) {
382         debug_assert!(!self.is_sealed(block));
383         let data = &mut self.ssa_blocks[block];
384         let pred = data
385             .predecessors
386             .as_slice(&self.inst_pool)
387             .iter()
388             .position(|&branch| branch == inst)
389             .expect("the predecessor you are trying to remove is not declared");
390         data.predecessors.swap_remove(pred, &mut self.inst_pool);
391     }
392 
393     /// Completes the global value numbering for a `Block`, all of its predecessors having been
394     /// already sealed.
395     ///
396     /// This method modifies the function's `Layout` by adding arguments to the `Block`s to
397     /// take into account the Phi function placed by the SSA algorithm.
398     ///
399     /// Returns the list of newly created blocks for critical edge splitting.
seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects400     pub fn seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects {
401         debug_assert!(
402             !self.is_sealed(block),
403             "Attempting to seal {block} which is already sealed."
404         );
405         self.seal_one_block(block, func);
406         mem::take(&mut self.side_effects)
407     }
408 
409     /// Completes the global value numbering for all unsealed `Block`s in `func`.
410     ///
411     /// It's more efficient to seal `Block`s as soon as possible, during
412     /// translation, but for frontends where this is impractical to do, this
413     /// function can be used at the end of translating all blocks to ensure
414     /// that everything is sealed.
seal_all_blocks(&mut self, func: &mut Function) -> SideEffects415     pub fn seal_all_blocks(&mut self, func: &mut Function) -> SideEffects {
416         // Seal all `Block`s currently in the function. This can entail splitting
417         // and creation of new blocks, however such new blocks are sealed on
418         // the fly, so we don't need to account for them here.
419         for block in self.ssa_blocks.keys() {
420             self.seal_one_block(block, func);
421         }
422         mem::take(&mut self.side_effects)
423     }
424 
425     /// Helper function for `seal_block` and `seal_all_blocks`.
seal_one_block(&mut self, block: Block, func: &mut Function)426     fn seal_one_block(&mut self, block: Block, func: &mut Function) {
427         // For each undef var we look up values in the predecessors and create a block parameter
428         // only if necessary.
429         let mut undef_variables =
430             match mem::replace(&mut self.ssa_blocks[block].sealed, Sealed::Yes) {
431                 Sealed::No { undef_variables } => undef_variables,
432                 Sealed::Yes => return,
433             };
434         let ssa_params = undef_variables.len(&self.variable_pool);
435 
436         let predecessors = self.predecessors(block);
437         if predecessors.len() == 1 {
438             let pred = func.layout.inst_block(predecessors[0]).unwrap();
439             self.ssa_blocks[block].single_predecessor = PackedOption::from(pred);
440         }
441 
442         // Note that begin_predecessors_lookup requires visiting these variables in the same order
443         // that they were defined by find_var, because it appends arguments to the jump instructions
444         // in all the predecessor blocks one variable at a time.
445         for idx in 0..ssa_params {
446             let var = undef_variables.get(idx, &self.variable_pool).unwrap();
447 
448             // We need the temporary Value that was assigned to this Variable. If that Value shows
449             // up as a result from any of our predecessors, then it never got assigned on the loop
450             // through that block. We get the value from the next block param, where it was first
451             // allocated in find_var.
452             let block_params = func.dfg.block_params(block);
453 
454             // On each iteration through this loop, there are (ssa_params - idx) undefined variables
455             // left to process. Previous iterations through the loop may have removed earlier block
456             // parameters, but the last (ssa_params - idx) block parameters always correspond to the
457             // remaining undefined variables. So index from the end of the current block params.
458             let val = block_params[block_params.len() - (ssa_params - idx)];
459 
460             debug_assert!(self.calls.is_empty());
461             debug_assert!(self.results.is_empty());
462             // self.side_effects may be non-empty here so that callers can
463             // accumulate side effects over multiple calls.
464             self.begin_predecessors_lookup(val, block);
465             self.run_state_machine(func, var, func.dfg.value_type(val));
466         }
467 
468         undef_variables.clear(&mut self.variable_pool);
469     }
470 
471     /// Given the local SSA Value of a Variable in a Block, perform a recursive lookup on
472     /// predecessors to determine if it is redundant with another Value earlier in the CFG.
473     ///
474     /// If such a Value exists and is redundant, the local Value is replaced by the
475     /// corresponding non-local Value. If the original Value was a Block parameter,
476     /// the parameter may be removed if redundant. Parameters are placed eagerly by callers
477     /// to avoid infinite loops when looking up a Value for a Block that is in a CFG loop.
478     ///
479     /// Doing this lookup for each Value in each Block preserves SSA form during construction.
480     ///
481     /// ## Arguments
482     ///
483     /// `sentinel` is a dummy Block parameter inserted by `use_var_nonlocal()`.
484     /// Its purpose is to allow detection of CFG cycles while traversing predecessors.
begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block)485     fn begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block) {
486         self.calls
487             .push(Call::FinishPredecessorsLookup(sentinel, dest_block));
488         // Iterate over the predecessors.
489         self.calls.extend(
490             self.ssa_blocks[dest_block]
491                 .predecessors
492                 .as_slice(&self.inst_pool)
493                 .iter()
494                 .rev()
495                 .copied()
496                 .map(Call::UseVar),
497         );
498     }
499 
500     /// Examine the values from the predecessors and compute a result value, creating
501     /// block parameters as needed.
finish_predecessors_lookup( &mut self, func: &mut Function, sentinel: Value, dest_block: Block, ) -> Value502     fn finish_predecessors_lookup(
503         &mut self,
504         func: &mut Function,
505         sentinel: Value,
506         dest_block: Block,
507     ) -> Value {
508         // Determine how many predecessors are yielding unique, non-temporary Values. If a variable
509         // is live and unmodified across several control-flow join points, earlier blocks will
510         // introduce aliases for that variable's definition, so we resolve aliases eagerly here to
511         // ensure that we can tell when the same definition has reached this block via multiple
512         // paths. Doing so also detects cyclic references to the sentinel, which can occur in
513         // unreachable code.
514         let num_predecessors = self.predecessors(dest_block).len();
515         // When this `Drain` is dropped, these elements will get truncated.
516         let results = self.results.drain(self.results.len() - num_predecessors..);
517 
518         let pred_val = {
519             let mut iter = results
520                 .as_slice()
521                 .iter()
522                 .map(|&val| func.dfg.resolve_aliases(val))
523                 .filter(|&val| val != sentinel);
524             if let Some(val) = iter.next() {
525                 // This variable has at least one non-temporary definition. If they're all the same
526                 // value, we can remove the block parameter and reference that value instead.
527                 if iter.all(|other| other == val) {
528                     Some(val)
529                 } else {
530                     None
531                 }
532             } else {
533                 // The variable is used but never defined before. This is an irregularity in the
534                 // code, but rather than throwing an error we silently initialize the variable to
535                 // 0. This will have no effect since this situation happens in unreachable code.
536                 if !func.layout.is_block_inserted(dest_block) {
537                     func.layout.append_block(dest_block);
538                 }
539                 self.side_effects
540                     .instructions_added_to_blocks
541                     .push(dest_block);
542                 let zero = emit_zero(
543                     func.dfg.value_type(sentinel),
544                     FuncCursor::new(func).at_first_insertion_point(dest_block),
545                 );
546                 Some(zero)
547             }
548         };
549 
550         if let Some(pred_val) = pred_val {
551             // Here all the predecessors use a single value to represent our variable
552             // so we don't need to have it as a block argument.
553             // We need to replace all the occurrences of val with pred_val but since
554             // we can't afford a re-writing pass right now we just declare an alias.
555             func.dfg.remove_block_param(sentinel);
556             func.dfg.change_to_alias(sentinel, pred_val);
557             pred_val
558         } else {
559             // There is disagreement in the predecessors on which value to use so we have
560             // to keep the block argument.
561             let mut preds = self.ssa_blocks[dest_block].predecessors;
562             let dfg = &mut func.stencil.dfg;
563             for (idx, &val) in results.as_slice().iter().enumerate() {
564                 let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
565                 let branch = *pred;
566 
567                 let dests = dfg.insts[branch]
568                     .branch_destination_mut(&mut dfg.jump_tables, &mut dfg.exception_tables);
569                 assert!(
570                     !dests.is_empty(),
571                     "you have declared a non-branch instruction as a predecessor to a block!"
572                 );
573                 for block in dests {
574                     if block.block(&dfg.value_lists) == dest_block {
575                         block.append_argument(val, &mut dfg.value_lists);
576                     }
577                 }
578             }
579             sentinel
580         }
581     }
582 
583     /// Returns the list of `Block`s that have been declared as predecessors of the argument.
predecessors(&self, block: Block) -> &[Inst]584     fn predecessors(&self, block: Block) -> &[Inst] {
585         self.ssa_blocks[block]
586             .predecessors
587             .as_slice(&self.inst_pool)
588     }
589 
590     /// Returns whether the given Block has any predecessor or not.
has_any_predecessors(&self, block: Block) -> bool591     pub fn has_any_predecessors(&self, block: Block) -> bool {
592         !self.predecessors(block).is_empty()
593     }
594 
595     /// Returns `true` if and only if `seal_block` has been called on the argument.
is_sealed(&self, block: Block) -> bool596     pub fn is_sealed(&self, block: Block) -> bool {
597         matches!(self.ssa_blocks[block].sealed, Sealed::Yes)
598     }
599 
600     /// The main algorithm is naturally recursive: when there's a `use_var` in a
601     /// block with no corresponding local defs, it recurses and performs a
602     /// `use_var` in each predecessor. To avoid risking running out of callstack
603     /// space, we keep an explicit stack and use a small state machine rather
604     /// than literal recursion.
run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value605     fn run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value {
606         // Process the calls scheduled in `self.calls` until it is empty.
607         while let Some(call) = self.calls.pop() {
608             match call {
609                 Call::UseVar(branch) => {
610                     let block = func.layout.inst_block(branch).unwrap();
611                     self.use_var_nonlocal(func, var, ty, block);
612                 }
613                 Call::FinishPredecessorsLookup(sentinel, dest_block) => {
614                     let val = self.finish_predecessors_lookup(func, sentinel, dest_block);
615                     self.results.push(val);
616                 }
617             }
618         }
619         debug_assert_eq!(self.results.len(), 1);
620         self.results.pop().unwrap()
621     }
622 }
623 
624 #[cfg(test)]
625 mod tests {
626     use crate::Variable;
627     use crate::ssa::SSABuilder;
628     use cranelift_codegen::cursor::{Cursor, FuncCursor};
629     use cranelift_codegen::entity::EntityRef;
630     use cranelift_codegen::ir;
631     use cranelift_codegen::ir::types::*;
632     use cranelift_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode};
633     use cranelift_codegen::settings;
634     use cranelift_codegen::verify_function;
635 
636     #[test]
simple_block()637     fn simple_block() {
638         let mut func = Function::new();
639         let mut ssa = SSABuilder::default();
640         let block0 = func.dfg.make_block();
641         // Here is the pseudo-program we want to translate:
642         // block0:
643         //    x = 1;
644         //    y = 2;
645         //    z = x + y;
646         //    z = x + z;
647 
648         ssa.declare_block(block0);
649         let x_var = Variable::new(0);
650         let x_ssa = {
651             let mut cur = FuncCursor::new(&mut func);
652             cur.insert_block(block0);
653             cur.ins().iconst(I32, 1)
654         };
655         ssa.def_var(x_var, x_ssa, block0);
656         let y_var = Variable::new(1);
657         let y_ssa = {
658             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
659             cur.ins().iconst(I32, 2)
660         };
661         ssa.def_var(y_var, y_ssa, block0);
662         assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
663         assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
664 
665         let z_var = Variable::new(2);
666         let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
667         let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
668         let z1_ssa = {
669             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
670             cur.ins().iadd(x_use1, y_use1)
671         };
672         ssa.def_var(z_var, z1_ssa, block0);
673         assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
674 
675         let x_use2 = ssa.use_var(&mut func, x_var, I32, block0).0;
676         let z_use1 = ssa.use_var(&mut func, z_var, I32, block0).0;
677         let z2_ssa = {
678             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
679             cur.ins().iadd(x_use2, z_use1)
680         };
681         ssa.def_var(z_var, z2_ssa, block0);
682         assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z2_ssa);
683     }
684 
685     #[test]
sequence_of_blocks()686     fn sequence_of_blocks() {
687         let mut func = Function::new();
688         let mut ssa = SSABuilder::default();
689         let block0 = func.dfg.make_block();
690         let block1 = func.dfg.make_block();
691         let block2 = func.dfg.make_block();
692         // Here is the pseudo-program we want to translate:
693         // block0:
694         //    x = 1;
695         //    y = 2;
696         //    z = x + y;
697         //    brif y, block1, block1;
698         // block1:
699         //    z = x + z;
700         //    jump block2;
701         // block2:
702         //    y = x + y;
703         {
704             let mut cur = FuncCursor::new(&mut func);
705             cur.insert_block(block0);
706             cur.insert_block(block1);
707             cur.insert_block(block2);
708         }
709 
710         // block0
711         ssa.declare_block(block0);
712         ssa.seal_block(block0, &mut func);
713         let x_var = Variable::new(0);
714         let x_ssa = {
715             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
716             cur.ins().iconst(I32, 1)
717         };
718         ssa.def_var(x_var, x_ssa, block0);
719         let y_var = Variable::new(1);
720         let y_ssa = {
721             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
722             cur.ins().iconst(I32, 2)
723         };
724         ssa.def_var(y_var, y_ssa, block0);
725         let z_var = Variable::new(2);
726         let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
727         let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
728         let z1_ssa = {
729             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
730             cur.ins().iadd(x_use1, y_use1)
731         };
732         ssa.def_var(z_var, z1_ssa, block0);
733         let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0;
734         let brif_block0_block2_block1: Inst = {
735             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
736             cur.ins().brif(y_use2, block2, &[], block1, &[])
737         };
738 
739         assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
740         assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
741         assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
742 
743         // block1
744         ssa.declare_block(block1);
745         ssa.declare_block_predecessor(block1, brif_block0_block2_block1);
746         ssa.seal_block(block1, &mut func);
747 
748         let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0;
749         let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0;
750         let z2_ssa = {
751             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
752             cur.ins().iadd(x_use2, z_use1)
753         };
754         ssa.def_var(z_var, z2_ssa, block1);
755         let jump_block1_block2: Inst = {
756             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
757             cur.ins().jump(block2, &[])
758         };
759 
760         assert_eq!(x_use2, x_ssa);
761         assert_eq!(z_use1, z1_ssa);
762         assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa);
763 
764         // block2
765         ssa.declare_block(block2);
766         ssa.declare_block_predecessor(block2, brif_block0_block2_block1);
767         ssa.declare_block_predecessor(block2, jump_block1_block2);
768         ssa.seal_block(block2, &mut func);
769         let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0;
770         let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0;
771         let y2_ssa = {
772             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
773             cur.ins().iadd(x_use3, y_use3)
774         };
775         ssa.def_var(y_var, y2_ssa, block2);
776 
777         assert_eq!(x_ssa, x_use3);
778         assert_eq!(y_ssa, y_use3);
779         match func.dfg.insts[brif_block0_block2_block1] {
780             ir::InstructionData::Brif {
781                 blocks: [block_then, block_else],
782                 ..
783             } => {
784                 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
785                 assert_eq!(block_then.args(&func.dfg.value_lists).len(), 0);
786                 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
787                 assert_eq!(block_else.args(&func.dfg.value_lists).len(), 0);
788             }
789             _ => assert!(false),
790         };
791         match func.dfg.insts[brif_block0_block2_block1] {
792             ir::InstructionData::Brif {
793                 blocks: [block_then, block_else],
794                 ..
795             } => {
796                 assert_eq!(block_then.block(&func.dfg.value_lists), block2);
797                 assert_eq!(block_then.args(&func.dfg.value_lists).len(), 0);
798                 assert_eq!(block_else.block(&func.dfg.value_lists), block1);
799                 assert_eq!(block_else.args(&func.dfg.value_lists).len(), 0);
800             }
801             _ => assert!(false),
802         };
803         match func.dfg.insts[jump_block1_block2] {
804             ir::InstructionData::Jump {
805                 destination: dest, ..
806             } => {
807                 assert_eq!(dest.block(&func.dfg.value_lists), block2);
808                 assert_eq!(dest.args(&func.dfg.value_lists).len(), 0);
809             }
810             _ => assert!(false),
811         };
812     }
813 
814     #[test]
program_with_loop()815     fn program_with_loop() {
816         let mut func = Function::new();
817         let mut ssa = SSABuilder::default();
818         let block0 = func.dfg.make_block();
819         let block1 = func.dfg.make_block();
820         let block2 = func.dfg.make_block();
821         let block3 = func.dfg.make_block();
822         {
823             let mut cur = FuncCursor::new(&mut func);
824             cur.insert_block(block0);
825             cur.insert_block(block1);
826             cur.insert_block(block2);
827             cur.insert_block(block3);
828         }
829         // Here is the pseudo-program we want to translate:
830         // block0:
831         //    x = 1;
832         //    y = 2;
833         //    z = x + y;
834         //    jump block1
835         // block1:
836         //    z = z + y;
837         //    brif y, block3, block2;
838         // block2:
839         //    z = z - x;
840         //    return y
841         // block3:
842         //    y = y - x
843         //    jump block1
844 
845         // block0
846         ssa.declare_block(block0);
847         ssa.seal_block(block0, &mut func);
848         let x_var = Variable::new(0);
849         let x1 = {
850             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
851             cur.ins().iconst(I32, 1)
852         };
853         ssa.def_var(x_var, x1, block0);
854         let y_var = Variable::new(1);
855         let y1 = {
856             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
857             cur.ins().iconst(I32, 2)
858         };
859         ssa.def_var(y_var, y1, block0);
860         let z_var = Variable::new(2);
861         let x2 = ssa.use_var(&mut func, x_var, I32, block0).0;
862         let y2 = ssa.use_var(&mut func, y_var, I32, block0).0;
863         let z1 = {
864             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
865             cur.ins().iadd(x2, y2)
866         };
867         ssa.def_var(z_var, z1, block0);
868         let jump_block0_block1 = {
869             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
870             cur.ins().jump(block1, &[])
871         };
872         assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1);
873         assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1);
874         assert_eq!(x2, x1);
875         assert_eq!(y2, y1);
876 
877         // block1
878         ssa.declare_block(block1);
879         ssa.declare_block_predecessor(block1, jump_block0_block1);
880         let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
881         let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
882         let z3 = {
883             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
884             cur.ins().iadd(z2, y3)
885         };
886         ssa.def_var(z_var, z3, block1);
887         let y4 = ssa.use_var(&mut func, y_var, I32, block1).0;
888         assert_eq!(y4, y3);
889         let brif_block1_block3_block2 = {
890             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
891             cur.ins().brif(y4, block3, &[], block2, &[])
892         };
893 
894         // block2
895         ssa.declare_block(block2);
896         ssa.declare_block_predecessor(block2, brif_block1_block3_block2);
897         ssa.seal_block(block2, &mut func);
898         let z4 = ssa.use_var(&mut func, z_var, I32, block2).0;
899         assert_eq!(z4, z3);
900         let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
901         let z5 = {
902             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
903             cur.ins().isub(z4, x3)
904         };
905         ssa.def_var(z_var, z5, block2);
906         let y5 = ssa.use_var(&mut func, y_var, I32, block2).0;
907         assert_eq!(y5, y3);
908         {
909             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
910             cur.ins().return_(&[y5])
911         };
912 
913         // block3
914         ssa.declare_block(block3);
915         ssa.declare_block_predecessor(block3, brif_block1_block3_block2);
916         ssa.seal_block(block3, &mut func);
917         let y6 = ssa.use_var(&mut func, y_var, I32, block3).0;
918         assert_eq!(y6, y3);
919         let x4 = ssa.use_var(&mut func, x_var, I32, block3).0;
920         assert_eq!(x4, x3);
921         let y7 = {
922             let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
923             cur.ins().isub(y6, x4)
924         };
925         ssa.def_var(y_var, y7, block3);
926         let jump_block3_block1 = {
927             let mut cur = FuncCursor::new(&mut func).at_bottom(block3);
928             cur.ins().jump(block1, &[])
929         };
930 
931         // block1 after all predecessors have been visited.
932         ssa.declare_block_predecessor(block1, jump_block3_block1);
933         ssa.seal_block(block1, &mut func);
934         assert_eq!(func.dfg.block_params(block1)[0], z2);
935         assert_eq!(func.dfg.block_params(block1)[1], y3);
936         assert_eq!(func.dfg.resolve_aliases(x3), x1);
937     }
938 
939     #[test]
br_table_with_args()940     fn br_table_with_args() {
941         // This tests the on-demand splitting of critical edges for br_table with jump arguments
942         //
943         // Here is the pseudo-program we want to translate:
944         //
945         // function %f {
946         // block0:
947         //    x = 1;
948         //    br_table x, block2, [block2, block1]
949         // block1:
950         //    x = 2
951         //    jump block2
952         // block2:
953         //    x = x + 1
954         //    return
955         // }
956 
957         let mut func = Function::new();
958         let mut ssa = SSABuilder::default();
959         let block0 = func.dfg.make_block();
960         let block1 = func.dfg.make_block();
961         let block2 = func.dfg.make_block();
962         {
963             let mut cur = FuncCursor::new(&mut func);
964             cur.insert_block(block0);
965             cur.insert_block(block1);
966             cur.insert_block(block2);
967         }
968 
969         // block0
970         let x1 = {
971             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
972             cur.ins().iconst(I32, 1)
973         };
974         ssa.declare_block(block0);
975         ssa.seal_block(block0, &mut func);
976         let x_var = Variable::new(0);
977         ssa.def_var(x_var, x1, block0);
978         ssa.use_var(&mut func, x_var, I32, block0).0;
979         let br_table = {
980             let jump_table = JumpTableData::new(
981                 func.dfg.block_call(block2, &[]),
982                 &[
983                     func.dfg.block_call(block2, &[]),
984                     func.dfg.block_call(block1, &[]),
985                 ],
986             );
987             let jt = func.create_jump_table(jump_table);
988             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
989             cur.ins().br_table(x1, jt)
990         };
991 
992         // block1
993         ssa.declare_block(block1);
994         ssa.declare_block_predecessor(block1, br_table);
995         ssa.seal_block(block1, &mut func);
996         let x2 = {
997             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
998             cur.ins().iconst(I32, 2)
999         };
1000         ssa.def_var(x_var, x2, block1);
1001         let jump_block1_block2 = {
1002             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1003             cur.ins().jump(block2, &[])
1004         };
1005 
1006         // block2
1007         ssa.declare_block(block2);
1008         ssa.declare_block_predecessor(block2, jump_block1_block2);
1009         ssa.declare_block_predecessor(block2, br_table);
1010         ssa.seal_block(block2, &mut func);
1011         let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
1012         let x4 = {
1013             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1014             cur.ins().iadd_imm(x3, 1)
1015         };
1016         ssa.def_var(x_var, x4, block2);
1017         {
1018             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1019             cur.ins().return_(&[])
1020         };
1021 
1022         let flags = settings::Flags::new(settings::builder());
1023         match verify_function(&func, &flags) {
1024             Ok(()) => {}
1025             Err(_errors) => {
1026                 #[cfg(feature = "std")]
1027                 panic!("{}", _errors);
1028                 #[cfg(not(feature = "std"))]
1029                 panic!("function failed to verify");
1030             }
1031         }
1032     }
1033 
1034     #[test]
undef_values_reordering()1035     fn undef_values_reordering() {
1036         // Here is the pseudo-program we want to translate:
1037         // block0:
1038         //    x = 0;
1039         //    y = 1;
1040         //    z = 2;
1041         //    jump block1;
1042         // block1:
1043         //    x = z + x;
1044         //    y = y - x;
1045         //    jump block1;
1046         //
1047         let mut func = Function::new();
1048         let mut ssa = SSABuilder::default();
1049         let block0 = func.dfg.make_block();
1050         let block1 = func.dfg.make_block();
1051         {
1052             let mut cur = FuncCursor::new(&mut func);
1053             cur.insert_block(block0);
1054             cur.insert_block(block1);
1055         }
1056 
1057         // block0
1058         ssa.declare_block(block0);
1059         let x_var = Variable::new(0);
1060         ssa.seal_block(block0, &mut func);
1061         let x1 = {
1062             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1063             cur.ins().iconst(I32, 0)
1064         };
1065         ssa.def_var(x_var, x1, block0);
1066         let y_var = Variable::new(1);
1067         let y1 = {
1068             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1069             cur.ins().iconst(I32, 1)
1070         };
1071         ssa.def_var(y_var, y1, block0);
1072         let z_var = Variable::new(2);
1073         let z1 = {
1074             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1075             cur.ins().iconst(I32, 2)
1076         };
1077         ssa.def_var(z_var, z1, block0);
1078         let jump_block0_block1 = {
1079             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1080             cur.ins().jump(block1, &[])
1081         };
1082 
1083         // block1
1084         ssa.declare_block(block1);
1085         ssa.declare_block_predecessor(block1, jump_block0_block1);
1086         let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
1087         assert_eq!(func.dfg.block_params(block1)[0], z2);
1088         let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
1089         assert_eq!(func.dfg.block_params(block1)[1], x2);
1090         let x3 = {
1091             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1092             cur.ins().iadd(x2, z2)
1093         };
1094         ssa.def_var(x_var, x3, block1);
1095         let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
1096         let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
1097         assert_eq!(func.dfg.block_params(block1)[2], y3);
1098         let y4 = {
1099             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1100             cur.ins().isub(y3, x4)
1101         };
1102         ssa.def_var(y_var, y4, block1);
1103         let jump_block1_block1 = {
1104             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1105             cur.ins().jump(block1, &[])
1106         };
1107         ssa.declare_block_predecessor(block1, jump_block1_block1);
1108         ssa.seal_block(block1, &mut func);
1109         // At sealing the "z" argument disappear but the remaining "x" and "y" args have to be
1110         // in the right order.
1111         assert_eq!(func.dfg.block_params(block1)[1], y3);
1112         assert_eq!(func.dfg.block_params(block1)[0], x2);
1113     }
1114 
1115     #[test]
undef()1116     fn undef() {
1117         // Use vars of various types which have not been defined.
1118         let mut func = Function::new();
1119         let mut ssa = SSABuilder::default();
1120         let block0 = func.dfg.make_block();
1121         ssa.declare_block(block0);
1122         ssa.seal_block(block0, &mut func);
1123         let i32_var = Variable::new(0);
1124         let f32_var = Variable::new(1);
1125         let f64_var = Variable::new(2);
1126         let i8_var = Variable::new(3);
1127         let f32x4_var = Variable::new(4);
1128         ssa.use_var(&mut func, i32_var, I32, block0);
1129         ssa.use_var(&mut func, f32_var, F32, block0);
1130         ssa.use_var(&mut func, f64_var, F64, block0);
1131         ssa.use_var(&mut func, i8_var, I8, block0);
1132         ssa.use_var(&mut func, f32x4_var, F32X4, block0);
1133         assert_eq!(func.dfg.num_block_params(block0), 0);
1134     }
1135 
1136     #[test]
undef_in_entry()1137     fn undef_in_entry() {
1138         // Use a var which has not been defined. The search should hit the
1139         // top of the entry block, and then fall back to inserting an iconst.
1140         let mut func = Function::new();
1141         let mut ssa = SSABuilder::default();
1142         let block0 = func.dfg.make_block();
1143         ssa.declare_block(block0);
1144         ssa.seal_block(block0, &mut func);
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), 0);
1149         assert_eq!(
1150             func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1151             Opcode::Iconst
1152         );
1153     }
1154 
1155     #[test]
undef_in_entry_sealed_after()1156     fn undef_in_entry_sealed_after() {
1157         // Use a var which has not been defined, but the block is not sealed
1158         // until afterward. Before sealing, the SSA builder should insert an
1159         // block param; after sealing, it should be removed.
1160         let mut func = Function::new();
1161         let mut ssa = SSABuilder::default();
1162         let block0 = func.dfg.make_block();
1163         ssa.declare_block(block0);
1164         let x_var = Variable::new(0);
1165         assert_eq!(func.dfg.num_block_params(block0), 0);
1166         ssa.use_var(&mut func, x_var, I32, block0);
1167         assert_eq!(func.dfg.num_block_params(block0), 1);
1168         ssa.seal_block(block0, &mut func);
1169         assert_eq!(func.dfg.num_block_params(block0), 0);
1170         assert_eq!(
1171             func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
1172             Opcode::Iconst
1173         );
1174     }
1175 
1176     #[test]
unreachable_use()1177     fn unreachable_use() {
1178         // Here is the pseudo-program we want to translate:
1179         // block0:
1180         //    return;
1181         // block1:
1182         //    brif x, block1, block1;
1183         let mut func = Function::new();
1184         let mut ssa = SSABuilder::default();
1185         let block0 = func.dfg.make_block();
1186         let block1 = func.dfg.make_block();
1187         {
1188             let mut cur = FuncCursor::new(&mut func);
1189             cur.insert_block(block0);
1190             cur.insert_block(block1);
1191         }
1192 
1193         // block0
1194         ssa.declare_block(block0);
1195         ssa.seal_block(block0, &mut func);
1196         {
1197             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1198             cur.ins().return_(&[]);
1199         }
1200 
1201         // block1
1202         ssa.declare_block(block1);
1203         {
1204             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1205             let x_var = Variable::new(0);
1206             let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1207             let brif = cur.ins().brif(x_val, block1, &[], block1, &[]);
1208             ssa.declare_block_predecessor(block1, brif);
1209         }
1210         ssa.seal_block(block1, &mut func);
1211 
1212         let flags = settings::Flags::new(settings::builder());
1213         match verify_function(&func, &flags) {
1214             Ok(()) => {}
1215             Err(_errors) => {
1216                 #[cfg(feature = "std")]
1217                 panic!("{}", _errors);
1218                 #[cfg(not(feature = "std"))]
1219                 panic!("function failed to verify");
1220             }
1221         }
1222     }
1223 
1224     #[test]
unreachable_use_with_multiple_preds()1225     fn unreachable_use_with_multiple_preds() {
1226         // Here is the pseudo-program we want to translate:
1227         // block0:
1228         //    return;
1229         // block1:
1230         //    brif x, block1, block2;
1231         // block2:
1232         //    jump block1;
1233         let mut func = Function::new();
1234         let mut ssa = SSABuilder::default();
1235         let block0 = func.dfg.make_block();
1236         let block1 = func.dfg.make_block();
1237         let block2 = func.dfg.make_block();
1238         {
1239             let mut cur = FuncCursor::new(&mut func);
1240             cur.insert_block(block0);
1241             cur.insert_block(block1);
1242             cur.insert_block(block2);
1243         }
1244 
1245         // block0
1246         ssa.declare_block(block0);
1247         ssa.seal_block(block0, &mut func);
1248         {
1249             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1250             cur.ins().return_(&[]);
1251         }
1252 
1253         // block1
1254         ssa.declare_block(block1);
1255         let brif = {
1256             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1257             let x_var = Variable::new(0);
1258             let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0;
1259             cur.ins().brif(x_val, block2, &[], block1, &[])
1260         };
1261 
1262         // block2
1263         ssa.declare_block(block2);
1264         ssa.declare_block_predecessor(block1, brif);
1265         ssa.declare_block_predecessor(block2, brif);
1266         ssa.seal_block(block2, &mut func);
1267         let jump_block2_block1 = {
1268             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1269             cur.ins().jump(block1, &[])
1270         };
1271 
1272         // seal block1
1273         ssa.declare_block_predecessor(block1, jump_block2_block1);
1274         ssa.seal_block(block1, &mut func);
1275         let flags = settings::Flags::new(settings::builder());
1276         match verify_function(&func, &flags) {
1277             Ok(()) => {}
1278             Err(_errors) => {
1279                 #[cfg(feature = "std")]
1280                 panic!("{}", _errors);
1281                 #[cfg(not(feature = "std"))]
1282                 panic!("function failed to verify");
1283             }
1284         }
1285     }
1286 
1287     #[test]
reassign_with_predecessor_loop_hangs()1288     fn reassign_with_predecessor_loop_hangs() {
1289         // Here is the pseudo-program we want to translate:
1290         // block0:
1291         //    var0 = iconst 0
1292         //    return;
1293         // block1:
1294         //    jump block2;
1295         // block2:
1296         //    ; phantom use of var0
1297         //    var0 = iconst 1
1298         //    jump block1;
1299 
1300         let mut func = Function::new();
1301         let mut ssa = SSABuilder::default();
1302         let block0 = func.dfg.make_block();
1303         let block1 = func.dfg.make_block();
1304         let block2 = func.dfg.make_block();
1305         let var0 = Variable::new(0);
1306 
1307         {
1308             let mut cur = FuncCursor::new(&mut func);
1309             for block in [block0, block1, block2] {
1310                 cur.insert_block(block);
1311                 ssa.declare_block(block);
1312             }
1313         }
1314 
1315         // block0
1316         {
1317             let mut cur = FuncCursor::new(&mut func).at_bottom(block0);
1318 
1319             let var0_iconst = cur.ins().iconst(I32, 0);
1320             ssa.def_var(var0, var0_iconst, block0);
1321 
1322             cur.ins().return_(&[]);
1323         }
1324 
1325         // block1
1326         {
1327             let mut cur = FuncCursor::new(&mut func).at_bottom(block1);
1328 
1329             let jump = cur.ins().jump(block2, &[]);
1330             ssa.declare_block_predecessor(block2, jump);
1331         }
1332 
1333         // block2
1334         {
1335             let mut cur = FuncCursor::new(&mut func).at_bottom(block2);
1336 
1337             let _ = ssa.use_var(&mut cur.func, var0, I32, block2).0;
1338             let var0_iconst = cur.ins().iconst(I32, 1);
1339             ssa.def_var(var0, var0_iconst, block2);
1340 
1341             let jump = cur.ins().jump(block1, &[]);
1342             ssa.declare_block_predecessor(block1, jump);
1343         }
1344 
1345         // The sealing algorithm would enter a infinite loop here
1346         ssa.seal_all_blocks(&mut func);
1347     }
1348 }
1349