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) => {
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::I8x16RelaxedSwizzle => {
1744            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1745            state.push1(builder.ins().swizzle(a, b))
1746        }
1747        Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1748            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1749            state.push1(builder.ins().iadd(a, b))
1750        }
1751        Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1752            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1753            state.push1(builder.ins().sadd_sat(a, b))
1754        }
1755        Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1756            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1757            state.push1(builder.ins().uadd_sat(a, b))
1758        }
1759        Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1760            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1761            state.push1(builder.ins().isub(a, b))
1762        }
1763        Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1764            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1765            state.push1(builder.ins().ssub_sat(a, b))
1766        }
1767        Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1768            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1769            state.push1(builder.ins().usub_sat(a, b))
1770        }
1771        Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1772            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1773            state.push1(builder.ins().smin(a, b))
1774        }
1775        Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1776            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1777            state.push1(builder.ins().umin(a, b))
1778        }
1779        Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1780            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1781            state.push1(builder.ins().smax(a, b))
1782        }
1783        Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1784            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1785            state.push1(builder.ins().umax(a, b))
1786        }
1787        Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1788            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1789            state.push1(builder.ins().avg_round(a, b))
1790        }
1791        Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1792            let a = pop1_with_bitcast(state, type_of(op), builder);
1793            state.push1(builder.ins().ineg(a))
1794        }
1795        Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1796            let a = pop1_with_bitcast(state, type_of(op), builder);
1797            state.push1(builder.ins().iabs(a))
1798        }
1799        Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1800            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1801            state.push1(builder.ins().imul(a, b))
1802        }
1803        Operator::V128Or => {
1804            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1805            state.push1(builder.ins().bor(a, b))
1806        }
1807        Operator::V128Xor => {
1808            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1809            state.push1(builder.ins().bxor(a, b))
1810        }
1811        Operator::V128And => {
1812            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1813            state.push1(builder.ins().band(a, b))
1814        }
1815        Operator::V128AndNot => {
1816            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1817            state.push1(builder.ins().band_not(a, b))
1818        }
1819        Operator::V128Not => {
1820            let a = state.pop1();
1821            state.push1(builder.ins().bnot(a));
1822        }
1823        Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
1824            let (a, b) = state.pop2();
1825            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1826            let bitwidth = i64::from(type_of(op).lane_bits());
1827            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1828            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1829            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1830            state.push1(builder.ins().ishl(bitcast_a, b_mod_bitwidth))
1831        }
1832        Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
1833            let (a, b) = state.pop2();
1834            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1835            let bitwidth = i64::from(type_of(op).lane_bits());
1836            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1837            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1838            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1839            state.push1(builder.ins().ushr(bitcast_a, b_mod_bitwidth))
1840        }
1841        Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
1842            let (a, b) = state.pop2();
1843            let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1844            let bitwidth = i64::from(type_of(op).lane_bits());
1845            // The spec expects to shift with `b mod lanewidth`; so, e.g., for 16 bit lane-width
1846            // we do `b AND 15`; this means fewer instructions than `iconst + urem`.
1847            let b_mod_bitwidth = builder.ins().band_imm(b, bitwidth - 1);
1848            state.push1(builder.ins().sshr(bitcast_a, b_mod_bitwidth))
1849        }
1850        Operator::V128Bitselect => {
1851            let (a, b, c) = state.pop3();
1852            let bitcast_a = optionally_bitcast_vector(a, I8X16, builder);
1853            let bitcast_b = optionally_bitcast_vector(b, I8X16, builder);
1854            let bitcast_c = optionally_bitcast_vector(c, I8X16, builder);
1855            // The CLIF operand ordering is slightly different and the types of all three
1856            // operands must match (hence the bitcast).
1857            state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
1858        }
1859        Operator::I8x16RelaxedLaneselect
1860        | Operator::I16x8RelaxedLaneselect
1861        | Operator::I32x4RelaxedLaneselect
1862        | Operator::I64x2RelaxedLaneselect => {
1863            let (a, b, c) = state.pop3();
1864            let ty = type_of(op);
1865            let bitcast_a = optionally_bitcast_vector(a, ty, builder);
1866            let bitcast_b = optionally_bitcast_vector(b, ty, builder);
1867            let bitcast_c = optionally_bitcast_vector(c, ty, builder);
1868            // The CLIF operand ordering is slightly different and the types of all three
1869            // operands must match (hence the bitcast).
1870            state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
1871        }
1872        Operator::V128AnyTrue => {
1873            let a = pop1_with_bitcast(state, type_of(op), builder);
1874            let bool_result = builder.ins().vany_true(a);
1875            state.push1(builder.ins().uextend(I32, bool_result))
1876        }
1877        Operator::I8x16AllTrue
1878        | Operator::I16x8AllTrue
1879        | Operator::I32x4AllTrue
1880        | Operator::I64x2AllTrue => {
1881            let a = pop1_with_bitcast(state, type_of(op), builder);
1882            let bool_result = builder.ins().vall_true(a);
1883            state.push1(builder.ins().uextend(I32, bool_result))
1884        }
1885        Operator::I8x16Bitmask
1886        | Operator::I16x8Bitmask
1887        | Operator::I32x4Bitmask
1888        | Operator::I64x2Bitmask => {
1889            let a = pop1_with_bitcast(state, type_of(op), builder);
1890            state.push1(builder.ins().vhigh_bits(I32, a));
1891        }
1892        Operator::I8x16Eq | Operator::I16x8Eq | Operator::I32x4Eq | Operator::I64x2Eq => {
1893            translate_vector_icmp(IntCC::Equal, type_of(op), builder, state)
1894        }
1895        Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
1896            translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, state)
1897        }
1898        Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
1899            translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, state)
1900        }
1901        Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
1902            translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, state)
1903        }
1904        Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
1905            translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, state)
1906        }
1907        Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
1908            translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, state)
1909        }
1910        Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
1911            translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, state)
1912        }
1913        Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
1914            translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, state)
1915        }
1916        Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
1917            IntCC::UnsignedGreaterThanOrEqual,
1918            type_of(op),
1919            builder,
1920            state,
1921        ),
1922        Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
1923            translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, state)
1924        }
1925        Operator::F32x4Eq | Operator::F64x2Eq => {
1926            translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, state)
1927        }
1928        Operator::F32x4Ne | Operator::F64x2Ne => {
1929            translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, state)
1930        }
1931        Operator::F32x4Lt | Operator::F64x2Lt => {
1932            translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, state)
1933        }
1934        Operator::F32x4Gt | Operator::F64x2Gt => {
1935            translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, state)
1936        }
1937        Operator::F32x4Le | Operator::F64x2Le => {
1938            translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, state)
1939        }
1940        Operator::F32x4Ge | Operator::F64x2Ge => {
1941            translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, state)
1942        }
1943        Operator::F32x4Add | Operator::F64x2Add => {
1944            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1945            state.push1(builder.ins().fadd(a, b))
1946        }
1947        Operator::F32x4Sub | Operator::F64x2Sub => {
1948            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1949            state.push1(builder.ins().fsub(a, b))
1950        }
1951        Operator::F32x4Mul | Operator::F64x2Mul => {
1952            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1953            state.push1(builder.ins().fmul(a, b))
1954        }
1955        Operator::F32x4RelaxedMadd | Operator::F64x2RelaxedMadd => {
1956            let ty = type_of(op);
1957            let (a, b, c) = state.pop3();
1958            let a = optionally_bitcast_vector(a, ty, builder);
1959            let b = optionally_bitcast_vector(b, ty, builder);
1960            let c = optionally_bitcast_vector(c, ty, builder);
1961            let mul = builder.ins().fmul(a, b);
1962            state.push1(builder.ins().fadd(mul, c))
1963        }
1964        Operator::F32x4RelaxedNmadd | Operator::F64x2RelaxedNmadd => {
1965            let ty = type_of(op);
1966            let (a, b, c) = state.pop3();
1967            let a = optionally_bitcast_vector(a, ty, builder);
1968            let b = optionally_bitcast_vector(b, ty, builder);
1969            let c = optionally_bitcast_vector(c, ty, builder);
1970            let a = builder.ins().fneg(a);
1971            let mul = builder.ins().fmul(a, b);
1972            state.push1(builder.ins().fadd(mul, c))
1973        }
1974        Operator::F32x4Div | Operator::F64x2Div => {
1975            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1976            state.push1(builder.ins().fdiv(a, b))
1977        }
1978        Operator::F32x4Max | Operator::F64x2Max => {
1979            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1980            state.push1(builder.ins().fmax(a, b))
1981        }
1982        Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => {
1983            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1984            state.push1(builder.ins().fmax(a, b))
1985        }
1986        Operator::F32x4Min | Operator::F64x2Min => {
1987            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1988            state.push1(builder.ins().fmin(a, b))
1989        }
1990        Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => {
1991            let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1992            state.push1(builder.ins().fmin(a, b))
1993        }
1994        Operator::F32x4PMax | Operator::F64x2PMax => {
1995            // Note the careful ordering here with respect to `fcmp` and
1996            // `bitselect`. This matches the spec definition of:
1997            //
1998            //  fpmax(z1, z2) =
1999            //      * If z1 is less than z2 then return z2.
2000            //      * Else return z1.
2001            let ty = type_of(op);
2002            let (a, b) = pop2_with_bitcast(state, ty, builder);
2003            let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
2004            let cmp = optionally_bitcast_vector(cmp, ty, builder);
2005            state.push1(builder.ins().bitselect(cmp, b, a))
2006        }
2007        Operator::F32x4PMin | Operator::F64x2PMin => {
2008            // Note the careful ordering here which is similar to `pmax` above:
2009            //
2010            //  fpmin(z1, z2) =
2011            //      * If z2 is less than z1 then return z2.
2012            //      * Else return z1.
2013            let ty = type_of(op);
2014            let (a, b) = pop2_with_bitcast(state, ty, builder);
2015            let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
2016            let cmp = optionally_bitcast_vector(cmp, ty, builder);
2017            state.push1(builder.ins().bitselect(cmp, b, a))
2018        }
2019        Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
2020            let a = pop1_with_bitcast(state, type_of(op), builder);
2021            state.push1(builder.ins().sqrt(a))
2022        }
2023        Operator::F32x4Neg | Operator::F64x2Neg => {
2024            let a = pop1_with_bitcast(state, type_of(op), builder);
2025            state.push1(builder.ins().fneg(a))
2026        }
2027        Operator::F32x4Abs | Operator::F64x2Abs => {
2028            let a = pop1_with_bitcast(state, type_of(op), builder);
2029            state.push1(builder.ins().fabs(a))
2030        }
2031        Operator::F32x4ConvertI32x4S => {
2032            let a = pop1_with_bitcast(state, I32X4, builder);
2033            state.push1(builder.ins().fcvt_from_sint(F32X4, a))
2034        }
2035        Operator::F32x4ConvertI32x4U => {
2036            let a = pop1_with_bitcast(state, I32X4, builder);
2037            state.push1(builder.ins().fcvt_from_uint(F32X4, a))
2038        }
2039        Operator::F64x2ConvertLowI32x4S => {
2040            let a = pop1_with_bitcast(state, I32X4, builder);
2041            let widened_a = builder.ins().swiden_low(a);
2042            state.push1(builder.ins().fcvt_from_sint(F64X2, widened_a));
2043        }
2044        Operator::F64x2ConvertLowI32x4U => {
2045            let a = pop1_with_bitcast(state, I32X4, builder);
2046            let widened_a = builder.ins().uwiden_low(a);
2047            state.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
2048        }
2049        Operator::F64x2PromoteLowF32x4 => {
2050            let a = pop1_with_bitcast(state, F32X4, builder);
2051            state.push1(builder.ins().fvpromote_low(a));
2052        }
2053        Operator::F32x4DemoteF64x2Zero => {
2054            let a = pop1_with_bitcast(state, F64X2, builder);
2055            state.push1(builder.ins().fvdemote(a));
2056        }
2057        Operator::I32x4TruncSatF32x4S => {
2058            let a = pop1_with_bitcast(state, F32X4, builder);
2059            state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2060        }
2061        Operator::I32x4RelaxedTruncF32x4S => {
2062            let a = pop1_with_bitcast(state, F32X4, builder);
2063            state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2064        }
2065        Operator::I32x4TruncSatF64x2SZero => {
2066            let a = pop1_with_bitcast(state, F64X2, builder);
2067            let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2068            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2069            let zero = builder.ins().vconst(I64X2, handle);
2070
2071            state.push1(builder.ins().snarrow(converted_a, zero));
2072        }
2073        Operator::I32x4RelaxedTruncF64x2SZero => {
2074            let a = pop1_with_bitcast(state, F64X2, builder);
2075            let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2076            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2077            let zero = builder.ins().vconst(I64X2, handle);
2078
2079            state.push1(builder.ins().snarrow(converted_a, zero));
2080        }
2081        Operator::I32x4TruncSatF32x4U => {
2082            let a = pop1_with_bitcast(state, F32X4, builder);
2083            state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2084        }
2085        Operator::I32x4RelaxedTruncF32x4U => {
2086            let a = pop1_with_bitcast(state, F32X4, builder);
2087            state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2088        }
2089        Operator::I32x4TruncSatF64x2UZero => {
2090            let a = pop1_with_bitcast(state, F64X2, builder);
2091            let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2092            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2093            let zero = builder.ins().vconst(I64X2, handle);
2094
2095            state.push1(builder.ins().uunarrow(converted_a, zero));
2096        }
2097        Operator::I32x4RelaxedTruncF64x2UZero => {
2098            let a = pop1_with_bitcast(state, F64X2, builder);
2099            let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2100            let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2101            let zero = builder.ins().vconst(I64X2, handle);
2102
2103            state.push1(builder.ins().uunarrow(converted_a, zero));
2104        }
2105        Operator::I8x16NarrowI16x8S => {
2106            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2107            state.push1(builder.ins().snarrow(a, b))
2108        }
2109        Operator::I16x8NarrowI32x4S => {
2110            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2111            state.push1(builder.ins().snarrow(a, b))
2112        }
2113        Operator::I8x16NarrowI16x8U => {
2114            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2115            state.push1(builder.ins().unarrow(a, b))
2116        }
2117        Operator::I16x8NarrowI32x4U => {
2118            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2119            state.push1(builder.ins().unarrow(a, b))
2120        }
2121        Operator::I16x8ExtendLowI8x16S => {
2122            let a = pop1_with_bitcast(state, I8X16, builder);
2123            state.push1(builder.ins().swiden_low(a))
2124        }
2125        Operator::I16x8ExtendHighI8x16S => {
2126            let a = pop1_with_bitcast(state, I8X16, builder);
2127            state.push1(builder.ins().swiden_high(a))
2128        }
2129        Operator::I16x8ExtendLowI8x16U => {
2130            let a = pop1_with_bitcast(state, I8X16, builder);
2131            state.push1(builder.ins().uwiden_low(a))
2132        }
2133        Operator::I16x8ExtendHighI8x16U => {
2134            let a = pop1_with_bitcast(state, I8X16, builder);
2135            state.push1(builder.ins().uwiden_high(a))
2136        }
2137        Operator::I32x4ExtendLowI16x8S => {
2138            let a = pop1_with_bitcast(state, I16X8, builder);
2139            state.push1(builder.ins().swiden_low(a))
2140        }
2141        Operator::I32x4ExtendHighI16x8S => {
2142            let a = pop1_with_bitcast(state, I16X8, builder);
2143            state.push1(builder.ins().swiden_high(a))
2144        }
2145        Operator::I32x4ExtendLowI16x8U => {
2146            let a = pop1_with_bitcast(state, I16X8, builder);
2147            state.push1(builder.ins().uwiden_low(a))
2148        }
2149        Operator::I32x4ExtendHighI16x8U => {
2150            let a = pop1_with_bitcast(state, I16X8, builder);
2151            state.push1(builder.ins().uwiden_high(a))
2152        }
2153
2154        Operator::I64x2ExtendLowI32x4S => {
2155            let a = pop1_with_bitcast(state, I32X4, builder);
2156            state.push1(builder.ins().swiden_low(a))
2157        }
2158        Operator::I64x2ExtendHighI32x4S => {
2159            let a = pop1_with_bitcast(state, I32X4, builder);
2160            state.push1(builder.ins().swiden_high(a))
2161        }
2162        Operator::I64x2ExtendLowI32x4U => {
2163            let a = pop1_with_bitcast(state, I32X4, builder);
2164            state.push1(builder.ins().uwiden_low(a))
2165        }
2166        Operator::I64x2ExtendHighI32x4U => {
2167            let a = pop1_with_bitcast(state, I32X4, builder);
2168            state.push1(builder.ins().uwiden_high(a))
2169        }
2170        Operator::I16x8ExtAddPairwiseI8x16S => {
2171            let a = pop1_with_bitcast(state, I8X16, builder);
2172            let widen_low = builder.ins().swiden_low(a);
2173            let widen_high = builder.ins().swiden_high(a);
2174            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2175        }
2176        Operator::I32x4ExtAddPairwiseI16x8S => {
2177            let a = pop1_with_bitcast(state, I16X8, builder);
2178            let widen_low = builder.ins().swiden_low(a);
2179            let widen_high = builder.ins().swiden_high(a);
2180            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2181        }
2182        Operator::I16x8ExtAddPairwiseI8x16U => {
2183            let a = pop1_with_bitcast(state, I8X16, builder);
2184            let widen_low = builder.ins().uwiden_low(a);
2185            let widen_high = builder.ins().uwiden_high(a);
2186            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2187        }
2188        Operator::I32x4ExtAddPairwiseI16x8U => {
2189            let a = pop1_with_bitcast(state, I16X8, builder);
2190            let widen_low = builder.ins().uwiden_low(a);
2191            let widen_high = builder.ins().uwiden_high(a);
2192            state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2193        }
2194        Operator::F32x4Ceil | Operator::F64x2Ceil => {
2195            // This is something of a misuse of `type_of`, because that produces the return type
2196            // of `op`.  In this case we want the arg type, but we know it's the same as the
2197            // return type.  Same for the 3 cases below.
2198            let arg = pop1_with_bitcast(state, type_of(op), builder);
2199            state.push1(builder.ins().ceil(arg));
2200        }
2201        Operator::F32x4Floor | Operator::F64x2Floor => {
2202            let arg = pop1_with_bitcast(state, type_of(op), builder);
2203            state.push1(builder.ins().floor(arg));
2204        }
2205        Operator::F32x4Trunc | Operator::F64x2Trunc => {
2206            let arg = pop1_with_bitcast(state, type_of(op), builder);
2207            state.push1(builder.ins().trunc(arg));
2208        }
2209        Operator::F32x4Nearest | Operator::F64x2Nearest => {
2210            let arg = pop1_with_bitcast(state, type_of(op), builder);
2211            state.push1(builder.ins().nearest(arg));
2212        }
2213        Operator::I32x4DotI16x8S => {
2214            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2215            let alow = builder.ins().swiden_low(a);
2216            let blow = builder.ins().swiden_low(b);
2217            let low = builder.ins().imul(alow, blow);
2218            let ahigh = builder.ins().swiden_high(a);
2219            let bhigh = builder.ins().swiden_high(b);
2220            let high = builder.ins().imul(ahigh, bhigh);
2221            state.push1(builder.ins().iadd_pairwise(low, high));
2222        }
2223        Operator::I16x8RelaxedDotI8x16I7x16S => {
2224            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2225            let alow = builder.ins().swiden_low(a);
2226            let blow = builder.ins().swiden_low(b);
2227            let low = builder.ins().imul(alow, blow);
2228            let ahigh = builder.ins().swiden_high(a);
2229            let bhigh = builder.ins().swiden_high(b);
2230            let high = builder.ins().imul(ahigh, bhigh);
2231            state.push1(builder.ins().iadd_pairwise(low, high));
2232        }
2233        Operator::I8x16Popcnt => {
2234            let arg = pop1_with_bitcast(state, type_of(op), builder);
2235            state.push1(builder.ins().popcnt(arg));
2236        }
2237        Operator::I16x8Q15MulrSatS => {
2238            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2239            state.push1(builder.ins().sqmul_round_sat(a, b))
2240        }
2241        Operator::I16x8RelaxedQ15mulrS => {
2242            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2243            state.push1(builder.ins().sqmul_round_sat(a, b))
2244        }
2245        Operator::I32x4RelaxedDotI8x16I7x16AddS => {
2246            let (a, b, c) = state.pop3();
2247            let a = optionally_bitcast_vector(a, I8X16, builder);
2248            let b = optionally_bitcast_vector(b, I8X16, builder);
2249            let c = optionally_bitcast_vector(c, I32X4, builder);
2250            let alow = builder.ins().swiden_low(a);
2251            let blow = builder.ins().swiden_low(b);
2252            let low = builder.ins().imul(alow, blow);
2253            let ahigh = builder.ins().swiden_high(a);
2254            let bhigh = builder.ins().swiden_high(b);
2255            let high = builder.ins().imul(ahigh, bhigh);
2256            let dot = builder.ins().iadd_pairwise(low, high);
2257            let dotlo = builder.ins().swiden_low(dot);
2258            let dothi = builder.ins().swiden_high(dot);
2259            let dot32 = builder.ins().iadd_pairwise(dotlo, dothi);
2260            state.push1(builder.ins().iadd(dot32, c));
2261        }
2262        Operator::I16x8ExtMulLowI8x16S => {
2263            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2264            let a_low = builder.ins().swiden_low(a);
2265            let b_low = builder.ins().swiden_low(b);
2266            state.push1(builder.ins().imul(a_low, b_low));
2267        }
2268        Operator::I16x8ExtMulHighI8x16S => {
2269            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2270            let a_high = builder.ins().swiden_high(a);
2271            let b_high = builder.ins().swiden_high(b);
2272            state.push1(builder.ins().imul(a_high, b_high));
2273        }
2274        Operator::I16x8ExtMulLowI8x16U => {
2275            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2276            let a_low = builder.ins().uwiden_low(a);
2277            let b_low = builder.ins().uwiden_low(b);
2278            state.push1(builder.ins().imul(a_low, b_low));
2279        }
2280        Operator::I16x8ExtMulHighI8x16U => {
2281            let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2282            let a_high = builder.ins().uwiden_high(a);
2283            let b_high = builder.ins().uwiden_high(b);
2284            state.push1(builder.ins().imul(a_high, b_high));
2285        }
2286        Operator::I32x4ExtMulLowI16x8S => {
2287            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2288            let a_low = builder.ins().swiden_low(a);
2289            let b_low = builder.ins().swiden_low(b);
2290            state.push1(builder.ins().imul(a_low, b_low));
2291        }
2292        Operator::I32x4ExtMulHighI16x8S => {
2293            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2294            let a_high = builder.ins().swiden_high(a);
2295            let b_high = builder.ins().swiden_high(b);
2296            state.push1(builder.ins().imul(a_high, b_high));
2297        }
2298        Operator::I32x4ExtMulLowI16x8U => {
2299            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2300            let a_low = builder.ins().uwiden_low(a);
2301            let b_low = builder.ins().uwiden_low(b);
2302            state.push1(builder.ins().imul(a_low, b_low));
2303        }
2304        Operator::I32x4ExtMulHighI16x8U => {
2305            let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2306            let a_high = builder.ins().uwiden_high(a);
2307            let b_high = builder.ins().uwiden_high(b);
2308            state.push1(builder.ins().imul(a_high, b_high));
2309        }
2310        Operator::I64x2ExtMulLowI32x4S => {
2311            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2312            let a_low = builder.ins().swiden_low(a);
2313            let b_low = builder.ins().swiden_low(b);
2314            state.push1(builder.ins().imul(a_low, b_low));
2315        }
2316        Operator::I64x2ExtMulHighI32x4S => {
2317            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2318            let a_high = builder.ins().swiden_high(a);
2319            let b_high = builder.ins().swiden_high(b);
2320            state.push1(builder.ins().imul(a_high, b_high));
2321        }
2322        Operator::I64x2ExtMulLowI32x4U => {
2323            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2324            let a_low = builder.ins().uwiden_low(a);
2325            let b_low = builder.ins().uwiden_low(b);
2326            state.push1(builder.ins().imul(a_low, b_low));
2327        }
2328        Operator::I64x2ExtMulHighI32x4U => {
2329            let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2330            let a_high = builder.ins().uwiden_high(a);
2331            let b_high = builder.ins().uwiden_high(b);
2332            state.push1(builder.ins().imul(a_high, b_high));
2333        }
2334        Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
2335            return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
2336        }
2337        Operator::RefEq
2338        | Operator::StructNew { .. }
2339        | Operator::StructNewDefault { .. }
2340        | Operator::StructGet { .. }
2341        | Operator::StructGetS { .. }
2342        | Operator::StructGetU { .. }
2343        | Operator::StructSet { .. }
2344        | Operator::ArrayNew { .. }
2345        | Operator::ArrayNewDefault { .. }
2346        | Operator::ArrayNewFixed { .. }
2347        | Operator::ArrayNewData { .. }
2348        | Operator::ArrayNewElem { .. }
2349        | Operator::ArrayGet { .. }
2350        | Operator::ArrayGetS { .. }
2351        | Operator::ArrayGetU { .. }
2352        | Operator::ArraySet { .. }
2353        | Operator::ArrayLen
2354        | Operator::ArrayFill { .. }
2355        | Operator::ArrayCopy { .. }
2356        | Operator::ArrayInitData { .. }
2357        | Operator::ArrayInitElem { .. }
2358        | Operator::RefTestNonNull { .. } => {}
2359        Operator::RefTestNullable { .. }
2360        | Operator::RefCastNonNull { .. }
2361        | Operator::RefCastNullable { .. }
2362        | Operator::BrOnCast { .. }
2363        | Operator::BrOnCastFail { .. }
2364        | Operator::AnyConvertExtern
2365        | Operator::ExternConvertAny
2366        | Operator::RefI31
2367        | Operator::RefI31Shared => todo!(),
2368        Operator::I31GetS
2369        | Operator::I31GetU
2370        | Operator::MemoryDiscard { .. }
2371        | Operator::CallRef { .. }
2372        | Operator::ReturnCallRef { .. }
2373        | Operator::RefAsNonNull
2374        | Operator::BrOnNull { .. }
2375        | Operator::BrOnNonNull { .. } => {
2376            return Err(wasm_unsupported!("GC proposal not (operator: {:?})", op));
2377        }
2378        Operator::GlobalAtomicGet { .. }
2379        | Operator::GlobalAtomicSet { .. }
2380        | Operator::GlobalAtomicRmwAdd { .. }
2381        | Operator::GlobalAtomicRmwSub { .. }
2382        | Operator::GlobalAtomicRmwAnd { .. }
2383        | Operator::GlobalAtomicRmwOr { .. }
2384        | Operator::GlobalAtomicRmwXor { .. }
2385        | Operator::GlobalAtomicRmwXchg { .. }
2386        | Operator::GlobalAtomicRmwCmpxchg { .. } => {
2387            return Err(wasm_unsupported!("Global atomics not supported yet!"));
2388        }
2389        Operator::TableAtomicGet { .. }
2390        | Operator::TableAtomicSet { .. }
2391        | Operator::TableAtomicRmwXchg { .. }
2392        | Operator::TableAtomicRmwCmpxchg { .. } => {
2393            return Err(wasm_unsupported!("Table atomics not supported yet!"));
2394        }
2395        Operator::StructAtomicGet { .. }
2396        | Operator::StructAtomicGetS { .. }
2397        | Operator::StructAtomicGetU { .. }
2398        | Operator::StructAtomicSet { .. }
2399        | Operator::StructAtomicRmwAdd { .. }
2400        | Operator::StructAtomicRmwSub { .. }
2401        | Operator::StructAtomicRmwAnd { .. }
2402        | Operator::StructAtomicRmwOr { .. }
2403        | Operator::StructAtomicRmwXor { .. }
2404        | Operator::StructAtomicRmwXchg { .. }
2405        | Operator::StructAtomicRmwCmpxchg { .. } => {
2406            return Err(wasm_unsupported!("Table atomics not supported yet!"));
2407        }
2408        Operator::ArrayAtomicGet { .. }
2409        | Operator::ArrayAtomicGetS { .. }
2410        | Operator::ArrayAtomicGetU { .. }
2411        | Operator::ArrayAtomicSet { .. }
2412        | Operator::ArrayAtomicRmwAdd { .. }
2413        | Operator::ArrayAtomicRmwSub { .. }
2414        | Operator::ArrayAtomicRmwAnd { .. }
2415        | Operator::ArrayAtomicRmwOr { .. }
2416        | Operator::ArrayAtomicRmwXor { .. }
2417        | Operator::ArrayAtomicRmwXchg { .. }
2418        | Operator::ArrayAtomicRmwCmpxchg { .. } => {
2419            return Err(wasm_unsupported!("Array atomics not supported yet!"));
2420        }
2421        Operator::ContNew { .. } => todo!(),
2422        Operator::ContBind { .. } => todo!(),
2423        Operator::Suspend { .. } => todo!(),
2424        Operator::Resume { .. } => todo!(),
2425        Operator::ResumeThrow { .. } => todo!(),
2426        Operator::Switch { .. } => todo!(),
2427        Operator::I64Add128 | Operator::I64Sub128 => {
2428            let (rhs_lo, rhs_hi) = state.pop2();
2429            let (lhs_lo, lhs_hi) = state.pop2();
2430
2431            let lhs = builder.ins().iconcat(lhs_lo, lhs_hi);
2432            let rhs = builder.ins().iconcat(rhs_lo, rhs_hi);
2433            let result = match op {
2434                Operator::I64Add128 => builder.ins().iadd(lhs, rhs),
2435                Operator::I64Sub128 => builder.ins().isub(lhs, rhs),
2436                _ => unreachable!(),
2437            };
2438            let (result_lo, result_hi) = builder.ins().isplit(result);
2439
2440            state.push1(result_lo);
2441            state.push1(result_hi);
2442        }
2443        Operator::I64MulWideS | Operator::I64MulWideU => {
2444            let (lhs, rhs) = state.pop2();
2445
2446            let lhs = match op {
2447                Operator::I64MulWideS => builder.ins().sextend(I128, lhs),
2448                Operator::I64MulWideU => builder.ins().uextend(I128, lhs),
2449                _ => unreachable!(),
2450            };
2451            let rhs = match op {
2452                Operator::I64MulWideS => builder.ins().sextend(I128, rhs),
2453                Operator::I64MulWideU => builder.ins().uextend(I128, rhs),
2454                _ => unreachable!(),
2455            };
2456
2457            let result = builder.ins().imul(lhs, rhs);
2458            let (result_lo, result_hi) = builder.ins().isplit(result);
2459            state.push1(result_lo);
2460            state.push1(result_hi);
2461        }
2462        _ => todo!(),
2463    };
2464    Ok(())
2465}
2466
2467// Clippy warns us of some fields we are deliberately ignoring
2468#[allow(clippy::unneeded_field_pattern)]
2469/// Deals with a Wasm instruction located in an unreachable portion of the code. Most of them
2470/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
2471/// portion so the translation state must be updated accordingly.
2472fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
2473    module_translation_state: &ModuleTranslationState,
2474    op: &Operator,
2475    builder: &mut FunctionBuilder,
2476    state: &mut FuncTranslationState,
2477    environ: &mut FE,
2478) -> WasmResult<()> {
2479    debug_assert!(!state.reachable);
2480    match *op {
2481        Operator::If { blockty } => {
2482            // Push a placeholder control stack entry. The if isn't reachable,
2483            // so we don't have any branches anywhere.
2484            state.push_if(
2485                ir::Block::reserved_value(),
2486                ElseData::NoElse {
2487                    branch_inst: ir::Inst::reserved_value(),
2488                    placeholder: ir::Block::reserved_value(),
2489                },
2490                0,
2491                0,
2492                blockty,
2493            );
2494        }
2495        Operator::Loop { blockty: _ }
2496        | Operator::Block { blockty: _ }
2497        | Operator::TryTable { try_table: _ } => {
2498            state.push_block(ir::Block::reserved_value(), 0, 0);
2499        }
2500        Operator::Else => {
2501            let i = state.control_stack.len() - 1;
2502            match state.control_stack[i] {
2503                ControlStackFrame::If {
2504                    ref else_data,
2505                    head_is_reachable,
2506                    ref mut consequent_ends_reachable,
2507                    blocktype,
2508                    ..
2509                } => {
2510                    debug_assert!(consequent_ends_reachable.is_none());
2511                    *consequent_ends_reachable = Some(state.reachable);
2512
2513                    if head_is_reachable {
2514                        // We have a branch from the head of the `if` to the `else`.
2515                        state.reachable = true;
2516
2517                        let else_block = match *else_data {
2518                            ElseData::NoElse {
2519                                branch_inst,
2520                                placeholder,
2521                            } => {
2522                                let (params, _results) = module_translation_state
2523                                    .blocktype_params_results(&blocktype)?;
2524                                let else_block =
2525                                    block_with_params(builder, params.iter(), environ)?;
2526                                let frame = state.control_stack.last().unwrap();
2527                                frame.truncate_value_stack_to_else_params(&mut state.stack);
2528
2529                                // We change the target of the branch instruction.
2530                                builder.change_jump_destination(
2531                                    branch_inst,
2532                                    placeholder,
2533                                    else_block,
2534                                );
2535                                builder.seal_block(else_block);
2536                                else_block
2537                            }
2538                            ElseData::WithElse { else_block } => {
2539                                let frame = state.control_stack.last().unwrap();
2540                                frame.truncate_value_stack_to_else_params(&mut state.stack);
2541                                else_block
2542                            }
2543                        };
2544
2545                        builder.switch_to_block(else_block);
2546
2547                        // Again, no need to push the parameters for the `else`,
2548                        // since we already did when we saw the original `if`. See
2549                        // the comment for translating `Operator::Else` in
2550                        // `translate_operator` for details.
2551                    }
2552                }
2553                _ => unreachable!(),
2554            }
2555        }
2556        Operator::End => {
2557            let stack = &mut state.stack;
2558            let control_stack = &mut state.control_stack;
2559            let frame = control_stack.pop().unwrap();
2560            frame.restore_catch_handlers(&mut state.handlers, builder);
2561
2562            // Pop unused parameters from stack.
2563            frame.truncate_value_stack_to_original_size(stack);
2564
2565            let reachable_anyway = match frame {
2566                // If it is a loop we also have to seal the body loop block
2567                ControlStackFrame::Loop { header, .. } => {
2568                    builder.seal_block(header);
2569                    // And loops can't have branches to the end.
2570                    false
2571                }
2572                // If we never set `consequent_ends_reachable` then that means
2573                // we are finishing the consequent now, and there was no
2574                // `else`. Whether the following block is reachable depends only
2575                // on if the head was reachable.
2576                ControlStackFrame::If {
2577                    head_is_reachable,
2578                    consequent_ends_reachable: None,
2579                    ..
2580                } => head_is_reachable,
2581                // Since we are only in this function when in unreachable code,
2582                // we know that the alternative just ended unreachable. Whether
2583                // the following block is reachable depends on if the consequent
2584                // ended reachable or not.
2585                ControlStackFrame::If {
2586                    head_is_reachable,
2587                    consequent_ends_reachable: Some(consequent_ends_reachable),
2588                    ..
2589                } => head_is_reachable && consequent_ends_reachable,
2590                // All other control constructs are already handled.
2591                _ => false,
2592            };
2593
2594            if frame.exit_is_branched_to() || reachable_anyway {
2595                builder.switch_to_block(frame.following_code());
2596                builder.seal_block(frame.following_code());
2597
2598                // And add the return values of the block but only if the next block is reachable
2599                // (which corresponds to testing if the stack depth is 1)
2600                stack.extend_from_slice(builder.block_params(frame.following_code()));
2601                state.reachable = true;
2602            }
2603        }
2604        _ => {
2605            // We don't translate because this is unreachable code
2606        }
2607    }
2608
2609    Ok(())
2610}
2611
2612/// This function is a generalized helper for validating that a wasm-supplied
2613/// heap address is in-bounds.
2614///
2615/// This function takes a litany of parameters and requires that the *Wasm*
2616/// address to be verified is at the top of the stack in `state`. This will
2617/// generate necessary IR to validate that the heap address is correctly
2618/// in-bounds, and various parameters are returned describing the valid *native*
2619/// heap address if execution reaches that point.
2620///
2621/// Returns `None` when the Wasm access will unconditionally trap.
2622///
2623/// Returns `(flags, wasm_addr, native_addr)`.
2624fn prepare_addr<FE>(
2625    memarg: &MemArg,
2626    access_size: u8,
2627    builder: &mut FunctionBuilder,
2628    state: &mut FuncTranslationState,
2629    environ: &mut FE,
2630) -> WasmResult<Reachability<(MemFlags, Value, Value)>>
2631where
2632    FE: FuncEnvironment + ?Sized,
2633{
2634    let index = state.pop1();
2635    let heap = state.get_heap(builder.func, memarg.memory, environ)?;
2636
2637    // How exactly the bounds check is performed here and what it's performed
2638    // on is a bit tricky. Generally we want to rely on access violations (e.g.
2639    // segfaults) to generate traps since that means we don't have to bounds
2640    // check anything explicitly.
2641    //
2642    // (1) If we don't have a guard page of unmapped memory, though, then we
2643    // can't rely on this trapping behavior through segfaults. Instead we need
2644    // to bounds-check the entire memory access here which is everything from
2645    // `addr32 + offset` to `addr32 + offset + width` (not inclusive). In this
2646    // scenario our adjusted offset that we're checking is `memarg.offset +
2647    // access_size`. Note that we do saturating arithmetic here to avoid
2648    // overflow. The addition here is in the 64-bit space, which means that
2649    // we'll never overflow for 32-bit wasm but for 64-bit this is an issue. If
2650    // our effective offset is u64::MAX though then it's impossible for for
2651    // that to actually be a valid offset because otherwise the wasm linear
2652    // memory would take all of the host memory!
2653    //
2654    // (2) If we have a guard page, however, then we can perform a further
2655    // optimization of the generated code by only checking multiples of the
2656    // offset-guard size to be more CSE-friendly. Knowing that we have at least
2657    // 1 page of a guard page we're then able to disregard the `width` since we
2658    // know it's always less than one page. Our bounds check will be for the
2659    // first byte which will either succeed and be guaranteed to fault if it's
2660    // actually out of bounds, or the bounds check itself will fail. In any case
2661    // we assert that the width is reasonably small for now so this assumption
2662    // can be adjusted in the future if we get larger widths.
2663    //
2664    // Put another way we can say, where `y < offset_guard_size`:
2665    //
2666    //      n * offset_guard_size + y = offset
2667    //
2668    // We'll then pass `n * offset_guard_size` as the bounds check value. If
2669    // this traps then our `offset` would have trapped anyway. If this check
2670    // passes we know
2671    //
2672    //      addr32 + n * offset_guard_size < bound
2673    //
2674    // which means
2675    //
2676    //      addr32 + n * offset_guard_size + y < bound + offset_guard_size
2677    //
2678    // because `y < offset_guard_size`, which then means:
2679    //
2680    //      addr32 + offset < bound + offset_guard_size
2681    //
2682    // Since we know that that guard size bytes are all unmapped we're
2683    // guaranteed that `offset` and the `width` bytes after it are either
2684    // in-bounds or will hit the guard page, meaning we'll get the desired
2685    // semantics we want.
2686    //
2687    // ---
2688    //
2689    // With all that in mind remember that the goal is to bounds check as few
2690    // things as possible. To facilitate this the "fast path" is expected to be
2691    // hit like so:
2692    //
2693    // * For wasm32, wasmtime defaults to 4gb "static" memories with 2gb guard
2694    //   regions. This means that for all offsets <=2gb, we hit the optimized
2695    //   case for `heap_addr` on static memories 4gb in size in cranelift's
2696    //   legalization of `heap_addr`, eliding the bounds check entirely.
2697    //
2698    // * For wasm64 offsets <=2gb will generate a single `heap_addr`
2699    //   instruction, but at this time all heaps are "dynamic" which means that
2700    //   a single bounds check is forced. Ideally we'd do better here, but
2701    //   that's the current state of affairs.
2702    //
2703    // Basically we assume that most configurations have a guard page and most
2704    // offsets in `memarg` are <=2gb, which means we get the fast path of one
2705    // `heap_addr` instruction plus a hardcoded i32-offset in memory-related
2706    // instructions.
2707    let heap = environ.heaps()[heap].clone();
2708    let addr = match u32::try_from(memarg.offset) {
2709        // If our offset fits within a u32, then we can place the it into the
2710        // offset immediate of the `heap_addr` instruction.
2711        Ok(offset) => bounds_checks::bounds_check_and_compute_addr(
2712            builder,
2713            environ,
2714            &heap,
2715            index,
2716            offset,
2717            access_size,
2718        )?,
2719
2720        // If the offset doesn't fit within a u32, then we can't pass it
2721        // directly into `heap_addr`.
2722        //
2723        // One reasonable question you might ask is "why not?". There's no
2724        // fundamental reason why `heap_addr` *must* take a 32-bit offset. The
2725        // reason this isn't done, though, is that blindly changing the offset
2726        // to a 64-bit offset increases the size of the `InstructionData` enum
2727        // in cranelift by 8 bytes (16 to 24). This can have significant
2728        // performance implications so the conclusion when this was written was
2729        // that we shouldn't do that.
2730        //
2731        // Without the ability to put the whole offset into the `heap_addr`
2732        // instruction we need to fold the offset into the address itself with
2733        // an unsigned addition. In doing so though we need to check for
2734        // overflow because that would mean the address is out-of-bounds (wasm
2735        // bounds checks happen on the effective 33 or 65 bit address once the
2736        // offset is factored in).
2737        //
2738        // Once we have the effective address, offset already folded in, then
2739        // `heap_addr` is used to verify that the address is indeed in-bounds.
2740        //
2741        // Note that this is generating what's likely to be at least two
2742        // branches, one for the overflow and one for the bounds check itself.
2743        // For now though that should hopefully be ok since 4gb+ offsets are
2744        // relatively odd/rare. In the future if needed we can look into
2745        // optimizing this more.
2746        Err(_) => {
2747            let offset = builder.ins().iconst(heap.index_type, memarg.offset as i64);
2748            let adjusted_index =
2749                builder
2750                    .ins()
2751                    .uadd_overflow_trap(index, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
2752            bounds_checks::bounds_check_and_compute_addr(
2753                builder,
2754                environ,
2755                &heap,
2756                adjusted_index,
2757                0,
2758                access_size,
2759            )?
2760        }
2761    };
2762    let addr = match addr {
2763        Reachability::Unreachable => return Ok(Reachability::Unreachable),
2764        Reachability::Reachable(a) => a,
2765    };
2766
2767    // Note that we don't set `is_aligned` here, even if the load instruction's
2768    // alignment immediate may says it's aligned, because WebAssembly's
2769    // immediate field is just a hint, while Cranelift's aligned flag needs a
2770    // guarantee. WebAssembly memory accesses are always little-endian.
2771    let mut flags = MemFlags::new();
2772    flags.set_endianness(ir::Endianness::Little);
2773
2774    if heap.memory_type.is_some() {
2775        // Proof-carrying code is enabled; check this memory access.
2776        flags.set_checked();
2777    }
2778
2779    // The access occurs to the `heap` disjoint category of abstract
2780    // state. This may allow alias analysis to merge redundant loads,
2781    // etc. when heap accesses occur interleaved with other (table,
2782    // vmctx, stack) accesses.
2783    flags.set_alias_region(Some(ir::AliasRegion::Heap));
2784
2785    Ok(Reachability::Reachable((flags, index, addr)))
2786}
2787
2788fn align_atomic_addr(
2789    memarg: &MemArg,
2790    loaded_bytes: u8,
2791    builder: &mut FunctionBuilder,
2792    state: &mut FuncTranslationState,
2793) {
2794    // Atomic addresses must all be aligned correctly, and for now we check
2795    // alignment before we check out-of-bounds-ness. The order of this check may
2796    // need to be updated depending on the outcome of the official threads
2797    // proposal itself.
2798    //
2799    // Note that with an offset>0 we generate an `iadd_imm` where the result is
2800    // thrown away after the offset check. This may truncate the offset and the
2801    // result may overflow as well, but those conditions won't affect the
2802    // alignment check itself. This can probably be optimized better and we
2803    // should do so in the future as well.
2804    if loaded_bytes > 1 {
2805        let addr = state.pop1(); // "peek" via pop then push
2806        state.push1(addr);
2807        let effective_addr = if memarg.offset == 0 {
2808            addr
2809        } else {
2810            builder
2811                .ins()
2812                .iadd_imm(addr, i64::from(memarg.offset as i32))
2813        };
2814        debug_assert!(loaded_bytes.is_power_of_two());
2815        let misalignment = builder
2816            .ins()
2817            .band_imm(effective_addr, i64::from(loaded_bytes - 1));
2818        let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0);
2819        builder.ins().trapnz(f, crate::TRAP_HEAP_MISALIGNED);
2820    }
2821}
2822
2823/// Like `prepare_addr` but for atomic accesses.
2824///
2825/// Returns `None` when the Wasm access will unconditionally trap.
2826fn prepare_atomic_addr<FE: FuncEnvironment + ?Sized>(
2827    memarg: &MemArg,
2828    loaded_bytes: u8,
2829    builder: &mut FunctionBuilder,
2830    state: &mut FuncTranslationState,
2831    environ: &mut FE,
2832) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
2833    align_atomic_addr(memarg, loaded_bytes, builder, state);
2834    prepare_addr(memarg, loaded_bytes, builder, state, environ)
2835}
2836
2837/// Like `Option<T>` but specifically for passing information about transitions
2838/// from reachable to unreachable state and the like from callees to callers.
2839///
2840/// Marked `must_use` to force callers to update
2841/// `FuncTranslationState::reachable` as necessary.
2842#[derive(PartialEq, Eq)]
2843#[must_use]
2844pub enum Reachability<T> {
2845    /// The Wasm execution state is reachable, here is a `T`.
2846    Reachable(T),
2847    /// The Wasm execution state has been determined to be statically
2848    /// unreachable. It is the receiver of this value's responsibility to update
2849    /// `FuncTranslationState::reachable` as necessary.
2850    Unreachable,
2851}
2852
2853/// Translate a load instruction.
2854///
2855/// Returns the execution state's reachability after the load is translated.
2856fn translate_load<FE: FuncEnvironment + ?Sized>(
2857    memarg: &MemArg,
2858    opcode: ir::Opcode,
2859    result_ty: Type,
2860    builder: &mut FunctionBuilder,
2861    state: &mut FuncTranslationState,
2862    environ: &mut FE,
2863) -> WasmResult<Reachability<()>> {
2864    let mem_op_size = mem_op_size(opcode, result_ty);
2865    let (flags, wasm_index, base) =
2866        match prepare_addr(memarg, mem_op_size, builder, state, environ)? {
2867            Reachability::Unreachable => return Ok(Reachability::Unreachable),
2868            Reachability::Reachable((f, i, b)) => (f, i, b),
2869        };
2870
2871    environ.before_load(builder, mem_op_size, wasm_index, memarg.offset);
2872
2873    let (load, dfg) = builder
2874        .ins()
2875        .Load(opcode, result_ty, flags, Offset32::new(0), base);
2876    state.push1(dfg.first_result(load));
2877    Ok(Reachability::Reachable(()))
2878}
2879
2880/// Translate a store instruction.
2881fn translate_store<FE: FuncEnvironment + ?Sized>(
2882    memarg: &MemArg,
2883    opcode: ir::Opcode,
2884    builder: &mut FunctionBuilder,
2885    state: &mut FuncTranslationState,
2886    environ: &mut FE,
2887) -> WasmResult<()> {
2888    let val = state.pop1();
2889    let val_ty = builder.func.dfg.value_type(val);
2890    let mem_op_size = mem_op_size(opcode, val_ty);
2891
2892    let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!(
2893        state,
2894        prepare_addr(memarg, mem_op_size, builder, state, environ)?
2895    );
2896
2897    environ.before_store(builder, mem_op_size, wasm_index, memarg.offset);
2898
2899    builder
2900        .ins()
2901        .Store(opcode, val_ty, flags, Offset32::new(0), val, base);
2902    Ok(())
2903}
2904
2905fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
2906    match opcode {
2907        ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
2908        ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
2909        ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
2910        ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
2911        _ => panic!("unknown size of mem op for {opcode:?}"),
2912    }
2913}
2914
2915fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
2916    let (arg0, arg1) = state.pop2();
2917    let val = builder.ins().icmp(cc, arg0, arg1);
2918    state.push1(builder.ins().uextend(I32, val));
2919}
2920
2921fn fold_atomic_mem_addr(
2922    linear_mem_addr: Value,
2923    memarg: &MemArg,
2924    access_ty: Type,
2925    builder: &mut FunctionBuilder,
2926) -> Value {
2927    let access_ty_bytes = access_ty.bytes();
2928    let final_lma = if memarg.offset > 0 {
2929        assert!(builder.func.dfg.value_type(linear_mem_addr) == I32);
2930        let linear_mem_addr = builder.ins().uextend(I64, linear_mem_addr);
2931        let a = builder
2932            .ins()
2933            .iadd_imm(linear_mem_addr, memarg.offset as i64);
2934        let r = builder
2935            .ins()
2936            .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, a, 0x1_0000_0000i64);
2937        builder.ins().trapnz(r, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
2938        builder.ins().ireduce(I32, a)
2939    } else {
2940        linear_mem_addr
2941    };
2942    assert!(access_ty_bytes == 4 || access_ty_bytes == 8);
2943    let final_lma_misalignment = builder
2944        .ins()
2945        .band_imm(final_lma, i64::from(access_ty_bytes - 1));
2946    let f = builder
2947        .ins()
2948        .icmp_imm(IntCC::Equal, final_lma_misalignment, i64::from(0));
2949    builder.ins().trapz(f, crate::TRAP_HEAP_MISALIGNED);
2950    final_lma
2951}
2952
2953fn translate_atomic_rmw<FE: FuncEnvironment + ?Sized>(
2954    widened_ty: Type,
2955    access_ty: Type,
2956    op: AtomicRmwOp,
2957    memarg: &MemArg,
2958    builder: &mut FunctionBuilder,
2959    state: &mut FuncTranslationState,
2960    environ: &mut FE,
2961) -> WasmResult<()> {
2962    let mut arg2 = state.pop1();
2963    let arg2_ty = builder.func.dfg.value_type(arg2);
2964
2965    // The operation is performed at type `access_ty`, and the old value is zero-extended
2966    // to type `widened_ty`.
2967    match access_ty {
2968        I8 | I16 | I32 | I64 => {}
2969        _ => {
2970            return Err(wasm_unsupported!(
2971                "atomic_rmw: unsupported access type {:?}",
2972                access_ty
2973            ));
2974        }
2975    };
2976    let w_ty_ok = matches!(widened_ty, I32 | I64);
2977    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2978
2979    assert!(arg2_ty.bytes() >= access_ty.bytes());
2980    if arg2_ty.bytes() > access_ty.bytes() {
2981        arg2 = builder.ins().ireduce(access_ty, arg2);
2982    }
2983
2984    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
2985        state,
2986        prepare_atomic_addr(
2987            memarg,
2988            u8::try_from(access_ty.bytes()).unwrap(),
2989            builder,
2990            state,
2991            environ,
2992        )?
2993    );
2994
2995    let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
2996    if access_ty != widened_ty {
2997        res = builder.ins().uextend(widened_ty, res);
2998    }
2999    state.push1(res);
3000    Ok(())
3001}
3002fn translate_atomic_cas<FE: FuncEnvironment + ?Sized>(
3003    widened_ty: Type,
3004    access_ty: Type,
3005    memarg: &MemArg,
3006    builder: &mut FunctionBuilder,
3007    state: &mut FuncTranslationState,
3008    environ: &mut FE,
3009) -> WasmResult<()> {
3010    let (mut expected, mut replacement) = state.pop2();
3011    let expected_ty = builder.func.dfg.value_type(expected);
3012    let replacement_ty = builder.func.dfg.value_type(replacement);
3013
3014    // The compare-and-swap is performed at type `access_ty`, and the old value is zero-extended
3015    // to type `widened_ty`.
3016    match access_ty {
3017        I8 | I16 | I32 | I64 => {}
3018        _ => {
3019            return Err(wasm_unsupported!(
3020                "atomic_cas: unsupported access type {:?}",
3021                access_ty
3022            ));
3023        }
3024    };
3025    let w_ty_ok = matches!(widened_ty, I32 | I64);
3026    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3027
3028    assert!(expected_ty.bytes() >= access_ty.bytes());
3029    if expected_ty.bytes() > access_ty.bytes() {
3030        expected = builder.ins().ireduce(access_ty, expected);
3031    }
3032    assert!(replacement_ty.bytes() >= access_ty.bytes());
3033    if replacement_ty.bytes() > access_ty.bytes() {
3034        replacement = builder.ins().ireduce(access_ty, replacement);
3035    }
3036
3037    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3038        state,
3039        prepare_atomic_addr(
3040            memarg,
3041            u8::try_from(access_ty.bytes()).unwrap(),
3042            builder,
3043            state,
3044            environ,
3045        )?
3046    );
3047    let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
3048    if access_ty != widened_ty {
3049        res = builder.ins().uextend(widened_ty, res);
3050    }
3051    state.push1(res);
3052    Ok(())
3053}
3054
3055fn translate_atomic_load<FE: FuncEnvironment + ?Sized>(
3056    widened_ty: Type,
3057    access_ty: Type,
3058    memarg: &MemArg,
3059    builder: &mut FunctionBuilder,
3060    state: &mut FuncTranslationState,
3061    environ: &mut FE,
3062) -> WasmResult<()> {
3063    // The load is performed at type `access_ty`, and the loaded value is zero extended
3064    // to `widened_ty`.
3065    match access_ty {
3066        I8 | I16 | I32 | I64 => {}
3067        _ => {
3068            return Err(wasm_unsupported!(
3069                "atomic_load: unsupported access type {:?}",
3070                access_ty
3071            ));
3072        }
3073    };
3074    let w_ty_ok = matches!(widened_ty, I32 | I64);
3075    assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3076
3077    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3078        state,
3079        prepare_atomic_addr(
3080            memarg,
3081            u8::try_from(access_ty.bytes()).unwrap(),
3082            builder,
3083            state,
3084            environ,
3085        )?
3086    );
3087    let mut res = builder.ins().atomic_load(access_ty, flags, addr);
3088    if access_ty != widened_ty {
3089        res = builder.ins().uextend(widened_ty, res);
3090    }
3091    state.push1(res);
3092    Ok(())
3093}
3094
3095fn translate_atomic_store<FE: FuncEnvironment + ?Sized>(
3096    access_ty: Type,
3097    memarg: &MemArg,
3098    builder: &mut FunctionBuilder,
3099    state: &mut FuncTranslationState,
3100    environ: &mut FE,
3101) -> WasmResult<()> {
3102    let mut data = state.pop1();
3103    let data_ty = builder.func.dfg.value_type(data);
3104
3105    // The operation is performed at type `access_ty`, and the data to be stored may first
3106    // need to be narrowed accordingly.
3107    match access_ty {
3108        I8 | I16 | I32 | I64 => {}
3109        _ => {
3110            return Err(wasm_unsupported!(
3111                "atomic_store: unsupported access type {:?}",
3112                access_ty
3113            ));
3114        }
3115    };
3116    let d_ty_ok = matches!(data_ty, I32 | I64);
3117    assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
3118
3119    if data_ty.bytes() > access_ty.bytes() {
3120        data = builder.ins().ireduce(access_ty, data);
3121    }
3122
3123    let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3124        state,
3125        prepare_atomic_addr(
3126            memarg,
3127            u8::try_from(access_ty.bytes()).unwrap(),
3128            builder,
3129            state,
3130            environ,
3131        )?
3132    );
3133    builder.ins().atomic_store(flags, data, addr);
3134    Ok(())
3135}
3136
3137fn translate_vector_icmp(
3138    cc: IntCC,
3139    needed_type: Type,
3140    builder: &mut FunctionBuilder,
3141    state: &mut FuncTranslationState,
3142) {
3143    let (a, b) = state.pop2();
3144    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3145    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3146    state.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3147}
3148
3149fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3150    let (arg0, arg1) = state.pop2();
3151    let val = builder.ins().fcmp(cc, arg0, arg1);
3152    state.push1(builder.ins().uextend(I32, val));
3153}
3154
3155fn translate_vector_fcmp(
3156    cc: FloatCC,
3157    needed_type: Type,
3158    builder: &mut FunctionBuilder,
3159    state: &mut FuncTranslationState,
3160) {
3161    let (a, b) = state.pop2();
3162    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3163    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3164    state.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3165}
3166
3167fn translate_br_if(
3168    relative_depth: u32,
3169    builder: &mut FunctionBuilder,
3170    state: &mut FuncTranslationState,
3171) {
3172    let val = state.pop1();
3173    let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
3174    let next_block = builder.create_block();
3175    canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3176
3177    builder.seal_block(next_block); // The only predecessor is the current block.
3178    builder.switch_to_block(next_block);
3179}
3180
3181fn translate_br_if_args(
3182    relative_depth: u32,
3183    state: &mut FuncTranslationState,
3184) -> (ir::Block, &mut [ir::Value]) {
3185    let i = state.control_stack.len() - 1 - (relative_depth as usize);
3186    let (return_count, br_destination) = {
3187        let frame = &mut state.control_stack[i];
3188        // The values returned by the branch are still available for the reachable
3189        // code that comes after it
3190        frame.set_branched_to_exit();
3191        let return_count = if frame.is_loop() {
3192            frame.num_param_values()
3193        } else {
3194            frame.num_return_values()
3195        };
3196        (return_count, frame.br_destination())
3197    };
3198    let inputs = state.peekn_mut(return_count);
3199    (br_destination, inputs)
3200}
3201
3202/// Determine the returned value type of a WebAssembly operator
3203fn type_of(operator: &Operator) -> Type {
3204    match operator {
3205        Operator::V128Load { .. }
3206        | Operator::V128Store { .. }
3207        | Operator::V128Const { .. }
3208        | Operator::V128Not
3209        | Operator::V128And
3210        | Operator::V128AndNot
3211        | Operator::V128Or
3212        | Operator::V128Xor
3213        | Operator::V128AnyTrue
3214        | Operator::V128Bitselect => I8X16, // default type representing V128
3215
3216        Operator::I8x16Shuffle { .. }
3217        | Operator::I8x16Splat
3218        | Operator::V128Load8Splat { .. }
3219        | Operator::V128Load8Lane { .. }
3220        | Operator::V128Store8Lane { .. }
3221        | Operator::I8x16ExtractLaneS { .. }
3222        | Operator::I8x16ExtractLaneU { .. }
3223        | Operator::I8x16ReplaceLane { .. }
3224        | Operator::I8x16RelaxedSwizzle
3225        | Operator::I8x16RelaxedLaneselect
3226        | Operator::I8x16Eq
3227        | Operator::I8x16Ne
3228        | Operator::I8x16LtS
3229        | Operator::I8x16LtU
3230        | Operator::I8x16GtS
3231        | Operator::I8x16GtU
3232        | Operator::I8x16LeS
3233        | Operator::I8x16LeU
3234        | Operator::I8x16GeS
3235        | Operator::I8x16GeU
3236        | Operator::I8x16Neg
3237        | Operator::I8x16Abs
3238        | Operator::I8x16AllTrue
3239        | Operator::I8x16Shl
3240        | Operator::I8x16ShrS
3241        | Operator::I8x16ShrU
3242        | Operator::I8x16Add
3243        | Operator::I8x16AddSatS
3244        | Operator::I8x16AddSatU
3245        | Operator::I8x16Sub
3246        | Operator::I8x16SubSatS
3247        | Operator::I8x16SubSatU
3248        | Operator::I8x16MinS
3249        | Operator::I8x16MinU
3250        | Operator::I8x16MaxS
3251        | Operator::I8x16MaxU
3252        | Operator::I8x16AvgrU
3253        | Operator::I8x16Bitmask
3254        | Operator::I8x16Popcnt => I8X16,
3255
3256        Operator::I16x8Splat
3257        | Operator::V128Load16Splat { .. }
3258        | Operator::V128Load16Lane { .. }
3259        | Operator::V128Store16Lane { .. }
3260        | Operator::I16x8ExtractLaneS { .. }
3261        | Operator::I16x8ExtractLaneU { .. }
3262        | Operator::I16x8ReplaceLane { .. }
3263        | Operator::I16x8RelaxedLaneselect
3264        | Operator::I16x8Eq
3265        | Operator::I16x8Ne
3266        | Operator::I16x8LtS
3267        | Operator::I16x8LtU
3268        | Operator::I16x8GtS
3269        | Operator::I16x8GtU
3270        | Operator::I16x8LeS
3271        | Operator::I16x8LeU
3272        | Operator::I16x8GeS
3273        | Operator::I16x8GeU
3274        | Operator::I16x8Neg
3275        | Operator::I16x8Abs
3276        | Operator::I16x8AllTrue
3277        | Operator::I16x8Shl
3278        | Operator::I16x8ShrS
3279        | Operator::I16x8ShrU
3280        | Operator::I16x8Add
3281        | Operator::I16x8AddSatS
3282        | Operator::I16x8AddSatU
3283        | Operator::I16x8Sub
3284        | Operator::I16x8SubSatS
3285        | Operator::I16x8SubSatU
3286        | Operator::I16x8MinS
3287        | Operator::I16x8MinU
3288        | Operator::I16x8MaxS
3289        | Operator::I16x8MaxU
3290        | Operator::I16x8AvgrU
3291        | Operator::I16x8Mul
3292        | Operator::I16x8RelaxedQ15mulrS
3293        | Operator::I16x8RelaxedDotI8x16I7x16S
3294        | Operator::I16x8Bitmask => I16X8,
3295
3296        Operator::I32x4Splat
3297        | Operator::V128Load32Splat { .. }
3298        | Operator::V128Load32Lane { .. }
3299        | Operator::V128Store32Lane { .. }
3300        | Operator::I32x4ExtractLane { .. }
3301        | Operator::I32x4ReplaceLane { .. }
3302        | Operator::I32x4RelaxedLaneselect
3303        | Operator::I32x4Eq
3304        | Operator::I32x4Ne
3305        | Operator::I32x4LtS
3306        | Operator::I32x4LtU
3307        | Operator::I32x4GtS
3308        | Operator::I32x4GtU
3309        | Operator::I32x4LeS
3310        | Operator::I32x4LeU
3311        | Operator::I32x4GeS
3312        | Operator::I32x4GeU
3313        | Operator::I32x4Neg
3314        | Operator::I32x4Abs
3315        | Operator::I32x4AllTrue
3316        | Operator::I32x4Shl
3317        | Operator::I32x4ShrS
3318        | Operator::I32x4ShrU
3319        | Operator::I32x4Add
3320        | Operator::I32x4Sub
3321        | Operator::I32x4Mul
3322        | Operator::I32x4MinS
3323        | Operator::I32x4MinU
3324        | Operator::I32x4MaxS
3325        | Operator::I32x4MaxU
3326        | Operator::I32x4Bitmask
3327        | Operator::I32x4TruncSatF32x4S
3328        | Operator::I32x4TruncSatF32x4U
3329        | Operator::I32x4RelaxedTruncF32x4S
3330        | Operator::I32x4RelaxedTruncF32x4U
3331        | Operator::I32x4RelaxedTruncF64x2SZero
3332        | Operator::I32x4RelaxedTruncF64x2UZero
3333        | Operator::I32x4RelaxedDotI8x16I7x16AddS
3334        | Operator::V128Load32Zero { .. } => I32X4,
3335
3336        Operator::I64x2Splat
3337        | Operator::V128Load64Splat { .. }
3338        | Operator::V128Load64Lane { .. }
3339        | Operator::V128Store64Lane { .. }
3340        | Operator::I64x2ExtractLane { .. }
3341        | Operator::I64x2ReplaceLane { .. }
3342        | Operator::I64x2RelaxedLaneselect
3343        | Operator::I64x2Eq
3344        | Operator::I64x2Ne
3345        | Operator::I64x2LtS
3346        | Operator::I64x2GtS
3347        | Operator::I64x2LeS
3348        | Operator::I64x2GeS
3349        | Operator::I64x2Neg
3350        | Operator::I64x2Abs
3351        | Operator::I64x2AllTrue
3352        | Operator::I64x2Shl
3353        | Operator::I64x2ShrS
3354        | Operator::I64x2ShrU
3355        | Operator::I64x2Add
3356        | Operator::I64x2Sub
3357        | Operator::I64x2Mul
3358        | Operator::I64x2Bitmask
3359        | Operator::V128Load64Zero { .. } => I64X2,
3360
3361        Operator::F32x4Splat
3362        | Operator::F32x4ExtractLane { .. }
3363        | Operator::F32x4ReplaceLane { .. }
3364        | Operator::F32x4Eq
3365        | Operator::F32x4Ne
3366        | Operator::F32x4Lt
3367        | Operator::F32x4Gt
3368        | Operator::F32x4Le
3369        | Operator::F32x4Ge
3370        | Operator::F32x4Abs
3371        | Operator::F32x4Neg
3372        | Operator::F32x4Sqrt
3373        | Operator::F32x4Add
3374        | Operator::F32x4Sub
3375        | Operator::F32x4Mul
3376        | Operator::F32x4Div
3377        | Operator::F32x4Min
3378        | Operator::F32x4Max
3379        | Operator::F32x4PMin
3380        | Operator::F32x4PMax
3381        | Operator::F32x4RelaxedMin
3382        | Operator::F32x4RelaxedMax
3383        | Operator::F32x4RelaxedMadd
3384        | Operator::F32x4RelaxedNmadd
3385        | Operator::F32x4ConvertI32x4S
3386        | Operator::F32x4ConvertI32x4U
3387        | Operator::F32x4Ceil
3388        | Operator::F32x4Floor
3389        | Operator::F32x4Trunc
3390        | Operator::F32x4Nearest => F32X4,
3391
3392        Operator::F64x2Splat
3393        | Operator::F64x2ExtractLane { .. }
3394        | Operator::F64x2ReplaceLane { .. }
3395        | Operator::F64x2Eq
3396        | Operator::F64x2Ne
3397        | Operator::F64x2Lt
3398        | Operator::F64x2Gt
3399        | Operator::F64x2Le
3400        | Operator::F64x2Ge
3401        | Operator::F64x2Abs
3402        | Operator::F64x2Neg
3403        | Operator::F64x2Sqrt
3404        | Operator::F64x2Add
3405        | Operator::F64x2Sub
3406        | Operator::F64x2Mul
3407        | Operator::F64x2Div
3408        | Operator::F64x2Min
3409        | Operator::F64x2Max
3410        | Operator::F64x2PMin
3411        | Operator::F64x2PMax
3412        | Operator::F64x2RelaxedMin
3413        | Operator::F64x2RelaxedMax
3414        | Operator::F64x2RelaxedMadd
3415        | Operator::F64x2RelaxedNmadd
3416        | Operator::F64x2Ceil
3417        | Operator::F64x2Floor
3418        | Operator::F64x2Trunc
3419        | Operator::F64x2Nearest => F64X2,
3420
3421        _ => unimplemented!(
3422            "Currently only SIMD instructions are mapped to their return type; the \
3423             following instruction is not mapped: {:?}",
3424            operator
3425        ),
3426    }
3427}
3428
3429/// Some SIMD operations only operate on I8X16 in CLIF; this will convert them to that type by
3430/// adding a raw_bitcast if necessary.
3431fn optionally_bitcast_vector(
3432    value: Value,
3433    needed_type: Type,
3434    builder: &mut FunctionBuilder,
3435) -> Value {
3436    if builder.func.dfg.value_type(value) != needed_type {
3437        builder.ins().bitcast(
3438            needed_type,
3439            MemFlags::new().with_endianness(ir::Endianness::Little),
3440            value,
3441        )
3442    } else {
3443        value
3444    }
3445}
3446
3447#[inline(always)]
3448fn is_non_canonical_v128(ty: ir::Type) -> bool {
3449    matches!(ty, I64X2 | I32X4 | I16X8 | F32X4 | F64X2)
3450}
3451
3452/// Cast to I8X16, any vector values in `values` that are of "non-canonical" type (meaning, not
3453/// I8X16), and return them in a slice.  A pre-scan is made to determine whether any casts are
3454/// actually necessary, and if not, the original slice is returned.  Otherwise the cast values
3455/// are returned in a slice that belongs to the caller-supplied `SmallVec`.
3456fn canonicalise_v128_values<'a>(
3457    tmp_canonicalised: &'a mut SmallVec<[ir::BlockArg; 16]>,
3458    builder: &mut FunctionBuilder,
3459    values: &'a [ir::Value],
3460) -> &'a [ir::BlockArg] {
3461    debug_assert!(tmp_canonicalised.is_empty());
3462    for v in values {
3463        let value = if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
3464            builder.ins().bitcast(
3465                I8X16,
3466                MemFlags::new().with_endianness(ir::Endianness::Little),
3467                *v,
3468            )
3469        } else {
3470            *v
3471        };
3472        tmp_canonicalised.push(BlockArg::from(value));
3473    }
3474    tmp_canonicalised.as_slice()
3475}
3476
3477/// Generate a `jump` instruction, but first cast all 128-bit vector values to I8X16 if they
3478/// don't have that type.  This is done in somewhat roundabout way so as to ensure that we
3479/// almost never have to do any heap allocation.
3480fn canonicalise_then_jump(
3481    builder: &mut FunctionBuilder,
3482    destination: ir::Block,
3483    params: &[ir::Value],
3484) -> ir::Inst {
3485    let mut tmp_canonicalised = SmallVec::<[_; 16]>::new();
3486    let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
3487    builder.ins().jump(destination, canonicalised)
3488}
3489
3490/// The same but for a `brif` instruction.
3491fn canonicalise_brif(
3492    builder: &mut FunctionBuilder,
3493    cond: ir::Value,
3494    block_then: ir::Block,
3495    params_then: &[ir::Value],
3496    block_else: ir::Block,
3497    params_else: &[ir::Value],
3498) -> ir::Inst {
3499    let mut tmp_canonicalised_then = SmallVec::<[_; 16]>::new();
3500    let canonicalised_then =
3501        canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
3502    let mut tmp_canonicalised_else = SmallVec::<[_; 16]>::new();
3503    let canonicalised_else =
3504        canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
3505    builder.ins().brif(
3506        cond,
3507        block_then,
3508        canonicalised_then,
3509        block_else,
3510        canonicalised_else,
3511    )
3512}
3513
3514/// A helper for popping and bitcasting a single value; since SIMD values can lose their type by
3515/// using v128 (i.e. CLIF's I8x16) we must re-type the values using a bitcast to avoid CLIF
3516/// typing issues.
3517fn pop1_with_bitcast(
3518    state: &mut FuncTranslationState,
3519    needed_type: Type,
3520    builder: &mut FunctionBuilder,
3521) -> Value {
3522    optionally_bitcast_vector(state.pop1(), needed_type, builder)
3523}
3524
3525/// A helper for popping and bitcasting two values; since SIMD values can lose their type by
3526/// using v128 (i.e. CLIF's I8x16) we must re-type the values using a bitcast to avoid CLIF
3527/// typing issues.
3528fn pop2_with_bitcast(
3529    state: &mut FuncTranslationState,
3530    needed_type: Type,
3531    builder: &mut FunctionBuilder,
3532) -> (Value, Value) {
3533    let (a, b) = state.pop2();
3534    let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3535    let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3536    (bitcast_a, bitcast_b)
3537}
3538
3539pub fn bitcast_arguments<'a>(
3540    builder: &FunctionBuilder,
3541    arguments: &'a mut [Value],
3542    params: &[ir::AbiParam],
3543    param_predicate: impl Fn(usize) -> bool,
3544) -> Vec<(Type, &'a mut Value)> {
3545    let filtered_param_types = params
3546        .iter()
3547        .enumerate()
3548        .filter(|(i, _)| param_predicate(*i))
3549        .map(|(_, param)| param.value_type);
3550
3551    // zip_eq, from the itertools::Itertools trait, is like Iterator::zip but panics if one
3552    // iterator ends before the other. The `param_predicate` is required to select exactly as many
3553    // elements of `params` as there are elements in `arguments`.
3554    let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
3555
3556    // The arguments which need to be bitcasted are those which have some vector type but the type
3557    // expected by the parameter is not the same vector type as that of the provided argument.
3558    pairs
3559        .filter(|(param_type, _)| param_type.is_vector())
3560        .filter(|(param_type, arg)| {
3561            let arg_type = builder.func.dfg.value_type(**arg);
3562            assert!(
3563                arg_type.is_vector(),
3564                "unexpected type mismatch: expected {}, argument {} was actually of type {}",
3565                param_type,
3566                *arg,
3567                arg_type
3568            );
3569
3570            // This is the same check that would be done by `optionally_bitcast_vector`, except we
3571            // can't take a mutable borrow of the FunctionBuilder here, so we defer inserting the
3572            // bitcast instruction to the caller.
3573            arg_type != *param_type
3574        })
3575        .collect()
3576}
3577
3578/// A helper for bitcasting a sequence of return values for the function currently being built. If
3579/// a value is a vector type that does not match its expected type, this will modify the value in
3580/// place to point to the result of a `bitcast`. This conversion is necessary to translate Wasm
3581/// code that uses `V128` as function parameters (or implicitly in block parameters) and still use
3582/// specific CLIF types (e.g. `I32X4`) in the function body.
3583pub fn bitcast_wasm_returns<FE: FuncEnvironment + ?Sized>(
3584    environ: &mut FE,
3585    arguments: &mut [Value],
3586    builder: &mut FunctionBuilder,
3587) {
3588    let changes = bitcast_arguments(builder, arguments, &builder.func.signature.returns, |i| {
3589        environ.is_wasm_return(&builder.func.signature, i)
3590    });
3591    for (t, arg) in changes {
3592        let mut flags = MemFlags::new();
3593        flags.set_endianness(ir::Endianness::Little);
3594        *arg = builder.ins().bitcast(t, flags, *arg);
3595    }
3596}
3597
3598/// Like `bitcast_wasm_returns`, but for the parameters being passed to a specified callee.
3599pub fn bitcast_wasm_params<FE: FuncEnvironment + ?Sized>(
3600    environ: &mut FE,
3601    callee_signature: ir::SigRef,
3602    arguments: &mut [Value],
3603    builder: &mut FunctionBuilder,
3604) {
3605    let callee_signature = &builder.func.dfg.signatures[callee_signature];
3606    let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
3607        environ.is_wasm_parameter(callee_signature, i)
3608    });
3609    for (t, arg) in changes {
3610        let mut flags = MemFlags::new();
3611        flags.set_endianness(ir::Endianness::Little);
3612        *arg = builder.ins().bitcast(t, flags, *arg);
3613    }
3614}
3615
3616#[derive(Debug, Clone)]
3617pub(crate) struct CatchClause {
3618    pub(crate) wasm_tag: Option<u32>,
3619    pub(crate) tag_value: i32,
3620    pub(crate) block: ir::Block,
3621}
3622
3623fn create_catch_block<FE: FuncEnvironment + ?Sized>(
3624    builder: &mut FunctionBuilder,
3625    state: &mut FuncTranslationState,
3626    catch: &wasmparser::Catch,
3627    environ: &mut FE,
3628) -> WasmResult<CatchClause> {
3629    let (is_ref, wasm_tag, label) = match catch {
3630        wasmparser::Catch::One { tag, label } => (false, Some(*tag), *label),
3631        wasmparser::Catch::OneRef { tag, label } => (true, Some(*tag), *label),
3632        wasmparser::Catch::All { label } => (false, None, *label),
3633        wasmparser::Catch::AllRef { label } => (true, None, *label),
3634    };
3635
3636    let tag_value = wasm_tag.map_or(CATCH_ALL_TAG_VALUE, |t| t as i32);
3637
3638    let block = builder.create_block();
3639    let exnref = builder.append_block_param(block, EXN_REF_TYPE);
3640
3641    builder.switch_to_block(block);
3642
3643    let mut params = SmallVec::<[Value; 4]>::new();
3644    if let Some(tag) = wasm_tag {
3645        let tag_index = TagIndex::from_u32(tag);
3646        params.extend(environ.translate_exn_unbox(builder, tag_index, exnref)?);
3647    }
3648    if is_ref {
3649        params.push(exnref);
3650    }
3651
3652    let depth = label as usize;
3653    let idx = state.control_stack.len() - 1 - depth;
3654    let frame = &mut state.control_stack[idx];
3655    frame.set_branched_to_exit();
3656    canonicalise_then_jump(builder, frame.br_destination(), params.as_slice());
3657
3658    Ok(CatchClause {
3659        wasm_tag,
3660        tag_value,
3661        block,
3662    })
3663}
3664
3665fn create_dispatch_block<FE: FuncEnvironment + ?Sized>(
3666    builder: &mut FunctionBuilder,
3667    environ: &mut FE,
3668    clauses: impl Iterator<Item = CatchClause>,
3669) -> WasmResult<ir::Block> {
3670    let clauses = clauses.collect_vec();
3671
3672    let catch_block = builder.create_block();
3673    let exn_ptr = builder.append_block_param(catch_block, environ.reference_type());
3674    let pre_selector = builder.append_block_param(catch_block, I64);
3675    let catch_all_block = builder.create_block();
3676    let catch_one_block = builder.create_block();
3677    let dispatch_block = builder.create_block();
3678
3679    builder.switch_to_block(catch_block);
3680    let catch_all_tag = builder.ins().iconst(I64, 0);
3681    let matches = builder
3682        .ins()
3683        .icmp(IntCC::Equal, pre_selector, catch_all_tag);
3684    canonicalise_brif(builder, matches, catch_all_block, &[], catch_one_block, &[]);
3685
3686    builder.switch_to_block(catch_all_block);
3687    let catch_all_tag = builder
3688        .ins()
3689        .iconst(TAG_TYPE, i64::from(CATCH_ALL_TAG_VALUE));
3690    canonicalise_then_jump(builder, dispatch_block, &[catch_all_tag]);
3691    builder.seal_block(catch_all_block);
3692
3693    builder.switch_to_block(catch_one_block);
3694    let selector = environ.translate_exn_personality_selector(builder, exn_ptr)?;
3695    canonicalise_then_jump(builder, dispatch_block, &[selector]);
3696    builder.seal_block(catch_one_block);
3697
3698    builder.switch_to_block(dispatch_block);
3699    let selector = builder.append_block_param(dispatch_block, TAG_TYPE);
3700    let exnref = environ.translate_exn_pointer_to_ref(builder, exn_ptr);
3701
3702    let rethrow_block = builder.create_block();
3703    builder.append_block_param(rethrow_block, EXN_REF_TYPE);
3704
3705    let mut current_selector = selector;
3706    let mut current_exn = exnref;
3707
3708    for (idx, clause) in clauses.iter().enumerate() {
3709        let tag_value = builder.ins().iconst(TAG_TYPE, i64::from(clause.tag_value));
3710        let matches = builder
3711            .ins()
3712            .icmp(IntCC::Equal, current_selector, tag_value);
3713
3714        if idx + 1 == clauses.len() {
3715            canonicalise_brif(
3716                builder,
3717                matches,
3718                clause.block,
3719                &[current_exn],
3720                rethrow_block,
3721                &[exnref],
3722            );
3723        } else {
3724            let continue_block = builder.create_block();
3725            builder.append_block_param(continue_block, TAG_TYPE);
3726            builder.append_block_param(continue_block, EXN_REF_TYPE);
3727
3728            canonicalise_brif(
3729                builder,
3730                matches,
3731                clause.block,
3732                &[current_exn],
3733                continue_block,
3734                &[current_selector, current_exn],
3735            );
3736
3737            builder.seal_block(continue_block);
3738            builder.switch_to_block(continue_block);
3739            let params = builder.func.dfg.block_params(continue_block);
3740            current_selector = params[0];
3741            current_exn = params[1];
3742        }
3743    }
3744    builder.seal_block(dispatch_block);
3745
3746    builder.switch_to_block(rethrow_block);
3747    let rethrow_exn = builder.func.dfg.block_params(rethrow_block)[0];
3748    environ.translate_exn_reraise_unmatched(builder, rethrow_exn)?;
3749    builder.seal_block(rethrow_block);
3750
3751    Ok(catch_block)
3752}