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::{Ieee16, Ieee32, Ieee64, Ieee128};
16use cranelift_codegen::ir::types::{F16, F32, F64, F128, I64, I128};
17use cranelift_codegen::ir::{Block, Function, Inst, InstBuilder, Type, Value};
18use cranelift_codegen::packed_option::PackedOption;
19
20/// 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        let Self {
75            instructions_added_to_blocks,
76        } = self;
77        instructions_added_to_blocks.is_empty()
78    }
79}
80
81#[derive(Clone)]
82enum 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
90impl Default for Sealed {
91    fn default() -> Self {
92        Sealed::No {
93            undef_variables: EntityList::new(),
94        }
95    }
96}
97
98#[derive(Clone, Default)]
99struct 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
108impl SSABuilder {
109    /// Clears a `SSABuilder` from all its data, letting it in a pristine state without
110    /// deallocating memory.
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.
122    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.
132enum Call {
133    UseVar(Inst),
134    FinishPredecessorsLookup(Value, Block),
135}
136
137/// Emit instructions to produce a zero value in the given type.
138fn 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///
203impl SSABuilder {
204    /// Get all of the values associated with the given variable that we have
205    /// inserted in the function thus far.
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`.
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.
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.
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.
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`.
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.
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
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.
400    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.
415    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`.
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.
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.
502    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.
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.
591    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.
596    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.
605    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)]
625mod 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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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}