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