cranelift_frontend/
ssa.rs

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