wasmer_compiler_cranelift/translator/
code_translator.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! This module contains the bulk of the interesting code performing the translation between
5//! WebAssembly bytecode and Cranelift IR.
6//!
7//! The translation is done in one pass, opcode by opcode. Two main data structures are used during
8//! code translations: the value stack and the control stack. The value stack mimics the execution
9//! of the WebAssembly stack machine: each instruction result is pushed onto the stack and
10//! instruction arguments are popped off the stack. Similarly, when encountering a control flow
11//! block, it is pushed onto the control stack and popped off when encountering the corresponding
12//! `End`.
13//!
14//! Another data structure, the translation state, records information concerning unreachable code
15//! status and about if inserting a return at the end of the function is necessary.
16//!
17//! Some of the WebAssembly instructions need information about the environment for which they
18//! are being translated:
19//!
20//! - the loads and stores need the memory base address;
21//! - the `get_global` and `set_global` instructions depend on how the globals are implemented;
22//! - `memory.size` and `memory.grow` are runtime functions;
23//! - `call_indirect` has to translate the function index into the address of where this
24//!   is;
25//!
26//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
27//! argument.
28//!
29//! There is extra complexity associated with translation of 128-bit SIMD instructions.
30//! Wasm only considers there to be a single 128-bit vector type.  But CLIF's type system
31//! distinguishes different lane configurations, so considers 8X16, 16X8, 32X4 and 64X2 to be
32//! different types.  The result is that, in wasm, it's perfectly OK to take the output of (eg)
33//! an `add.16x8` and use that as an operand of a `sub.32x4`, without using any cast.  But when
34//! translated into CLIF, that will cause a verifier error due to the apparent type mismatch.
35//!
36//! This file works around that problem by liberally inserting `bitcast` instructions in many
37//! places -- mostly, before the use of vector values, either as arguments to CLIF instructions
38//! or as block actual parameters.  These are no-op casts which nevertheless have different
39//! input and output types, and are used (mostly) to "convert" 16X8, 32X4 and 64X2-typed vectors
40//! to the "canonical" type, 8X16.  Hence the functions `optionally_bitcast_vector`,
41//! `bitcast_arguments`, `pop*_with_bitcast`, `canonicalise_then_jump`,
42//! `canonicalise_then_br{z,nz}`, `is_non_canonical_v128` and `canonicalise_v128_values`.
43//! Note that the `bitcast*` functions are occasionally used to convert to some type other than
44//! 8X16, but the `canonicalise*` functions always convert to type 8X16.
45//!
46//! Be careful when adding support for new vector instructions.  And when adding new jumps, even
47//! if they are apparently don't have any connection to vectors.  Never generate any kind of
48//! (inter-block) jump directly.  Instead use `canonicalise_then_jump` and
49//! `canonicalise_then_br{z,nz}`.
50//!
51//! The use of bitcasts is ugly and inefficient, but currently unavoidable:
52//!
53//! * they make the logic in this file fragile: miss out a bitcast for any reason, and there is
54//!   the risk of the system failing in the verifier.  At least for debug builds.
55//!
56//! * in the new backends, they potentially interfere with pattern matching on CLIF -- the
57//!   patterns need to take into account the presence of bitcast nodes.
58//!
59//! * in the new backends, they get translated into machine-level vector-register-copy
60//!   instructions, none of which are actually necessary.  We then depend on the register
61//!   allocator to coalesce them all out.
62//!
63//! * they increase the total number of CLIF nodes that have to be processed, hence slowing down
64//!   the compilation pipeline.  Also, the extra coalescing work generates a slowdown.
65//!
66//! A better solution which would avoid all four problems would be to remove the 8X16, 16X8,
67//! 32X4 and 64X2 types from CLIF and instead have a single V128 type.
68//!
69//! For further background see also:
70//!   <https://github.com/bytecodealliance/wasmtime/issues/1147>
71//!     ("Too many raw_bitcasts in SIMD code")
72//!   <https://github.com/bytecodealliance/cranelift/pull/1251>
73//!     ("Add X128 type to represent WebAssembly's V128 type")
74//!   <https://github.com/bytecodealliance/cranelift/pull/1236>
75//!     ("Relax verification to allow I8X16 to act as a default vector type")
76
77mod bounds_checks;
78
79pub(crate) const TAG_TYPE: ir::Type = I32;
80pub(crate) const EXN_REF_TYPE: ir::Type = I32;
81
82use super::func_environ::{FuncEnvironment, GlobalVariable};
83use super::func_state::{ControlStackFrame, ElseData, FuncTranslationState};
84use super::translation_utils::{block_with_params, f32_translation, f64_translation};
85use crate::{HashMap, hash_map};
86use core::convert::TryFrom;
87use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
88use cranelift_codegen::ir::immediates::Offset32;
89use cranelift_codegen::ir::types::*;
90use cranelift_codegen::ir::{
91    self, AtomicRmwOp, BlockArg, ConstantData, InstBuilder, JumpTableData, MemFlags, Value,
92    ValueLabel,
93};
94use cranelift_codegen::packed_option::ReservedValue;
95use cranelift_frontend::{FunctionBuilder, Variable};
96use itertools::Itertools;
97use smallvec::SmallVec;
98use std::vec::Vec;
99
100use wasmer_compiler::wasmparser::{self, Catch, MemArg, Operator};
101use wasmer_compiler::{ModuleTranslationState, from_binaryreadererror_wasmerror, wasm_unsupported};
102use wasmer_types::{
103    CATCH_ALL_TAG_VALUE, FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex,
104    TagIndex, WasmResult,
105};
106
107/// Given a `Reachability<T>`, unwrap the inner `T` or, when unreachable, set
108/// `state.reachable = false` and return.
109///
110/// Used in combination with calling `prepare_addr` and `prepare_atomic_addr`
111/// when we can statically determine that a Wasm access will unconditionally
112/// trap.
113macro_rules! unwrap_or_return_unreachable_state {
114    ($state:ident, $value:expr_2021) => {
115        match $value {
116            Reachability::Reachable(x) => x,
117            Reachability::Unreachable => {
118                $state.reachable = false;
119                return Ok(());
120            }
121        }
122    };
123}
124
125// Clippy warns about "align: _" but its important to document that the align field is ignored
126#[allow(clippy::unneeded_field_pattern, clippy::cognitive_complexity)]
127/// Translates wasm operators into Cranelift IR instructions. Returns `true` if it inserted
128/// a return.
129pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
130    module_translation_state: &ModuleTranslationState,
131    op: &Operator,
132    builder: &mut FunctionBuilder,
133    state: &mut FuncTranslationState,
134    environ: &mut FE,
135) -> WasmResult<()> {
136    if !state.reachable {
137        translate_unreachable_operator(module_translation_state, op, builder, state, environ)?;
138        return Ok(());
139    }
140
141    // This big match treats all Wasm code operators.
142    match op {
143        /********************************** Locals ****************************************
144         *  `get_local` and `set_local` are treated as non-SSA variables and will completely
145         *  disappear in the Cranelift Code
146         ***********************************************************************************/
147        Operator::LocalGet { local_index } => {
148            let val = builder.use_var(Variable::from_u32(*local_index));
149            state.push1(val);
150            let label = ValueLabel::from_u32(*local_index);
151            builder.set_val_label(val, label);
152        }
153        Operator::LocalSet { local_index } => {
154            let mut val = state.pop1();
155
156            // Ensure SIMD values are cast to their default Cranelift type, I8x16.
157            let ty = builder.func.dfg.value_type(val);
158            if ty.is_vector() {
159                val = optionally_bitcast_vector(val, I8X16, builder);
160            }
161
162            builder.def_var(Variable::from_u32(*local_index), val);
163            let label = ValueLabel::from_u32(*local_index);
164            builder.set_val_label(val, label);
165        }
166        Operator::LocalTee { local_index } => {
167            let mut val = state.peek1();
168
169            // Ensure SIMD values are cast to their default Cranelift type, I8x16.
170            let ty = builder.func.dfg.value_type(val);
171            if ty.is_vector() {
172                val = optionally_bitcast_vector(val, I8X16, builder);
173            }
174
175            builder.def_var(Variable::from_u32(*local_index), val);
176            let label = ValueLabel::from_u32(*local_index);
177            builder.set_val_label(val, label);
178        }
179        /********************************** Globals ****************************************
180         *  `get_global` and `set_global` are handled by the environment.
181         ***********************************************************************************/
182        Operator::GlobalGet { global_index } => {
183            let val = match state.get_global(builder.func, *global_index, environ)? {
184                GlobalVariable::Const(val) => val,
185                GlobalVariable::Memory { gv, offset, ty } => {
186                    let addr = builder.ins().global_value(environ.pointer_type(), gv);
187                    let mut flags = ir::MemFlags::trusted();
188                    // Put globals in the "table" abstract heap category as well.
189                    flags.set_alias_region(Some(ir::AliasRegion::Table));
190                    builder.ins().load(ty, flags, addr, offset)
191                }
192                GlobalVariable::Custom => environ.translate_custom_global_get(
193                    builder.cursor(),
194                    GlobalIndex::from_u32(*global_index),
195                )?,
196            };
197            state.push1(val);
198        }
199        Operator::GlobalSet { global_index } => {
200            match state.get_global(builder.func, *global_index, environ)? {
201                GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
202                GlobalVariable::Memory { gv, offset, ty } => {
203                    let addr = builder.ins().global_value(environ.pointer_type(), gv);
204                    let mut flags = ir::MemFlags::trusted();
205                    // Put globals in the "table" abstract heap category as well.
206                    flags.set_alias_region(Some(ir::AliasRegion::Table));
207                    let mut val = state.pop1();
208                    // Ensure SIMD values are cast to their default Cranelift type, I8x16.
209                    if ty.is_vector() {
210                        val = optionally_bitcast_vector(val, I8X16, builder);
211                    }
212                    debug_assert_eq!(ty, builder.func.dfg.value_type(val));
213                    builder.ins().store(flags, val, addr, offset);
214                    environ.update_global(builder, *global_index, val);
215                }
216                GlobalVariable::Custom => {
217                    let val = state.pop1();
218                    environ.translate_custom_global_set(
219                        builder.cursor(),
220                        GlobalIndex::from_u32(*global_index),
221                        val,
222                    )?;
223                }
224            }
225        }
226        /********************************* Stack misc ***************************************
227         *  `drop`, `nop`, `unreachable` and `select`.
228         ***********************************************************************************/
229        Operator::Drop => {
230            state.pop1();
231        }
232        Operator::Select => {
233            // we can ignore metadata because extern ref must use TypedSelect
234            let (mut arg1, mut arg2, cond) = state.pop3();
235            if builder.func.dfg.value_type(arg1).is_vector() {
236                arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
237            }
238            if builder.func.dfg.value_type(arg2).is_vector() {
239                arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
240            }
241            state.push1(builder.ins().select(cond, arg1, arg2));
242        }
243        Operator::TypedSelect { ty: _ } => {
244            // We ignore the explicit type parameter as it is only needed for
245            // validation, which we require to have been performed before
246            // translation.
247            let (mut arg1, mut arg2, cond) = state.pop3();
248            if builder.func.dfg.value_type(arg1).is_vector() {
249                arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
250            }
251            if builder.func.dfg.value_type(arg2).is_vector() {
252                arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
253            }
254            state.push1(builder.ins().select(cond, arg1, arg2));
255        }
256        Operator::Nop => {
257            // We do nothing
258        }
259        Operator::Unreachable => {
260            builder.ins().trap(crate::TRAP_UNREACHABLE);
261            state.reachable = false;
262        }
263        /***************************** Control flow blocks **********************************
264         *  When starting a control flow block, we create a new `Block` that will hold the code
265         *  after the block, and we push a frame on the control stack. Depending on the type
266         *  of block, we create a new `Block` for the body of the block with an associated
267         *  jump instruction.
268         *
269         *  The `End` instruction pops the last control frame from the control stack, seals
270         *  the destination block (since `br` instructions targeting it only appear inside the
271         *  block and have already been translated) and modify the value stack to use the
272         *  possible `Block`'s arguments values.
273         ***********************************************************************************/
274        Operator::Block { blockty } => {
275            let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
276            let next = block_with_params(builder, results.iter(), environ)?;
277            state.push_block(next, params.len(), results.len());
278        }
279        Operator::Loop { blockty } => {
280            let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
281            let loop_body = block_with_params(builder, params.iter(), environ)?;
282            let next = block_with_params(builder, results.iter(), environ)?;
283            canonicalise_then_jump(builder, loop_body, state.peekn(params.len()));
284            state.push_loop(loop_body, next, params.len(), results.len());
285
286            // Pop the initial `Block` actuals and replace them with the `Block`'s
287            // params since control flow joins at the top of the loop.
288            state.popn(params.len());
289            state
290                .stack
291                .extend_from_slice(builder.block_params(loop_body));
292
293            builder.switch_to_block(loop_body);
294            environ.translate_loop_header(builder.cursor())?;
295        }
296        Operator::If { blockty } => {
297            let val = state.pop1();
298
299            let next_block = builder.create_block();
300            let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
301            let results: Vec<_> = results.iter().copied().collect();
302            let (destination, else_data) = if params == results {
303                // It is possible there is no `else` block, so we will only
304                // allocate a block for it if/when we find the `else`. For now,
305                // we if the condition isn't true, then we jump directly to the
306                // destination block following the whole `if...end`. If we do end
307                // up discovering an `else`, then we will allocate a block for it
308                // and go back and patch the jump.
309                let destination = block_with_params(builder, results.iter(), environ)?;
310                let branch_inst = canonicalise_brif(
311                    builder,
312                    val,
313                    next_block,
314                    &[],
315                    destination,
316                    state.peekn(params.len()),
317                );
318                (
319                    destination,
320                    ElseData::NoElse {
321                        branch_inst,
322                        placeholder: destination,
323                    },
324                )
325            } else {
326                // The `if` type signature is not valid without an `else` block,
327                // so we eagerly allocate the `else` block here.
328                let destination = block_with_params(builder, results.iter(), environ)?;
329                let else_block = block_with_params(builder, params.iter(), environ)?;
330                canonicalise_brif(
331                    builder,
332                    val,
333                    next_block,
334                    &[],
335                    else_block,
336                    state.peekn(params.len()),
337                );
338                builder.seal_block(else_block);
339                (destination, ElseData::WithElse { else_block })
340            };
341
342            builder.seal_block(next_block); // Only predecessor is the current block.
343            builder.switch_to_block(next_block);
344
345            // Here we append an argument to a Block targeted by an argumentless jump instruction
346            // But in fact there are two cases:
347            // - either the If does not have a Else clause, in that case ty = EmptyBlock
348            //   and we add nothing;
349            // - either the If have an Else clause, in that case the destination of this jump
350            //   instruction will be changed later when we translate the Else operator.
351            state.push_if(
352                destination,
353                else_data,
354                params.len(),
355                results.len(),
356                *blockty,
357            );
358        }
359        Operator::Else => {
360            let i = state.control_stack.len() - 1;
361            match state.control_stack[i] {
362                ControlStackFrame::If {
363                    ref else_data,
364                    head_is_reachable,
365                    ref mut consequent_ends_reachable,
366                    num_return_values,
367                    blocktype,
368                    destination,
369                    ..
370                } => {
371                    // We finished the consequent, so record its final
372                    // reachability state.
373                    debug_assert!(consequent_ends_reachable.is_none());
374                    *consequent_ends_reachable = Some(state.reachable);
375
376                    if head_is_reachable {
377                        // We have a branch from the head of the `if` to the `else`.
378                        state.reachable = true;
379
380                        // Ensure we have a block for the `else` block (it may have
381                        // already been pre-allocated, see `ElseData` for details).
382                        let else_block = match *else_data {
383                            ElseData::NoElse {
384                                branch_inst,
385                                placeholder,
386                            } => {
387                                let (params, _results) = module_translation_state
388                                    .blocktype_params_results(&blocktype)?;
389                                debug_assert_eq!(params.len(), num_return_values);
390                                let else_block =
391                                    block_with_params(builder, params.iter(), environ)?;
392                                canonicalise_then_jump(
393                                    builder,
394                                    destination,
395                                    state.peekn(params.len()),
396                                );
397                                state.popn(params.len());
398
399                                builder.change_jump_destination(
400                                    branch_inst,
401                                    placeholder,
402                                    else_block,
403                                );
404                                builder.seal_block(else_block);
405                                else_block
406                            }
407                            ElseData::WithElse { else_block } => {
408                                canonicalise_then_jump(
409                                    builder,
410                                    destination,
411                                    state.peekn(num_return_values),
412                                );
413                                state.popn(num_return_values);
414                                else_block
415                            }
416                        };
417
418                        // You might be expecting that we push the parameters for this
419                        // `else` block here, something like this:
420                        //
421                        //     state.pushn(&control_stack_frame.params);
422                        //
423                        // We don't do that because they are already on the top of the stack
424                        // for us: we pushed the parameters twice when we saw the initial
425                        // `if` so that we wouldn't have to save the parameters in the
426                        // `ControlStackFrame` as another `Vec` allocation.
427
428                        builder.switch_to_block(else_block);
429
430                        // We don't bother updating the control frame's `ElseData`
431                        // to `WithElse` because nothing else will read it.
432                    }
433                }
434                _ => unreachable!(),
435            }
436        }
437        Operator::End => {
438            let frame = state.control_stack.pop().unwrap();
439            frame.restore_catch_handlers(&mut state.handlers, builder);
440            let next_block = frame.following_code();
441            let return_count = frame.num_return_values();
442            let return_args = state.peekn_mut(return_count);
443
444            canonicalise_then_jump(builder, next_block, return_args);
445            // You might expect that if we just finished an `if` block that
446            // didn't have a corresponding `else` block, then we would clean
447            // up our duplicate set of parameters that we pushed earlier
448            // right here. However, we don't have to explicitly do that,
449            // since we truncate the stack back to the original height
450            // below.
451
452            builder.switch_to_block(next_block);
453            builder.seal_block(next_block);
454
455            // If it is a loop we also have to seal the body loop block
456            if let ControlStackFrame::Loop { header, .. } = frame {
457                builder.seal_block(header)
458            }
459
460            frame.truncate_value_stack_to_original_size(&mut state.stack);
461            state
462                .stack
463                .extend_from_slice(builder.block_params(next_block));
464        }
465        /**************************** Branch instructions *********************************
466         * The branch instructions all have as arguments a target nesting level, which
467         * corresponds to how many control stack frames do we have to pop to get the
468         * destination `Block`.
469         *
470         * Once the destination `Block` is found, we sometimes have to declare a certain depth
471         * of the stack unreachable, because some branch instructions are terminator.
472         *
473         * The `br_table` case is much more complicated because Cranelift's `br_table` instruction
474         * does not support jump arguments like all the other branch instructions. That is why, in
475         * the case where we would use jump arguments for every other branch instruction, we
476         * need to split the critical edges leaving the `br_tables` by creating one `Block` per
477         * table destination; the `br_table` will point to these newly created `Blocks` and these
478         * `Block`s contain only a jump instruction pointing to the final destination, this time with
479         * jump arguments.
480         *
481         * This system is also implemented in Cranelift's SSA construction algorithm, because
482         * `use_var` located in a destination `Block` of a `br_table` might trigger the addition
483         * of jump arguments in each predecessor branch instruction, one of which might be a
484         * `br_table`.
485         ***********************************************************************************/
486        Operator::Br { relative_depth } => {
487            let i = state.control_stack.len() - 1 - (*relative_depth as usize);
488            let (return_count, br_destination) = {
489                let frame = &mut state.control_stack[i];
490                // We signal that all the code that follows until the next End is unreachable
491                frame.set_branched_to_exit();
492                let return_count = if frame.is_loop() {
493                    frame.num_param_values()
494                } else {
495                    frame.num_return_values()
496                };
497                (return_count, frame.br_destination())
498            };
499            let destination_args = state.peekn(return_count);
500            canonicalise_then_jump(builder, br_destination, destination_args);
501            state.popn(return_count);
502            state.reachable = false;
503        }
504        Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, state),
505        Operator::BrTable { targets } => {
506            let default = targets.default();
507            let mut min_depth = default;
508            for depth in targets.targets() {
509                let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
510                if depth < min_depth {
511                    min_depth = depth;
512                }
513            }
514            let jump_args_count = {
515                let i = state.control_stack.len() - 1 - (min_depth as usize);
516                let min_depth_frame = &state.control_stack[i];
517                if min_depth_frame.is_loop() {
518                    min_depth_frame.num_param_values()
519                } else {
520                    min_depth_frame.num_return_values()
521                }
522            };
523            let val = state.pop1();
524            let mut data = Vec::with_capacity(targets.len() as usize);
525            if jump_args_count == 0 {
526                // No jump arguments
527                for depth in targets.targets() {
528                    let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
529                    let block = {
530                        let i = state.control_stack.len() - 1 - (depth as usize);
531                        let frame = &mut state.control_stack[i];
532                        frame.set_branched_to_exit();
533                        frame.br_destination()
534                    };
535                    data.push(builder.func.dfg.block_call(block, &[]));
536                }
537                let block = {
538                    let i = state.control_stack.len() - 1 - (default as usize);
539                    let frame = &mut state.control_stack[i];
540                    frame.set_branched_to_exit();
541                    frame.br_destination()
542                };
543                let block = builder.func.dfg.block_call(block, &[]);
544                let jt = builder.create_jump_table(JumpTableData::new(block, &data));
545                builder.ins().br_table(val, jt);
546            } else {
547                // Here we have jump arguments, but Cranelift's br_table doesn't support them
548                // We then proceed to split the edges going out of the br_table
549                let return_count = jump_args_count;
550                let mut dest_block_sequence = vec![];
551                let mut dest_block_map = HashMap::new();
552                for depth in targets.targets() {
553                    let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
554                    let branch_block = match dest_block_map.entry(depth as usize) {
555                        hash_map::Entry::Occupied(entry) => *entry.get(),
556                        hash_map::Entry::Vacant(entry) => {
557                            let block = builder.create_block();
558                            dest_block_sequence.push((depth as usize, block));
559                            *entry.insert(block)
560                        }
561                    };
562                    data.push(builder.func.dfg.block_call(branch_block, &[]));
563                }
564                let default_branch_block = match dest_block_map.entry(default as usize) {
565                    hash_map::Entry::Occupied(entry) => *entry.get(),
566                    hash_map::Entry::Vacant(entry) => {
567                        let block = builder.create_block();
568                        dest_block_sequence.push((default as usize, block));
569                        *entry.insert(block)
570                    }
571                };
572                let default_branch_block = builder.func.dfg.block_call(default_branch_block, &[]);
573                let jt = builder.create_jump_table(JumpTableData::new(default_branch_block, &data));
574                builder.ins().br_table(val, jt);
575                for (depth, dest_block) in dest_block_sequence {
576                    builder.switch_to_block(dest_block);
577                    builder.seal_block(dest_block);
578                    let real_dest_block = {
579                        let i = state.control_stack.len() - 1 - depth;
580                        let frame = &mut state.control_stack[i];
581                        frame.set_branched_to_exit();
582                        frame.br_destination()
583                    };
584                    let destination_args = state.peekn_mut(return_count);
585                    canonicalise_then_jump(builder, real_dest_block, destination_args);
586                }
587                state.popn(return_count);
588            }
589            state.reachable = false;
590        }
591        Operator::Return => {
592            let return_count = {
593                let frame = &mut state.control_stack[0];
594                frame.num_return_values()
595            };
596            {
597                let return_args = state.peekn_mut(return_count);
598                environ.handle_before_return(return_args, builder);
599                bitcast_wasm_returns(environ, return_args, builder);
600                builder.ins().return_(return_args);
601            }
602            state.popn(return_count);
603            state.reachable = false;
604        }
605
606        /********************************** Exception handing **********************************/
607        Operator::Try { .. }
608        | Operator::Catch { .. }
609        | Operator::Rethrow { .. }
610        | Operator::Delegate { .. }
611        | Operator::CatchAll => {
612            return Err(wasm_unsupported!(
613                "proposed exception handling operator {:?}",
614                op
615            ));
616        }
617        Operator::TryTable { try_table } => {
618            let body = builder.create_block();
619            let (params, results) =
620                module_translation_state.blocktype_params_results(&try_table.ty)?;
621            let next = block_with_params(builder, results.iter(), environ)?;
622            builder.ins().jump(body, &[]);
623            builder.seal_block(body);
624
625            let checkpoint = state.handlers.take_checkpoint();
626            let mut clauses = Vec::with_capacity(try_table.catches.len());
627            let outer_clauses = state.handlers.unique_clauses().into_iter().collect_vec();
628            let mut catch_blocks = Vec::with_capacity(try_table.catches.len() + 1);
629
630            let catches = try_table
631                .catches
632                .iter()
633                .unique_by(|v| match v {
634                    Catch::One { tag, .. } | Catch::OneRef { tag, .. } => *tag as i32,
635                    Catch::All { .. } | Catch::AllRef { .. } => CATCH_ALL_TAG_VALUE,
636                })
637                .collect_vec();
638
639            for catch in catches.iter().rev() {
640                let clause = create_catch_block(builder, state, catch, environ)?;
641                catch_blocks.push(clause.block);
642                state.handlers.add_clause(clause.clone());
643                clauses.push(clause);
644            }
645
646            let outer_clauses = outer_clauses
647                .into_iter()
648                .filter(|clause| clauses.iter().all(|c| c.tag_value != clause.tag_value))
649                .collect_vec();
650
651            if !clauses.is_empty() {
652                let dispatch_block = create_dispatch_block(
653                    builder,
654                    environ,
655                    clauses.iter().chain(outer_clauses.iter()).cloned(),
656                )?;
657                catch_blocks.push(dispatch_block);
658                state.handlers.add_handler(dispatch_block);
659            }
660
661            state.push_try_table_block(next, catch_blocks, params.len(), results.len(), checkpoint);
662
663            builder.switch_to_block(body);
664        }
665        Operator::Throw { tag_index } => {
666            let tag_index = TagIndex::from_u32(*tag_index);
667            let arity = environ.tag_param_arity(tag_index);
668            let args = state.peekn(arity);
669            environ.translate_exn_throw(builder, tag_index, args, state.handlers.landing_pad())?;
670            state.popn(arity);
671            state.reachable = false;
672        }
673        Operator::ThrowRef => {
674            let exnref = state.pop1();
675            environ.translate_exn_throw_ref(builder, exnref, state.handlers.landing_pad())?;
676            state.reachable = false;
677        }
678        /************************************ Calls ****************************************
679         * The call instructions pop off their arguments from the stack and append their
680         * return values to it. `call_indirect` needs environment support because there is an
681         * argument referring to an index in the external functions table of the module.
682         ************************************************************************************/
683        Operator::Call { function_index } => {
684            let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
685
686            // Bitcast any vector arguments to their default type, I8X16, before calling.
687            {
688                let args_mut = state.peekn_mut(num_args);
689                bitcast_wasm_params(
690                    environ,
691                    builder.func.dfg.ext_funcs[fref].signature,
692                    args_mut,
693                    builder,
694                );
695            }
696            let args = state.peekn(num_args);
697            let results = environ.translate_call(
698                builder,
699                FunctionIndex::from_u32(*function_index),
700                fref,
701                args,
702                state.handlers.landing_pad(),
703            )?;
704            let sig_ref = builder.func.dfg.ext_funcs[fref].signature;
705            debug_assert_eq!(
706                results.len(),
707                builder.func.dfg.signatures[sig_ref].returns.len(),
708                "translate_call results should match the call signature"
709            );
710            state.popn(num_args);
711            state.pushn(results.as_slice());
712        }
713        Operator::CallIndirect {
714            type_index,
715            table_index,
716            ..
717        } => {
718            // `type_index` is the index of the function's signature and
719            // `table_index` is the index of the table to search the function
720            // in.
721            let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
722            let callee = state.pop1();
723
724            // Bitcast any vector arguments to their default type, I8X16, before calling.
725            {
726                let args_mut = state.peekn_mut(num_args);
727                bitcast_wasm_params(environ, sigref, args_mut, builder);
728            }
729            let args = state.peekn(num_args);
730            let results = environ.translate_call_indirect(
731                builder,
732                TableIndex::from_u32(*table_index),
733                SignatureIndex::from_u32(*type_index),
734                sigref,
735                callee,
736                args,
737                state.handlers.landing_pad(),
738            )?;
739            debug_assert_eq!(
740                results.len(),
741                builder.func.dfg.signatures[sigref].returns.len(),
742                "translate_call_indirect results should match the call signature"
743            );
744            state.popn(num_args);
745            state.pushn(results.as_slice());
746        }
747        /******************************* Memory management ***********************************
748         * Memory management is handled by environment. It is usually translated into calls to
749         * special functions.
750         ************************************************************************************/
751        Operator::MemoryGrow { mem } => {
752            // The WebAssembly MVP only supports one linear memory, but we expect the reserved
753            // argument to be a memory index.
754            let heap_index = MemoryIndex::from_u32(*mem);
755            let heap = state.get_heap(builder.func, *mem, environ)?;
756            let val = state.pop1();
757            state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
758        }
759        Operator::MemorySize { mem } => {
760            let heap_index = MemoryIndex::from_u32(*mem);
761            let heap = state.get_heap(builder.func, *mem, environ)?;
762            state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
763        }
764        /******************************* Load instructions ***********************************
765         * Wasm specifies an integer alignment flag but we drop it in Cranelift.
766         * The memory base address is provided by the environment.
767         ************************************************************************************/
768        Operator::I32Load8U { memarg } => {
769            unwrap_or_return_unreachable_state!(
770                state,
771                translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?
772            );
773        }
774        Operator::I32Load16U { memarg } => {
775            unwrap_or_return_unreachable_state!(
776                state,
777                translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?
778            );
779        }
780        Operator::I32Load8S { memarg } => {
781            unwrap_or_return_unreachable_state!(
782                state,
783                translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?
784            );
785        }
786        Operator::I32Load16S { memarg } => {
787            unwrap_or_return_unreachable_state!(
788                state,
789                translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?
790            );
791        }
792        Operator::I64Load8U { memarg } => {
793            unwrap_or_return_unreachable_state!(
794                state,
795                translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?
796            );
797        }
798        Operator::I64Load16U { memarg } => {
799            unwrap_or_return_unreachable_state!(
800                state,
801                translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?
802            );
803        }
804        Operator::I64Load8S { memarg } => {
805            unwrap_or_return_unreachable_state!(
806                state,
807                translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?
808            );
809        }
810        Operator::I64Load16S { memarg } => {
811            unwrap_or_return_unreachable_state!(
812                state,
813                translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?
814            );
815        }
816        Operator::I64Load32S { memarg } => {
817            unwrap_or_return_unreachable_state!(
818                state,
819                translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?
820            );
821        }
822        Operator::I64Load32U { memarg } => {
823            unwrap_or_return_unreachable_state!(
824                state,
825                translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?
826            );
827        }
828        Operator::I32Load { memarg } => {
829            unwrap_or_return_unreachable_state!(
830                state,
831                translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?
832            );
833        }
834        Operator::F32Load { memarg } => {
835            unwrap_or_return_unreachable_state!(
836                state,
837                translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?
838            );
839        }
840        Operator::I64Load { memarg } => {
841            unwrap_or_return_unreachable_state!(
842                state,
843                translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?
844            );
845        }
846        Operator::F64Load { memarg } => {
847            unwrap_or_return_unreachable_state!(
848                state,
849                translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?
850            );
851        }
852        Operator::V128Load { memarg } => {
853            unwrap_or_return_unreachable_state!(
854                state,
855                translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?
856            );
857        }
858        Operator::V128Load8x8S { memarg } => {
859            //TODO(#6829): add before_load() and before_store() hooks for SIMD loads and stores.
860            let (flags, _, base) = unwrap_or_return_unreachable_state!(
861                state,
862                prepare_addr(memarg, 8, builder, state, environ)?
863            );
864            let loaded = builder.ins().sload8x8(flags, base, 0);
865            state.push1(loaded);
866        }
867        Operator::V128Load8x8U { memarg } => {
868            let (flags, _, base) = unwrap_or_return_unreachable_state!(
869                state,
870                prepare_addr(memarg, 8, builder, state, environ)?
871            );
872            let loaded = builder.ins().uload8x8(flags, base, 0);
873            state.push1(loaded);
874        }
875        Operator::V128Load16x4S { memarg } => {
876            let (flags, _, base) = unwrap_or_return_unreachable_state!(
877                state,
878                prepare_addr(memarg, 8, builder, state, environ)?
879            );
880            let loaded = builder.ins().sload16x4(flags, base, 0);
881            state.push1(loaded);
882        }
883        Operator::V128Load16x4U { memarg } => {
884            let (flags, _, base) = unwrap_or_return_unreachable_state!(
885                state,
886                prepare_addr(memarg, 8, builder, state, environ)?
887            );
888            let loaded = builder.ins().uload16x4(flags, base, 0);
889            state.push1(loaded);
890        }
891        Operator::V128Load32x2S { memarg } => {
892            let (flags, _, base) = unwrap_or_return_unreachable_state!(
893                state,
894                prepare_addr(memarg, 8, builder, state, environ)?
895            );
896            let loaded = builder.ins().sload32x2(flags, base, 0);
897            state.push1(loaded);
898        }
899        Operator::V128Load32x2U { memarg } => {
900            let (flags, _, base) = unwrap_or_return_unreachable_state!(
901                state,
902                prepare_addr(memarg, 8, builder, state, environ)?
903            );
904            let loaded = builder.ins().uload32x2(flags, base, 0);
905            state.push1(loaded);
906        }
907        /****************************** Store instructions ***********************************
908         * Wasm specifies an integer alignment flag but we drop it in Cranelift.
909         * The memory base address is provided by the environment.
910         ************************************************************************************/
911        Operator::I32Store { memarg }
912        | Operator::I64Store { memarg }
913        | Operator::F32Store { memarg }
914        | Operator::F64Store { memarg } => {
915            translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
916        }
917        Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
918            translate_store(memarg, ir::Opcode::Istore8, builder, state, environ)?;
919        }
920        Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
921            translate_store(memarg, ir::Opcode::Istore16, builder, state, environ)?;
922        }
923        Operator::I64Store32 { memarg } => {
924            translate_store(memarg, ir::Opcode::Istore32, builder, state, environ)?;
925        }
926        Operator::V128Store { memarg } => {
927            translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
928        }
929        /****************************** Nullary Operators ************************************/
930        Operator::I32Const { value } => {
931            state.push1(builder.ins().iconst(I32, *value as u32 as i64))
932        }
933        Operator::I64Const { value } => state.push1(builder.ins().iconst(I64, *value)),
934        Operator::F32Const { value } => {
935            state.push1(builder.ins().f32const(f32_translation(*value)));
936        }
937        Operator::F64Const { value } => {
938            state.push1(builder.ins().f64const(f64_translation(*value)));
939        }
940        /******************************* Unary Operators *************************************/
941        Operator::I32Clz | Operator::I64Clz => {
942            let arg = state.pop1();
943            state.push1(builder.ins().clz(arg));
944        }
945        Operator::I32Ctz | Operator::I64Ctz => {
946            let arg = state.pop1();
947            state.push1(builder.ins().ctz(arg));
948        }
949        Operator::I32Popcnt | Operator::I64Popcnt => {
950            let arg = state.pop1();
951            state.push1(builder.ins().popcnt(arg));
952        }
953        Operator::I64ExtendI32S => {
954            let val = state.pop1();
955            state.push1(builder.ins().sextend(I64, val));
956        }
957        Operator::I64ExtendI32U => {
958            let val = state.pop1();
959            state.push1(builder.ins().uextend(I64, val));
960        }
961        Operator::I32WrapI64 => {
962            let val = state.pop1();
963            state.push1(builder.ins().ireduce(I32, val));
964        }
965        Operator::F32Sqrt | Operator::F64Sqrt => {
966            let arg = state.pop1();
967            state.push1(builder.ins().sqrt(arg));
968        }
969        Operator::F32Ceil | Operator::F64Ceil => {
970            let arg = state.pop1();
971            state.push1(builder.ins().ceil(arg));
972        }
973        Operator::F32Floor | Operator::F64Floor => {
974            let arg = state.pop1();
975            state.push1(builder.ins().floor(arg));
976        }
977        Operator::F32Trunc | Operator::F64Trunc => {
978            let arg = state.pop1();
979            state.push1(builder.ins().trunc(arg));
980        }
981        Operator::F32Nearest | Operator::F64Nearest => {
982            let arg = state.pop1();
983            state.push1(builder.ins().nearest(arg));
984        }
985        Operator::F32Abs | Operator::F64Abs => {
986            let val = state.pop1();
987            state.push1(builder.ins().fabs(val));
988        }
989        Operator::F32Neg | Operator::F64Neg => {
990            let arg = state.pop1();
991            state.push1(builder.ins().fneg(arg));
992        }
993        Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
994            let val = state.pop1();
995            state.push1(builder.ins().fcvt_from_uint(F64, val));
996        }
997        Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
998            let val = state.pop1();
999            state.push1(builder.ins().fcvt_from_sint(F64, val));
1000        }
1001        Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
1002            let val = state.pop1();
1003            state.push1(builder.ins().fcvt_from_sint(F32, val));
1004        }
1005        Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
1006            let val = state.pop1();
1007            state.push1(builder.ins().fcvt_from_uint(F32, val));
1008        }
1009        Operator::F64PromoteF32 => {
1010            let val = state.pop1();
1011            state.push1(builder.ins().fpromote(F64, val));
1012        }
1013        Operator::F32DemoteF64 => {
1014            let val = state.pop1();
1015            state.push1(builder.ins().fdemote(F32, val));
1016        }
1017        Operator::I64TruncF64S | Operator::I64TruncF32S => {
1018            let val = state.pop1();
1019            state.push1(builder.ins().fcvt_to_sint(I64, val));
1020        }
1021        Operator::I32TruncF64S | Operator::I32TruncF32S => {
1022            let val = state.pop1();
1023            state.push1(builder.ins().fcvt_to_sint(I32, val));
1024        }
1025        Operator::I64TruncF64U | Operator::I64TruncF32U => {
1026            let val = state.pop1();
1027            state.push1(builder.ins().fcvt_to_uint(I64, val));
1028        }
1029        Operator::I32TruncF64U | Operator::I32TruncF32U => {
1030            let val = state.pop1();
1031            state.push1(builder.ins().fcvt_to_uint(I32, val));
1032        }
1033        Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
1034            let val = state.pop1();
1035            state.push1(builder.ins().fcvt_to_sint_sat(I64, val));
1036        }
1037        Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
1038            let val = state.pop1();
1039            state.push1(builder.ins().fcvt_to_sint_sat(I32, val));
1040        }
1041        Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
1042            let val = state.pop1();
1043            state.push1(builder.ins().fcvt_to_uint_sat(I64, val));
1044        }
1045        Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
1046            let val = state.pop1();
1047            state.push1(builder.ins().fcvt_to_uint_sat(I32, val));
1048        }
1049        Operator::F32ReinterpretI32 => {
1050            let val = state.pop1();
1051            state.push1(builder.ins().bitcast(F32, MemFlags::new(), val));
1052        }
1053        Operator::F64ReinterpretI64 => {
1054            let val = state.pop1();
1055            state.push1(builder.ins().bitcast(F64, MemFlags::new(), val));
1056        }
1057        Operator::I32ReinterpretF32 => {
1058            let val = state.pop1();
1059            state.push1(builder.ins().bitcast(I32, MemFlags::new(), val));
1060        }
1061        Operator::I64ReinterpretF64 => {
1062            let val = state.pop1();
1063            state.push1(builder.ins().bitcast(I64, MemFlags::new(), val));
1064        }
1065        Operator::I32Extend8S => {
1066            let val = state.pop1();
1067            state.push1(builder.ins().ireduce(I8, val));
1068            let val = state.pop1();
1069            state.push1(builder.ins().sextend(I32, val));
1070        }
1071        Operator::I32Extend16S => {
1072            let val = state.pop1();
1073            state.push1(builder.ins().ireduce(I16, val));
1074            let val = state.pop1();
1075            state.push1(builder.ins().sextend(I32, val));
1076        }
1077        Operator::I64Extend8S => {
1078            let val = state.pop1();
1079            state.push1(builder.ins().ireduce(I8, val));
1080            let val = state.pop1();
1081            state.push1(builder.ins().sextend(I64, val));
1082        }
1083        Operator::I64Extend16S => {
1084            let val = state.pop1();
1085            state.push1(builder.ins().ireduce(I16, val));
1086            let val = state.pop1();
1087            state.push1(builder.ins().sextend(I64, val));
1088        }
1089        Operator::I64Extend32S => {
1090            let val = state.pop1();
1091            state.push1(builder.ins().ireduce(I32, val));
1092            let val = state.pop1();
1093            state.push1(builder.ins().sextend(I64, val));
1094        }
1095        /****************************** Binary Operators ************************************/
1096        Operator::I32Add | Operator::I64Add => {
1097            let (arg1, arg2) = state.pop2();
1098            state.push1(builder.ins().iadd(arg1, arg2));
1099        }
1100        Operator::I32And | Operator::I64And => {
1101            let (arg1, arg2) = state.pop2();
1102            state.push1(builder.ins().band(arg1, arg2));
1103        }
1104        Operator::I32Or | Operator::I64Or => {
1105            let (arg1, arg2) = state.pop2();
1106            state.push1(builder.ins().bor(arg1, arg2));
1107        }
1108        Operator::I32Xor | Operator::I64Xor => {
1109            let (arg1, arg2) = state.pop2();
1110            state.push1(builder.ins().bxor(arg1, arg2));
1111        }
1112        Operator::I32Shl | Operator::I64Shl => {
1113            let (arg1, arg2) = state.pop2();
1114            state.push1(builder.ins().ishl(arg1, arg2));
1115        }
1116        Operator::I32ShrS | Operator::I64ShrS => {
1117            let (arg1, arg2) = state.pop2();
1118            state.push1(builder.ins().sshr(arg1, arg2));
1119        }
1120        Operator::I32ShrU | Operator::I64ShrU => {
1121            let (arg1, arg2) = state.pop2();
1122            state.push1(builder.ins().ushr(arg1, arg2));
1123        }
1124        Operator::I32Rotl | Operator::I64Rotl => {
1125            let (arg1, arg2) = state.pop2();
1126            state.push1(builder.ins().rotl(arg1, arg2));
1127        }
1128        Operator::I32Rotr | Operator::I64Rotr => {
1129            let (arg1, arg2) = state.pop2();
1130            state.push1(builder.ins().rotr(arg1, arg2));
1131        }
1132        Operator::F32Add | Operator::F64Add => {
1133            let (arg1, arg2) = state.pop2();
1134            state.push1(builder.ins().fadd(arg1, arg2));
1135        }
1136        Operator::I32Sub | Operator::I64Sub => {
1137            let (arg1, arg2) = state.pop2();
1138            state.push1(builder.ins().isub(arg1, arg2));
1139        }
1140        Operator::F32Sub | Operator::F64Sub => {
1141            let (arg1, arg2) = state.pop2();
1142            state.push1(builder.ins().fsub(arg1, arg2));
1143        }
1144        Operator::I32Mul | Operator::I64Mul => {
1145            let (arg1, arg2) = state.pop2();
1146            state.push1(builder.ins().imul(arg1, arg2));
1147        }
1148        Operator::F32Mul | Operator::F64Mul => {
1149            let (arg1, arg2) = state.pop2();
1150            state.push1(builder.ins().fmul(arg1, arg2));
1151        }
1152        Operator::F32Div | Operator::F64Div => {
1153            let (arg1, arg2) = state.pop2();
1154            state.push1(builder.ins().fdiv(arg1, arg2));
1155        }
1156        Operator::I32DivS | Operator::I64DivS => {
1157            let (arg1, arg2) = state.pop2();
1158            state.push1(builder.ins().sdiv(arg1, arg2));
1159        }
1160        Operator::I32DivU | Operator::I64DivU => {
1161            let (arg1, arg2) = state.pop2();
1162            state.push1(builder.ins().udiv(arg1, arg2));
1163        }
1164        Operator::I32RemS | Operator::I64RemS => {
1165            let (arg1, arg2) = state.pop2();
1166            state.push1(builder.ins().srem(arg1, arg2));
1167        }
1168        Operator::I32RemU | Operator::I64RemU => {
1169            let (arg1, arg2) = state.pop2();
1170            state.push1(builder.ins().urem(arg1, arg2));
1171        }
1172        Operator::F32Min | Operator::F64Min => {
1173            let (arg1, arg2) = state.pop2();
1174            state.push1(builder.ins().fmin(arg1, arg2));
1175        }
1176        Operator::F32Max | Operator::F64Max => {
1177            let (arg1, arg2) = state.pop2();
1178            state.push1(builder.ins().fmax(arg1, arg2));
1179        }
1180        Operator::F32Copysign | Operator::F64Copysign => {
1181            let (arg1, arg2) = state.pop2();
1182            state.push1(builder.ins().fcopysign(arg1, arg2));
1183        }
1184        /**************************** Comparison Operators **********************************/
1185        Operator::I32LtS | Operator::I64LtS => {
1186            translate_icmp(IntCC::SignedLessThan, builder, state)
1187        }
1188        Operator::I32LtU | Operator::I64LtU => {
1189            translate_icmp(IntCC::UnsignedLessThan, builder, state)
1190        }
1191        Operator::I32LeS | Operator::I64LeS => {
1192            translate_icmp(IntCC::SignedLessThanOrEqual, builder, state)
1193        }
1194        Operator::I32LeU | Operator::I64LeU => {
1195            translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, state)
1196        }
1197        Operator::I32GtS | Operator::I64GtS => {
1198            translate_icmp(IntCC::SignedGreaterThan, builder, state)
1199        }
1200        Operator::I32GtU | Operator::I64GtU => {
1201            translate_icmp(IntCC::UnsignedGreaterThan, builder, state)
1202        }
1203        Operator::I32GeS | Operator::I64GeS => {
1204            translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, state)
1205        }
1206        Operator::I32GeU | Operator::I64GeU => {
1207            translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, state)
1208        }
1209        Operator::I32Eqz | Operator::I64Eqz => {
1210            let arg = state.pop1();
1211            let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0);
1212            state.push1(builder.ins().uextend(I32, val));
1213        }
1214        Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, state),
1215        Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, state),
1216        Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, state),
1217        Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, state),
1218        Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, state),
1219        Operator::F32Ge | Operator::F64Ge => {
1220            translate_fcmp(FloatCC::GreaterThanOrEqual, builder, state)
1221        }
1222        Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, state),
1223        Operator::F32Le | Operator::F64Le => {
1224            translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
1225        }
1226        Operator::RefNull { hty } => {
1227            state.push1(environ.translate_ref_null(builder.cursor(), *hty)?)
1228        }
1229        Operator::RefIsNull => {
1230            let value = state.pop1();
1231            state.push1(environ.translate_ref_is_null(builder.cursor(), value)?);
1232        }
1233        Operator::RefFunc { function_index } => {
1234            let index = FunctionIndex::from_u32(*function_index);
1235            state.push1(environ.translate_ref_func(builder.cursor(), index)?);
1236        }
1237        Operator::MemoryAtomicWait32 { memarg } | Operator::MemoryAtomicWait64 { memarg } => {
1238            // The WebAssembly MVP only supports one linear memory and
1239            // wasmparser will ensure that the memory indices specified are
1240            // zero.
1241            let implied_ty = match op {
1242                Operator::MemoryAtomicWait64 { .. } => I64,
1243                Operator::MemoryAtomicWait32 { .. } => I32,
1244                _ => unreachable!(),
1245            };
1246            let heap_index = MemoryIndex::from_u32(memarg.memory);
1247            let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1248            let timeout = state.pop1(); // 64 (fixed)
1249            let expected = state.pop1(); // 32 or 64 (per the `Ixx` in `IxxAtomicWait`)
1250            let addr = state.pop1(); // 32 (fixed)
1251            let addr = fold_atomic_mem_addr(addr, memarg, implied_ty, builder);
1252            assert!(builder.func.dfg.value_type(expected) == implied_ty);
1253            // `fn translate_atomic_wait` can inspect the type of `expected` to figure out what
1254            // code it needs to generate, if it wants.
1255            match environ.translate_atomic_wait(
1256                builder.cursor(),
1257                heap_index,
1258                heap,
1259                addr,
1260                expected,
1261                timeout,
1262            ) {
1263                Ok(res) => {
1264                    state.push1(res);
1265                }
1266                Err(wasmer_types::WasmError::Unsupported(_err)) => {
1267                    // If multiple threads hit a mutex then the function will fail
1268                    builder.ins().trap(crate::TRAP_UNREACHABLE);
1269                    state.reachable = false;
1270                }
1271                Err(err) => {
1272                    return Err(err);
1273                }
1274            };
1275        }
1276        Operator::MemoryAtomicNotify { memarg } => {
1277            let heap_index = MemoryIndex::from_u32(memarg.memory);
1278            let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1279            let count = state.pop1(); // 32 (fixed)
1280            let addr = state.pop1(); // 32 (fixed)
1281            let addr = fold_atomic_mem_addr(addr, memarg, I32, builder);
1282            match environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count) {
1283                Ok(res) => {
1284                    state.push1(res);
1285                }
1286                Err(wasmer_types::WasmError::Unsupported(_err)) => {
1287                    // Simple return a zero as this function is needed for the __wasi_init_memory function
1288                    // but the equivalent notify.wait will not be called (as only one thread calls __start)
1289                    // hence these atomic operations are not needed
1290                    state.push1(builder.ins().iconst(I32, i64::from(0)));
1291                }
1292                Err(err) => {
1293                    return Err(err);
1294                }
1295            };
1296        }
1297        Operator::I32AtomicLoad { memarg } => {
1298            translate_atomic_load(I32, I32, memarg, builder, state, environ)?
1299        }
1300        Operator::I64AtomicLoad { memarg } => {
1301            translate_atomic_load(I64, I64, memarg, builder, state, environ)?
1302        }
1303        Operator::I32AtomicLoad8U { memarg } => {
1304            translate_atomic_load(I32, I8, memarg, builder, state, environ)?
1305        }
1306        Operator::I32AtomicLoad16U { memarg } => {
1307            translate_atomic_load(I32, I16, memarg, builder, state, environ)?
1308        }
1309        Operator::I64AtomicLoad8U { memarg } => {
1310            translate_atomic_load(I64, I8, memarg, builder, state, environ)?
1311        }
1312        Operator::I64AtomicLoad16U { memarg } => {
1313            translate_atomic_load(I64, I16, memarg, builder, state, environ)?
1314        }
1315        Operator::I64AtomicLoad32U { memarg } => {
1316            translate_atomic_load(I64, I32, memarg, builder, state, environ)?
1317        }
1318
1319        Operator::I32AtomicStore { memarg } => {
1320            translate_atomic_store(I32, memarg, builder, state, environ)?
1321        }
1322        Operator::I64AtomicStore { memarg } => {
1323            translate_atomic_store(I64, memarg, builder, state, environ)?
1324        }
1325        Operator::I32AtomicStore8 { memarg } => {
1326            translate_atomic_store(I8, memarg, builder, state, environ)?
1327        }
1328        Operator::I32AtomicStore16 { memarg } => {
1329            translate_atomic_store(I16, memarg, builder, state, environ)?
1330        }
1331        Operator::I64AtomicStore8 { memarg } => {
1332            translate_atomic_store(I8, memarg, builder, state, environ)?
1333        }
1334        Operator::I64AtomicStore16 { memarg } => {
1335            translate_atomic_store(I16, memarg, builder, state, environ)?
1336        }
1337        Operator::I64AtomicStore32 { memarg } => {
1338            translate_atomic_store(I32, memarg, builder, state, environ)?
1339        }
1340
1341        Operator::I32AtomicRmwAdd { memarg } => {
1342            translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1343        }
1344        Operator::I64AtomicRmwAdd { memarg } => {
1345            translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, state, environ)?
1346        }
1347        Operator::I32AtomicRmw8AddU { memarg } => {
1348            translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1349        }
1350        Operator::I32AtomicRmw16AddU { memarg } => {
1351            translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1352        }
1353        Operator::I64AtomicRmw8AddU { memarg } => {
1354            translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1355        }
1356        Operator::I64AtomicRmw16AddU { memarg } => {
1357            translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1358        }
1359        Operator::I64AtomicRmw32AddU { memarg } => {
1360            translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1361        }
1362
1363        Operator::I32AtomicRmwSub { memarg } => {
1364            translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1365        }
1366        Operator::I64AtomicRmwSub { memarg } => {
1367            translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1368        }
1369        Operator::I32AtomicRmw8SubU { memarg } => {
1370            translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1371        }
1372        Operator::I32AtomicRmw16SubU { memarg } => {
1373            translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1374        }
1375        Operator::I64AtomicRmw8SubU { memarg } => {
1376            translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1377        }
1378        Operator::I64AtomicRmw16SubU { memarg } => {
1379            translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1380        }
1381        Operator::I64AtomicRmw32SubU { memarg } => {
1382            translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1383        }
1384
1385        Operator::I32AtomicRmwAnd { memarg } => {
1386            translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1387        }
1388        Operator::I64AtomicRmwAnd { memarg } => {
1389            translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, state, environ)?
1390        }
1391        Operator::I32AtomicRmw8AndU { memarg } => {
1392            translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1393        }
1394        Operator::I32AtomicRmw16AndU { memarg } => {
1395            translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1396        }
1397        Operator::I64AtomicRmw8AndU { memarg } => {
1398            translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1399        }
1400        Operator::I64AtomicRmw16AndU { memarg } => {
1401            translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1402        }
1403        Operator::I64AtomicRmw32AndU { memarg } => {
1404            translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1405        }
1406
1407        Operator::I32AtomicRmwOr { memarg } => {
1408            translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1409        }
1410        Operator::I64AtomicRmwOr { memarg } => {
1411            translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, state, environ)?
1412        }
1413        Operator::I32AtomicRmw8OrU { memarg } => {
1414            translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1415        }
1416        Operator::I32AtomicRmw16OrU { memarg } => {
1417            translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1418        }
1419        Operator::I64AtomicRmw8OrU { memarg } => {
1420            translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1421        }
1422        Operator::I64AtomicRmw16OrU { memarg } => {
1423            translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1424        }
1425        Operator::I64AtomicRmw32OrU { memarg } => {
1426            translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1427        }
1428
1429        Operator::I32AtomicRmwXor { memarg } => {
1430            translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1431        }
1432        Operator::I64AtomicRmwXor { memarg } => {
1433            translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1434        }
1435        Operator::I32AtomicRmw8XorU { memarg } => {
1436            translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1437        }
1438        Operator::I32AtomicRmw16XorU { memarg } => {
1439            translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1440        }
1441        Operator::I64AtomicRmw8XorU { memarg } => {
1442            translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1443        }
1444        Operator::I64AtomicRmw16XorU { memarg } => {
1445            translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1446        }
1447        Operator::I64AtomicRmw32XorU { memarg } => {
1448            translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1449        }
1450
1451        Operator::I32AtomicRmwXchg { memarg } => {
1452            translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1453        }
1454        Operator::I64AtomicRmwXchg { memarg } => {
1455            translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1456        }
1457        Operator::I32AtomicRmw8XchgU { memarg } => {
1458            translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1459        }
1460        Operator::I32AtomicRmw16XchgU { memarg } => {
1461            translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1462        }
1463        Operator::I64AtomicRmw8XchgU { memarg } => {
1464            translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1465        }
1466        Operator::I64AtomicRmw16XchgU { memarg } => {
1467            translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1468        }
1469        Operator::I64AtomicRmw32XchgU { memarg } => {
1470            translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1471        }
1472
1473        Operator::I32AtomicRmwCmpxchg { memarg } => {
1474            translate_atomic_cas(I32, I32, memarg, builder, state, environ)?
1475        }
1476        Operator::I64AtomicRmwCmpxchg { memarg } => {
1477            translate_atomic_cas(I64, I64, memarg, builder, state, environ)?
1478        }
1479        Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1480            translate_atomic_cas(I32, I8, memarg, builder, state, environ)?
1481        }
1482        Operator::I32AtomicRmw16CmpxchgU { memarg } => {
1483            translate_atomic_cas(I32, I16, memarg, builder, state, environ)?
1484        }
1485        Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1486            translate_atomic_cas(I64, I8, memarg, builder, state, environ)?
1487        }
1488        Operator::I64AtomicRmw16CmpxchgU { memarg } => {
1489            translate_atomic_cas(I64, I16, memarg, builder, state, environ)?
1490        }
1491        Operator::I64AtomicRmw32CmpxchgU { memarg } => {
1492            translate_atomic_cas(I64, I32, memarg, builder, state, environ)?
1493        }
1494
1495        Operator::AtomicFence { .. } => {
1496            builder.ins().fence();
1497        }
1498        Operator::MemoryCopy { dst_mem, src_mem } => {
1499            let src_index = MemoryIndex::from_u32(*src_mem);
1500            let dst_index = MemoryIndex::from_u32(*dst_mem);
1501            let src_heap = state.get_heap(builder.func, *src_mem, environ)?;
1502            let dst_heap = state.get_heap(builder.func, *dst_mem, environ)?;
1503            let len = state.pop1();
1504            let src_pos = state.pop1();
1505            let dst_pos = state.pop1();
1506            environ.translate_memory_copy(
1507                builder.cursor(),
1508                src_index,
1509                src_heap,
1510                dst_index,
1511                dst_heap,
1512                dst_pos,
1513                src_pos,
1514                len,
1515            )?;
1516        }
1517        Operator::MemoryFill { mem } => {
1518            let heap_index = MemoryIndex::from_u32(*mem);
1519            let heap = state.get_heap(builder.func, *mem, environ)?;
1520            let len = state.pop1();
1521            let val = state.pop1();
1522            let dest = state.pop1();
1523            environ.translate_memory_fill(builder.cursor(), heap_index, heap, dest, val, len)?;
1524        }
1525        Operator::MemoryInit { data_index, mem } => {
1526            let heap_index = MemoryIndex::from_u32(*mem);
1527            let heap = state.get_heap(builder.func, *mem, environ)?;
1528            let len = state.pop1();
1529            let src = state.pop1();
1530            let dest = state.pop1();
1531            environ.translate_memory_init(
1532                builder.cursor(),
1533                heap_index,
1534                heap,
1535                *data_index,
1536                dest,
1537                src,
1538                len,
1539            )?;
1540        }
1541        Operator::DataDrop { data_index } => {
1542            environ.translate_data_drop(builder.cursor(), *data_index)?;
1543        }
1544        Operator::TableSize { table: index } => {
1545            state.push1(
1546                environ.translate_table_size(builder.cursor(), TableIndex::from_u32(*index))?,
1547            );
1548        }
1549        Operator::TableGrow { table: index } => {
1550            let table_index = TableIndex::from_u32(*index);
1551            let delta = state.pop1();
1552            let init_value = state.pop1();
1553            state.push1(environ.translate_table_grow(
1554                builder.cursor(),
1555                table_index,
1556                delta,
1557                init_value,
1558            )?);
1559        }
1560        Operator::TableGet { table: index } => {
1561            let table_index = TableIndex::from_u32(*index);
1562            let index = state.pop1();
1563            state.push1(environ.translate_table_get(builder, table_index, index)?);
1564        }
1565        Operator::TableSet { table: index } => {
1566            let table_index = TableIndex::from_u32(*index);
1567            let value = state.pop1();
1568            let index = state.pop1();
1569            environ.translate_table_set(builder, table_index, value, index)?;
1570        }
1571        Operator::TableCopy {
1572            dst_table: dst_table_index,
1573            src_table: src_table_index,
1574        } => {
1575            let len = state.pop1();
1576            let src = state.pop1();
1577            let dest = state.pop1();
1578            environ.translate_table_copy(
1579                builder.cursor(),
1580                TableIndex::from_u32(*dst_table_index),
1581                TableIndex::from_u32(*src_table_index),
1582                dest,
1583                src,
1584                len,
1585            )?;
1586        }
1587        Operator::TableFill { table } => {
1588            let table_index = TableIndex::from_u32(*table);
1589            let len = state.pop1();
1590            let val = state.pop1();
1591            let dest = state.pop1();
1592            environ.translate_table_fill(builder.cursor(), table_index, dest, val, len)?;
1593        }
1594        Operator::TableInit {
1595            elem_index,
1596            table: table_index,
1597        } => {
1598            let len = state.pop1();
1599            let src = state.pop1();
1600            let dest = state.pop1();
1601            environ.translate_table_init(
1602                builder.cursor(),
1603                *elem_index,
1604                TableIndex::from_u32(*table_index),
1605                dest,
1606                src,
1607                len,
1608            )?;
1609        }
1610        Operator::ElemDrop { elem_index } => {
1611            environ.translate_elem_drop(builder.cursor(), *elem_index)?;
1612        }
1613        Operator::V128Const { value } => {
1614            let data = value.bytes().to_vec().into();
1615            let handle = builder.func.dfg.constants.insert(data);
1616            let value = builder.ins().vconst(I8X16, handle);
1617            // the v128.const is typed in CLIF as a I8x16 but raw_bitcast to a different type
1618            // before use
1619            state.push1(value)
1620        }
1621        Operator::I8x16Splat | Operator::I16x8Splat => {
1622            let reduced = builder.ins().ireduce(type_of(op).lane_type(), state.pop1());
1623            let splatted = builder.ins().splat(type_of(op), reduced);
1624            state.push1(splatted)
1625        }
1626        Operator::I32x4Splat
1627        | Operator::I64x2Splat
1628        | Operator::F32x4Splat
1629        | Operator::F64x2Splat => {
1630            let splatted = builder.ins().splat(type_of(op), state.pop1());
1631            state.push1(splatted)
1632        }
1633        Operator::V128Load8Splat { memarg }
1634        | Operator::V128Load16Splat { memarg }
1635        | Operator::V128Load32Splat { memarg }
1636        | Operator::V128Load64Splat { memarg } => {
1637            unwrap_or_return_unreachable_state!(
1638                state,
1639                translate_load(
1640                    memarg,
1641                    ir::Opcode::Load,
1642                    type_of(op).lane_type(),
1643                    builder,
1644                    state,
1645                    environ,
1646                )?
1647            );
1648            let splatted = builder.ins().splat(type_of(op), state.pop1());
1649            state.push1(splatted)
1650        }
1651        Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
1652            unwrap_or_return_unreachable_state!(
1653                state,
1654                translate_load(
1655                    memarg,
1656                    ir::Opcode::Load,
1657                    type_of(op).lane_type(),
1658                    builder,
1659                    state,
1660                    environ,
1661                )?
1662            );
1663            let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
1664            state.push1(as_vector)
1665        }
1666        Operator::V128Load8Lane { memarg, lane }
1667        | Operator::V128Load16Lane { memarg, lane }
1668        | Operator::V128Load32Lane { memarg, lane }
1669        | Operator::V128Load64Lane { memarg, lane } => {
1670            let vector = pop1_with_bitcast(state, type_of(op), builder);
1671            unwrap_or_return_unreachable_state!(
1672                state,
1673                translate_load(
1674                    memarg,
1675                    ir::Opcode::Load,
1676                    type_of(op).lane_type(),
1677                    builder,
1678                    state,
1679                    environ,
1680                )?
1681            );
1682            let replacement = state.pop1();
1683            state.push1(builder.ins().insertlane(vector, replacement, *lane))
1684        }
1685        Operator::V128Store8Lane { memarg, lane }
1686        | Operator::V128Store16Lane { memarg, lane }
1687        | Operator::V128Store32Lane { memarg, lane }
1688        | Operator::V128Store64Lane { memarg, lane } => {
1689            let vector = pop1_with_bitcast(state, type_of(op), builder);
1690            state.push1(builder.ins().extractlane(vector, *lane));
1691            translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
1692        }
1693        Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => {
1694            let vector = pop1_with_bitcast(state, type_of(op), builder);
1695            let extracted = builder.ins().extractlane(vector, *lane);
1696            state.push1(builder.ins().sextend(I32, extracted))
1697        }
1698        Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
1699            let vector = pop1_with_bitcast(state, type_of(op), builder);
1700            let extracted = builder.ins().extractlane(vector, *lane);
1701            state.push1(builder.ins().uextend(I32, extracted));
1702            // On x86, PEXTRB zeroes the upper bits of the destination register of extractlane so
1703            // uextend could be elided; for now, uextend is needed for Cranelift's type checks to
1704            // work.
1705        }
1706        Operator::I32x4ExtractLane { lane }
1707        | Operator::I64x2ExtractLane { lane }
1708        | Operator::F32x4ExtractLane { lane }
1709        | Operator::F64x2ExtractLane { lane } => {
1710            let vector = pop1_with_bitcast(state, type_of(op), builder);
1711            state.push1(builder.ins().extractlane(vector, *lane))
1712        }
1713        Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => {
1714            let (vector, replacement) = state.pop2();
1715            let ty = type_of(op);
1716            let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
1717            let vector = optionally_bitcast_vector(vector, ty, builder);
1718            state.push1(builder.ins().insertlane(vector, reduced, *lane))
1719        }
1720        Operator::I32x4ReplaceLane { lane }
1721        | Operator::I64x2ReplaceLane { lane }
1722        | Operator::F32x4ReplaceLane { lane }
1723        | Operator::F64x2ReplaceLane { lane } => {
1724            let (vector, replacement) = state.pop2();
1725            let vector = optionally_bitcast_vector(vector, type_of(op), builder);
1726            state.push1(builder.ins().insertlane(vector, replacement, *lane))
1727        }
1728        Operator::I8x16Shuffle { lanes, .. } => {
1729            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1730            let lanes = ConstantData::from(lanes.as_ref());
1731            let mask = builder.func.dfg.immediates.push(lanes);
1732            let shuffled = builder.ins().shuffle(a, b, mask);
1733            state.push1(shuffled)
1734            // At this point the original types of a and b are lost; users of this value (i.e. this
1735            // WASM-to-CLIF translator) may need to raw_bitcast for type-correctness. This is due
1736            // to WASM using the less specific v128 type for certain operations and more specific
1737            // types (e.g. i8x16) for others.
1738        }
1739        Operator::I8x16Swizzle => {
1740            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1741            state.push1(builder.ins().swizzle(a, b))
1742        }
1743        Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1744            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1745            state.push1(builder.ins().iadd(a, b))
1746        }
1747        Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1748            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1749            state.push1(builder.ins().sadd_sat(a, b))
1750        }
1751        Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1752            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1753            state.push1(builder.ins().uadd_sat(a, b))
1754        }
1755        Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1756            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1757            state.push1(builder.ins().isub(a, b))
1758        }
1759        Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1760            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1761            state.push1(builder.ins().ssub_sat(a, b))
1762        }
1763        Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1764            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1765            state.push1(builder.ins().usub_sat(a, b))
1766        }
1767        Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1768            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1769            state.push1(builder.ins().smin(a, b))
1770        }
1771        Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1772            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1773            state.push1(builder.ins().umin(a, b))
1774        }
1775        Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1776            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1777            state.push1(builder.ins().smax(a, b))
1778        }
1779        Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1780            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1781            state.push1(builder.ins().umax(a, b))
1782        }
1783        Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1784            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1785            state.push1(builder.ins().avg_round(a, b))
1786        }
1787        Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1788            let a = pop1_with_bitcast(state, type_of(op), builder);
1789            state.push1(builder.ins().ineg(a))
1790        }
1791        Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1792            let a = pop1_with_bitcast(state, type_of(op), builder);
1793            state.push1(builder.ins().iabs(a))
1794        }
1795        Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1796            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1797            state.push1(builder.ins().imul(a, b))
1798        }
1799        Operator::V128Or => {
1800            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1801            state.push1(builder.ins().bor(a, b))
1802        }
1803        Operator::V128Xor => {
1804            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1805            state.push1(builder.ins().bxor(a, b))
1806        }
1807        Operator::V128And => {
1808            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1809            state.push1(builder.ins().band(a, b))
1810        }
1811        Operator::V128AndNot => {
1812            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1813            state.push1(builder.ins().band_not(a, b))
1814        }
1815        Operator::V128Not => {
1816            let a = state.pop1();
1817            state.push1(builder.ins().bnot(a));
1818        }
1819        Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
1820            let (a, b) = state.pop2();
1821            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1822            let bitwidth = i64::from(type_of(op).lane_bits());
1823            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1824            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1825            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1826            state.push1(builder.ins().ishl(bitcast_a, b_mod_bitwidth))
1827        }
1828        Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
1829            let (a, b) = state.pop2();
1830            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1831            let bitwidth = i64::from(type_of(op).lane_bits());
1832            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1833            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1834            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1835            state.push1(builder.ins().ushr(bitcast_a, b_mod_bitwidth))
1836        }
1837        Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
1838            let (a, b) = state.pop2();
1839            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1840            let bitwidth = i64::from(type_of(op).lane_bits());
1841            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1842            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1843            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1844            state.push1(builder.ins().sshr(bitcast_a, b_mod_bitwidth))
1845        }
1846        Operator::V128Bitselect => {
1847            let (a, b, c) = state.pop3();
1848            let bitcast_a = optionally_bitcast_vector(a, I8X16, builder);
1849            let bitcast_b = optionally_bitcast_vector(b, I8X16, builder);
1850            let bitcast_c = optionally_bitcast_vector(c, I8X16, builder);
1851            // The CLIF operand ordering is slightly different and the types of all three
1852            // operands must match (hence the bitcast).
1853            state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
1854        }
1855        Operator::V128AnyTrue => {
1856            let a = pop1_with_bitcast(state, type_of(op), builder);
1857            let bool_result = builder.ins().vany_true(a);
1858            state.push1(builder.ins().uextend(I32, bool_result))
1859        }
1860        Operator::I8x16AllTrue
1861        | Operator::I16x8AllTrue
1862        | Operator::I32x4AllTrue
1863        | Operator::I64x2AllTrue => {
1864            let a = pop1_with_bitcast(state, type_of(op), builder);
1865            let bool_result = builder.ins().vall_true(a);
1866            state.push1(builder.ins().uextend(I32, bool_result))
1867        }
1868        Operator::I8x16Bitmask
1869        | Operator::I16x8Bitmask
1870        | Operator::I32x4Bitmask
1871        | Operator::I64x2Bitmask => {
1872            let a = pop1_with_bitcast(state, type_of(op), builder);
1873            state.push1(builder.ins().vhigh_bits(I32, a));
1874        }
1875        Operator::I8x16Eq | Operator::I16x8Eq | Operator::I32x4Eq | Operator::I64x2Eq => {
1876            translate_vector_icmp(IntCC::Equal, type_of(op), builder, state)
1877        }
1878        Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
1879            translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, state)
1880        }
1881        Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
1882            translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, state)
1883        }
1884        Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
1885            translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, state)
1886        }
1887        Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
1888            translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, state)
1889        }
1890        Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
1891            translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, state)
1892        }
1893        Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
1894            translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, state)
1895        }
1896        Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
1897            translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, state)
1898        }
1899        Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
1900            IntCC::UnsignedGreaterThanOrEqual,
1901            type_of(op),
1902            builder,
1903            state,
1904        ),
1905        Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
1906            translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, state)
1907        }
1908        Operator::F32x4Eq | Operator::F64x2Eq => {
1909            translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, state)
1910        }
1911        Operator::F32x4Ne | Operator::F64x2Ne => {
1912            translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, state)
1913        }
1914        Operator::F32x4Lt | Operator::F64x2Lt => {
1915            translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, state)
1916        }
1917        Operator::F32x4Gt | Operator::F64x2Gt => {
1918            translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, state)
1919        }
1920        Operator::F32x4Le | Operator::F64x2Le => {
1921            translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, state)
1922        }
1923        Operator::F32x4Ge | Operator::F64x2Ge => {
1924            translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, state)
1925        }
1926        Operator::F32x4Add | Operator::F64x2Add => {
1927            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1928            state.push1(builder.ins().fadd(a, b))
1929        }
1930        Operator::F32x4Sub | Operator::F64x2Sub => {
1931            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1932            state.push1(builder.ins().fsub(a, b))
1933        }
1934        Operator::F32x4Mul | Operator::F64x2Mul => {
1935            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1936            state.push1(builder.ins().fmul(a, b))
1937        }
1938        Operator::F32x4Div | Operator::F64x2Div => {
1939            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1940            state.push1(builder.ins().fdiv(a, b))
1941        }
1942        Operator::F32x4Max | Operator::F64x2Max => {
1943            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1944            state.push1(builder.ins().fmax(a, b))
1945        }
1946        Operator::F32x4Min | Operator::F64x2Min => {
1947            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1948            state.push1(builder.ins().fmin(a, b))
1949        }
1950        Operator::F32x4PMax | Operator::F64x2PMax => {
1951            // Note the careful ordering here with respect to `fcmp` and
1952            // `bitselect`. This matches the spec definition of:
1953            //
1954            //  fpmax(z1, z2) =
1955            //      * If z1 is less than z2 then return z2.
1956            //      * Else return z1.
1957            let ty = type_of(op);
1958            let (a, b) = pop2_with_bitcast(state, ty, builder);
1959            let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
1960            let cmp = optionally_bitcast_vector(cmp, ty, builder);
1961            state.push1(builder.ins().bitselect(cmp, b, a))
1962        }
1963        Operator::F32x4PMin | Operator::F64x2PMin => {
1964            // Note the careful ordering here which is similar to `pmax` above:
1965            //
1966            //  fpmin(z1, z2) =
1967            //      * If z2 is less than z1 then return z2.
1968            //      * Else return z1.
1969            let ty = type_of(op);
1970            let (a, b) = pop2_with_bitcast(state, ty, builder);
1971            let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
1972            let cmp = optionally_bitcast_vector(cmp, ty, builder);
1973            state.push1(builder.ins().bitselect(cmp, b, a))
1974        }
1975        Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
1976            let a = pop1_with_bitcast(state, type_of(op), builder);
1977            state.push1(builder.ins().sqrt(a))
1978        }
1979        Operator::F32x4Neg | Operator::F64x2Neg => {
1980            let a = pop1_with_bitcast(state, type_of(op), builder);
1981            state.push1(builder.ins().fneg(a))
1982        }
1983        Operator::F32x4Abs | Operator::F64x2Abs => {
1984            let a = pop1_with_bitcast(state, type_of(op), builder);
1985            state.push1(builder.ins().fabs(a))
1986        }
1987        Operator::F32x4ConvertI32x4S => {
1988            let a = pop1_with_bitcast(state, I32X4, builder);
1989            state.push1(builder.ins().fcvt_from_sint(F32X4, a))
1990        }
1991        Operator::F32x4ConvertI32x4U => {
1992            let a = pop1_with_bitcast(state, I32X4, builder);
1993            state.push1(builder.ins().fcvt_from_uint(F32X4, a))
1994        }
1995        Operator::F64x2ConvertLowI32x4S => {
1996            let a = pop1_with_bitcast(state, I32X4, builder);
1997            let widened_a = builder.ins().swiden_low(a);
1998            state.push1(builder.ins().fcvt_from_sint(F64X2, widened_a));
1999        }
2000        Operator::F64x2ConvertLowI32x4U => {
2001            let a = pop1_with_bitcast(state, I32X4, builder);
2002            let widened_a = builder.ins().uwiden_low(a);
2003            state.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
2004        }
2005        Operator::F64x2PromoteLowF32x4 => {
2006            let a = pop1_with_bitcast(state, F32X4, builder);
2007            state.push1(builder.ins().fvpromote_low(a));
2008        }
2009        Operator::F32x4DemoteF64x2Zero => {
2010            let a = pop1_with_bitcast(state, F64X2, builder);
2011            state.push1(builder.ins().fvdemote(a));
2012        }
2013        Operator::I32x4TruncSatF32x4S => {
2014            let a = pop1_with_bitcast(state, F32X4, builder);
2015            state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2016        }
2017        Operator::I32x4TruncSatF64x2SZero => {
2018            let a = pop1_with_bitcast(state, F64X2, builder);
2019            let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2020            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2021            let zero = builder.ins().vconst(I64X2, handle);
2022
2023            state.push1(builder.ins().snarrow(converted_a, zero));
2024        }
2025        Operator::I32x4TruncSatF32x4U => {
2026            let a = pop1_with_bitcast(state, F32X4, builder);
2027            state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2028        }
2029        Operator::I32x4TruncSatF64x2UZero => {
2030            let a = pop1_with_bitcast(state, F64X2, builder);
2031            let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2032            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2033            let zero = builder.ins().vconst(I64X2, handle);
2034
2035            state.push1(builder.ins().uunarrow(converted_a, zero));
2036        }
2037        Operator::I8x16NarrowI16x8S => {
2038            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2039            state.push1(builder.ins().snarrow(a, b))
2040        }
2041        Operator::I16x8NarrowI32x4S => {
2042            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2043            state.push1(builder.ins().snarrow(a, b))
2044        }
2045        Operator::I8x16NarrowI16x8U => {
2046            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2047            state.push1(builder.ins().unarrow(a, b))
2048        }
2049        Operator::I16x8NarrowI32x4U => {
2050            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2051            state.push1(builder.ins().unarrow(a, b))
2052        }
2053        Operator::I16x8ExtendLowI8x16S => {
2054            let a = pop1_with_bitcast(state, I8X16, builder);
2055            state.push1(builder.ins().swiden_low(a))
2056        }
2057        Operator::I16x8ExtendHighI8x16S => {
2058            let a = pop1_with_bitcast(state, I8X16, builder);
2059            state.push1(builder.ins().swiden_high(a))
2060        }
2061        Operator::I16x8ExtendLowI8x16U => {
2062            let a = pop1_with_bitcast(state, I8X16, builder);
2063            state.push1(builder.ins().uwiden_low(a))
2064        }
2065        Operator::I16x8ExtendHighI8x16U => {
2066            let a = pop1_with_bitcast(state, I8X16, builder);
2067            state.push1(builder.ins().uwiden_high(a))
2068        }
2069        Operator::I32x4ExtendLowI16x8S => {
2070            let a = pop1_with_bitcast(state, I16X8, builder);
2071            state.push1(builder.ins().swiden_low(a))
2072        }
2073        Operator::I32x4ExtendHighI16x8S => {
2074            let a = pop1_with_bitcast(state, I16X8, builder);
2075            state.push1(builder.ins().swiden_high(a))
2076        }
2077        Operator::I32x4ExtendLowI16x8U => {
2078            let a = pop1_with_bitcast(state, I16X8, builder);
2079            state.push1(builder.ins().uwiden_low(a))
2080        }
2081        Operator::I32x4ExtendHighI16x8U => {
2082            let a = pop1_with_bitcast(state, I16X8, builder);
2083            state.push1(builder.ins().uwiden_high(a))
2084        }
2085
2086        Operator::I64x2ExtendLowI32x4S => {
2087            let a = pop1_with_bitcast(state, I32X4, builder);
2088            state.push1(builder.ins().swiden_low(a))
2089        }
2090        Operator::I64x2ExtendHighI32x4S => {
2091            let a = pop1_with_bitcast(state, I32X4, builder);
2092            state.push1(builder.ins().swiden_high(a))
2093        }
2094        Operator::I64x2ExtendLowI32x4U => {
2095            let a = pop1_with_bitcast(state, I32X4, builder);
2096            state.push1(builder.ins().uwiden_low(a))
2097        }
2098        Operator::I64x2ExtendHighI32x4U => {
2099            let a = pop1_with_bitcast(state, I32X4, builder);
2100            state.push1(builder.ins().uwiden_high(a))
2101        }
2102        Operator::I16x8ExtAddPairwiseI8x16S => {
2103            let a = pop1_with_bitcast(state, I8X16, builder);
2104            let widen_low = builder.ins().swiden_low(a);
2105            let widen_high = builder.ins().swiden_high(a);
2106            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2107        }
2108        Operator::I32x4ExtAddPairwiseI16x8S => {
2109            let a = pop1_with_bitcast(state, I16X8, builder);
2110            let widen_low = builder.ins().swiden_low(a);
2111            let widen_high = builder.ins().swiden_high(a);
2112            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2113        }
2114        Operator::I16x8ExtAddPairwiseI8x16U => {
2115            let a = pop1_with_bitcast(state, I8X16, builder);
2116            let widen_low = builder.ins().uwiden_low(a);
2117            let widen_high = builder.ins().uwiden_high(a);
2118            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2119        }
2120        Operator::I32x4ExtAddPairwiseI16x8U => {
2121            let a = pop1_with_bitcast(state, I16X8, builder);
2122            let widen_low = builder.ins().uwiden_low(a);
2123            let widen_high = builder.ins().uwiden_high(a);
2124            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2125        }
2126        Operator::F32x4Ceil | Operator::F64x2Ceil => {
2127            // This is something of a misuse of `type_of`, because that produces the return type
2128            // of `op`.  In this case we want the arg type, but we know it's the same as the
2129            // return type.  Same for the 3 cases below.
2130            let arg = pop1_with_bitcast(state, type_of(op), builder);
2131            state.push1(builder.ins().ceil(arg));
2132        }
2133        Operator::F32x4Floor | Operator::F64x2Floor => {
2134            let arg = pop1_with_bitcast(state, type_of(op), builder);
2135            state.push1(builder.ins().floor(arg));
2136        }
2137        Operator::F32x4Trunc | Operator::F64x2Trunc => {
2138            let arg = pop1_with_bitcast(state, type_of(op), builder);
2139            state.push1(builder.ins().trunc(arg));
2140        }
2141        Operator::F32x4Nearest | Operator::F64x2Nearest => {
2142            let arg = pop1_with_bitcast(state, type_of(op), builder);
2143            state.push1(builder.ins().nearest(arg));
2144        }
2145        Operator::I32x4DotI16x8S => {
2146            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2147            let alow = builder.ins().swiden_low(a);
2148            let blow = builder.ins().swiden_low(b);
2149            let low = builder.ins().imul(alow, blow);
2150            let ahigh = builder.ins().swiden_high(a);
2151            let bhigh = builder.ins().swiden_high(b);
2152            let high = builder.ins().imul(ahigh, bhigh);
2153            state.push1(builder.ins().iadd_pairwise(low, high));
2154        }
2155        Operator::I8x16Popcnt => {
2156            let arg = pop1_with_bitcast(state, type_of(op), builder);
2157            state.push1(builder.ins().popcnt(arg));
2158        }
2159        Operator::I16x8Q15MulrSatS => {
2160            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2161            state.push1(builder.ins().sqmul_round_sat(a, b))
2162        }
2163        Operator::I16x8ExtMulLowI8x16S => {
2164            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2165            let a_low = builder.ins().swiden_low(a);
2166            let b_low = builder.ins().swiden_low(b);
2167            state.push1(builder.ins().imul(a_low, b_low));
2168        }
2169        Operator::I16x8ExtMulHighI8x16S => {
2170            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2171            let a_high = builder.ins().swiden_high(a);
2172            let b_high = builder.ins().swiden_high(b);
2173            state.push1(builder.ins().imul(a_high, b_high));
2174        }
2175        Operator::I16x8ExtMulLowI8x16U => {
2176            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2177            let a_low = builder.ins().uwiden_low(a);
2178            let b_low = builder.ins().uwiden_low(b);
2179            state.push1(builder.ins().imul(a_low, b_low));
2180        }
2181        Operator::I16x8ExtMulHighI8x16U => {
2182            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2183            let a_high = builder.ins().uwiden_high(a);
2184            let b_high = builder.ins().uwiden_high(b);
2185            state.push1(builder.ins().imul(a_high, b_high));
2186        }
2187        Operator::I32x4ExtMulLowI16x8S => {
2188            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2189            let a_low = builder.ins().swiden_low(a);
2190            let b_low = builder.ins().swiden_low(b);
2191            state.push1(builder.ins().imul(a_low, b_low));
2192        }
2193        Operator::I32x4ExtMulHighI16x8S => {
2194            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2195            let a_high = builder.ins().swiden_high(a);
2196            let b_high = builder.ins().swiden_high(b);
2197            state.push1(builder.ins().imul(a_high, b_high));
2198        }
2199        Operator::I32x4ExtMulLowI16x8U => {
2200            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2201            let a_low = builder.ins().uwiden_low(a);
2202            let b_low = builder.ins().uwiden_low(b);
2203            state.push1(builder.ins().imul(a_low, b_low));
2204        }
2205        Operator::I32x4ExtMulHighI16x8U => {
2206            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2207            let a_high = builder.ins().uwiden_high(a);
2208            let b_high = builder.ins().uwiden_high(b);
2209            state.push1(builder.ins().imul(a_high, b_high));
2210        }
2211        Operator::I64x2ExtMulLowI32x4S => {
2212            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2213            let a_low = builder.ins().swiden_low(a);
2214            let b_low = builder.ins().swiden_low(b);
2215            state.push1(builder.ins().imul(a_low, b_low));
2216        }
2217        Operator::I64x2ExtMulHighI32x4S => {
2218            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2219            let a_high = builder.ins().swiden_high(a);
2220            let b_high = builder.ins().swiden_high(b);
2221            state.push1(builder.ins().imul(a_high, b_high));
2222        }
2223        Operator::I64x2ExtMulLowI32x4U => {
2224            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2225            let a_low = builder.ins().uwiden_low(a);
2226            let b_low = builder.ins().uwiden_low(b);
2227            state.push1(builder.ins().imul(a_low, b_low));
2228        }
2229        Operator::I64x2ExtMulHighI32x4U => {
2230            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2231            let a_high = builder.ins().uwiden_high(a);
2232            let b_high = builder.ins().uwiden_high(b);
2233            state.push1(builder.ins().imul(a_high, b_high));
2234        }
2235        Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
2236            return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
2237        }
2238        Operator::I8x16RelaxedSwizzle
2239        | Operator::I32x4RelaxedTruncF32x4S
2240        | Operator::I32x4RelaxedTruncF32x4U
2241        | Operator::I32x4RelaxedTruncF64x2SZero
2242        | Operator::I32x4RelaxedTruncF64x2UZero
2243        | Operator::F32x4RelaxedNmadd
2244        | Operator::F32x4RelaxedMadd
2245        | Operator::I8x16RelaxedLaneselect
2246        | Operator::I16x8RelaxedLaneselect
2247        | Operator::I32x4RelaxedLaneselect
2248        | Operator::I64x2RelaxedLaneselect
2249        | Operator::F32x4RelaxedMin
2250        | Operator::F32x4RelaxedMax
2251        | Operator::F64x2RelaxedMin
2252        | Operator::F64x2RelaxedMax
2253        | Operator::F64x2RelaxedMadd
2254        | Operator::F64x2RelaxedNmadd
2255        | Operator::I16x8RelaxedDotI8x16I7x16S
2256        | Operator::I32x4RelaxedDotI8x16I7x16AddS
2257        | Operator::I16x8RelaxedQ15mulrS => {
2258            return Err(wasm_unsupported!("proposed relaxed-simd operator {:?}", op));
2259        }
2260        Operator::RefEq
2261        | Operator::StructNew { .. }
2262        | Operator::StructNewDefault { .. }
2263        | Operator::StructGet { .. }
2264        | Operator::StructGetS { .. }
2265        | Operator::StructGetU { .. }
2266        | Operator::StructSet { .. }
2267        | Operator::ArrayNew { .. }
2268        | Operator::ArrayNewDefault { .. }
2269        | Operator::ArrayNewFixed { .. }
2270        | Operator::ArrayNewData { .. }
2271        | Operator::ArrayNewElem { .. }
2272        | Operator::ArrayGet { .. }
2273        | Operator::ArrayGetS { .. }
2274        | Operator::ArrayGetU { .. }
2275        | Operator::ArraySet { .. }
2276        | Operator::ArrayLen
2277        | Operator::ArrayFill { .. }
2278        | Operator::ArrayCopy { .. }
2279        | Operator::ArrayInitData { .. }
2280        | Operator::ArrayInitElem { .. }
2281        | Operator::RefTestNonNull { .. } => {}
2282        Operator::RefTestNullable { .. }
2283        | Operator::RefCastNonNull { .. }
2284        | Operator::RefCastNullable { .. }
2285        | Operator::BrOnCast { .. }
2286        | Operator::BrOnCastFail { .. }
2287        | Operator::AnyConvertExtern
2288        | Operator::ExternConvertAny
2289        | Operator::RefI31
2290        | Operator::RefI31Shared => todo!(),
2291        Operator::I31GetS
2292        | Operator::I31GetU
2293        | Operator::MemoryDiscard { .. }
2294        | Operator::CallRef { .. }
2295        | Operator::ReturnCallRef { .. }
2296        | Operator::RefAsNonNull
2297        | Operator::BrOnNull { .. }
2298        | Operator::BrOnNonNull { .. } => {
2299            return Err(wasm_unsupported!("GC proposal not (operator: {:?})", op));
2300        }
2301        Operator::GlobalAtomicGet { .. }
2302        | Operator::GlobalAtomicSet { .. }
2303        | Operator::GlobalAtomicRmwAdd { .. }
2304        | Operator::GlobalAtomicRmwSub { .. }
2305        | Operator::GlobalAtomicRmwAnd { .. }
2306        | Operator::GlobalAtomicRmwOr { .. }
2307        | Operator::GlobalAtomicRmwXor { .. }
2308        | Operator::GlobalAtomicRmwXchg { .. }
2309        | Operator::GlobalAtomicRmwCmpxchg { .. } => {
2310            return Err(wasm_unsupported!("Global atomics not supported yet!"));
2311        }
2312        Operator::TableAtomicGet { .. }
2313        | Operator::TableAtomicSet { .. }
2314        | Operator::TableAtomicRmwXchg { .. }
2315        | Operator::TableAtomicRmwCmpxchg { .. } => {
2316            return Err(wasm_unsupported!("Table atomics not supported yet!"));
2317        }
2318        Operator::StructAtomicGet { .. }
2319        | Operator::StructAtomicGetS { .. }
2320        | Operator::StructAtomicGetU { .. }
2321        | Operator::StructAtomicSet { .. }
2322        | Operator::StructAtomicRmwAdd { .. }
2323        | Operator::StructAtomicRmwSub { .. }
2324        | Operator::StructAtomicRmwAnd { .. }
2325        | Operator::StructAtomicRmwOr { .. }
2326        | Operator::StructAtomicRmwXor { .. }
2327        | Operator::StructAtomicRmwXchg { .. }
2328        | Operator::StructAtomicRmwCmpxchg { .. } => {
2329            return Err(wasm_unsupported!("Table atomics not supported yet!"));
2330        }
2331        Operator::ArrayAtomicGet { .. }
2332        | Operator::ArrayAtomicGetS { .. }
2333        | Operator::ArrayAtomicGetU { .. }
2334        | Operator::ArrayAtomicSet { .. }
2335        | Operator::ArrayAtomicRmwAdd { .. }
2336        | Operator::ArrayAtomicRmwSub { .. }
2337        | Operator::ArrayAtomicRmwAnd { .. }
2338        | Operator::ArrayAtomicRmwOr { .. }
2339        | Operator::ArrayAtomicRmwXor { .. }
2340        | Operator::ArrayAtomicRmwXchg { .. }
2341        | Operator::ArrayAtomicRmwCmpxchg { .. } => {
2342            return Err(wasm_unsupported!("Array atomics not supported yet!"));
2343        }
2344        Operator::ContNew { .. } => todo!(),
2345        Operator::ContBind { .. } => todo!(),
2346        Operator::Suspend { .. } => todo!(),
2347        Operator::Resume { .. } => todo!(),
2348        Operator::ResumeThrow { .. } => todo!(),
2349        Operator::Switch { .. } => todo!(),
2350        Operator::I64Add128 => todo!(),
2351        Operator::I64Sub128 => todo!(),
2352        Operator::I64MulWideS => todo!(),
2353        Operator::I64MulWideU => todo!(),
2354        _ => todo!(),
2355    };
2356    Ok(())
2357}
2358
2359// Clippy warns us of some fields we are deliberately ignoring
2360#[allow(clippy::unneeded_field_pattern)]
2361/// Deals with a Wasm instruction located in an unreachable portion of the code. Most of them
2362/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
2363/// portion so the translation state must be updated accordingly.
2364fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
2365    module_translation_state: &ModuleTranslationState,
2366    op: &Operator,
2367    builder: &mut FunctionBuilder,
2368    state: &mut FuncTranslationState,
2369    environ: &mut FE,
2370) -> WasmResult<()> {
2371    debug_assert!(!state.reachable);
2372    match *op {
2373        Operator::If { blockty } => {
2374            // Push a placeholder control stack entry. The if isn't reachable,
2375            // so we don't have any branches anywhere.
2376            state.push_if(
2377                ir::Block::reserved_value(),
2378                ElseData::NoElse {
2379                    branch_inst: ir::Inst::reserved_value(),
2380                    placeholder: ir::Block::reserved_value(),
2381                },
2382                0,
2383                0,
2384                blockty,
2385            );
2386        }
2387        Operator::Loop { blockty: _ }
2388        | Operator::Block { blockty: _ }
2389        | Operator::TryTable { try_table: _ } => {
2390            state.push_block(ir::Block::reserved_value(), 0, 0);
2391        }
2392        Operator::Else => {
2393            let i = state.control_stack.len() - 1;
2394            match state.control_stack[i] {
2395                ControlStackFrame::If {
2396                    ref else_data,
2397                    head_is_reachable,
2398                    ref mut consequent_ends_reachable,
2399                    blocktype,
2400                    ..
2401                } => {
2402                    debug_assert!(consequent_ends_reachable.is_none());
2403                    *consequent_ends_reachable = Some(state.reachable);
2404
2405                    if head_is_reachable {
2406                        // We have a branch from the head of the `if` to the `else`.
2407                        state.reachable = true;
2408
2409                        let else_block = match *else_data {
2410                            ElseData::NoElse {
2411                                branch_inst,
2412                                placeholder,
2413                            } => {
2414                                let (params, _results) = module_translation_state
2415                                    .blocktype_params_results(&blocktype)?;
2416                                let else_block =
2417                                    block_with_params(builder, params.iter(), environ)?;
2418                                let frame = state.control_stack.last().unwrap();
2419                                frame.truncate_value_stack_to_else_params(&mut state.stack);
2420
2421                                // We change the target of the branch instruction.
2422                                builder.change_jump_destination(
2423                                    branch_inst,
2424                                    placeholder,
2425                                    else_block,
2426                                );
2427                                builder.seal_block(else_block);
2428                                else_block
2429                            }
2430                            ElseData::WithElse { else_block } => {
2431                                let frame = state.control_stack.last().unwrap();
2432                                frame.truncate_value_stack_to_else_params(&mut state.stack);
2433                                else_block
2434                            }
2435                        };
2436
2437                        builder.switch_to_block(else_block);
2438
2439                        // Again, no need to push the parameters for the `else`,
2440                        // since we already did when we saw the original `if`. See
2441                        // the comment for translating `Operator::Else` in
2442                        // `translate_operator` for details.
2443                    }
2444                }
2445                _ => unreachable!(),
2446            }
2447        }
2448        Operator::End => {
2449            let stack = &mut state.stack;
2450            let control_stack = &mut state.control_stack;
2451            let frame = control_stack.pop().unwrap();
2452            frame.restore_catch_handlers(&mut state.handlers, builder);
2453
2454            // Pop unused parameters from stack.
2455            frame.truncate_value_stack_to_original_size(stack);
2456
2457            let reachable_anyway = match frame {
2458                // If it is a loop we also have to seal the body loop block
2459                ControlStackFrame::Loop { header, .. } => {
2460                    builder.seal_block(header);
2461                    // And loops can't have branches to the end.
2462                    false
2463                }
2464                // If we never set `consequent_ends_reachable` then that means
2465                // we are finishing the consequent now, and there was no
2466                // `else`. Whether the following block is reachable depends only
2467                // on if the head was reachable.
2468                ControlStackFrame::If {
2469                    head_is_reachable,
2470                    consequent_ends_reachable: None,
2471                    ..
2472                } => head_is_reachable,
2473                // Since we are only in this function when in unreachable code,
2474                // we know that the alternative just ended unreachable. Whether
2475                // the following block is reachable depends on if the consequent
2476                // ended reachable or not.
2477                ControlStackFrame::If {
2478                    head_is_reachable,
2479                    consequent_ends_reachable: Some(consequent_ends_reachable),
2480                    ..
2481                } => head_is_reachable && consequent_ends_reachable,
2482                // All other control constructs are already handled.
2483                _ => false,
2484            };
2485
2486            if frame.exit_is_branched_to() || reachable_anyway {
2487                builder.switch_to_block(frame.following_code());
2488                builder.seal_block(frame.following_code());
2489
2490                // And add the return values of the block but only if the next block is reachable
2491                // (which corresponds to testing if the stack depth is 1)
2492                stack.extend_from_slice(builder.block_params(frame.following_code()));
2493                state.reachable = true;
2494            }
2495        }
2496        _ => {
2497            // We don't translate because this is unreachable code
2498        }
2499    }
2500
2501    Ok(())
2502}
2503
2504/// This function is a generalized helper for validating that a wasm-supplied
2505/// heap address is in-bounds.
2506///
2507/// This function takes a litany of parameters and requires that the *Wasm*
2508/// address to be verified is at the top of the stack in `state`. This will
2509/// generate necessary IR to validate that the heap address is correctly
2510/// in-bounds, and various parameters are returned describing the valid *native*
2511/// heap address if execution reaches that point.
2512///
2513/// Returns `None` when the Wasm access will unconditionally trap.
2514///
2515/// Returns `(flags, wasm_addr, native_addr)`.
2516fn prepare_addr<FE>(
2517    memarg: &MemArg,
2518    access_size: u8,
2519    builder: &mut FunctionBuilder,
2520    state: &mut FuncTranslationState,
2521    environ: &mut FE,
2522) -> WasmResult<Reachability<(MemFlags, Value, Value)>>
2523where
2524    FE: FuncEnvironment + ?Sized,
2525{
2526    let index = state.pop1();
2527    let heap = state.get_heap(builder.func, memarg.memory, environ)?;
2528
2529    // How exactly the bounds check is performed here and what it's performed
2530    // on is a bit tricky. Generally we want to rely on access violations (e.g.
2531    // segfaults) to generate traps since that means we don't have to bounds
2532    // check anything explicitly.
2533    //
2534    // (1) If we don't have a guard page of unmapped memory, though, then we
2535    // can't rely on this trapping behavior through segfaults. Instead we need
2536    // to bounds-check the entire memory access here which is everything from
2537    // `addr32 + offset` to `addr32 + offset + width` (not inclusive). In this
2538    // scenario our adjusted offset that we're checking is `memarg.offset +
2539    // access_size`. Note that we do saturating arithmetic here to avoid
2540    // overflow. The addition here is in the 64-bit space, which means that
2541    // we'll never overflow for 32-bit wasm but for 64-bit this is an issue. If
2542    // our effective offset is u64::MAX though then it's impossible for for
2543    // that to actually be a valid offset because otherwise the wasm linear
2544    // memory would take all of the host memory!
2545    //
2546    // (2) If we have a guard page, however, then we can perform a further
2547    // optimization of the generated code by only checking multiples of the
2548    // offset-guard size to be more CSE-friendly. Knowing that we have at least
2549    // 1 page of a guard page we're then able to disregard the `width` since we
2550    // know it's always less than one page. Our bounds check will be for the
2551    // first byte which will either succeed and be guaranteed to fault if it's
2552    // actually out of bounds, or the bounds check itself will fail. In any case
2553    // we assert that the width is reasonably small for now so this assumption
2554    // can be adjusted in the future if we get larger widths.
2555    //
2556    // Put another way we can say, where `y < offset_guard_size`:
2557    //
2558    //      n * offset_guard_size + y = offset
2559    //
2560    // We'll then pass `n * offset_guard_size` as the bounds check value. If
2561    // this traps then our `offset` would have trapped anyway. If this check
2562    // passes we know
2563    //
2564    //      addr32 + n * offset_guard_size < bound
2565    //
2566    // which means
2567    //
2568    //      addr32 + n * offset_guard_size + y < bound + offset_guard_size
2569    //
2570    // because `y < offset_guard_size`, which then means:
2571    //
2572    //      addr32 + offset < bound + offset_guard_size
2573    //
2574    // Since we know that that guard size bytes are all unmapped we're
2575    // guaranteed that `offset` and the `width` bytes after it are either
2576    // in-bounds or will hit the guard page, meaning we'll get the desired
2577    // semantics we want.
2578    //
2579    // ---
2580    //
2581    // With all that in mind remember that the goal is to bounds check as few
2582    // things as possible. To facilitate this the "fast path" is expected to be
2583    // hit like so:
2584    //
2585    // * For wasm32, wasmtime defaults to 4gb "static" memories with 2gb guard
2586    //   regions. This means that for all offsets <=2gb, we hit the optimized
2587    //   case for `heap_addr` on static memories 4gb in size in cranelift's
2588    //   legalization of `heap_addr`, eliding the bounds check entirely.
2589    //
2590    // * For wasm64 offsets <=2gb will generate a single `heap_addr`
2591    //   instruction, but at this time all heaps are "dynamic" which means that
2592    //   a single bounds check is forced. Ideally we'd do better here, but
2593    //   that's the current state of affairs.
2594    //
2595    // Basically we assume that most configurations have a guard page and most
2596    // offsets in `memarg` are <=2gb, which means we get the fast path of one
2597    // `heap_addr` instruction plus a hardcoded i32-offset in memory-related
2598    // instructions.
2599    let heap = environ.heaps()[heap].clone();
2600    let addr = match u32::try_from(memarg.offset) {
2601        // If our offset fits within a u32, then we can place the it into the
2602        // offset immediate of the `heap_addr` instruction.
2603        Ok(offset) => bounds_checks::bounds_check_and_compute_addr(
2604            builder,
2605            environ,
2606            &heap,
2607            index,
2608            offset,
2609            access_size,
2610        )?,
2611
2612        // If the offset doesn't fit within a u32, then we can't pass it
2613        // directly into `heap_addr`.
2614        //
2615        // One reasonable question you might ask is "why not?". There's no
2616        // fundamental reason why `heap_addr` *must* take a 32-bit offset. The
2617        // reason this isn't done, though, is that blindly changing the offset
2618        // to a 64-bit offset increases the size of the `InstructionData` enum
2619        // in cranelift by 8 bytes (16 to 24). This can have significant
2620        // performance implications so the conclusion when this was written was
2621        // that we shouldn't do that.
2622        //
2623        // Without the ability to put the whole offset into the `heap_addr`
2624        // instruction we need to fold the offset into the address itself with
2625        // an unsigned addition. In doing so though we need to check for
2626        // overflow because that would mean the address is out-of-bounds (wasm
2627        // bounds checks happen on the effective 33 or 65 bit address once the
2628        // offset is factored in).
2629        //
2630        // Once we have the effective address, offset already folded in, then
2631        // `heap_addr` is used to verify that the address is indeed in-bounds.
2632        //
2633        // Note that this is generating what's likely to be at least two
2634        // branches, one for the overflow and one for the bounds check itself.
2635        // For now though that should hopefully be ok since 4gb+ offsets are
2636        // relatively odd/rare. In the future if needed we can look into
2637        // optimizing this more.
2638        Err(_) => {
2639            let offset = builder.ins().iconst(heap.index_type, memarg.offset as i64);
2640            let adjusted_index =
2641                builder
2642                    .ins()
2643                    .uadd_overflow_trap(index, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
2644            bounds_checks::bounds_check_and_compute_addr(
2645                builder,
2646                environ,
2647                &heap,
2648                adjusted_index,
2649                0,
2650                access_size,
2651            )?
2652        }
2653    };
2654    let addr = match addr {
2655        Reachability::Unreachable => return Ok(Reachability::Unreachable),
2656        Reachability::Reachable(a) => a,
2657    };
2658
2659    // Note that we don't set `is_aligned` here, even if the load instruction's
2660    // alignment immediate may says it's aligned, because WebAssembly's
2661    // immediate field is just a hint, while Cranelift's aligned flag needs a
2662    // guarantee. WebAssembly memory accesses are always little-endian.
2663    let mut flags = MemFlags::new();
2664    flags.set_endianness(ir::Endianness::Little);
2665
2666    if heap.memory_type.is_some() {
2667        // Proof-carrying code is enabled; check this memory access.
2668        flags.set_checked();
2669    }
2670
2671    // The access occurs to the `heap` disjoint category of abstract
2672    // state. This may allow alias analysis to merge redundant loads,
2673    // etc. when heap accesses occur interleaved with other (table,
2674    // vmctx, stack) accesses.
2675    flags.set_alias_region(Some(ir::AliasRegion::Heap));
2676
2677    Ok(Reachability::Reachable((flags, index, addr)))
2678}
2679
2680fn align_atomic_addr(
2681    memarg: &MemArg,
2682    loaded_bytes: u8,
2683    builder: &mut FunctionBuilder,
2684    state: &mut FuncTranslationState,
2685) {
2686    // Atomic addresses must all be aligned correctly, and for now we check
2687    // alignment before we check out-of-bounds-ness. The order of this check may
2688    // need to be updated depending on the outcome of the official threads
2689    // proposal itself.
2690    //
2691    // Note that with an offset>0 we generate an `iadd_imm` where the result is
2692    // thrown away after the offset check. This may truncate the offset and the
2693    // result may overflow as well, but those conditions won't affect the
2694    // alignment check itself. This can probably be optimized better and we
2695    // should do so in the future as well.
2696    if loaded_bytes > 1 {
2697        let addr = state.pop1(); // "peek" via pop then push
2698        state.push1(addr);
2699        let effective_addr = if memarg.offset == 0 {
2700            addr
2701        } else {
2702            builder
2703                .ins()
2704                .iadd_imm(addr, i64::from(memarg.offset as i32))
2705        };
2706        debug_assert!(loaded_bytes.is_power_of_two());
2707        let misalignment = builder
2708            .ins()
2709            .band_imm(effective_addr, i64::from(loaded_bytes - 1));
2710        let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0);
2711        builder.ins().trapnz(f, crate::TRAP_HEAP_MISALIGNED);
2712    }
2713}
2714
2715/// Like `prepare_addr` but for atomic accesses.
2716///
2717/// Returns `None` when the Wasm access will unconditionally trap.
2718fn prepare_atomic_addr<FE: FuncEnvironment + ?Sized>(
2719    memarg: &MemArg,
2720    loaded_bytes: u8,
2721    builder: &mut FunctionBuilder,
2722    state: &mut FuncTranslationState,
2723    environ: &mut FE,
2724) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
2725    align_atomic_addr(memarg, loaded_bytes, builder, state);
2726    prepare_addr(memarg, loaded_bytes, builder, state, environ)
2727}
2728
2729/// Like `Option<T>` but specifically for passing information about transitions
2730/// from reachable to unreachable state and the like from callees to callers.
2731///
2732/// Marked `must_use` to force callers to update
2733/// `FuncTranslationState::reachable` as necessary.
2734#[derive(PartialEq, Eq)]
2735#[must_use]
2736pub enum Reachability<T> {
2737    /// The Wasm execution state is reachable, here is a `T`.
2738    Reachable(T),
2739    /// The Wasm execution state has been determined to be statically
2740    /// unreachable. It is the receiver of this value's responsibility to update
2741    /// `FuncTranslationState::reachable` as necessary.
2742    Unreachable,
2743}
2744
2745/// Translate a load instruction.
2746///
2747/// Returns the execution state's reachability after the load is translated.
2748fn translate_load<FE: FuncEnvironment + ?Sized>(
2749    memarg: &MemArg,
2750    opcode: ir::Opcode,
2751    result_ty: Type,
2752    builder: &mut FunctionBuilder,
2753    state: &mut FuncTranslationState,
2754    environ: &mut FE,
2755) -> WasmResult<Reachability<()>> {
2756    let mem_op_size = mem_op_size(opcode, result_ty);
2757    let (flags, wasm_index, base) =
2758        match prepare_addr(memarg, mem_op_size, builder, state, environ)? {
2759            Reachability::Unreachable => return Ok(Reachability::Unreachable),
2760            Reachability::Reachable((f, i, b)) => (f, i, b),
2761        };
2762
2763    environ.before_load(builder, mem_op_size, wasm_index, memarg.offset);
2764
2765    let (load, dfg) = builder
2766        .ins()
2767        .Load(opcode, result_ty, flags, Offset32::new(0), base);
2768    state.push1(dfg.first_result(load));
2769    Ok(Reachability::Reachable(()))
2770}
2771
2772/// Translate a store instruction.
2773fn translate_store<FE: FuncEnvironment + ?Sized>(
2774    memarg: &MemArg,
2775    opcode: ir::Opcode,
2776    builder: &mut FunctionBuilder,
2777    state: &mut FuncTranslationState,
2778    environ: &mut FE,
2779) -> WasmResult<()> {
2780    let val = state.pop1();
2781    let val_ty = builder.func.dfg.value_type(val);
2782    let mem_op_size = mem_op_size(opcode, val_ty);
2783
2784    let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!(
2785        state,
2786        prepare_addr(memarg, mem_op_size, builder, state, environ)?
2787    );
2788
2789    environ.before_store(builder, mem_op_size, wasm_index, memarg.offset);
2790
2791    builder
2792        .ins()
2793        .Store(opcode, val_ty, flags, Offset32::new(0), val, base);
2794    Ok(())
2795}
2796
2797fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
2798    match opcode {
2799        ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
2800        ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
2801        ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
2802        ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
2803        _ => panic!("unknown size of mem op for {opcode:?}"),
2804    }
2805}
2806
2807fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
2808    let (arg0, arg1) = state.pop2();
2809    let val = builder.ins().icmp(cc, arg0, arg1);
2810    state.push1(builder.ins().uextend(I32, val));
2811}
2812
2813fn fold_atomic_mem_addr(
2814    linear_mem_addr: Value,
2815    memarg: &MemArg,
2816    access_ty: Type,
2817    builder: &mut FunctionBuilder,
2818) -> Value {
2819    let access_ty_bytes = access_ty.bytes();
2820    let final_lma = if memarg.offset > 0 {
2821        assert!(builder.func.dfg.value_type(linear_mem_addr) == I32);
2822        let linear_mem_addr = builder.ins().uextend(I64, linear_mem_addr);
2823        let a = builder
2824            .ins()
2825            .iadd_imm(linear_mem_addr, memarg.offset as i64);
2826        let r = builder
2827            .ins()
2828            .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, a, 0x1_0000_0000i64);
2829        builder.ins().trapnz(r, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
2830        builder.ins().ireduce(I32, a)
2831    } else {
2832        linear_mem_addr
2833    };
2834    assert!(access_ty_bytes == 4 || access_ty_bytes == 8);
2835    let final_lma_misalignment = builder
2836        .ins()
2837        .band_imm(final_lma, i64::from(access_ty_bytes - 1));
2838    let f = builder
2839        .ins()
2840        .icmp_imm(IntCC::Equal, final_lma_misalignment, i64::from(0));
2841    builder.ins().trapz(f, crate::TRAP_HEAP_MISALIGNED);
2842    final_lma
2843}
2844
2845fn translate_atomic_rmw<FE: FuncEnvironment + ?Sized>(
2846    widened_ty: Type,
2847    access_ty: Type,
2848    op: AtomicRmwOp,
2849    memarg: &MemArg,
2850    builder: &mut FunctionBuilder,
2851    state: &mut FuncTranslationState,
2852    environ: &mut FE,
2853) -> WasmResult<()> {
2854    let mut arg2 = state.pop1();
2855    let arg2_ty = builder.func.dfg.value_type(arg2);
2856
2857    // The operation is performed at type `access_ty`, and the old value is zero-extended
2858    // to type `widened_ty`.
2859    match access_ty {
2860        I8 | I16 | I32 | I64 => {}
2861        _ => {
2862            return Err(wasm_unsupported!(
2863                "atomic_rmw: unsupported access type {:?}",
2864                access_ty
2865            ));
2866        }
2867    };
2868    let w_ty_ok = matches!(widened_ty, I32 | I64);
2869    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2870
2871    assert!(arg2_ty.bytes() >= access_ty.bytes());
2872    if arg2_ty.bytes() > access_ty.bytes() {
2873        arg2 = builder.ins().ireduce(access_ty, arg2);
2874    }
2875
2876    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
2877        state,
2878        prepare_atomic_addr(
2879            memarg,
2880            u8::try_from(access_ty.bytes()).unwrap(),
2881            builder,
2882            state,
2883            environ,
2884        )?
2885    );
2886
2887    let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
2888    if access_ty != widened_ty {
2889        res = builder.ins().uextend(widened_ty, res);
2890    }
2891    state.push1(res);
2892    Ok(())
2893}
2894fn translate_atomic_cas<FE: FuncEnvironment + ?Sized>(
2895    widened_ty: Type,
2896    access_ty: Type,
2897    memarg: &MemArg,
2898    builder: &mut FunctionBuilder,
2899    state: &mut FuncTranslationState,
2900    environ: &mut FE,
2901) -> WasmResult<()> {
2902    let (mut expected, mut replacement) = state.pop2();
2903    let expected_ty = builder.func.dfg.value_type(expected);
2904    let replacement_ty = builder.func.dfg.value_type(replacement);
2905
2906    // The compare-and-swap is performed at type `access_ty`, and the old value is zero-extended
2907    // to type `widened_ty`.
2908    match access_ty {
2909        I8 | I16 | I32 | I64 => {}
2910        _ => {
2911            return Err(wasm_unsupported!(
2912                "atomic_cas: unsupported access type {:?}",
2913                access_ty
2914            ));
2915        }
2916    };
2917    let w_ty_ok = matches!(widened_ty, I32 | I64);
2918    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2919
2920    assert!(expected_ty.bytes() >= access_ty.bytes());
2921    if expected_ty.bytes() > access_ty.bytes() {
2922        expected = builder.ins().ireduce(access_ty, expected);
2923    }
2924    assert!(replacement_ty.bytes() >= access_ty.bytes());
2925    if replacement_ty.bytes() > access_ty.bytes() {
2926        replacement = builder.ins().ireduce(access_ty, replacement);
2927    }
2928
2929    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
2930        state,
2931        prepare_atomic_addr(
2932            memarg,
2933            u8::try_from(access_ty.bytes()).unwrap(),
2934            builder,
2935            state,
2936            environ,
2937        )?
2938    );
2939    let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
2940    if access_ty != widened_ty {
2941        res = builder.ins().uextend(widened_ty, res);
2942    }
2943    state.push1(res);
2944    Ok(())
2945}
2946
2947fn translate_atomic_load<FE: FuncEnvironment + ?Sized>(
2948    widened_ty: Type,
2949    access_ty: Type,
2950    memarg: &MemArg,
2951    builder: &mut FunctionBuilder,
2952    state: &mut FuncTranslationState,
2953    environ: &mut FE,
2954) -> WasmResult<()> {
2955    // The load is performed at type `access_ty`, and the loaded value is zero extended
2956    // to `widened_ty`.
2957    match access_ty {
2958        I8 | I16 | I32 | I64 => {}
2959        _ => {
2960            return Err(wasm_unsupported!(
2961                "atomic_load: unsupported access type {:?}",
2962                access_ty
2963            ));
2964        }
2965    };
2966    let w_ty_ok = matches!(widened_ty, I32 | I64);
2967    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2968
2969    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
2970        state,
2971        prepare_atomic_addr(
2972            memarg,
2973            u8::try_from(access_ty.bytes()).unwrap(),
2974            builder,
2975            state,
2976            environ,
2977        )?
2978    );
2979    let mut res = builder.ins().atomic_load(access_ty, flags, addr);
2980    if access_ty != widened_ty {
2981        res = builder.ins().uextend(widened_ty, res);
2982    }
2983    state.push1(res);
2984    Ok(())
2985}
2986
2987fn translate_atomic_store<FE: FuncEnvironment + ?Sized>(
2988    access_ty: Type,
2989    memarg: &MemArg,
2990    builder: &mut FunctionBuilder,
2991    state: &mut FuncTranslationState,
2992    environ: &mut FE,
2993) -> WasmResult<()> {
2994    let mut data = state.pop1();
2995    let data_ty = builder.func.dfg.value_type(data);
2996
2997    // The operation is performed at type `access_ty`, and the data to be stored may first
2998    // need to be narrowed accordingly.
2999    match access_ty {
3000        I8 | I16 | I32 | I64 => {}
3001        _ => {
3002            return Err(wasm_unsupported!(
3003                "atomic_store: unsupported access type {:?}",
3004                access_ty
3005            ));
3006        }
3007    };
3008    let d_ty_ok = matches!(data_ty, I32 | I64);
3009    assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
3010
3011    if data_ty.bytes() > access_ty.bytes() {
3012        data = builder.ins().ireduce(access_ty, data);
3013    }
3014
3015    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3016        state,
3017        prepare_atomic_addr(
3018            memarg,
3019            u8::try_from(access_ty.bytes()).unwrap(),
3020            builder,
3021            state,
3022            environ,
3023        )?
3024    );
3025    builder.ins().atomic_store(flags, data, addr);
3026    Ok(())
3027}
3028
3029fn translate_vector_icmp(
3030    cc: IntCC,
3031    needed_type: Type,
3032    builder: &mut FunctionBuilder,
3033    state: &mut FuncTranslationState,
3034) {
3035    let (a, b) = state.pop2();
3036    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3037    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3038    state.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3039}
3040
3041fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3042    let (arg0, arg1) = state.pop2();
3043    let val = builder.ins().fcmp(cc, arg0, arg1);
3044    state.push1(builder.ins().uextend(I32, val));
3045}
3046
3047fn translate_vector_fcmp(
3048    cc: FloatCC,
3049    needed_type: Type,
3050    builder: &mut FunctionBuilder,
3051    state: &mut FuncTranslationState,
3052) {
3053    let (a, b) = state.pop2();
3054    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3055    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3056    state.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3057}
3058
3059fn translate_br_if(
3060    relative_depth: u32,
3061    builder: &mut FunctionBuilder,
3062    state: &mut FuncTranslationState,
3063) {
3064    let val = state.pop1();
3065    let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
3066    let next_block = builder.create_block();
3067    canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3068
3069    builder.seal_block(next_block); // The only predecessor is the current block.
3070    builder.switch_to_block(next_block);
3071}
3072
3073fn translate_br_if_args(
3074    relative_depth: u32,
3075    state: &mut FuncTranslationState,
3076) -> (ir::Block, &mut [ir::Value]) {
3077    let i = state.control_stack.len() - 1 - (relative_depth as usize);
3078    let (return_count, br_destination) = {
3079        let frame = &mut state.control_stack[i];
3080        // The values returned by the branch are still available for the reachable
3081        // code that comes after it
3082        frame.set_branched_to_exit();
3083        let return_count = if frame.is_loop() {
3084            frame.num_param_values()
3085        } else {
3086            frame.num_return_values()
3087        };
3088        (return_count, frame.br_destination())
3089    };
3090    let inputs = state.peekn_mut(return_count);
3091    (br_destination, inputs)
3092}
3093
3094/// Determine the returned value type of a WebAssembly operator
3095fn type_of(operator: &Operator) -> Type {
3096    match operator {
3097        Operator::V128Load { .. }
3098        | Operator::V128Store { .. }
3099        | Operator::V128Const { .. }
3100        | Operator::V128Not
3101        | Operator::V128And
3102        | Operator::V128AndNot
3103        | Operator::V128Or
3104        | Operator::V128Xor
3105        | Operator::V128AnyTrue
3106        | Operator::V128Bitselect => I8X16, // default type representing V128
3107
3108        Operator::I8x16Shuffle { .. }
3109        | Operator::I8x16Splat
3110        | Operator::V128Load8Splat { .. }
3111        | Operator::V128Load8Lane { .. }
3112        | Operator::V128Store8Lane { .. }
3113        | Operator::I8x16ExtractLaneS { .. }
3114        | Operator::I8x16ExtractLaneU { .. }
3115        | Operator::I8x16ReplaceLane { .. }
3116        | Operator::I8x16Eq
3117        | Operator::I8x16Ne
3118        | Operator::I8x16LtS
3119        | Operator::I8x16LtU
3120        | Operator::I8x16GtS
3121        | Operator::I8x16GtU
3122        | Operator::I8x16LeS
3123        | Operator::I8x16LeU
3124        | Operator::I8x16GeS
3125        | Operator::I8x16GeU
3126        | Operator::I8x16Neg
3127        | Operator::I8x16Abs
3128        | Operator::I8x16AllTrue
3129        | Operator::I8x16Shl
3130        | Operator::I8x16ShrS
3131        | Operator::I8x16ShrU
3132        | Operator::I8x16Add
3133        | Operator::I8x16AddSatS
3134        | Operator::I8x16AddSatU
3135        | Operator::I8x16Sub
3136        | Operator::I8x16SubSatS
3137        | Operator::I8x16SubSatU
3138        | Operator::I8x16MinS
3139        | Operator::I8x16MinU
3140        | Operator::I8x16MaxS
3141        | Operator::I8x16MaxU
3142        | Operator::I8x16AvgrU
3143        | Operator::I8x16Bitmask
3144        | Operator::I8x16Popcnt => I8X16,
3145
3146        Operator::I16x8Splat
3147        | Operator::V128Load16Splat { .. }
3148        | Operator::V128Load16Lane { .. }
3149        | Operator::V128Store16Lane { .. }
3150        | Operator::I16x8ExtractLaneS { .. }
3151        | Operator::I16x8ExtractLaneU { .. }
3152        | Operator::I16x8ReplaceLane { .. }
3153        | Operator::I16x8Eq
3154        | Operator::I16x8Ne
3155        | Operator::I16x8LtS
3156        | Operator::I16x8LtU
3157        | Operator::I16x8GtS
3158        | Operator::I16x8GtU
3159        | Operator::I16x8LeS
3160        | Operator::I16x8LeU
3161        | Operator::I16x8GeS
3162        | Operator::I16x8GeU
3163        | Operator::I16x8Neg
3164        | Operator::I16x8Abs
3165        | Operator::I16x8AllTrue
3166        | Operator::I16x8Shl
3167        | Operator::I16x8ShrS
3168        | Operator::I16x8ShrU
3169        | Operator::I16x8Add
3170        | Operator::I16x8AddSatS
3171        | Operator::I16x8AddSatU
3172        | Operator::I16x8Sub
3173        | Operator::I16x8SubSatS
3174        | Operator::I16x8SubSatU
3175        | Operator::I16x8MinS
3176        | Operator::I16x8MinU
3177        | Operator::I16x8MaxS
3178        | Operator::I16x8MaxU
3179        | Operator::I16x8AvgrU
3180        | Operator::I16x8Mul
3181        | Operator::I16x8Bitmask => I16X8,
3182
3183        Operator::I32x4Splat
3184        | Operator::V128Load32Splat { .. }
3185        | Operator::V128Load32Lane { .. }
3186        | Operator::V128Store32Lane { .. }
3187        | Operator::I32x4ExtractLane { .. }
3188        | Operator::I32x4ReplaceLane { .. }
3189        | Operator::I32x4Eq
3190        | Operator::I32x4Ne
3191        | Operator::I32x4LtS
3192        | Operator::I32x4LtU
3193        | Operator::I32x4GtS
3194        | Operator::I32x4GtU
3195        | Operator::I32x4LeS
3196        | Operator::I32x4LeU
3197        | Operator::I32x4GeS
3198        | Operator::I32x4GeU
3199        | Operator::I32x4Neg
3200        | Operator::I32x4Abs
3201        | Operator::I32x4AllTrue
3202        | Operator::I32x4Shl
3203        | Operator::I32x4ShrS
3204        | Operator::I32x4ShrU
3205        | Operator::I32x4Add
3206        | Operator::I32x4Sub
3207        | Operator::I32x4Mul
3208        | Operator::I32x4MinS
3209        | Operator::I32x4MinU
3210        | Operator::I32x4MaxS
3211        | Operator::I32x4MaxU
3212        | Operator::I32x4Bitmask
3213        | Operator::I32x4TruncSatF32x4S
3214        | Operator::I32x4TruncSatF32x4U
3215        | Operator::V128Load32Zero { .. } => I32X4,
3216
3217        Operator::I64x2Splat
3218        | Operator::V128Load64Splat { .. }
3219        | Operator::V128Load64Lane { .. }
3220        | Operator::V128Store64Lane { .. }
3221        | Operator::I64x2ExtractLane { .. }
3222        | Operator::I64x2ReplaceLane { .. }
3223        | Operator::I64x2Eq
3224        | Operator::I64x2Ne
3225        | Operator::I64x2LtS
3226        | Operator::I64x2GtS
3227        | Operator::I64x2LeS
3228        | Operator::I64x2GeS
3229        | Operator::I64x2Neg
3230        | Operator::I64x2Abs
3231        | Operator::I64x2AllTrue
3232        | Operator::I64x2Shl
3233        | Operator::I64x2ShrS
3234        | Operator::I64x2ShrU
3235        | Operator::I64x2Add
3236        | Operator::I64x2Sub
3237        | Operator::I64x2Mul
3238        | Operator::I64x2Bitmask
3239        | Operator::V128Load64Zero { .. } => I64X2,
3240
3241        Operator::F32x4Splat
3242        | Operator::F32x4ExtractLane { .. }
3243        | Operator::F32x4ReplaceLane { .. }
3244        | Operator::F32x4Eq
3245        | Operator::F32x4Ne
3246        | Operator::F32x4Lt
3247        | Operator::F32x4Gt
3248        | Operator::F32x4Le
3249        | Operator::F32x4Ge
3250        | Operator::F32x4Abs
3251        | Operator::F32x4Neg
3252        | Operator::F32x4Sqrt
3253        | Operator::F32x4Add
3254        | Operator::F32x4Sub
3255        | Operator::F32x4Mul
3256        | Operator::F32x4Div
3257        | Operator::F32x4Min
3258        | Operator::F32x4Max
3259        | Operator::F32x4PMin
3260        | Operator::F32x4PMax
3261        | Operator::F32x4ConvertI32x4S
3262        | Operator::F32x4ConvertI32x4U
3263        | Operator::F32x4Ceil
3264        | Operator::F32x4Floor
3265        | Operator::F32x4Trunc
3266        | Operator::F32x4Nearest => F32X4,
3267
3268        Operator::F64x2Splat
3269        | Operator::F64x2ExtractLane { .. }
3270        | Operator::F64x2ReplaceLane { .. }
3271        | Operator::F64x2Eq
3272        | Operator::F64x2Ne
3273        | Operator::F64x2Lt
3274        | Operator::F64x2Gt
3275        | Operator::F64x2Le
3276        | Operator::F64x2Ge
3277        | Operator::F64x2Abs
3278        | Operator::F64x2Neg
3279        | Operator::F64x2Sqrt
3280        | Operator::F64x2Add
3281        | Operator::F64x2Sub
3282        | Operator::F64x2Mul
3283        | Operator::F64x2Div
3284        | Operator::F64x2Min
3285        | Operator::F64x2Max
3286        | Operator::F64x2PMin
3287        | Operator::F64x2PMax
3288        | Operator::F64x2Ceil
3289        | Operator::F64x2Floor
3290        | Operator::F64x2Trunc
3291        | Operator::F64x2Nearest => F64X2,
3292
3293        _ => unimplemented!(
3294            "Currently only SIMD instructions are mapped to their return type; the \
3295             following instruction is not mapped: {:?}",
3296            operator
3297        ),
3298    }
3299}
3300
3301/// Some SIMD operations only operate on I8X16 in CLIF; this will convert them to that type by
3302/// adding a raw_bitcast if necessary.
3303fn optionally_bitcast_vector(
3304    value: Value,
3305    needed_type: Type,
3306    builder: &mut FunctionBuilder,
3307) -> Value {
3308    if builder.func.dfg.value_type(value) != needed_type {
3309        builder.ins().bitcast(
3310            needed_type,
3311            MemFlags::new().with_endianness(ir::Endianness::Little),
3312            value,
3313        )
3314    } else {
3315        value
3316    }
3317}
3318
3319#[inline(always)]
3320fn is_non_canonical_v128(ty: ir::Type) -> bool {
3321    matches!(ty, I64X2 | I32X4 | I16X8 | F32X4 | F64X2)
3322}
3323
3324/// Cast to I8X16, any vector values in `values` that are of "non-canonical" type (meaning, not
3325/// I8X16), and return them in a slice.  A pre-scan is made to determine whether any casts are
3326/// actually necessary, and if not, the original slice is returned.  Otherwise the cast values
3327/// are returned in a slice that belongs to the caller-supplied `SmallVec`.
3328fn canonicalise_v128_values<'a>(
3329    tmp_canonicalised: &'a mut SmallVec<[ir::BlockArg; 16]>,
3330    builder: &mut FunctionBuilder,
3331    values: &'a [ir::Value],
3332) -> &'a [ir::BlockArg] {
3333    debug_assert!(tmp_canonicalised.is_empty());
3334    for v in values {
3335        let value = if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
3336            builder.ins().bitcast(
3337                I8X16,
3338                MemFlags::new().with_endianness(ir::Endianness::Little),
3339                *v,
3340            )
3341        } else {
3342            *v
3343        };
3344        tmp_canonicalised.push(BlockArg::from(value));
3345    }
3346    tmp_canonicalised.as_slice()
3347}
3348
3349/// Generate a `jump` instruction, but first cast all 128-bit vector values to I8X16 if they
3350/// don't have that type.  This is done in somewhat roundabout way so as to ensure that we
3351/// almost never have to do any heap allocation.
3352fn canonicalise_then_jump(
3353    builder: &mut FunctionBuilder,
3354    destination: ir::Block,
3355    params: &[ir::Value],
3356) -> ir::Inst {
3357    let mut tmp_canonicalised = SmallVec::<[_; 16]>::new();
3358    let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
3359    builder.ins().jump(destination, canonicalised)
3360}
3361
3362/// The same but for a `brif` instruction.
3363fn canonicalise_brif(
3364    builder: &mut FunctionBuilder,
3365    cond: ir::Value,
3366    block_then: ir::Block,
3367    params_then: &[ir::Value],
3368    block_else: ir::Block,
3369    params_else: &[ir::Value],
3370) -> ir::Inst {
3371    let mut tmp_canonicalised_then = SmallVec::<[_; 16]>::new();
3372    let canonicalised_then =
3373        canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
3374    let mut tmp_canonicalised_else = SmallVec::<[_; 16]>::new();
3375    let canonicalised_else =
3376        canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
3377    builder.ins().brif(
3378        cond,
3379        block_then,
3380        canonicalised_then,
3381        block_else,
3382        canonicalised_else,
3383    )
3384}
3385
3386/// A helper for popping and bitcasting a single value; since SIMD values can lose their type by
3387/// using v128 (i.e. CLIF's I8x16) we must re-type the values using a bitcast to avoid CLIF
3388/// typing issues.
3389fn pop1_with_bitcast(
3390    state: &mut FuncTranslationState,
3391    needed_type: Type,
3392    builder: &mut FunctionBuilder,
3393) -> Value {
3394    optionally_bitcast_vector(state.pop1(), needed_type, builder)
3395}
3396
3397/// A helper for popping and bitcasting two values; since SIMD values can lose their type by
3398/// using v128 (i.e. CLIF's I8x16) we must re-type the values using a bitcast to avoid CLIF
3399/// typing issues.
3400fn pop2_with_bitcast(
3401    state: &mut FuncTranslationState,
3402    needed_type: Type,
3403    builder: &mut FunctionBuilder,
3404) -> (Value, Value) {
3405    let (a, b) = state.pop2();
3406    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3407    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3408    (bitcast_a, bitcast_b)
3409}
3410
3411pub fn bitcast_arguments<'a>(
3412    builder: &FunctionBuilder,
3413    arguments: &'a mut [Value],
3414    params: &[ir::AbiParam],
3415    param_predicate: impl Fn(usize) -> bool,
3416) -> Vec<(Type, &'a mut Value)> {
3417    let filtered_param_types = params
3418        .iter()
3419        .enumerate()
3420        .filter(|(i, _)| param_predicate(*i))
3421        .map(|(_, param)| param.value_type);
3422
3423    // zip_eq, from the itertools::Itertools trait, is like Iterator::zip but panics if one
3424    // iterator ends before the other. The `param_predicate` is required to select exactly as many
3425    // elements of `params` as there are elements in `arguments`.
3426    let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
3427
3428    // The arguments which need to be bitcasted are those which have some vector type but the type
3429    // expected by the parameter is not the same vector type as that of the provided argument.
3430    pairs
3431        .filter(|(param_type, _)| param_type.is_vector())
3432        .filter(|(param_type, arg)| {
3433            let arg_type = builder.func.dfg.value_type(**arg);
3434            assert!(
3435                arg_type.is_vector(),
3436                "unexpected type mismatch: expected {}, argument {} was actually of type {}",
3437                param_type,
3438                *arg,
3439                arg_type
3440            );
3441
3442            // This is the same check that would be done by `optionally_bitcast_vector`, except we
3443            // can't take a mutable borrow of the FunctionBuilder here, so we defer inserting the
3444            // bitcast instruction to the caller.
3445            arg_type != *param_type
3446        })
3447        .collect()
3448}
3449
3450/// A helper for bitcasting a sequence of return values for the function currently being built. If
3451/// a value is a vector type that does not match its expected type, this will modify the value in
3452/// place to point to the result of a `bitcast`. This conversion is necessary to translate Wasm
3453/// code that uses `V128` as function parameters (or implicitly in block parameters) and still use
3454/// specific CLIF types (e.g. `I32X4`) in the function body.
3455pub fn bitcast_wasm_returns<FE: FuncEnvironment + ?Sized>(
3456    environ: &mut FE,
3457    arguments: &mut [Value],
3458    builder: &mut FunctionBuilder,
3459) {
3460    let changes = bitcast_arguments(builder, arguments, &builder.func.signature.returns, |i| {
3461        environ.is_wasm_return(&builder.func.signature, i)
3462    });
3463    for (t, arg) in changes {
3464        let mut flags = MemFlags::new();
3465        flags.set_endianness(ir::Endianness::Little);
3466        *arg = builder.ins().bitcast(t, flags, *arg);
3467    }
3468}
3469
3470/// Like `bitcast_wasm_returns`, but for the parameters being passed to a specified callee.
3471pub fn bitcast_wasm_params<FE: FuncEnvironment + ?Sized>(
3472    environ: &mut FE,
3473    callee_signature: ir::SigRef,
3474    arguments: &mut [Value],
3475    builder: &mut FunctionBuilder,
3476) {
3477    let callee_signature = &builder.func.dfg.signatures[callee_signature];
3478    let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
3479        environ.is_wasm_parameter(callee_signature, i)
3480    });
3481    for (t, arg) in changes {
3482        let mut flags = MemFlags::new();
3483        flags.set_endianness(ir::Endianness::Little);
3484        *arg = builder.ins().bitcast(t, flags, *arg);
3485    }
3486}
3487
3488#[derive(Debug, Clone)]
3489pub(crate) struct CatchClause {
3490    pub(crate) wasm_tag: Option<u32>,
3491    pub(crate) tag_value: i32,
3492    pub(crate) block: ir::Block,
3493}
3494
3495fn create_catch_block<FE: FuncEnvironment + ?Sized>(
3496    builder: &mut FunctionBuilder,
3497    state: &mut FuncTranslationState,
3498    catch: &wasmparser::Catch,
3499    environ: &mut FE,
3500) -> WasmResult<CatchClause> {
3501    let (is_ref, wasm_tag, label) = match catch {
3502        wasmparser::Catch::One { tag, label } => (false, Some(*tag), *label),
3503        wasmparser::Catch::OneRef { tag, label } => (true, Some(*tag), *label),
3504        wasmparser::Catch::All { label } => (false, None, *label),
3505        wasmparser::Catch::AllRef { label } => (true, None, *label),
3506    };
3507
3508    let tag_value = wasm_tag.map_or(CATCH_ALL_TAG_VALUE, |t| t as i32);
3509
3510    let block = builder.create_block();
3511    let exnref = builder.append_block_param(block, EXN_REF_TYPE);
3512
3513    builder.switch_to_block(block);
3514
3515    let mut params = SmallVec::<[Value; 4]>::new();
3516    if let Some(tag) = wasm_tag {
3517        let tag_index = TagIndex::from_u32(tag);
3518        params.extend(environ.translate_exn_unbox(builder, tag_index, exnref)?);
3519    }
3520    if is_ref {
3521        params.push(exnref);
3522    }
3523
3524    let depth = label as usize;
3525    let idx = state.control_stack.len() - 1 - depth;
3526    let frame = &mut state.control_stack[idx];
3527    frame.set_branched_to_exit();
3528    canonicalise_then_jump(builder, frame.br_destination(), params.as_slice());
3529
3530    Ok(CatchClause {
3531        wasm_tag,
3532        tag_value,
3533        block,
3534    })
3535}
3536
3537fn create_dispatch_block<FE: FuncEnvironment + ?Sized>(
3538    builder: &mut FunctionBuilder,
3539    environ: &mut FE,
3540    clauses: impl Iterator<Item = CatchClause>,
3541) -> WasmResult<ir::Block> {
3542    let clauses = clauses.collect_vec();
3543
3544    let catch_block = builder.create_block();
3545    let exn_ptr = builder.append_block_param(catch_block, environ.reference_type());
3546    let pre_selector = builder.append_block_param(catch_block, I64);
3547    let catch_all_block = builder.create_block();
3548    let catch_one_block = builder.create_block();
3549    let dispatch_block = builder.create_block();
3550
3551    builder.switch_to_block(catch_block);
3552    let catch_all_tag = builder.ins().iconst(I64, 0);
3553    let matches = builder
3554        .ins()
3555        .icmp(IntCC::Equal, pre_selector, catch_all_tag);
3556    canonicalise_brif(builder, matches, catch_all_block, &[], catch_one_block, &[]);
3557
3558    builder.switch_to_block(catch_all_block);
3559    let catch_all_tag = builder
3560        .ins()
3561        .iconst(TAG_TYPE, i64::from(CATCH_ALL_TAG_VALUE));
3562    canonicalise_then_jump(builder, dispatch_block, &[catch_all_tag]);
3563    builder.seal_block(catch_all_block);
3564
3565    builder.switch_to_block(catch_one_block);
3566    let selector = environ.translate_exn_personality_selector(builder, exn_ptr)?;
3567    canonicalise_then_jump(builder, dispatch_block, &[selector]);
3568    builder.seal_block(catch_one_block);
3569
3570    builder.switch_to_block(dispatch_block);
3571    let selector = builder.append_block_param(dispatch_block, TAG_TYPE);
3572    let exnref = environ.translate_exn_pointer_to_ref(builder, exn_ptr);
3573
3574    let rethrow_block = builder.create_block();
3575    builder.append_block_param(rethrow_block, EXN_REF_TYPE);
3576
3577    let mut current_selector = selector;
3578    let mut current_exn = exnref;
3579
3580    for (idx, clause) in clauses.iter().enumerate() {
3581        let tag_value = builder.ins().iconst(TAG_TYPE, i64::from(clause.tag_value));
3582        let matches = builder
3583            .ins()
3584            .icmp(IntCC::Equal, current_selector, tag_value);
3585
3586        if idx + 1 == clauses.len() {
3587            canonicalise_brif(
3588                builder,
3589                matches,
3590                clause.block,
3591                &[current_exn],
3592                rethrow_block,
3593                &[exnref],
3594            );
3595        } else {
3596            let continue_block = builder.create_block();
3597            builder.append_block_param(continue_block, TAG_TYPE);
3598            builder.append_block_param(continue_block, EXN_REF_TYPE);
3599
3600            canonicalise_brif(
3601                builder,
3602                matches,
3603                clause.block,
3604                &[current_exn],
3605                continue_block,
3606                &[current_selector, current_exn],
3607            );
3608
3609            builder.seal_block(continue_block);
3610            builder.switch_to_block(continue_block);
3611            let params = builder.func.dfg.block_params(continue_block);
3612            current_selector = params[0];
3613            current_exn = params[1];
3614        }
3615    }
3616    builder.seal_block(dispatch_block);
3617
3618    builder.switch_to_block(rethrow_block);
3619    let rethrow_exn = builder.func.dfg.block_params(rethrow_block)[0];
3620    environ.translate_exn_reraise_unmatched(builder, rethrow_exn)?;
3621    builder.seal_block(rethrow_block);
3622
3623    Ok(catch_block)
3624}