Skip to main content

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