1mod bounds_checks;
78
79pub(crate) const TAG_TYPE: ir::Type = I32;
80pub(crate) const EXN_REF_TYPE: ir::Type = I32;
81
82use super::func_state::{ControlStackFrame, ElseData, FuncTranslationState};
83use super::translation_utils::{
84 block_with_params, f32_translation, f64_translation, materialize_global_value,
85};
86use crate::func_environ::{FuncEnvironment, GlobalVariable};
87use crate::{HashMap, hash_map};
88use core::convert::TryFrom;
89use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
90use cranelift_codegen::ir::immediates::Offset32;
91use cranelift_codegen::ir::{
92 self, AtomicRmwOp, BlockArg, ConstantData, InstBuilder, JumpTableData, MemFlagsData, Value,
93 ValueLabel,
94};
95use cranelift_codegen::ir::{Function, types::*};
96use cranelift_codegen::packed_option::ReservedValue;
97use cranelift_frontend::{FunctionBuilder, Variable};
98use itertools::Itertools;
99use smallvec::SmallVec;
100use std::vec::Vec;
101
102use wasmer_compiler::wasmparser::{self, Catch, MemArg, Operator};
103use wasmer_compiler::{ModuleTranslationState, from_binaryreadererror_wasmerror, wasm_unsupported};
104use wasmer_types::{
105 CATCH_ALL_TAG_VALUE, FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex,
106 TagIndex, WasmError, WasmResult,
107};
108
109macro_rules! unwrap_or_return_unreachable_state {
116 ($state:ident, $value:expr) => {
117 match $value {
118 Reachability::Reachable(x) => x,
119 Reachability::Unreachable => {
120 $state.reachable = false;
121 return Ok(());
122 }
123 }
124 };
125}
126
127pub(crate) enum MemoryAliasRegion {
128 Heap,
129 Table,
130}
131
132fn insert_mem_flags(func: &mut Function, flags: ir::MemFlagsData) -> ir::MemFlags {
133 func.dfg.mem_flags.insert(flags).unwrap()
134}
135
136pub fn set_memflags_alias_region(
137 func: &mut Function,
138 flags: &mut MemFlagsData,
139 region: MemoryAliasRegion,
140) {
141 flags.set_alias_region(Some(func.dfg.alias_regions.insert(match region {
142 MemoryAliasRegion::Heap => ir::AliasRegionData {
143 user_id: 0,
144 description: "heap".into(),
145 },
146 MemoryAliasRegion::Table => ir::AliasRegionData {
147 user_id: 1,
148 description: "table".into(),
149 },
150 })));
151}
152
153#[allow(clippy::unneeded_field_pattern, clippy::cognitive_complexity)]
155pub fn translate_operator(
158 module_translation_state: &ModuleTranslationState,
159 op: &Operator,
160 builder: &mut FunctionBuilder,
161 state: &mut FuncTranslationState,
162 environ: &mut FuncEnvironment<'_>,
163 allow_unaligned_memory_accesses: bool,
164) -> WasmResult<()> {
165 if !state.reachable {
166 translate_unreachable_operator(module_translation_state, op, builder, state, environ)?;
167 return Ok(());
168 }
169
170 match op {
172 Operator::LocalGet { local_index } => {
177 let val = builder.use_var(Variable::from_u32(*local_index));
178 state.push1(val);
179 let label = ValueLabel::from_u32(*local_index);
180 builder.set_val_label(val, label);
181 }
182 Operator::LocalSet { local_index } => {
183 let mut val = state.pop1();
184
185 let ty = builder.func.dfg.value_type(val);
187 if ty.is_vector() {
188 val = optionally_bitcast_vector(val, I8X16, builder);
189 }
190
191 builder.def_var(Variable::from_u32(*local_index), val);
192 let label = ValueLabel::from_u32(*local_index);
193 builder.set_val_label(val, label);
194 }
195 Operator::LocalTee { local_index } => {
196 let mut val = state.peek1();
197
198 let ty = builder.func.dfg.value_type(val);
200 if ty.is_vector() {
201 val = optionally_bitcast_vector(val, I8X16, builder);
202 }
203
204 builder.def_var(Variable::from_u32(*local_index), val);
205 let label = ValueLabel::from_u32(*local_index);
206 builder.set_val_label(val, label);
207 }
208 Operator::GlobalGet { global_index } => {
212 let val = match state.get_global(builder.func, *global_index, environ)? {
213 GlobalVariable::Const(val) => val,
214 GlobalVariable::Memory { gv, offset, ty } => {
215 let addr =
216 materialize_global_value(&mut builder.cursor(), environ.pointer_type(), gv);
217 let mut flags = ir::MemFlagsData::trusted();
218 set_memflags_alias_region(builder.func, &mut flags, MemoryAliasRegion::Table);
220 builder.ins().load(ty, flags, addr, offset)
221 }
222 GlobalVariable::Custom => environ.translate_custom_global_get(
223 builder.cursor(),
224 GlobalIndex::from_u32(*global_index),
225 )?,
226 };
227 state.push1(val);
228 }
229 Operator::GlobalSet { global_index } => {
230 match state.get_global(builder.func, *global_index, environ)? {
231 GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
232 GlobalVariable::Memory { gv, offset, ty } => {
233 let addr =
234 materialize_global_value(&mut builder.cursor(), environ.pointer_type(), gv);
235 let mut flags = ir::MemFlagsData::trusted();
236 set_memflags_alias_region(builder.func, &mut flags, MemoryAliasRegion::Table);
238 let mut val = state.pop1();
239 if ty.is_vector() {
241 val = optionally_bitcast_vector(val, I8X16, builder);
242 }
243 debug_assert_eq!(ty, builder.func.dfg.value_type(val));
244 builder.ins().store(flags, val, addr, offset);
245 }
246 GlobalVariable::Custom => {
247 let val = state.pop1();
248 environ.translate_custom_global_set(
249 builder.cursor(),
250 GlobalIndex::from_u32(*global_index),
251 val,
252 )?;
253 }
254 }
255 }
256 Operator::Drop => {
260 state.pop1();
261 }
262 Operator::Select => {
263 let (mut arg1, mut arg2, cond) = state.pop3();
265 if builder.func.dfg.value_type(arg1).is_vector() {
266 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
267 }
268 if builder.func.dfg.value_type(arg2).is_vector() {
269 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
270 }
271 state.push1(builder.ins().select(cond, arg1, arg2));
272 }
273 Operator::TypedSelect { ty: _ } => {
274 let (mut arg1, mut arg2, cond) = state.pop3();
278 if builder.func.dfg.value_type(arg1).is_vector() {
279 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
280 }
281 if builder.func.dfg.value_type(arg2).is_vector() {
282 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
283 }
284 state.push1(builder.ins().select(cond, arg1, arg2));
285 }
286 Operator::Nop => {
287 }
289 Operator::Unreachable => {
290 environ.translate_unreachable(builder)?;
291 state.reachable = false;
292 }
293 Operator::Block { blockty } => {
305 let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
306 let next = block_with_params(builder, results.iter(), environ)?;
307 state.push_block(next, params.len(), results.len());
308 }
309 Operator::Loop { blockty } => {
310 let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
311 let loop_body = block_with_params(builder, params.iter(), environ)?;
312 let next = block_with_params(builder, results.iter(), environ)?;
313 canonicalise_then_jump(builder, loop_body, state.peekn(params.len()));
314 state.push_loop(loop_body, next, params.len(), results.len());
315
316 state.popn(params.len());
319 state
320 .stack
321 .extend_from_slice(builder.block_params(loop_body));
322
323 builder.switch_to_block(loop_body);
324 }
325 Operator::If { blockty } => {
326 let val = state.pop1();
327
328 let next_block = builder.create_block();
329 let (params, results) = module_translation_state.blocktype_params_results(blockty)?;
330 let results: Vec<_> = results.iter().copied().collect();
331 let (destination, else_data) = if params == results {
332 let destination = block_with_params(builder, results.iter(), environ)?;
339 let branch_inst = canonicalise_brif(
340 builder,
341 val,
342 next_block,
343 &[],
344 destination,
345 state.peekn(params.len()),
346 );
347 (
348 destination,
349 ElseData::NoElse {
350 branch_inst,
351 placeholder: destination,
352 },
353 )
354 } else {
355 let destination = block_with_params(builder, results.iter(), environ)?;
358 let else_block = block_with_params(builder, params.iter(), environ)?;
359 canonicalise_brif(
360 builder,
361 val,
362 next_block,
363 &[],
364 else_block,
365 state.peekn(params.len()),
366 );
367 builder.seal_block(else_block);
368 (destination, ElseData::WithElse { else_block })
369 };
370
371 builder.seal_block(next_block); builder.switch_to_block(next_block);
373
374 state.push_if(
381 destination,
382 else_data,
383 params.len(),
384 results.len(),
385 *blockty,
386 );
387 }
388 Operator::Else => {
389 let i = state.control_stack.len() - 1;
390 match state.control_stack[i] {
391 ControlStackFrame::If {
392 ref else_data,
393 head_is_reachable,
394 ref mut consequent_ends_reachable,
395 num_return_values,
396 blocktype,
397 destination,
398 ..
399 } => {
400 debug_assert!(consequent_ends_reachable.is_none());
403 *consequent_ends_reachable = Some(state.reachable);
404
405 if head_is_reachable {
406 state.reachable = true;
408
409 let else_block = match *else_data {
412 ElseData::NoElse {
413 branch_inst,
414 placeholder,
415 } => {
416 let (params, _results) = module_translation_state
417 .blocktype_params_results(&blocktype)?;
418 debug_assert_eq!(params.len(), num_return_values);
419 let else_block =
420 block_with_params(builder, params.iter(), environ)?;
421 canonicalise_then_jump(
422 builder,
423 destination,
424 state.peekn(params.len()),
425 );
426 state.popn(params.len());
427
428 builder.change_jump_destination(
429 branch_inst,
430 placeholder,
431 else_block,
432 );
433 builder.seal_block(else_block);
434 else_block
435 }
436 ElseData::WithElse { else_block } => {
437 canonicalise_then_jump(
438 builder,
439 destination,
440 state.peekn(num_return_values),
441 );
442 state.popn(num_return_values);
443 else_block
444 }
445 };
446
447 builder.switch_to_block(else_block);
458
459 }
462 }
463 _ => unreachable!(),
464 }
465 }
466 Operator::End => {
467 let frame = state.control_stack.pop().unwrap();
468 frame.restore_catch_handlers(&mut state.handlers, builder);
469 let next_block = frame.following_code();
470 let return_count = frame.num_return_values();
471 let return_args = state.peekn_mut(return_count);
472
473 canonicalise_then_jump(builder, next_block, return_args);
474 builder.switch_to_block(next_block);
482 builder.seal_block(next_block);
483
484 if let ControlStackFrame::Loop { header, .. } = frame {
486 builder.seal_block(header)
487 }
488
489 frame.truncate_value_stack_to_original_size(&mut state.stack);
490 state
491 .stack
492 .extend_from_slice(builder.block_params(next_block));
493 }
494 Operator::Br { relative_depth } => {
516 let i = state.control_stack.len() - 1 - (*relative_depth as usize);
517 let (return_count, br_destination) = {
518 let frame = &mut state.control_stack[i];
519 frame.set_branched_to_exit();
521 let return_count = if frame.is_loop() {
522 frame.num_param_values()
523 } else {
524 frame.num_return_values()
525 };
526 (return_count, frame.br_destination())
527 };
528 let destination_args = state.peekn(return_count);
529 canonicalise_then_jump(builder, br_destination, destination_args);
530 state.popn(return_count);
531 state.reachable = false;
532 }
533 Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, state),
534 Operator::BrTable { targets } => {
535 let default = targets.default();
536 let mut min_depth = default;
537 for depth in targets.targets() {
538 let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
539 if depth < min_depth {
540 min_depth = depth;
541 }
542 }
543 let jump_args_count = {
544 let i = state.control_stack.len() - 1 - (min_depth as usize);
545 let min_depth_frame = &state.control_stack[i];
546 if min_depth_frame.is_loop() {
547 min_depth_frame.num_param_values()
548 } else {
549 min_depth_frame.num_return_values()
550 }
551 };
552 let val = state.pop1();
553 let mut data = Vec::with_capacity(targets.len() as usize);
554 if jump_args_count == 0 {
555 for depth in targets.targets() {
557 let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
558 let block = {
559 let i = state.control_stack.len() - 1 - (depth as usize);
560 let frame = &mut state.control_stack[i];
561 frame.set_branched_to_exit();
562 frame.br_destination()
563 };
564 data.push(builder.func.dfg.block_call(block, &[]));
565 }
566 let block = {
567 let i = state.control_stack.len() - 1 - (default as usize);
568 let frame = &mut state.control_stack[i];
569 frame.set_branched_to_exit();
570 frame.br_destination()
571 };
572 let block = builder.func.dfg.block_call(block, &[]);
573 let jt = builder.create_jump_table(JumpTableData::new(block, &data));
574 builder.ins().br_table(val, jt);
575 } else {
576 let return_count = jump_args_count;
579 let mut dest_block_sequence = vec![];
580 let mut dest_block_map = HashMap::new();
581 for depth in targets.targets() {
582 let depth = depth.map_err(from_binaryreadererror_wasmerror)?;
583 let branch_block = match dest_block_map.entry(depth as usize) {
584 hash_map::Entry::Occupied(entry) => *entry.get(),
585 hash_map::Entry::Vacant(entry) => {
586 let block = builder.create_block();
587 dest_block_sequence.push((depth as usize, block));
588 *entry.insert(block)
589 }
590 };
591 data.push(builder.func.dfg.block_call(branch_block, &[]));
592 }
593 let default_branch_block = match dest_block_map.entry(default as usize) {
594 hash_map::Entry::Occupied(entry) => *entry.get(),
595 hash_map::Entry::Vacant(entry) => {
596 let block = builder.create_block();
597 dest_block_sequence.push((default as usize, block));
598 *entry.insert(block)
599 }
600 };
601 let default_branch_block = builder.func.dfg.block_call(default_branch_block, &[]);
602 let jt = builder.create_jump_table(JumpTableData::new(default_branch_block, &data));
603 builder.ins().br_table(val, jt);
604 for (depth, dest_block) in dest_block_sequence {
605 builder.switch_to_block(dest_block);
606 builder.seal_block(dest_block);
607 let real_dest_block = {
608 let i = state.control_stack.len() - 1 - depth;
609 let frame = &mut state.control_stack[i];
610 frame.set_branched_to_exit();
611 frame.br_destination()
612 };
613 let destination_args = state.peekn_mut(return_count);
614 canonicalise_then_jump(builder, real_dest_block, destination_args);
615 }
616 state.popn(return_count);
617 }
618 state.reachable = false;
619 }
620 Operator::Return => {
621 let return_count = {
622 let frame = &mut state.control_stack[0];
623 frame.num_return_values()
624 };
625 {
626 let return_args = state.peekn(return_count).to_vec();
627 environ.emit_wasm_return(builder, &return_args);
628 }
629 state.popn(return_count);
630 state.reachable = false;
631 }
632
633 Operator::Try { .. }
635 | Operator::Catch { .. }
636 | Operator::Rethrow { .. }
637 | Operator::Delegate { .. }
638 | Operator::CatchAll => {
639 return Err(wasm_unsupported!(
640 "proposed exception handling operator {:?}",
641 op
642 ));
643 }
644 Operator::TryTable { try_table } => {
645 let body = builder.create_block();
646 let (params, results) =
647 module_translation_state.blocktype_params_results(&try_table.ty)?;
648 let next = block_with_params(builder, results.iter(), environ)?;
649 builder.ins().jump(body, &[]);
650 builder.seal_block(body);
651
652 let checkpoint = state.handlers.take_checkpoint();
653 let mut clauses = Vec::with_capacity(try_table.catches.len());
654 let outer_clauses = state.handlers.unique_clauses().into_iter().collect_vec();
655 let mut catch_blocks = Vec::with_capacity(try_table.catches.len() + 1);
656
657 let catches = try_table
658 .catches
659 .iter()
660 .unique_by(|v| match v {
661 Catch::One { tag, .. } | Catch::OneRef { tag, .. } => *tag as i32,
662 Catch::All { .. } | Catch::AllRef { .. } => CATCH_ALL_TAG_VALUE,
663 })
664 .collect_vec();
665
666 for catch in catches.iter().rev() {
667 let clause = create_catch_block(builder, state, catch, environ)?;
668 catch_blocks.push(clause.block);
669 state.handlers.add_clause(clause.clone());
670 clauses.push(clause);
671 }
672
673 let outer_clauses = outer_clauses
674 .into_iter()
675 .filter(|clause| clauses.iter().all(|c| c.tag_value != clause.tag_value))
676 .collect_vec();
677
678 if !clauses.is_empty() {
679 let dispatch_block = create_dispatch_block(
680 builder,
681 environ,
682 clauses.iter().chain(outer_clauses.iter()).cloned(),
683 )?;
684 catch_blocks.push(dispatch_block);
685 state.handlers.add_handler(dispatch_block);
686 }
687
688 state.push_try_table_block(next, catch_blocks, params.len(), results.len(), checkpoint);
689
690 builder.switch_to_block(body);
691 }
692 Operator::Throw { tag_index } => {
693 let tag_index = TagIndex::from_u32(*tag_index);
694 let arity = environ.tag_param_arity(tag_index);
695 let args = state.peekn(arity);
696 environ.translate_exn_throw(builder, tag_index, args, state.handlers.landing_pad())?;
697 state.popn(arity);
698 state.reachable = false;
699 }
700 Operator::ThrowRef => {
701 let exnref = state.pop1();
702 environ.translate_exn_throw_ref(builder, exnref, state.handlers.landing_pad())?;
703 state.reachable = false;
704 }
705 Operator::Call { function_index } => {
711 let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
712
713 {
715 let args_mut = state.peekn_mut(num_args);
716 bitcast_wasm_params(
717 environ,
718 builder.func.dfg.ext_funcs[fref].signature,
719 args_mut,
720 builder,
721 );
722 }
723 let args = state.peekn(num_args);
724 let results = environ.translate_call(
725 builder,
726 FunctionIndex::from_u32(*function_index),
727 fref,
728 args,
729 state.handlers.landing_pad(),
730 )?;
731 state.popn(num_args);
732 state.pushn(results.as_slice());
733 }
734 Operator::CallIndirect {
735 type_index,
736 table_index,
737 ..
738 } => {
739 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
743 let callee = state.pop1();
744
745 {
747 let args_mut = state.peekn_mut(num_args);
748 bitcast_wasm_params(environ, sigref, args_mut, builder);
749 }
750 let args = state.peekn(num_args);
751 let results = environ.translate_call_indirect(
752 builder,
753 TableIndex::from_u32(*table_index),
754 SignatureIndex::from_u32(*type_index),
755 sigref,
756 callee,
757 args,
758 state.handlers.landing_pad(),
759 )?;
760 state.popn(num_args);
761 state.pushn(results.as_slice());
762 }
763 Operator::MemoryGrow { mem } => {
768 let heap_index = MemoryIndex::from_u32(*mem);
769 let heap = state.get_heap(builder.func, *mem, environ)?;
770 let val = state.pop1();
771 state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
772 }
773 Operator::MemorySize { mem } => {
774 let heap_index = MemoryIndex::from_u32(*mem);
775 let heap = state.get_heap(builder.func, *mem, environ)?;
776 state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
777 }
778 Operator::I32Load8U { memarg } => {
783 unwrap_or_return_unreachable_state!(
784 state,
785 translate_load(
786 memarg,
787 ir::Opcode::Uload8,
788 I32,
789 builder,
790 state,
791 environ,
792 allow_unaligned_memory_accesses,
793 )?
794 );
795 }
796 Operator::I32Load16U { memarg } => {
797 unwrap_or_return_unreachable_state!(
798 state,
799 translate_load(
800 memarg,
801 ir::Opcode::Uload16,
802 I32,
803 builder,
804 state,
805 environ,
806 allow_unaligned_memory_accesses,
807 )?
808 );
809 }
810 Operator::I32Load8S { memarg } => {
811 unwrap_or_return_unreachable_state!(
812 state,
813 translate_load(
814 memarg,
815 ir::Opcode::Sload8,
816 I32,
817 builder,
818 state,
819 environ,
820 allow_unaligned_memory_accesses,
821 )?
822 );
823 }
824 Operator::I32Load16S { memarg } => {
825 unwrap_or_return_unreachable_state!(
826 state,
827 translate_load(
828 memarg,
829 ir::Opcode::Sload16,
830 I32,
831 builder,
832 state,
833 environ,
834 allow_unaligned_memory_accesses,
835 )?
836 );
837 }
838 Operator::I64Load8U { memarg } => {
839 unwrap_or_return_unreachable_state!(
840 state,
841 translate_load(
842 memarg,
843 ir::Opcode::Uload8,
844 I64,
845 builder,
846 state,
847 environ,
848 allow_unaligned_memory_accesses,
849 )?
850 );
851 }
852 Operator::I64Load16U { memarg } => {
853 unwrap_or_return_unreachable_state!(
854 state,
855 translate_load(
856 memarg,
857 ir::Opcode::Uload16,
858 I64,
859 builder,
860 state,
861 environ,
862 allow_unaligned_memory_accesses,
863 )?
864 );
865 }
866 Operator::I64Load8S { memarg } => {
867 unwrap_or_return_unreachable_state!(
868 state,
869 translate_load(
870 memarg,
871 ir::Opcode::Sload8,
872 I64,
873 builder,
874 state,
875 environ,
876 allow_unaligned_memory_accesses,
877 )?
878 );
879 }
880 Operator::I64Load16S { memarg } => {
881 unwrap_or_return_unreachable_state!(
882 state,
883 translate_load(
884 memarg,
885 ir::Opcode::Sload16,
886 I64,
887 builder,
888 state,
889 environ,
890 allow_unaligned_memory_accesses,
891 )?
892 );
893 }
894 Operator::I64Load32S { memarg } => {
895 unwrap_or_return_unreachable_state!(
896 state,
897 translate_load(
898 memarg,
899 ir::Opcode::Sload32,
900 I64,
901 builder,
902 state,
903 environ,
904 allow_unaligned_memory_accesses,
905 )?
906 );
907 }
908 Operator::I64Load32U { memarg } => {
909 unwrap_or_return_unreachable_state!(
910 state,
911 translate_load(
912 memarg,
913 ir::Opcode::Uload32,
914 I64,
915 builder,
916 state,
917 environ,
918 allow_unaligned_memory_accesses,
919 )?
920 );
921 }
922 Operator::I32Load { memarg } => {
923 unwrap_or_return_unreachable_state!(
924 state,
925 translate_load(
926 memarg,
927 ir::Opcode::Load,
928 I32,
929 builder,
930 state,
931 environ,
932 allow_unaligned_memory_accesses,
933 )?
934 );
935 }
936 Operator::F32Load { memarg } => {
937 unwrap_or_return_unreachable_state!(
938 state,
939 translate_load(
940 memarg,
941 ir::Opcode::Load,
942 F32,
943 builder,
944 state,
945 environ,
946 allow_unaligned_memory_accesses,
947 )?
948 );
949 }
950 Operator::I64Load { memarg } => {
951 unwrap_or_return_unreachable_state!(
952 state,
953 translate_load(
954 memarg,
955 ir::Opcode::Load,
956 I64,
957 builder,
958 state,
959 environ,
960 allow_unaligned_memory_accesses,
961 )?
962 );
963 }
964 Operator::F64Load { memarg } => {
965 unwrap_or_return_unreachable_state!(
966 state,
967 translate_load(
968 memarg,
969 ir::Opcode::Load,
970 F64,
971 builder,
972 state,
973 environ,
974 allow_unaligned_memory_accesses,
975 )?
976 );
977 }
978 Operator::V128Load { memarg } => {
979 unwrap_or_return_unreachable_state!(
980 state,
981 translate_load(
982 memarg,
983 ir::Opcode::Load,
984 I8X16,
985 builder,
986 state,
987 environ,
988 allow_unaligned_memory_accesses,
989 )?
990 );
991 }
992 Operator::V128Load8x8S { memarg } => {
993 let (flags, _, base) = unwrap_or_return_unreachable_state!(
995 state,
996 prepare_addr(memarg, 8, builder, state, environ)?
997 );
998 let loaded = builder.ins().sload8x8(flags, base, 0);
999 state.push1(loaded);
1000 }
1001 Operator::V128Load8x8U { memarg } => {
1002 let (flags, _, base) = unwrap_or_return_unreachable_state!(
1003 state,
1004 prepare_addr(memarg, 8, builder, state, environ)?
1005 );
1006 let loaded = builder.ins().uload8x8(flags, base, 0);
1007 state.push1(loaded);
1008 }
1009 Operator::V128Load16x4S { memarg } => {
1010 let (flags, _, base) = unwrap_or_return_unreachable_state!(
1011 state,
1012 prepare_addr(memarg, 8, builder, state, environ)?
1013 );
1014 let loaded = builder.ins().sload16x4(flags, base, 0);
1015 state.push1(loaded);
1016 }
1017 Operator::V128Load16x4U { memarg } => {
1018 let (flags, _, base) = unwrap_or_return_unreachable_state!(
1019 state,
1020 prepare_addr(memarg, 8, builder, state, environ)?
1021 );
1022 let loaded = builder.ins().uload16x4(flags, base, 0);
1023 state.push1(loaded);
1024 }
1025 Operator::V128Load32x2S { memarg } => {
1026 let (flags, _, base) = unwrap_or_return_unreachable_state!(
1027 state,
1028 prepare_addr(memarg, 8, builder, state, environ)?
1029 );
1030 let loaded = builder.ins().sload32x2(flags, base, 0);
1031 state.push1(loaded);
1032 }
1033 Operator::V128Load32x2U { memarg } => {
1034 let (flags, _, base) = unwrap_or_return_unreachable_state!(
1035 state,
1036 prepare_addr(memarg, 8, builder, state, environ)?
1037 );
1038 let loaded = builder.ins().uload32x2(flags, base, 0);
1039 state.push1(loaded);
1040 }
1041 Operator::I32Store { memarg }
1046 | Operator::I64Store { memarg }
1047 | Operator::F32Store { memarg }
1048 | Operator::F64Store { memarg } => {
1049 translate_store(
1050 memarg,
1051 ir::Opcode::Store,
1052 builder,
1053 state,
1054 environ,
1055 allow_unaligned_memory_accesses,
1056 )?;
1057 }
1058 Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
1059 translate_store(
1060 memarg,
1061 ir::Opcode::Istore8,
1062 builder,
1063 state,
1064 environ,
1065 allow_unaligned_memory_accesses,
1066 )?;
1067 }
1068 Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
1069 translate_store(
1070 memarg,
1071 ir::Opcode::Istore16,
1072 builder,
1073 state,
1074 environ,
1075 allow_unaligned_memory_accesses,
1076 )?;
1077 }
1078 Operator::I64Store32 { memarg } => {
1079 translate_store(
1080 memarg,
1081 ir::Opcode::Istore32,
1082 builder,
1083 state,
1084 environ,
1085 allow_unaligned_memory_accesses,
1086 )?;
1087 }
1088 Operator::V128Store { memarg } => {
1089 translate_store(
1090 memarg,
1091 ir::Opcode::Store,
1092 builder,
1093 state,
1094 environ,
1095 allow_unaligned_memory_accesses,
1096 )?;
1097 }
1098 Operator::I32Const { value } => {
1100 state.push1(builder.ins().iconst(I32, *value as u32 as i64))
1101 }
1102 Operator::I64Const { value } => state.push1(builder.ins().iconst(I64, *value)),
1103 Operator::F32Const { value } => {
1104 state.push1(builder.ins().f32const(f32_translation(*value)));
1105 }
1106 Operator::F64Const { value } => {
1107 state.push1(builder.ins().f64const(f64_translation(*value)));
1108 }
1109 Operator::I32Clz | Operator::I64Clz => {
1111 let arg = state.pop1();
1112 state.push1(builder.ins().clz(arg));
1113 }
1114 Operator::I32Ctz | Operator::I64Ctz => {
1115 let arg = state.pop1();
1116 state.push1(builder.ins().ctz(arg));
1117 }
1118 Operator::I32Popcnt | Operator::I64Popcnt => {
1119 let arg = state.pop1();
1120 state.push1(builder.ins().popcnt(arg));
1121 }
1122 Operator::I64ExtendI32S => {
1123 let val = state.pop1();
1124 state.push1(builder.ins().sextend(I64, val));
1125 }
1126 Operator::I64ExtendI32U => {
1127 let val = state.pop1();
1128 state.push1(builder.ins().uextend(I64, val));
1129 }
1130 Operator::I32WrapI64 => {
1131 let val = state.pop1();
1132 state.push1(builder.ins().ireduce(I32, val));
1133 }
1134 Operator::F32Sqrt | Operator::F64Sqrt => {
1135 let arg = state.pop1();
1136 state.push1(builder.ins().sqrt(arg));
1137 }
1138 Operator::F32Ceil | Operator::F64Ceil => {
1139 let arg = state.pop1();
1140 state.push1(builder.ins().ceil(arg));
1141 }
1142 Operator::F32Floor | Operator::F64Floor => {
1143 let arg = state.pop1();
1144 state.push1(builder.ins().floor(arg));
1145 }
1146 Operator::F32Trunc | Operator::F64Trunc => {
1147 let arg = state.pop1();
1148 state.push1(builder.ins().trunc(arg));
1149 }
1150 Operator::F32Nearest | Operator::F64Nearest => {
1151 let arg = state.pop1();
1152 state.push1(builder.ins().nearest(arg));
1153 }
1154 Operator::F32Abs | Operator::F64Abs => {
1155 let val = state.pop1();
1156 state.push1(builder.ins().fabs(val));
1157 }
1158 Operator::F32Neg | Operator::F64Neg => {
1159 let arg = state.pop1();
1160 state.push1(builder.ins().fneg(arg));
1161 }
1162 Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
1163 let val = state.pop1();
1164 state.push1(builder.ins().fcvt_from_uint(F64, val));
1165 }
1166 Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
1167 let val = state.pop1();
1168 state.push1(builder.ins().fcvt_from_sint(F64, val));
1169 }
1170 Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
1171 let val = state.pop1();
1172 state.push1(builder.ins().fcvt_from_sint(F32, val));
1173 }
1174 Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
1175 let val = state.pop1();
1176 state.push1(builder.ins().fcvt_from_uint(F32, val));
1177 }
1178 Operator::F64PromoteF32 => {
1179 let val = state.pop1();
1180 state.push1(builder.ins().fpromote(F64, val));
1181 }
1182 Operator::F32DemoteF64 => {
1183 let val = state.pop1();
1184 state.push1(builder.ins().fdemote(F32, val));
1185 }
1186 Operator::I64TruncF64S | Operator::I64TruncF32S => {
1187 let val = state.pop1();
1188 state.push1(builder.ins().fcvt_to_sint(I64, val));
1189 }
1190 Operator::I32TruncF64S | Operator::I32TruncF32S => {
1191 let val = state.pop1();
1192 state.push1(builder.ins().fcvt_to_sint(I32, val));
1193 }
1194 Operator::I64TruncF64U | Operator::I64TruncF32U => {
1195 let val = state.pop1();
1196 state.push1(builder.ins().fcvt_to_uint(I64, val));
1197 }
1198 Operator::I32TruncF64U | Operator::I32TruncF32U => {
1199 let val = state.pop1();
1200 state.push1(builder.ins().fcvt_to_uint(I32, val));
1201 }
1202 Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
1203 let val = state.pop1();
1204 state.push1(builder.ins().fcvt_to_sint_sat(I64, val));
1205 }
1206 Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
1207 let val = state.pop1();
1208 state.push1(builder.ins().fcvt_to_sint_sat(I32, val));
1209 }
1210 Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
1211 let val = state.pop1();
1212 state.push1(builder.ins().fcvt_to_uint_sat(I64, val));
1213 }
1214 Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
1215 let val = state.pop1();
1216 state.push1(builder.ins().fcvt_to_uint_sat(I32, val));
1217 }
1218 Operator::F32ReinterpretI32 => {
1219 let val = state.pop1();
1220 state.push1(builder.ins().bitcast(F32, MemFlagsData::new(), val));
1221 }
1222 Operator::F64ReinterpretI64 => {
1223 let val = state.pop1();
1224 state.push1(builder.ins().bitcast(F64, MemFlagsData::new(), val));
1225 }
1226 Operator::I32ReinterpretF32 => {
1227 let val = state.pop1();
1228 state.push1(builder.ins().bitcast(I32, MemFlagsData::new(), val));
1229 }
1230 Operator::I64ReinterpretF64 => {
1231 let val = state.pop1();
1232 state.push1(builder.ins().bitcast(I64, MemFlagsData::new(), val));
1233 }
1234 Operator::I32Extend8S => {
1235 let val = state.pop1();
1236 state.push1(builder.ins().ireduce(I8, val));
1237 let val = state.pop1();
1238 state.push1(builder.ins().sextend(I32, val));
1239 }
1240 Operator::I32Extend16S => {
1241 let val = state.pop1();
1242 state.push1(builder.ins().ireduce(I16, val));
1243 let val = state.pop1();
1244 state.push1(builder.ins().sextend(I32, val));
1245 }
1246 Operator::I64Extend8S => {
1247 let val = state.pop1();
1248 state.push1(builder.ins().ireduce(I8, val));
1249 let val = state.pop1();
1250 state.push1(builder.ins().sextend(I64, val));
1251 }
1252 Operator::I64Extend16S => {
1253 let val = state.pop1();
1254 state.push1(builder.ins().ireduce(I16, val));
1255 let val = state.pop1();
1256 state.push1(builder.ins().sextend(I64, val));
1257 }
1258 Operator::I64Extend32S => {
1259 let val = state.pop1();
1260 state.push1(builder.ins().ireduce(I32, val));
1261 let val = state.pop1();
1262 state.push1(builder.ins().sextend(I64, val));
1263 }
1264 Operator::I32Add | Operator::I64Add => {
1266 let (arg1, arg2) = state.pop2();
1267 state.push1(builder.ins().iadd(arg1, arg2));
1268 }
1269 Operator::I32And | Operator::I64And => {
1270 let (arg1, arg2) = state.pop2();
1271 state.push1(builder.ins().band(arg1, arg2));
1272 }
1273 Operator::I32Or | Operator::I64Or => {
1274 let (arg1, arg2) = state.pop2();
1275 state.push1(builder.ins().bor(arg1, arg2));
1276 }
1277 Operator::I32Xor | Operator::I64Xor => {
1278 let (arg1, arg2) = state.pop2();
1279 state.push1(builder.ins().bxor(arg1, arg2));
1280 }
1281 Operator::I32Shl | Operator::I64Shl => {
1282 let (arg1, arg2) = state.pop2();
1283 state.push1(builder.ins().ishl(arg1, arg2));
1284 }
1285 Operator::I32ShrS | Operator::I64ShrS => {
1286 let (arg1, arg2) = state.pop2();
1287 state.push1(builder.ins().sshr(arg1, arg2));
1288 }
1289 Operator::I32ShrU | Operator::I64ShrU => {
1290 let (arg1, arg2) = state.pop2();
1291 state.push1(builder.ins().ushr(arg1, arg2));
1292 }
1293 Operator::I32Rotl | Operator::I64Rotl => {
1294 let (arg1, arg2) = state.pop2();
1295 state.push1(builder.ins().rotl(arg1, arg2));
1296 }
1297 Operator::I32Rotr | Operator::I64Rotr => {
1298 let (arg1, arg2) = state.pop2();
1299 state.push1(builder.ins().rotr(arg1, arg2));
1300 }
1301 Operator::F32Add | Operator::F64Add => {
1302 let (arg1, arg2) = state.pop2();
1303 state.push1(builder.ins().fadd(arg1, arg2));
1304 }
1305 Operator::I32Sub | Operator::I64Sub => {
1306 let (arg1, arg2) = state.pop2();
1307 state.push1(builder.ins().isub(arg1, arg2));
1308 }
1309 Operator::F32Sub | Operator::F64Sub => {
1310 let (arg1, arg2) = state.pop2();
1311 state.push1(builder.ins().fsub(arg1, arg2));
1312 }
1313 Operator::I32Mul | Operator::I64Mul => {
1314 let (arg1, arg2) = state.pop2();
1315 state.push1(builder.ins().imul(arg1, arg2));
1316 }
1317 Operator::F32Mul | Operator::F64Mul => {
1318 let (arg1, arg2) = state.pop2();
1319 state.push1(builder.ins().fmul(arg1, arg2));
1320 }
1321 Operator::F32Div | Operator::F64Div => {
1322 let (arg1, arg2) = state.pop2();
1323 state.push1(builder.ins().fdiv(arg1, arg2));
1324 }
1325 Operator::I32DivS | Operator::I64DivS => {
1326 let (arg1, arg2) = state.pop2();
1327 state.push1(builder.ins().sdiv(arg1, arg2));
1328 }
1329 Operator::I32DivU | Operator::I64DivU => {
1330 let (arg1, arg2) = state.pop2();
1331 state.push1(builder.ins().udiv(arg1, arg2));
1332 }
1333 Operator::I32RemS | Operator::I64RemS => {
1334 let (arg1, arg2) = state.pop2();
1335 state.push1(builder.ins().srem(arg1, arg2));
1336 }
1337 Operator::I32RemU | Operator::I64RemU => {
1338 let (arg1, arg2) = state.pop2();
1339 state.push1(builder.ins().urem(arg1, arg2));
1340 }
1341 Operator::F32Min | Operator::F64Min => {
1342 let (arg1, arg2) = state.pop2();
1343 state.push1(builder.ins().fmin(arg1, arg2));
1344 }
1345 Operator::F32Max | Operator::F64Max => {
1346 let (arg1, arg2) = state.pop2();
1347 state.push1(builder.ins().fmax(arg1, arg2));
1348 }
1349 Operator::F32Copysign | Operator::F64Copysign => {
1350 let (arg1, arg2) = state.pop2();
1351 state.push1(builder.ins().fcopysign(arg1, arg2));
1352 }
1353 Operator::I32LtS | Operator::I64LtS => {
1355 translate_icmp(IntCC::SignedLessThan, builder, state)
1356 }
1357 Operator::I32LtU | Operator::I64LtU => {
1358 translate_icmp(IntCC::UnsignedLessThan, builder, state)
1359 }
1360 Operator::I32LeS | Operator::I64LeS => {
1361 translate_icmp(IntCC::SignedLessThanOrEqual, builder, state)
1362 }
1363 Operator::I32LeU | Operator::I64LeU => {
1364 translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, state)
1365 }
1366 Operator::I32GtS | Operator::I64GtS => {
1367 translate_icmp(IntCC::SignedGreaterThan, builder, state)
1368 }
1369 Operator::I32GtU | Operator::I64GtU => {
1370 translate_icmp(IntCC::UnsignedGreaterThan, builder, state)
1371 }
1372 Operator::I32GeS | Operator::I64GeS => {
1373 translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, state)
1374 }
1375 Operator::I32GeU | Operator::I64GeU => {
1376 translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, state)
1377 }
1378 Operator::I32Eqz | Operator::I64Eqz => {
1379 let arg = state.pop1();
1380 let val = builder.ins().icmp_imm_u(IntCC::Equal, arg, 0);
1381 state.push1(builder.ins().uextend(I32, val));
1382 }
1383 Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, state),
1384 Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, state),
1385 Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, state),
1386 Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, state),
1387 Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, state),
1388 Operator::F32Ge | Operator::F64Ge => {
1389 translate_fcmp(FloatCC::GreaterThanOrEqual, builder, state)
1390 }
1391 Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, state),
1392 Operator::F32Le | Operator::F64Le => {
1393 translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
1394 }
1395 Operator::RefNull { hty } => {
1396 state.push1(environ.translate_ref_null(builder.cursor(), *hty)?)
1397 }
1398 Operator::RefIsNull => {
1399 let value = state.pop1();
1400 state.push1(environ.translate_ref_is_null(builder.cursor(), value)?);
1401 }
1402 Operator::RefFunc { function_index } => {
1403 let index = FunctionIndex::from_u32(*function_index);
1404 state.push1(environ.translate_ref_func(builder.cursor(), index)?);
1405 }
1406 Operator::MemoryAtomicWait32 { memarg } | Operator::MemoryAtomicWait64 { memarg } => {
1407 let implied_ty = match op {
1408 Operator::MemoryAtomicWait64 { .. } => I64,
1409 Operator::MemoryAtomicWait32 { .. } => I32,
1410 _ => unreachable!(),
1411 };
1412 let heap_index = MemoryIndex::from_u32(memarg.memory);
1413 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1414 let timeout = state.pop1(); let expected = state.pop1(); let addr = state.pop1(); let addr = fold_atomic_mem_addr(addr, memarg, builder);
1418 assert!(builder.func.dfg.value_type(expected) == implied_ty);
1419 match environ.translate_atomic_wait(
1422 builder.cursor(),
1423 heap_index,
1424 heap,
1425 addr,
1426 expected,
1427 timeout,
1428 ) {
1429 Ok(res) => {
1430 state.push1(res);
1431 }
1432 Err(wasmer_types::WasmError::Unsupported(_err)) => {
1433 builder.ins().trap(crate::TRAP_UNREACHABLE);
1435 state.reachable = false;
1436 }
1437 Err(err) => {
1438 return Err(err);
1439 }
1440 };
1441 }
1442 Operator::MemoryAtomicNotify { memarg } => {
1443 let heap_index = MemoryIndex::from_u32(memarg.memory);
1444 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1445 let count = state.pop1(); let addr = state.pop1(); let addr = fold_atomic_mem_addr(addr, memarg, builder);
1448 match environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count) {
1449 Ok(res) => {
1450 state.push1(res);
1451 }
1452 Err(wasmer_types::WasmError::Unsupported(_err)) => {
1453 state.push1(builder.ins().iconst(I32, i64::from(0)));
1457 }
1458 Err(err) => {
1459 return Err(err);
1460 }
1461 };
1462 }
1463 Operator::I32AtomicLoad { memarg } => {
1464 translate_atomic_load(I32, I32, memarg, builder, state, environ)?
1465 }
1466 Operator::I64AtomicLoad { memarg } => {
1467 translate_atomic_load(I64, I64, memarg, builder, state, environ)?
1468 }
1469 Operator::I32AtomicLoad8U { memarg } => {
1470 translate_atomic_load(I32, I8, memarg, builder, state, environ)?
1471 }
1472 Operator::I32AtomicLoad16U { memarg } => {
1473 translate_atomic_load(I32, I16, memarg, builder, state, environ)?
1474 }
1475 Operator::I64AtomicLoad8U { memarg } => {
1476 translate_atomic_load(I64, I8, memarg, builder, state, environ)?
1477 }
1478 Operator::I64AtomicLoad16U { memarg } => {
1479 translate_atomic_load(I64, I16, memarg, builder, state, environ)?
1480 }
1481 Operator::I64AtomicLoad32U { memarg } => {
1482 translate_atomic_load(I64, I32, memarg, builder, state, environ)?
1483 }
1484
1485 Operator::I32AtomicStore { memarg } => {
1486 translate_atomic_store(I32, memarg, builder, state, environ)?
1487 }
1488 Operator::I64AtomicStore { memarg } => {
1489 translate_atomic_store(I64, memarg, builder, state, environ)?
1490 }
1491 Operator::I32AtomicStore8 { memarg } => {
1492 translate_atomic_store(I8, memarg, builder, state, environ)?
1493 }
1494 Operator::I32AtomicStore16 { memarg } => {
1495 translate_atomic_store(I16, memarg, builder, state, environ)?
1496 }
1497 Operator::I64AtomicStore8 { memarg } => {
1498 translate_atomic_store(I8, memarg, builder, state, environ)?
1499 }
1500 Operator::I64AtomicStore16 { memarg } => {
1501 translate_atomic_store(I16, memarg, builder, state, environ)?
1502 }
1503 Operator::I64AtomicStore32 { memarg } => {
1504 translate_atomic_store(I32, memarg, builder, state, environ)?
1505 }
1506
1507 Operator::I32AtomicRmwAdd { memarg } => {
1508 translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1509 }
1510 Operator::I64AtomicRmwAdd { memarg } => {
1511 translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, state, environ)?
1512 }
1513 Operator::I32AtomicRmw8AddU { memarg } => {
1514 translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1515 }
1516 Operator::I32AtomicRmw16AddU { memarg } => {
1517 translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1518 }
1519 Operator::I64AtomicRmw8AddU { memarg } => {
1520 translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1521 }
1522 Operator::I64AtomicRmw16AddU { memarg } => {
1523 translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1524 }
1525 Operator::I64AtomicRmw32AddU { memarg } => {
1526 translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1527 }
1528
1529 Operator::I32AtomicRmwSub { memarg } => {
1530 translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1531 }
1532 Operator::I64AtomicRmwSub { memarg } => {
1533 translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1534 }
1535 Operator::I32AtomicRmw8SubU { memarg } => {
1536 translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1537 }
1538 Operator::I32AtomicRmw16SubU { memarg } => {
1539 translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1540 }
1541 Operator::I64AtomicRmw8SubU { memarg } => {
1542 translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1543 }
1544 Operator::I64AtomicRmw16SubU { memarg } => {
1545 translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1546 }
1547 Operator::I64AtomicRmw32SubU { memarg } => {
1548 translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1549 }
1550
1551 Operator::I32AtomicRmwAnd { memarg } => {
1552 translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1553 }
1554 Operator::I64AtomicRmwAnd { memarg } => {
1555 translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, state, environ)?
1556 }
1557 Operator::I32AtomicRmw8AndU { memarg } => {
1558 translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1559 }
1560 Operator::I32AtomicRmw16AndU { memarg } => {
1561 translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1562 }
1563 Operator::I64AtomicRmw8AndU { memarg } => {
1564 translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1565 }
1566 Operator::I64AtomicRmw16AndU { memarg } => {
1567 translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1568 }
1569 Operator::I64AtomicRmw32AndU { memarg } => {
1570 translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1571 }
1572
1573 Operator::I32AtomicRmwOr { memarg } => {
1574 translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1575 }
1576 Operator::I64AtomicRmwOr { memarg } => {
1577 translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, state, environ)?
1578 }
1579 Operator::I32AtomicRmw8OrU { memarg } => {
1580 translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1581 }
1582 Operator::I32AtomicRmw16OrU { memarg } => {
1583 translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1584 }
1585 Operator::I64AtomicRmw8OrU { memarg } => {
1586 translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1587 }
1588 Operator::I64AtomicRmw16OrU { memarg } => {
1589 translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1590 }
1591 Operator::I64AtomicRmw32OrU { memarg } => {
1592 translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1593 }
1594
1595 Operator::I32AtomicRmwXor { memarg } => {
1596 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1597 }
1598 Operator::I64AtomicRmwXor { memarg } => {
1599 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1600 }
1601 Operator::I32AtomicRmw8XorU { memarg } => {
1602 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1603 }
1604 Operator::I32AtomicRmw16XorU { memarg } => {
1605 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1606 }
1607 Operator::I64AtomicRmw8XorU { memarg } => {
1608 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1609 }
1610 Operator::I64AtomicRmw16XorU { memarg } => {
1611 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1612 }
1613 Operator::I64AtomicRmw32XorU { memarg } => {
1614 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1615 }
1616
1617 Operator::I32AtomicRmwXchg { memarg } => {
1618 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1619 }
1620 Operator::I64AtomicRmwXchg { memarg } => {
1621 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1622 }
1623 Operator::I32AtomicRmw8XchgU { memarg } => {
1624 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1625 }
1626 Operator::I32AtomicRmw16XchgU { memarg } => {
1627 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1628 }
1629 Operator::I64AtomicRmw8XchgU { memarg } => {
1630 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1631 }
1632 Operator::I64AtomicRmw16XchgU { memarg } => {
1633 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1634 }
1635 Operator::I64AtomicRmw32XchgU { memarg } => {
1636 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1637 }
1638
1639 Operator::I32AtomicRmwCmpxchg { memarg } => {
1640 translate_atomic_cas(I32, I32, memarg, builder, state, environ)?
1641 }
1642 Operator::I64AtomicRmwCmpxchg { memarg } => {
1643 translate_atomic_cas(I64, I64, memarg, builder, state, environ)?
1644 }
1645 Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1646 translate_atomic_cas(I32, I8, memarg, builder, state, environ)?
1647 }
1648 Operator::I32AtomicRmw16CmpxchgU { memarg } => {
1649 translate_atomic_cas(I32, I16, memarg, builder, state, environ)?
1650 }
1651 Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1652 translate_atomic_cas(I64, I8, memarg, builder, state, environ)?
1653 }
1654 Operator::I64AtomicRmw16CmpxchgU { memarg } => {
1655 translate_atomic_cas(I64, I16, memarg, builder, state, environ)?
1656 }
1657 Operator::I64AtomicRmw32CmpxchgU { memarg } => {
1658 translate_atomic_cas(I64, I32, memarg, builder, state, environ)?
1659 }
1660
1661 Operator::AtomicFence { .. } => {
1662 builder.ins().fence();
1663 }
1664 Operator::MemoryCopy { dst_mem, src_mem } => {
1665 let src_index = MemoryIndex::from_u32(*src_mem);
1666 let dst_index = MemoryIndex::from_u32(*dst_mem);
1667 let src_heap = state.get_heap(builder.func, *src_mem, environ)?;
1668 let dst_heap = state.get_heap(builder.func, *dst_mem, environ)?;
1669 let len = state.pop1();
1670 let src_pos = state.pop1();
1671 let dst_pos = state.pop1();
1672 environ.translate_memory_copy(
1673 builder.cursor(),
1674 src_index,
1675 src_heap,
1676 dst_index,
1677 dst_heap,
1678 dst_pos,
1679 src_pos,
1680 len,
1681 )?;
1682 }
1683 Operator::MemoryFill { mem } => {
1684 let heap_index = MemoryIndex::from_u32(*mem);
1685 let heap = state.get_heap(builder.func, *mem, environ)?;
1686 let len = state.pop1();
1687 let val = state.pop1();
1688 let dest = state.pop1();
1689 environ.translate_memory_fill(builder.cursor(), heap_index, heap, dest, val, len)?;
1690 }
1691 Operator::MemoryInit { data_index, mem } => {
1692 let heap_index = MemoryIndex::from_u32(*mem);
1693 let heap = state.get_heap(builder.func, *mem, environ)?;
1694 let len = state.pop1();
1695 let src = state.pop1();
1696 let dest = state.pop1();
1697 environ.translate_memory_init(
1698 builder.cursor(),
1699 heap_index,
1700 heap,
1701 *data_index,
1702 dest,
1703 src,
1704 len,
1705 )?;
1706 }
1707 Operator::DataDrop { data_index } => {
1708 environ.translate_data_drop(builder.cursor(), *data_index)?;
1709 }
1710 Operator::TableSize { table: index } => {
1711 state.push1(
1712 environ.translate_table_size(builder.cursor(), TableIndex::from_u32(*index))?,
1713 );
1714 }
1715 Operator::TableGrow { table: index } => {
1716 let table_index = TableIndex::from_u32(*index);
1717 let delta = state.pop1();
1718 let init_value = state.pop1();
1719 state.push1(environ.translate_table_grow(
1720 builder.cursor(),
1721 table_index,
1722 delta,
1723 init_value,
1724 )?);
1725 }
1726 Operator::TableGet { table: index } => {
1727 let table_index = TableIndex::from_u32(*index);
1728 let index = state.pop1();
1729 state.push1(environ.translate_table_get(builder, table_index, index)?);
1730 }
1731 Operator::TableSet { table: index } => {
1732 let table_index = TableIndex::from_u32(*index);
1733 let value = state.pop1();
1734 let index = state.pop1();
1735 environ.translate_table_set(builder, table_index, value, index)?;
1736 }
1737 Operator::TableCopy {
1738 dst_table: dst_table_index,
1739 src_table: src_table_index,
1740 } => {
1741 let len = state.pop1();
1742 let src = state.pop1();
1743 let dest = state.pop1();
1744 environ.translate_table_copy(
1745 builder.cursor(),
1746 TableIndex::from_u32(*dst_table_index),
1747 TableIndex::from_u32(*src_table_index),
1748 dest,
1749 src,
1750 len,
1751 )?;
1752 }
1753 Operator::TableFill { table } => {
1754 let table_index = TableIndex::from_u32(*table);
1755 let len = state.pop1();
1756 let val = state.pop1();
1757 let dest = state.pop1();
1758 environ.translate_table_fill(builder.cursor(), table_index, dest, val, len)?;
1759 }
1760 Operator::TableInit {
1761 elem_index,
1762 table: table_index,
1763 } => {
1764 let len = state.pop1();
1765 let src = state.pop1();
1766 let dest = state.pop1();
1767 environ.translate_table_init(
1768 builder.cursor(),
1769 *elem_index,
1770 TableIndex::from_u32(*table_index),
1771 dest,
1772 src,
1773 len,
1774 )?;
1775 }
1776 Operator::ElemDrop { elem_index } => {
1777 environ.translate_elem_drop(builder.cursor(), *elem_index)?;
1778 }
1779 Operator::V128Const { value } => {
1780 let data = value.bytes().to_vec().into();
1781 let handle = builder.func.dfg.constants.insert(data);
1782 let value = builder.ins().vconst(I8X16, handle);
1783 state.push1(value)
1786 }
1787 Operator::I8x16Splat | Operator::I16x8Splat => {
1788 let reduced = builder.ins().ireduce(type_of(op).lane_type(), state.pop1());
1789 let splatted = builder.ins().splat(type_of(op), reduced);
1790 state.push1(splatted)
1791 }
1792 Operator::I32x4Splat
1793 | Operator::I64x2Splat
1794 | Operator::F32x4Splat
1795 | Operator::F64x2Splat => {
1796 let splatted = builder.ins().splat(type_of(op), state.pop1());
1797 state.push1(splatted)
1798 }
1799 Operator::V128Load8Splat { memarg }
1800 | Operator::V128Load16Splat { memarg }
1801 | Operator::V128Load32Splat { memarg }
1802 | Operator::V128Load64Splat { memarg } => {
1803 unwrap_or_return_unreachable_state!(
1804 state,
1805 translate_load(
1806 memarg,
1807 ir::Opcode::Load,
1808 type_of(op).lane_type(),
1809 builder,
1810 state,
1811 environ,
1812 allow_unaligned_memory_accesses,
1813 )?
1814 );
1815 let splatted = builder.ins().splat(type_of(op), state.pop1());
1816 state.push1(splatted)
1817 }
1818 Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
1819 unwrap_or_return_unreachable_state!(
1820 state,
1821 translate_load(
1822 memarg,
1823 ir::Opcode::Load,
1824 type_of(op).lane_type(),
1825 builder,
1826 state,
1827 environ,
1828 allow_unaligned_memory_accesses,
1829 )?
1830 );
1831 let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
1832 state.push1(as_vector)
1833 }
1834 Operator::V128Load8Lane { memarg, lane }
1835 | Operator::V128Load16Lane { memarg, lane }
1836 | Operator::V128Load32Lane { memarg, lane }
1837 | Operator::V128Load64Lane { memarg, lane } => {
1838 let vector = pop1_with_bitcast(state, type_of(op), builder);
1839 unwrap_or_return_unreachable_state!(
1840 state,
1841 translate_load(
1842 memarg,
1843 ir::Opcode::Load,
1844 type_of(op).lane_type(),
1845 builder,
1846 state,
1847 environ,
1848 allow_unaligned_memory_accesses,
1849 )?
1850 );
1851 let replacement = state.pop1();
1852 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1853 }
1854 Operator::V128Store8Lane { memarg, lane }
1855 | Operator::V128Store16Lane { memarg, lane }
1856 | Operator::V128Store32Lane { memarg, lane }
1857 | Operator::V128Store64Lane { memarg, lane } => {
1858 let vector = pop1_with_bitcast(state, type_of(op), builder);
1859 state.push1(builder.ins().extractlane(vector, *lane));
1860 translate_store(
1861 memarg,
1862 ir::Opcode::Store,
1863 builder,
1864 state,
1865 environ,
1866 allow_unaligned_memory_accesses,
1867 )?;
1868 }
1869 Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => {
1870 let vector = pop1_with_bitcast(state, type_of(op), builder);
1871 let extracted = builder.ins().extractlane(vector, *lane);
1872 state.push1(builder.ins().sextend(I32, extracted))
1873 }
1874 Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
1875 let vector = pop1_with_bitcast(state, type_of(op), builder);
1876 let extracted = builder.ins().extractlane(vector, *lane);
1877 state.push1(builder.ins().uextend(I32, extracted));
1878 }
1882 Operator::I32x4ExtractLane { lane }
1883 | Operator::I64x2ExtractLane { lane }
1884 | Operator::F32x4ExtractLane { lane }
1885 | Operator::F64x2ExtractLane { lane } => {
1886 let vector = pop1_with_bitcast(state, type_of(op), builder);
1887 state.push1(builder.ins().extractlane(vector, *lane))
1888 }
1889 Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => {
1890 let (vector, replacement) = state.pop2();
1891 let ty = type_of(op);
1892 let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
1893 let vector = optionally_bitcast_vector(vector, ty, builder);
1894 state.push1(builder.ins().insertlane(vector, reduced, *lane))
1895 }
1896 Operator::I32x4ReplaceLane { lane }
1897 | Operator::I64x2ReplaceLane { lane }
1898 | Operator::F32x4ReplaceLane { lane }
1899 | Operator::F64x2ReplaceLane { lane } => {
1900 let (vector, replacement) = state.pop2();
1901 let vector = optionally_bitcast_vector(vector, type_of(op), builder);
1902 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1903 }
1904 Operator::I8x16Shuffle { lanes, .. } => {
1905 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1906 let lanes = ConstantData::from(lanes.as_ref());
1907 let mask = builder.func.dfg.immediates.push(lanes);
1908 let shuffled = builder.ins().shuffle(a, b, mask);
1909 state.push1(shuffled)
1910 }
1915 Operator::I8x16Swizzle => {
1916 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1917 state.push1(builder.ins().swizzle(a, b))
1918 }
1919 Operator::I8x16RelaxedSwizzle => {
1920 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1921 state.push1(builder.ins().swizzle(a, b))
1922 }
1923 Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1924 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1925 state.push1(builder.ins().iadd(a, b))
1926 }
1927 Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1928 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1929 state.push1(builder.ins().sadd_sat(a, b))
1930 }
1931 Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1932 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1933 state.push1(builder.ins().uadd_sat(a, b))
1934 }
1935 Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1936 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1937 state.push1(builder.ins().isub(a, b))
1938 }
1939 Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1940 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1941 state.push1(builder.ins().ssub_sat(a, b))
1942 }
1943 Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1944 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1945 state.push1(builder.ins().usub_sat(a, b))
1946 }
1947 Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1948 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1949 state.push1(builder.ins().smin(a, b))
1950 }
1951 Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1952 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1953 state.push1(builder.ins().umin(a, b))
1954 }
1955 Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1956 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1957 state.push1(builder.ins().smax(a, b))
1958 }
1959 Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1960 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1961 state.push1(builder.ins().umax(a, b))
1962 }
1963 Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1964 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1965 state.push1(builder.ins().avg_round(a, b))
1966 }
1967 Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1968 let a = pop1_with_bitcast(state, type_of(op), builder);
1969 state.push1(builder.ins().ineg(a))
1970 }
1971 Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1972 let a = pop1_with_bitcast(state, type_of(op), builder);
1973 state.push1(builder.ins().iabs(a))
1974 }
1975 Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1976 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1977 state.push1(builder.ins().imul(a, b))
1978 }
1979 Operator::V128Or => {
1980 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1981 state.push1(builder.ins().bor(a, b))
1982 }
1983 Operator::V128Xor => {
1984 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1985 state.push1(builder.ins().bxor(a, b))
1986 }
1987 Operator::V128And => {
1988 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1989 state.push1(builder.ins().band(a, b))
1990 }
1991 Operator::V128AndNot => {
1992 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1993 state.push1(builder.ins().band_not(a, b))
1994 }
1995 Operator::V128Not => {
1996 let a = state.pop1();
1997 state.push1(builder.ins().bnot(a));
1998 }
1999 Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
2000 let (a, b) = state.pop2();
2001 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
2002 let bitwidth = i64::from(type_of(op).lane_bits());
2003 let b_mod_bitwidth = builder.ins().band_imm_u(b, bitwidth - 1);
2006 state.push1(builder.ins().ishl(bitcast_a, b_mod_bitwidth))
2007 }
2008 Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
2009 let (a, b) = state.pop2();
2010 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
2011 let bitwidth = i64::from(type_of(op).lane_bits());
2012 let b_mod_bitwidth = builder.ins().band_imm_u(b, bitwidth - 1);
2015 state.push1(builder.ins().ushr(bitcast_a, b_mod_bitwidth))
2016 }
2017 Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
2018 let (a, b) = state.pop2();
2019 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
2020 let bitwidth = i64::from(type_of(op).lane_bits());
2021 let b_mod_bitwidth = builder.ins().band_imm_u(b, bitwidth - 1);
2024 state.push1(builder.ins().sshr(bitcast_a, b_mod_bitwidth))
2025 }
2026 Operator::V128Bitselect => {
2027 let (a, b, c) = state.pop3();
2028 let bitcast_a = optionally_bitcast_vector(a, I8X16, builder);
2029 let bitcast_b = optionally_bitcast_vector(b, I8X16, builder);
2030 let bitcast_c = optionally_bitcast_vector(c, I8X16, builder);
2031 state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
2034 }
2035 Operator::I8x16RelaxedLaneselect
2036 | Operator::I16x8RelaxedLaneselect
2037 | Operator::I32x4RelaxedLaneselect
2038 | Operator::I64x2RelaxedLaneselect => {
2039 let (a, b, c) = state.pop3();
2040 let ty = type_of(op);
2041 let bitcast_a = optionally_bitcast_vector(a, ty, builder);
2042 let bitcast_b = optionally_bitcast_vector(b, ty, builder);
2043 let bitcast_c = optionally_bitcast_vector(c, ty, builder);
2044 state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
2047 }
2048 Operator::V128AnyTrue => {
2049 let a = pop1_with_bitcast(state, type_of(op), builder);
2050 let bool_result = builder.ins().vany_true(a);
2051 state.push1(builder.ins().uextend(I32, bool_result))
2052 }
2053 Operator::I8x16AllTrue
2054 | Operator::I16x8AllTrue
2055 | Operator::I32x4AllTrue
2056 | Operator::I64x2AllTrue => {
2057 let a = pop1_with_bitcast(state, type_of(op), builder);
2058 let bool_result = builder.ins().vall_true(a);
2059 state.push1(builder.ins().uextend(I32, bool_result))
2060 }
2061 Operator::I8x16Bitmask
2062 | Operator::I16x8Bitmask
2063 | Operator::I32x4Bitmask
2064 | Operator::I64x2Bitmask => {
2065 let a = pop1_with_bitcast(state, type_of(op), builder);
2066 state.push1(builder.ins().vhigh_bits(I32, a));
2067 }
2068 Operator::I8x16Eq | Operator::I16x8Eq | Operator::I32x4Eq | Operator::I64x2Eq => {
2069 translate_vector_icmp(IntCC::Equal, type_of(op), builder, state)
2070 }
2071 Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
2072 translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, state)
2073 }
2074 Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
2075 translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, state)
2076 }
2077 Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
2078 translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, state)
2079 }
2080 Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
2081 translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, state)
2082 }
2083 Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
2084 translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, state)
2085 }
2086 Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
2087 translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, state)
2088 }
2089 Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
2090 translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, state)
2091 }
2092 Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
2093 IntCC::UnsignedGreaterThanOrEqual,
2094 type_of(op),
2095 builder,
2096 state,
2097 ),
2098 Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
2099 translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, state)
2100 }
2101 Operator::F32x4Eq | Operator::F64x2Eq => {
2102 translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, state)
2103 }
2104 Operator::F32x4Ne | Operator::F64x2Ne => {
2105 translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, state)
2106 }
2107 Operator::F32x4Lt | Operator::F64x2Lt => {
2108 translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, state)
2109 }
2110 Operator::F32x4Gt | Operator::F64x2Gt => {
2111 translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, state)
2112 }
2113 Operator::F32x4Le | Operator::F64x2Le => {
2114 translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, state)
2115 }
2116 Operator::F32x4Ge | Operator::F64x2Ge => {
2117 translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, state)
2118 }
2119 Operator::F32x4Add | Operator::F64x2Add => {
2120 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2121 state.push1(builder.ins().fadd(a, b))
2122 }
2123 Operator::F32x4Sub | Operator::F64x2Sub => {
2124 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2125 state.push1(builder.ins().fsub(a, b))
2126 }
2127 Operator::F32x4Mul | Operator::F64x2Mul => {
2128 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2129 state.push1(builder.ins().fmul(a, b))
2130 }
2131 Operator::F32x4RelaxedMadd | Operator::F64x2RelaxedMadd => {
2132 let ty = type_of(op);
2133 let (a, b, c) = state.pop3();
2134 let a = optionally_bitcast_vector(a, ty, builder);
2135 let b = optionally_bitcast_vector(b, ty, builder);
2136 let c = optionally_bitcast_vector(c, ty, builder);
2137 let mul = builder.ins().fmul(a, b);
2138 state.push1(builder.ins().fadd(mul, c))
2139 }
2140 Operator::F32x4RelaxedNmadd | Operator::F64x2RelaxedNmadd => {
2141 let ty = type_of(op);
2142 let (a, b, c) = state.pop3();
2143 let a = optionally_bitcast_vector(a, ty, builder);
2144 let b = optionally_bitcast_vector(b, ty, builder);
2145 let c = optionally_bitcast_vector(c, ty, builder);
2146 let a = builder.ins().fneg(a);
2147 let mul = builder.ins().fmul(a, b);
2148 state.push1(builder.ins().fadd(mul, c))
2149 }
2150 Operator::F32x4Div | Operator::F64x2Div => {
2151 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2152 state.push1(builder.ins().fdiv(a, b))
2153 }
2154 Operator::F32x4Max | Operator::F64x2Max => {
2155 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2156 state.push1(builder.ins().fmax(a, b))
2157 }
2158 Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => {
2159 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2160 state.push1(builder.ins().fmax(a, b))
2161 }
2162 Operator::F32x4Min | Operator::F64x2Min => {
2163 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2164 state.push1(builder.ins().fmin(a, b))
2165 }
2166 Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => {
2167 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2168 state.push1(builder.ins().fmin(a, b))
2169 }
2170 Operator::F32x4PMax | Operator::F64x2PMax => {
2171 let ty = type_of(op);
2178 let (a, b) = pop2_with_bitcast(state, ty, builder);
2179 let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
2180 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2181 state.push1(builder.ins().bitselect(cmp, b, a))
2182 }
2183 Operator::F32x4PMin | Operator::F64x2PMin => {
2184 let ty = type_of(op);
2190 let (a, b) = pop2_with_bitcast(state, ty, builder);
2191 let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
2192 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2193 state.push1(builder.ins().bitselect(cmp, b, a))
2194 }
2195 Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
2196 let a = pop1_with_bitcast(state, type_of(op), builder);
2197 state.push1(builder.ins().sqrt(a))
2198 }
2199 Operator::F32x4Neg | Operator::F64x2Neg => {
2200 let a = pop1_with_bitcast(state, type_of(op), builder);
2201 state.push1(builder.ins().fneg(a))
2202 }
2203 Operator::F32x4Abs | Operator::F64x2Abs => {
2204 let a = pop1_with_bitcast(state, type_of(op), builder);
2205 state.push1(builder.ins().fabs(a))
2206 }
2207 Operator::F32x4ConvertI32x4S => {
2208 let a = pop1_with_bitcast(state, I32X4, builder);
2209 state.push1(builder.ins().fcvt_from_sint(F32X4, a))
2210 }
2211 Operator::F32x4ConvertI32x4U => {
2212 let a = pop1_with_bitcast(state, I32X4, builder);
2213 state.push1(builder.ins().fcvt_from_uint(F32X4, a))
2214 }
2215 Operator::F64x2ConvertLowI32x4S => {
2216 let a = pop1_with_bitcast(state, I32X4, builder);
2217 let widened_a = builder.ins().swiden_low(a);
2218 state.push1(builder.ins().fcvt_from_sint(F64X2, widened_a));
2219 }
2220 Operator::F64x2ConvertLowI32x4U => {
2221 let a = pop1_with_bitcast(state, I32X4, builder);
2222 let widened_a = builder.ins().uwiden_low(a);
2223 state.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
2224 }
2225 Operator::F64x2PromoteLowF32x4 => {
2226 let a = pop1_with_bitcast(state, F32X4, builder);
2227 state.push1(builder.ins().fvpromote_low(a));
2228 }
2229 Operator::F32x4DemoteF64x2Zero => {
2230 let a = pop1_with_bitcast(state, F64X2, builder);
2231 state.push1(builder.ins().fvdemote(a));
2232 }
2233 Operator::I32x4TruncSatF32x4S => {
2234 let a = pop1_with_bitcast(state, F32X4, builder);
2235 state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2236 }
2237 Operator::I32x4RelaxedTruncF32x4S => {
2238 let a = pop1_with_bitcast(state, F32X4, builder);
2239 state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2240 }
2241 Operator::I32x4TruncSatF64x2SZero => {
2242 let a = pop1_with_bitcast(state, F64X2, builder);
2243 let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2244 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2245 let zero = builder.ins().vconst(I64X2, handle);
2246
2247 state.push1(builder.ins().snarrow(converted_a, zero));
2248 }
2249 Operator::I32x4RelaxedTruncF64x2SZero => {
2250 let a = pop1_with_bitcast(state, F64X2, builder);
2251 let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2252 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2253 let zero = builder.ins().vconst(I64X2, handle);
2254
2255 state.push1(builder.ins().snarrow(converted_a, zero));
2256 }
2257 Operator::I32x4TruncSatF32x4U => {
2258 let a = pop1_with_bitcast(state, F32X4, builder);
2259 state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2260 }
2261 Operator::I32x4RelaxedTruncF32x4U => {
2262 let a = pop1_with_bitcast(state, F32X4, builder);
2263 state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2264 }
2265 Operator::I32x4TruncSatF64x2UZero => {
2266 let a = pop1_with_bitcast(state, F64X2, builder);
2267 let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2268 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2269 let zero = builder.ins().vconst(I64X2, handle);
2270
2271 state.push1(builder.ins().uunarrow(converted_a, zero));
2272 }
2273 Operator::I32x4RelaxedTruncF64x2UZero => {
2274 let a = pop1_with_bitcast(state, F64X2, builder);
2275 let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2276 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2277 let zero = builder.ins().vconst(I64X2, handle);
2278
2279 state.push1(builder.ins().uunarrow(converted_a, zero));
2280 }
2281 Operator::I8x16NarrowI16x8S => {
2282 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2283 state.push1(builder.ins().snarrow(a, b))
2284 }
2285 Operator::I16x8NarrowI32x4S => {
2286 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2287 state.push1(builder.ins().snarrow(a, b))
2288 }
2289 Operator::I8x16NarrowI16x8U => {
2290 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2291 state.push1(builder.ins().unarrow(a, b))
2292 }
2293 Operator::I16x8NarrowI32x4U => {
2294 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2295 state.push1(builder.ins().unarrow(a, b))
2296 }
2297 Operator::I16x8ExtendLowI8x16S => {
2298 let a = pop1_with_bitcast(state, I8X16, builder);
2299 state.push1(builder.ins().swiden_low(a))
2300 }
2301 Operator::I16x8ExtendHighI8x16S => {
2302 let a = pop1_with_bitcast(state, I8X16, builder);
2303 state.push1(builder.ins().swiden_high(a))
2304 }
2305 Operator::I16x8ExtendLowI8x16U => {
2306 let a = pop1_with_bitcast(state, I8X16, builder);
2307 state.push1(builder.ins().uwiden_low(a))
2308 }
2309 Operator::I16x8ExtendHighI8x16U => {
2310 let a = pop1_with_bitcast(state, I8X16, builder);
2311 state.push1(builder.ins().uwiden_high(a))
2312 }
2313 Operator::I32x4ExtendLowI16x8S => {
2314 let a = pop1_with_bitcast(state, I16X8, builder);
2315 state.push1(builder.ins().swiden_low(a))
2316 }
2317 Operator::I32x4ExtendHighI16x8S => {
2318 let a = pop1_with_bitcast(state, I16X8, builder);
2319 state.push1(builder.ins().swiden_high(a))
2320 }
2321 Operator::I32x4ExtendLowI16x8U => {
2322 let a = pop1_with_bitcast(state, I16X8, builder);
2323 state.push1(builder.ins().uwiden_low(a))
2324 }
2325 Operator::I32x4ExtendHighI16x8U => {
2326 let a = pop1_with_bitcast(state, I16X8, builder);
2327 state.push1(builder.ins().uwiden_high(a))
2328 }
2329
2330 Operator::I64x2ExtendLowI32x4S => {
2331 let a = pop1_with_bitcast(state, I32X4, builder);
2332 state.push1(builder.ins().swiden_low(a))
2333 }
2334 Operator::I64x2ExtendHighI32x4S => {
2335 let a = pop1_with_bitcast(state, I32X4, builder);
2336 state.push1(builder.ins().swiden_high(a))
2337 }
2338 Operator::I64x2ExtendLowI32x4U => {
2339 let a = pop1_with_bitcast(state, I32X4, builder);
2340 state.push1(builder.ins().uwiden_low(a))
2341 }
2342 Operator::I64x2ExtendHighI32x4U => {
2343 let a = pop1_with_bitcast(state, I32X4, builder);
2344 state.push1(builder.ins().uwiden_high(a))
2345 }
2346 Operator::I16x8ExtAddPairwiseI8x16S => {
2347 let a = pop1_with_bitcast(state, I8X16, builder);
2348 let widen_low = builder.ins().swiden_low(a);
2349 let widen_high = builder.ins().swiden_high(a);
2350 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2351 }
2352 Operator::I32x4ExtAddPairwiseI16x8S => {
2353 let a = pop1_with_bitcast(state, I16X8, builder);
2354 let widen_low = builder.ins().swiden_low(a);
2355 let widen_high = builder.ins().swiden_high(a);
2356 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2357 }
2358 Operator::I16x8ExtAddPairwiseI8x16U => {
2359 let a = pop1_with_bitcast(state, I8X16, builder);
2360 let widen_low = builder.ins().uwiden_low(a);
2361 let widen_high = builder.ins().uwiden_high(a);
2362 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2363 }
2364 Operator::I32x4ExtAddPairwiseI16x8U => {
2365 let a = pop1_with_bitcast(state, I16X8, builder);
2366 let widen_low = builder.ins().uwiden_low(a);
2367 let widen_high = builder.ins().uwiden_high(a);
2368 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2369 }
2370 Operator::F32x4Ceil | Operator::F64x2Ceil => {
2371 let arg = pop1_with_bitcast(state, type_of(op), builder);
2375 state.push1(builder.ins().ceil(arg));
2376 }
2377 Operator::F32x4Floor | Operator::F64x2Floor => {
2378 let arg = pop1_with_bitcast(state, type_of(op), builder);
2379 state.push1(builder.ins().floor(arg));
2380 }
2381 Operator::F32x4Trunc | Operator::F64x2Trunc => {
2382 let arg = pop1_with_bitcast(state, type_of(op), builder);
2383 state.push1(builder.ins().trunc(arg));
2384 }
2385 Operator::F32x4Nearest | Operator::F64x2Nearest => {
2386 let arg = pop1_with_bitcast(state, type_of(op), builder);
2387 state.push1(builder.ins().nearest(arg));
2388 }
2389 Operator::I32x4DotI16x8S => {
2390 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2391 let alow = builder.ins().swiden_low(a);
2392 let blow = builder.ins().swiden_low(b);
2393 let low = builder.ins().imul(alow, blow);
2394 let ahigh = builder.ins().swiden_high(a);
2395 let bhigh = builder.ins().swiden_high(b);
2396 let high = builder.ins().imul(ahigh, bhigh);
2397 state.push1(builder.ins().iadd_pairwise(low, high));
2398 }
2399 Operator::I16x8RelaxedDotI8x16I7x16S => {
2400 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2401 let alow = builder.ins().swiden_low(a);
2402 let blow = builder.ins().swiden_low(b);
2403 let low = builder.ins().imul(alow, blow);
2404 let ahigh = builder.ins().swiden_high(a);
2405 let bhigh = builder.ins().swiden_high(b);
2406 let high = builder.ins().imul(ahigh, bhigh);
2407 state.push1(builder.ins().iadd_pairwise(low, high));
2408 }
2409 Operator::I8x16Popcnt => {
2410 let arg = pop1_with_bitcast(state, type_of(op), builder);
2411 state.push1(builder.ins().popcnt(arg));
2412 }
2413 Operator::I16x8Q15MulrSatS => {
2414 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2415 state.push1(builder.ins().sqmul_round_sat(a, b))
2416 }
2417 Operator::I16x8RelaxedQ15mulrS => {
2418 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2419 state.push1(builder.ins().sqmul_round_sat(a, b))
2420 }
2421 Operator::I32x4RelaxedDotI8x16I7x16AddS => {
2422 let (a, b, c) = state.pop3();
2423 let a = optionally_bitcast_vector(a, I8X16, builder);
2424 let b = optionally_bitcast_vector(b, I8X16, builder);
2425 let c = optionally_bitcast_vector(c, I32X4, builder);
2426 let alow = builder.ins().swiden_low(a);
2427 let blow = builder.ins().swiden_low(b);
2428 let low = builder.ins().imul(alow, blow);
2429 let ahigh = builder.ins().swiden_high(a);
2430 let bhigh = builder.ins().swiden_high(b);
2431 let high = builder.ins().imul(ahigh, bhigh);
2432 let dot = builder.ins().iadd_pairwise(low, high);
2433 let dotlo = builder.ins().swiden_low(dot);
2434 let dothi = builder.ins().swiden_high(dot);
2435 let dot32 = builder.ins().iadd_pairwise(dotlo, dothi);
2436 state.push1(builder.ins().iadd(dot32, c));
2437 }
2438 Operator::I16x8ExtMulLowI8x16S => {
2439 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2440 let a_low = builder.ins().swiden_low(a);
2441 let b_low = builder.ins().swiden_low(b);
2442 state.push1(builder.ins().imul(a_low, b_low));
2443 }
2444 Operator::I16x8ExtMulHighI8x16S => {
2445 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2446 let a_high = builder.ins().swiden_high(a);
2447 let b_high = builder.ins().swiden_high(b);
2448 state.push1(builder.ins().imul(a_high, b_high));
2449 }
2450 Operator::I16x8ExtMulLowI8x16U => {
2451 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2452 let a_low = builder.ins().uwiden_low(a);
2453 let b_low = builder.ins().uwiden_low(b);
2454 state.push1(builder.ins().imul(a_low, b_low));
2455 }
2456 Operator::I16x8ExtMulHighI8x16U => {
2457 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2458 let a_high = builder.ins().uwiden_high(a);
2459 let b_high = builder.ins().uwiden_high(b);
2460 state.push1(builder.ins().imul(a_high, b_high));
2461 }
2462 Operator::I32x4ExtMulLowI16x8S => {
2463 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2464 let a_low = builder.ins().swiden_low(a);
2465 let b_low = builder.ins().swiden_low(b);
2466 state.push1(builder.ins().imul(a_low, b_low));
2467 }
2468 Operator::I32x4ExtMulHighI16x8S => {
2469 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2470 let a_high = builder.ins().swiden_high(a);
2471 let b_high = builder.ins().swiden_high(b);
2472 state.push1(builder.ins().imul(a_high, b_high));
2473 }
2474 Operator::I32x4ExtMulLowI16x8U => {
2475 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2476 let a_low = builder.ins().uwiden_low(a);
2477 let b_low = builder.ins().uwiden_low(b);
2478 state.push1(builder.ins().imul(a_low, b_low));
2479 }
2480 Operator::I32x4ExtMulHighI16x8U => {
2481 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2482 let a_high = builder.ins().uwiden_high(a);
2483 let b_high = builder.ins().uwiden_high(b);
2484 state.push1(builder.ins().imul(a_high, b_high));
2485 }
2486 Operator::I64x2ExtMulLowI32x4S => {
2487 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2488 let a_low = builder.ins().swiden_low(a);
2489 let b_low = builder.ins().swiden_low(b);
2490 state.push1(builder.ins().imul(a_low, b_low));
2491 }
2492 Operator::I64x2ExtMulHighI32x4S => {
2493 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2494 let a_high = builder.ins().swiden_high(a);
2495 let b_high = builder.ins().swiden_high(b);
2496 state.push1(builder.ins().imul(a_high, b_high));
2497 }
2498 Operator::I64x2ExtMulLowI32x4U => {
2499 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2500 let a_low = builder.ins().uwiden_low(a);
2501 let b_low = builder.ins().uwiden_low(b);
2502 state.push1(builder.ins().imul(a_low, b_low));
2503 }
2504 Operator::I64x2ExtMulHighI32x4U => {
2505 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2506 let a_high = builder.ins().uwiden_high(a);
2507 let b_high = builder.ins().uwiden_high(b);
2508 state.push1(builder.ins().imul(a_high, b_high));
2509 }
2510 Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
2511 return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
2512 }
2513 Operator::RefEq
2514 | Operator::StructNew { .. }
2515 | Operator::StructNewDefault { .. }
2516 | Operator::StructGet { .. }
2517 | Operator::StructGetS { .. }
2518 | Operator::StructGetU { .. }
2519 | Operator::StructSet { .. }
2520 | Operator::ArrayNew { .. }
2521 | Operator::ArrayNewDefault { .. }
2522 | Operator::ArrayNewFixed { .. }
2523 | Operator::ArrayNewData { .. }
2524 | Operator::ArrayNewElem { .. }
2525 | Operator::ArrayGet { .. }
2526 | Operator::ArrayGetS { .. }
2527 | Operator::ArrayGetU { .. }
2528 | Operator::ArraySet { .. }
2529 | Operator::ArrayLen
2530 | Operator::ArrayFill { .. }
2531 | Operator::ArrayCopy { .. }
2532 | Operator::ArrayInitData { .. }
2533 | Operator::ArrayInitElem { .. }
2534 | Operator::RefTestNonNull { .. } => {}
2535 Operator::RefTestNullable { .. }
2536 | Operator::RefCastNonNull { .. }
2537 | Operator::RefCastNullable { .. }
2538 | Operator::BrOnCast { .. }
2539 | Operator::BrOnCastFail { .. }
2540 | Operator::AnyConvertExtern
2541 | Operator::ExternConvertAny
2542 | Operator::RefI31
2543 | Operator::RefI31Shared => todo!(),
2544 Operator::I31GetS
2545 | Operator::I31GetU
2546 | Operator::MemoryDiscard { .. }
2547 | Operator::CallRef { .. }
2548 | Operator::ReturnCallRef { .. }
2549 | Operator::RefAsNonNull
2550 | Operator::BrOnNull { .. }
2551 | Operator::BrOnNonNull { .. } => {
2552 return Err(wasm_unsupported!("GC proposal not (operator: {:?})", op));
2553 }
2554 Operator::GlobalAtomicGet { .. }
2555 | Operator::GlobalAtomicSet { .. }
2556 | Operator::GlobalAtomicRmwAdd { .. }
2557 | Operator::GlobalAtomicRmwSub { .. }
2558 | Operator::GlobalAtomicRmwAnd { .. }
2559 | Operator::GlobalAtomicRmwOr { .. }
2560 | Operator::GlobalAtomicRmwXor { .. }
2561 | Operator::GlobalAtomicRmwXchg { .. }
2562 | Operator::GlobalAtomicRmwCmpxchg { .. } => {
2563 return Err(wasm_unsupported!("Global atomics not supported yet!"));
2564 }
2565 Operator::TableAtomicGet { .. }
2566 | Operator::TableAtomicSet { .. }
2567 | Operator::TableAtomicRmwXchg { .. }
2568 | Operator::TableAtomicRmwCmpxchg { .. } => {
2569 return Err(wasm_unsupported!("Table atomics not supported yet!"));
2570 }
2571 Operator::StructAtomicGet { .. }
2572 | Operator::StructAtomicGetS { .. }
2573 | Operator::StructAtomicGetU { .. }
2574 | Operator::StructAtomicSet { .. }
2575 | Operator::StructAtomicRmwAdd { .. }
2576 | Operator::StructAtomicRmwSub { .. }
2577 | Operator::StructAtomicRmwAnd { .. }
2578 | Operator::StructAtomicRmwOr { .. }
2579 | Operator::StructAtomicRmwXor { .. }
2580 | Operator::StructAtomicRmwXchg { .. }
2581 | Operator::StructAtomicRmwCmpxchg { .. } => {
2582 return Err(wasm_unsupported!("Table atomics not supported yet!"));
2583 }
2584 Operator::ArrayAtomicGet { .. }
2585 | Operator::ArrayAtomicGetS { .. }
2586 | Operator::ArrayAtomicGetU { .. }
2587 | Operator::ArrayAtomicSet { .. }
2588 | Operator::ArrayAtomicRmwAdd { .. }
2589 | Operator::ArrayAtomicRmwSub { .. }
2590 | Operator::ArrayAtomicRmwAnd { .. }
2591 | Operator::ArrayAtomicRmwOr { .. }
2592 | Operator::ArrayAtomicRmwXor { .. }
2593 | Operator::ArrayAtomicRmwXchg { .. }
2594 | Operator::ArrayAtomicRmwCmpxchg { .. } => {
2595 return Err(wasm_unsupported!("Array atomics not supported yet!"));
2596 }
2597 Operator::ContNew { .. } => todo!(),
2598 Operator::ContBind { .. } => todo!(),
2599 Operator::Suspend { .. } => todo!(),
2600 Operator::Resume { .. } => todo!(),
2601 Operator::ResumeThrow { .. } => todo!(),
2602 Operator::Switch { .. } => todo!(),
2603 Operator::I64Add128 | Operator::I64Sub128 => {
2604 let (rhs_lo, rhs_hi) = state.pop2();
2605 let (lhs_lo, lhs_hi) = state.pop2();
2606
2607 let lhs = builder.ins().iconcat(lhs_lo, lhs_hi);
2608 let rhs = builder.ins().iconcat(rhs_lo, rhs_hi);
2609 let result = match op {
2610 Operator::I64Add128 => builder.ins().iadd(lhs, rhs),
2611 Operator::I64Sub128 => builder.ins().isub(lhs, rhs),
2612 _ => unreachable!(),
2613 };
2614 let (result_lo, result_hi) = builder.ins().isplit(result);
2615
2616 state.push1(result_lo);
2617 state.push1(result_hi);
2618 }
2619 Operator::I64MulWideS | Operator::I64MulWideU => {
2620 let (lhs, rhs) = state.pop2();
2621
2622 let lhs = match op {
2623 Operator::I64MulWideS => builder.ins().sextend(I128, lhs),
2624 Operator::I64MulWideU => builder.ins().uextend(I128, lhs),
2625 _ => unreachable!(),
2626 };
2627 let rhs = match op {
2628 Operator::I64MulWideS => builder.ins().sextend(I128, rhs),
2629 Operator::I64MulWideU => builder.ins().uextend(I128, rhs),
2630 _ => unreachable!(),
2631 };
2632
2633 let result = builder.ins().imul(lhs, rhs);
2634 let (result_lo, result_hi) = builder.ins().isplit(result);
2635 state.push1(result_lo);
2636 state.push1(result_hi);
2637 }
2638 _ => todo!(),
2639 };
2640 Ok(())
2641}
2642
2643#[allow(clippy::unneeded_field_pattern)]
2645fn translate_unreachable_operator(
2649 module_translation_state: &ModuleTranslationState,
2650 op: &Operator,
2651 builder: &mut FunctionBuilder,
2652 state: &mut FuncTranslationState,
2653 environ: &mut FuncEnvironment<'_>,
2654) -> WasmResult<()> {
2655 debug_assert!(!state.reachable);
2656 match *op {
2657 Operator::If { blockty } => {
2658 state.push_if(
2661 ir::Block::reserved_value(),
2662 ElseData::NoElse {
2663 branch_inst: ir::Inst::reserved_value(),
2664 placeholder: ir::Block::reserved_value(),
2665 },
2666 0,
2667 0,
2668 blockty,
2669 );
2670 }
2671 Operator::Loop { blockty: _ }
2672 | Operator::Block { blockty: _ }
2673 | Operator::TryTable { try_table: _ } => {
2674 state.push_block(ir::Block::reserved_value(), 0, 0);
2675 }
2676 Operator::Else => {
2677 let i = state.control_stack.len() - 1;
2678 match state.control_stack[i] {
2679 ControlStackFrame::If {
2680 ref else_data,
2681 head_is_reachable,
2682 ref mut consequent_ends_reachable,
2683 blocktype,
2684 ..
2685 } => {
2686 debug_assert!(consequent_ends_reachable.is_none());
2687 *consequent_ends_reachable = Some(state.reachable);
2688
2689 if head_is_reachable {
2690 state.reachable = true;
2692
2693 let else_block = match *else_data {
2694 ElseData::NoElse {
2695 branch_inst,
2696 placeholder,
2697 } => {
2698 let (params, _results) = module_translation_state
2699 .blocktype_params_results(&blocktype)?;
2700 let else_block =
2701 block_with_params(builder, params.iter(), environ)?;
2702 let frame = state.control_stack.last().unwrap();
2703 frame.truncate_value_stack_to_else_params(&mut state.stack);
2704
2705 builder.change_jump_destination(
2707 branch_inst,
2708 placeholder,
2709 else_block,
2710 );
2711 builder.seal_block(else_block);
2712 else_block
2713 }
2714 ElseData::WithElse { else_block } => {
2715 let frame = state.control_stack.last().unwrap();
2716 frame.truncate_value_stack_to_else_params(&mut state.stack);
2717 else_block
2718 }
2719 };
2720
2721 builder.switch_to_block(else_block);
2722
2723 }
2728 }
2729 _ => unreachable!(),
2730 }
2731 }
2732 Operator::End => {
2733 let stack = &mut state.stack;
2734 let control_stack = &mut state.control_stack;
2735 let frame = control_stack.pop().unwrap();
2736 frame.restore_catch_handlers(&mut state.handlers, builder);
2737
2738 frame.truncate_value_stack_to_original_size(stack);
2740
2741 let reachable_anyway = match frame {
2742 ControlStackFrame::Loop { header, .. } => {
2744 builder.seal_block(header);
2745 false
2747 }
2748 ControlStackFrame::If {
2753 head_is_reachable,
2754 consequent_ends_reachable: None,
2755 ..
2756 } => head_is_reachable,
2757 ControlStackFrame::If {
2762 head_is_reachable,
2763 consequent_ends_reachable: Some(consequent_ends_reachable),
2764 ..
2765 } => head_is_reachable && consequent_ends_reachable,
2766 _ => false,
2768 };
2769
2770 if frame.exit_is_branched_to() || reachable_anyway {
2771 builder.switch_to_block(frame.following_code());
2772 builder.seal_block(frame.following_code());
2773
2774 stack.extend_from_slice(builder.block_params(frame.following_code()));
2777 state.reachable = true;
2778 }
2779 }
2780 _ => {
2781 }
2783 }
2784
2785 Ok(())
2786}
2787
2788fn prepare_addr(
2801 memarg: &MemArg,
2802 access_size: u8,
2803 builder: &mut FunctionBuilder,
2804 state: &mut FuncTranslationState,
2805 environ: &mut FuncEnvironment<'_>,
2806) -> WasmResult<Reachability<(MemFlagsData, Value, Value)>> {
2807 let index = state.pop1();
2808 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
2809
2810 let heap = environ.heaps()[heap].clone();
2881 let addr = match u32::try_from(memarg.offset) {
2882 Ok(offset) => bounds_checks::bounds_check_and_compute_addr(
2885 builder,
2886 environ,
2887 &heap,
2888 index,
2889 offset,
2890 access_size,
2891 )?,
2892
2893 Err(_) => {
2920 let offset = builder.ins().iconst(heap.index_type, memarg.offset as i64);
2921 let adjusted_index =
2922 builder
2923 .ins()
2924 .uadd_overflow_trap(index, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
2925 bounds_checks::bounds_check_and_compute_addr(
2926 builder,
2927 environ,
2928 &heap,
2929 adjusted_index,
2930 0,
2931 access_size,
2932 )?
2933 }
2934 };
2935 let addr = match addr {
2936 Reachability::Unreachable => return Ok(Reachability::Unreachable),
2937 Reachability::Reachable(a) => a,
2938 };
2939
2940 let mut flags = MemFlagsData::new();
2945 flags.set_endianness(ir::Endianness::Little);
2946
2947 set_memflags_alias_region(builder.func, &mut flags, MemoryAliasRegion::Heap);
2952
2953 Ok(Reachability::Reachable((flags, index, addr)))
2954}
2955
2956fn align_atomic_addr(
2957 memarg: &MemArg,
2958 loaded_bytes: u8,
2959 builder: &mut FunctionBuilder,
2960 state: &mut FuncTranslationState,
2961) {
2962 if loaded_bytes > 1 {
2973 let addr = state.pop1(); state.push1(addr);
2975 let effective_addr = if memarg.offset == 0 {
2976 addr
2977 } else {
2978 builder
2979 .ins()
2980 .iadd_imm_s(addr, i64::from(memarg.offset as i32))
2981 };
2982 debug_assert!(loaded_bytes.is_power_of_two());
2983 let misalignment = builder
2984 .ins()
2985 .band_imm_u(effective_addr, i64::from(loaded_bytes - 1));
2986 let f = builder.ins().icmp_imm_u(IntCC::NotEqual, misalignment, 0);
2987 builder.ins().trapnz(f, crate::TRAP_HEAP_MISALIGNED);
2988 }
2989}
2990
2991fn prepare_atomic_addr(
2995 memarg: &MemArg,
2996 loaded_bytes: u8,
2997 builder: &mut FunctionBuilder,
2998 state: &mut FuncTranslationState,
2999 environ: &mut FuncEnvironment<'_>,
3000) -> WasmResult<Reachability<(MemFlagsData, Value, Value)>> {
3001 align_atomic_addr(memarg, loaded_bytes, builder, state);
3002 prepare_addr(memarg, loaded_bytes, builder, state, environ)
3003}
3004
3005#[derive(PartialEq, Eq)]
3011#[must_use]
3012pub enum Reachability<T> {
3013 Reachable(T),
3015 #[allow(dead_code)]
3019 Unreachable,
3020}
3021
3022fn translate_load(
3026 memarg: &MemArg,
3027 opcode: ir::Opcode,
3028 result_ty: Type,
3029 builder: &mut FunctionBuilder,
3030 state: &mut FuncTranslationState,
3031 environ: &mut FuncEnvironment<'_>,
3032 allow_unaligned_memory_accesses: bool,
3033) -> WasmResult<Reachability<()>> {
3034 let mem_op_size = mem_op_size(opcode, result_ty);
3035 let (flags, _wasm_index, base) =
3036 match prepare_addr(memarg, mem_op_size, builder, state, environ)? {
3037 Reachability::Unreachable => return Ok(Reachability::Unreachable),
3038 Reachability::Reachable((f, i, b)) => (f, i, b),
3039 };
3040 let raw_flags = insert_mem_flags(builder.func, flags);
3041
3042 if allow_unaligned_memory_accesses && mem_op_size > 1 && mem_op_size < 16 {
3044 let block_aligned = builder.create_block();
3046 let block_unaligned = builder.create_block();
3047 let block_merge = builder.create_block();
3048 builder.append_block_param(block_merge, result_ty);
3049
3050 let alignment_check = builder.ins().band_imm_u(base, (mem_op_size - 1) as i64);
3051 builder
3052 .ins()
3053 .brif(alignment_check, block_unaligned, &[], block_aligned, &[]);
3054
3055 builder.seal_block(block_aligned);
3056 builder.seal_block(block_unaligned);
3057
3058 builder.switch_to_block(block_aligned);
3059 let (fast_load, fast_dfg) =
3060 builder
3061 .ins()
3062 .Load(opcode, result_ty, raw_flags, Offset32::new(0), base);
3063 let fast_val = fast_dfg.first_result(fast_load);
3064 builder.ins().jump(block_merge, &[fast_val.into()]);
3065
3066 builder.switch_to_block(block_unaligned);
3067
3068 let result_uint_type = Type::int_with_byte_size(u16::try_from(result_ty.bytes()).unwrap())
3070 .ok_or(WasmError::Generic(
3071 "cannot get uint type for memory load".to_string(),
3072 ))?;
3073 let raw_uint_type = Type::int_with_byte_size(u16::from(mem_op_size)).ok_or(
3074 WasmError::Generic("cannot get uint type for memory load".to_string()),
3075 )?;
3076 let mut slow_val = builder.ins().uload8(result_uint_type, flags, base, 0);
3077 for i in 1..mem_op_size {
3078 let byte = builder
3079 .ins()
3080 .uload8(result_uint_type, flags, base, i as i32);
3081 let shifted = builder.ins().ishl_imm_u(byte, (i * 8) as i64);
3082 slow_val = builder.ins().bor(slow_val, shifted);
3083 }
3084 if matches!(
3085 opcode,
3086 ir::Opcode::Sload8 | ir::Opcode::Sload16 | ir::Opcode::Sload32
3087 ) {
3088 let narrow = builder.ins().ireduce(raw_uint_type, slow_val);
3089 slow_val = builder.ins().sextend(result_uint_type, narrow);
3090 }
3091 let slow_val = builder.ins().bitcast(
3092 result_ty,
3093 MemFlagsData::new().with_endianness(ir::Endianness::Little),
3094 slow_val,
3095 );
3096 builder.ins().jump(block_merge, &[slow_val.into()]);
3097
3098 builder.seal_block(block_merge);
3099 builder.switch_to_block(block_merge);
3100 state.push1(builder.block_params(block_merge)[0]);
3101 } else {
3102 let (load, dfg) = builder
3103 .ins()
3104 .Load(opcode, result_ty, raw_flags, Offset32::new(0), base);
3105 state.push1(dfg.first_result(load));
3106 }
3107
3108 Ok(Reachability::Reachable(()))
3109}
3110
3111fn translate_store(
3113 memarg: &MemArg,
3114 opcode: ir::Opcode,
3115 builder: &mut FunctionBuilder,
3116 state: &mut FuncTranslationState,
3117 environ: &mut FuncEnvironment<'_>,
3118 allow_unaligned_memory_accesses: bool,
3119) -> WasmResult<()> {
3120 let val = state.pop1();
3121 let val_ty = builder.func.dfg.value_type(val);
3122 let mem_op_size = mem_op_size(opcode, val_ty);
3123
3124 let (flags, _wasm_index, base) = unwrap_or_return_unreachable_state!(
3125 state,
3126 prepare_addr(memarg, mem_op_size, builder, state, environ)?
3127 );
3128 let raw_flags = insert_mem_flags(builder.func, flags);
3129
3130 if allow_unaligned_memory_accesses && mem_op_size > 1 && mem_op_size < 16 {
3131 let block_aligned = builder.create_block();
3132 let block_unaligned = builder.create_block();
3133 let block_merge = builder.create_block();
3134
3135 let alignment_check = builder.ins().band_imm_u(base, (mem_op_size - 1) as i64);
3136 builder
3137 .ins()
3138 .brif(alignment_check, block_unaligned, &[], block_aligned, &[]);
3139
3140 builder.seal_block(block_aligned);
3141 builder.seal_block(block_unaligned);
3142
3143 builder.switch_to_block(block_aligned);
3144 builder
3145 .ins()
3146 .Store(opcode, val_ty, raw_flags, Offset32::new(0), val, base);
3147 builder.ins().jump(block_merge, &[]);
3148
3149 builder.switch_to_block(block_unaligned);
3150 let val = if val_ty.is_int() {
3151 val
3152 } else {
3153 let result_uint_type = Type::int_with_byte_size(u16::from(mem_op_size)).ok_or(
3154 WasmError::Generic(format!(
3155 "cannot get uint type of size {mem_op_size} bytes for memory store from {val_ty:?}",
3156 )),
3157 )?;
3158 builder.ins().bitcast(
3159 result_uint_type,
3160 MemFlagsData::new().with_endianness(ir::Endianness::Little),
3161 val,
3162 )
3163 };
3164 for i in 0..mem_op_size {
3165 let shifted = builder.ins().ushr_imm_u(val, (i * 8) as i64);
3166 builder.ins().istore8(flags, shifted, base, i as i32);
3167 }
3168 builder.ins().jump(block_merge, &[]);
3169
3170 builder.seal_block(block_merge);
3171 builder.switch_to_block(block_merge);
3172 } else {
3173 builder
3174 .ins()
3175 .Store(opcode, val_ty, raw_flags, Offset32::new(0), val, base);
3176 }
3177
3178 Ok(())
3179}
3180
3181fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
3182 match opcode {
3183 ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
3184 ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
3185 ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
3186 ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
3187 _ => panic!("unknown size of mem op for {opcode:?}"),
3188 }
3189}
3190
3191fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3192 let (arg0, arg1) = state.pop2();
3193 let val = builder.ins().icmp(cc, arg0, arg1);
3194 state.push1(builder.ins().uextend(I32, val));
3195}
3196
3197fn fold_atomic_mem_addr(
3198 linear_mem_addr: Value,
3199 memarg: &MemArg,
3200 builder: &mut FunctionBuilder,
3201) -> Value {
3202 if memarg.offset > 0 {
3203 assert!(builder.func.dfg.value_type(linear_mem_addr) == I32);
3204 let linear_mem_addr = builder.ins().uextend(I64, linear_mem_addr);
3205 let a = builder
3206 .ins()
3207 .iadd_imm_u(linear_mem_addr, memarg.offset as i64);
3208 let r = builder
3209 .ins()
3210 .icmp_imm_u(IntCC::UnsignedGreaterThanOrEqual, a, 0x1_0000_0000);
3211 builder.ins().trapnz(r, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
3212 builder.ins().ireduce(I32, a)
3213 } else {
3214 linear_mem_addr
3215 }
3216 }
3218
3219fn translate_atomic_rmw(
3220 widened_ty: Type,
3221 access_ty: Type,
3222 op: AtomicRmwOp,
3223 memarg: &MemArg,
3224 builder: &mut FunctionBuilder,
3225 state: &mut FuncTranslationState,
3226 environ: &mut FuncEnvironment<'_>,
3227) -> WasmResult<()> {
3228 let mut arg2 = state.pop1();
3229 let arg2_ty = builder.func.dfg.value_type(arg2);
3230
3231 match access_ty {
3234 I8 | I16 | I32 | I64 => {}
3235 _ => {
3236 return Err(wasm_unsupported!(
3237 "atomic_rmw: unsupported access type {:?}",
3238 access_ty
3239 ));
3240 }
3241 };
3242 let w_ty_ok = matches!(widened_ty, I32 | I64);
3243 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3244
3245 assert!(arg2_ty.bytes() >= access_ty.bytes());
3246 if arg2_ty.bytes() > access_ty.bytes() {
3247 arg2 = builder.ins().ireduce(access_ty, arg2);
3248 }
3249
3250 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3251 state,
3252 prepare_atomic_addr(
3253 memarg,
3254 u8::try_from(access_ty.bytes()).unwrap(),
3255 builder,
3256 state,
3257 environ,
3258 )?
3259 );
3260
3261 let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
3262 if access_ty != widened_ty {
3263 res = builder.ins().uextend(widened_ty, res);
3264 }
3265 state.push1(res);
3266 Ok(())
3267}
3268fn translate_atomic_cas(
3269 widened_ty: Type,
3270 access_ty: Type,
3271 memarg: &MemArg,
3272 builder: &mut FunctionBuilder,
3273 state: &mut FuncTranslationState,
3274 environ: &mut FuncEnvironment<'_>,
3275) -> WasmResult<()> {
3276 let (mut expected, mut replacement) = state.pop2();
3277 let expected_ty = builder.func.dfg.value_type(expected);
3278 let replacement_ty = builder.func.dfg.value_type(replacement);
3279
3280 match access_ty {
3283 I8 | I16 | I32 | I64 => {}
3284 _ => {
3285 return Err(wasm_unsupported!(
3286 "atomic_cas: unsupported access type {:?}",
3287 access_ty
3288 ));
3289 }
3290 };
3291 let w_ty_ok = matches!(widened_ty, I32 | I64);
3292 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3293
3294 assert!(expected_ty.bytes() >= access_ty.bytes());
3295 if expected_ty.bytes() > access_ty.bytes() {
3296 expected = builder.ins().ireduce(access_ty, expected);
3297 }
3298 assert!(replacement_ty.bytes() >= access_ty.bytes());
3299 if replacement_ty.bytes() > access_ty.bytes() {
3300 replacement = builder.ins().ireduce(access_ty, replacement);
3301 }
3302
3303 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3304 state,
3305 prepare_atomic_addr(
3306 memarg,
3307 u8::try_from(access_ty.bytes()).unwrap(),
3308 builder,
3309 state,
3310 environ,
3311 )?
3312 );
3313 let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
3314 if access_ty != widened_ty {
3315 res = builder.ins().uextend(widened_ty, res);
3316 }
3317 state.push1(res);
3318 Ok(())
3319}
3320
3321fn translate_atomic_load(
3322 widened_ty: Type,
3323 access_ty: Type,
3324 memarg: &MemArg,
3325 builder: &mut FunctionBuilder,
3326 state: &mut FuncTranslationState,
3327 environ: &mut FuncEnvironment<'_>,
3328) -> WasmResult<()> {
3329 match access_ty {
3332 I8 | I16 | I32 | I64 => {}
3333 _ => {
3334 return Err(wasm_unsupported!(
3335 "atomic_load: unsupported access type {:?}",
3336 access_ty
3337 ));
3338 }
3339 };
3340 let w_ty_ok = matches!(widened_ty, I32 | I64);
3341 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3342
3343 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3344 state,
3345 prepare_atomic_addr(
3346 memarg,
3347 u8::try_from(access_ty.bytes()).unwrap(),
3348 builder,
3349 state,
3350 environ,
3351 )?
3352 );
3353 let mut res = builder.ins().atomic_load(access_ty, flags, addr);
3354 if access_ty != widened_ty {
3355 res = builder.ins().uextend(widened_ty, res);
3356 }
3357 state.push1(res);
3358 Ok(())
3359}
3360
3361fn translate_atomic_store(
3362 access_ty: Type,
3363 memarg: &MemArg,
3364 builder: &mut FunctionBuilder,
3365 state: &mut FuncTranslationState,
3366 environ: &mut FuncEnvironment<'_>,
3367) -> WasmResult<()> {
3368 let mut data = state.pop1();
3369 let data_ty = builder.func.dfg.value_type(data);
3370
3371 match access_ty {
3374 I8 | I16 | I32 | I64 => {}
3375 _ => {
3376 return Err(wasm_unsupported!(
3377 "atomic_store: unsupported access type {:?}",
3378 access_ty
3379 ));
3380 }
3381 };
3382 let d_ty_ok = matches!(data_ty, I32 | I64);
3383 assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
3384
3385 if data_ty.bytes() > access_ty.bytes() {
3386 data = builder.ins().ireduce(access_ty, data);
3387 }
3388
3389 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3390 state,
3391 prepare_atomic_addr(
3392 memarg,
3393 u8::try_from(access_ty.bytes()).unwrap(),
3394 builder,
3395 state,
3396 environ,
3397 )?
3398 );
3399 builder.ins().atomic_store(flags, data, addr);
3400 Ok(())
3401}
3402
3403fn translate_vector_icmp(
3404 cc: IntCC,
3405 needed_type: Type,
3406 builder: &mut FunctionBuilder,
3407 state: &mut FuncTranslationState,
3408) {
3409 let (a, b) = state.pop2();
3410 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3411 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3412 state.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3413}
3414
3415fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3416 let (arg0, arg1) = state.pop2();
3417 let val = builder.ins().fcmp(cc, arg0, arg1);
3418 state.push1(builder.ins().uextend(I32, val));
3419}
3420
3421fn translate_vector_fcmp(
3422 cc: FloatCC,
3423 needed_type: Type,
3424 builder: &mut FunctionBuilder,
3425 state: &mut FuncTranslationState,
3426) {
3427 let (a, b) = state.pop2();
3428 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3429 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3430 state.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3431}
3432
3433fn translate_br_if(
3434 relative_depth: u32,
3435 builder: &mut FunctionBuilder,
3436 state: &mut FuncTranslationState,
3437) {
3438 let val = state.pop1();
3439 let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
3440 let next_block = builder.create_block();
3441 canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3442
3443 builder.seal_block(next_block); builder.switch_to_block(next_block);
3445}
3446
3447fn translate_br_if_args(
3448 relative_depth: u32,
3449 state: &mut FuncTranslationState,
3450) -> (ir::Block, &mut [ir::Value]) {
3451 let i = state.control_stack.len() - 1 - (relative_depth as usize);
3452 let (return_count, br_destination) = {
3453 let frame = &mut state.control_stack[i];
3454 frame.set_branched_to_exit();
3457 let return_count = if frame.is_loop() {
3458 frame.num_param_values()
3459 } else {
3460 frame.num_return_values()
3461 };
3462 (return_count, frame.br_destination())
3463 };
3464 let inputs = state.peekn_mut(return_count);
3465 (br_destination, inputs)
3466}
3467
3468fn type_of(operator: &Operator) -> Type {
3470 match operator {
3471 Operator::V128Load { .. }
3472 | Operator::V128Store { .. }
3473 | Operator::V128Const { .. }
3474 | Operator::V128Not
3475 | Operator::V128And
3476 | Operator::V128AndNot
3477 | Operator::V128Or
3478 | Operator::V128Xor
3479 | Operator::V128AnyTrue
3480 | Operator::V128Bitselect => I8X16, Operator::I8x16Shuffle { .. }
3483 | Operator::I8x16Splat
3484 | Operator::V128Load8Splat { .. }
3485 | Operator::V128Load8Lane { .. }
3486 | Operator::V128Store8Lane { .. }
3487 | Operator::I8x16ExtractLaneS { .. }
3488 | Operator::I8x16ExtractLaneU { .. }
3489 | Operator::I8x16ReplaceLane { .. }
3490 | Operator::I8x16RelaxedSwizzle
3491 | Operator::I8x16RelaxedLaneselect
3492 | Operator::I8x16Eq
3493 | Operator::I8x16Ne
3494 | Operator::I8x16LtS
3495 | Operator::I8x16LtU
3496 | Operator::I8x16GtS
3497 | Operator::I8x16GtU
3498 | Operator::I8x16LeS
3499 | Operator::I8x16LeU
3500 | Operator::I8x16GeS
3501 | Operator::I8x16GeU
3502 | Operator::I8x16Neg
3503 | Operator::I8x16Abs
3504 | Operator::I8x16AllTrue
3505 | Operator::I8x16Shl
3506 | Operator::I8x16ShrS
3507 | Operator::I8x16ShrU
3508 | Operator::I8x16Add
3509 | Operator::I8x16AddSatS
3510 | Operator::I8x16AddSatU
3511 | Operator::I8x16Sub
3512 | Operator::I8x16SubSatS
3513 | Operator::I8x16SubSatU
3514 | Operator::I8x16MinS
3515 | Operator::I8x16MinU
3516 | Operator::I8x16MaxS
3517 | Operator::I8x16MaxU
3518 | Operator::I8x16AvgrU
3519 | Operator::I8x16Bitmask
3520 | Operator::I8x16Popcnt => I8X16,
3521
3522 Operator::I16x8Splat
3523 | Operator::V128Load16Splat { .. }
3524 | Operator::V128Load16Lane { .. }
3525 | Operator::V128Store16Lane { .. }
3526 | Operator::I16x8ExtractLaneS { .. }
3527 | Operator::I16x8ExtractLaneU { .. }
3528 | Operator::I16x8ReplaceLane { .. }
3529 | Operator::I16x8RelaxedLaneselect
3530 | Operator::I16x8Eq
3531 | Operator::I16x8Ne
3532 | Operator::I16x8LtS
3533 | Operator::I16x8LtU
3534 | Operator::I16x8GtS
3535 | Operator::I16x8GtU
3536 | Operator::I16x8LeS
3537 | Operator::I16x8LeU
3538 | Operator::I16x8GeS
3539 | Operator::I16x8GeU
3540 | Operator::I16x8Neg
3541 | Operator::I16x8Abs
3542 | Operator::I16x8AllTrue
3543 | Operator::I16x8Shl
3544 | Operator::I16x8ShrS
3545 | Operator::I16x8ShrU
3546 | Operator::I16x8Add
3547 | Operator::I16x8AddSatS
3548 | Operator::I16x8AddSatU
3549 | Operator::I16x8Sub
3550 | Operator::I16x8SubSatS
3551 | Operator::I16x8SubSatU
3552 | Operator::I16x8MinS
3553 | Operator::I16x8MinU
3554 | Operator::I16x8MaxS
3555 | Operator::I16x8MaxU
3556 | Operator::I16x8AvgrU
3557 | Operator::I16x8Mul
3558 | Operator::I16x8RelaxedQ15mulrS
3559 | Operator::I16x8RelaxedDotI8x16I7x16S
3560 | Operator::I16x8Bitmask => I16X8,
3561
3562 Operator::I32x4Splat
3563 | Operator::V128Load32Splat { .. }
3564 | Operator::V128Load32Lane { .. }
3565 | Operator::V128Store32Lane { .. }
3566 | Operator::I32x4ExtractLane { .. }
3567 | Operator::I32x4ReplaceLane { .. }
3568 | Operator::I32x4RelaxedLaneselect
3569 | Operator::I32x4Eq
3570 | Operator::I32x4Ne
3571 | Operator::I32x4LtS
3572 | Operator::I32x4LtU
3573 | Operator::I32x4GtS
3574 | Operator::I32x4GtU
3575 | Operator::I32x4LeS
3576 | Operator::I32x4LeU
3577 | Operator::I32x4GeS
3578 | Operator::I32x4GeU
3579 | Operator::I32x4Neg
3580 | Operator::I32x4Abs
3581 | Operator::I32x4AllTrue
3582 | Operator::I32x4Shl
3583 | Operator::I32x4ShrS
3584 | Operator::I32x4ShrU
3585 | Operator::I32x4Add
3586 | Operator::I32x4Sub
3587 | Operator::I32x4Mul
3588 | Operator::I32x4MinS
3589 | Operator::I32x4MinU
3590 | Operator::I32x4MaxS
3591 | Operator::I32x4MaxU
3592 | Operator::I32x4Bitmask
3593 | Operator::I32x4TruncSatF32x4S
3594 | Operator::I32x4TruncSatF32x4U
3595 | Operator::I32x4RelaxedTruncF32x4S
3596 | Operator::I32x4RelaxedTruncF32x4U
3597 | Operator::I32x4RelaxedTruncF64x2SZero
3598 | Operator::I32x4RelaxedTruncF64x2UZero
3599 | Operator::I32x4RelaxedDotI8x16I7x16AddS
3600 | Operator::V128Load32Zero { .. } => I32X4,
3601
3602 Operator::I64x2Splat
3603 | Operator::V128Load64Splat { .. }
3604 | Operator::V128Load64Lane { .. }
3605 | Operator::V128Store64Lane { .. }
3606 | Operator::I64x2ExtractLane { .. }
3607 | Operator::I64x2ReplaceLane { .. }
3608 | Operator::I64x2RelaxedLaneselect
3609 | Operator::I64x2Eq
3610 | Operator::I64x2Ne
3611 | Operator::I64x2LtS
3612 | Operator::I64x2GtS
3613 | Operator::I64x2LeS
3614 | Operator::I64x2GeS
3615 | Operator::I64x2Neg
3616 | Operator::I64x2Abs
3617 | Operator::I64x2AllTrue
3618 | Operator::I64x2Shl
3619 | Operator::I64x2ShrS
3620 | Operator::I64x2ShrU
3621 | Operator::I64x2Add
3622 | Operator::I64x2Sub
3623 | Operator::I64x2Mul
3624 | Operator::I64x2Bitmask
3625 | Operator::V128Load64Zero { .. } => I64X2,
3626
3627 Operator::F32x4Splat
3628 | Operator::F32x4ExtractLane { .. }
3629 | Operator::F32x4ReplaceLane { .. }
3630 | Operator::F32x4Eq
3631 | Operator::F32x4Ne
3632 | Operator::F32x4Lt
3633 | Operator::F32x4Gt
3634 | Operator::F32x4Le
3635 | Operator::F32x4Ge
3636 | Operator::F32x4Abs
3637 | Operator::F32x4Neg
3638 | Operator::F32x4Sqrt
3639 | Operator::F32x4Add
3640 | Operator::F32x4Sub
3641 | Operator::F32x4Mul
3642 | Operator::F32x4Div
3643 | Operator::F32x4Min
3644 | Operator::F32x4Max
3645 | Operator::F32x4PMin
3646 | Operator::F32x4PMax
3647 | Operator::F32x4RelaxedMin
3648 | Operator::F32x4RelaxedMax
3649 | Operator::F32x4RelaxedMadd
3650 | Operator::F32x4RelaxedNmadd
3651 | Operator::F32x4ConvertI32x4S
3652 | Operator::F32x4ConvertI32x4U
3653 | Operator::F32x4Ceil
3654 | Operator::F32x4Floor
3655 | Operator::F32x4Trunc
3656 | Operator::F32x4Nearest => F32X4,
3657
3658 Operator::F64x2Splat
3659 | Operator::F64x2ExtractLane { .. }
3660 | Operator::F64x2ReplaceLane { .. }
3661 | Operator::F64x2Eq
3662 | Operator::F64x2Ne
3663 | Operator::F64x2Lt
3664 | Operator::F64x2Gt
3665 | Operator::F64x2Le
3666 | Operator::F64x2Ge
3667 | Operator::F64x2Abs
3668 | Operator::F64x2Neg
3669 | Operator::F64x2Sqrt
3670 | Operator::F64x2Add
3671 | Operator::F64x2Sub
3672 | Operator::F64x2Mul
3673 | Operator::F64x2Div
3674 | Operator::F64x2Min
3675 | Operator::F64x2Max
3676 | Operator::F64x2PMin
3677 | Operator::F64x2PMax
3678 | Operator::F64x2RelaxedMin
3679 | Operator::F64x2RelaxedMax
3680 | Operator::F64x2RelaxedMadd
3681 | Operator::F64x2RelaxedNmadd
3682 | Operator::F64x2Ceil
3683 | Operator::F64x2Floor
3684 | Operator::F64x2Trunc
3685 | Operator::F64x2Nearest => F64X2,
3686
3687 _ => unimplemented!(
3688 "Currently only SIMD instructions are mapped to their return type; the \
3689 following instruction is not mapped: {:?}",
3690 operator
3691 ),
3692 }
3693}
3694
3695fn optionally_bitcast_vector(
3698 value: Value,
3699 needed_type: Type,
3700 builder: &mut FunctionBuilder,
3701) -> Value {
3702 if builder.func.dfg.value_type(value) != needed_type {
3703 builder.ins().bitcast(
3704 needed_type,
3705 MemFlagsData::new().with_endianness(ir::Endianness::Little),
3706 value,
3707 )
3708 } else {
3709 value
3710 }
3711}
3712
3713#[inline(always)]
3714fn is_non_canonical_v128(ty: ir::Type) -> bool {
3715 matches!(ty, I64X2 | I32X4 | I16X8 | F32X4 | F64X2)
3716}
3717
3718fn canonicalise_v128_values<'a>(
3723 tmp_canonicalised: &'a mut SmallVec<[ir::BlockArg; 16]>,
3724 builder: &mut FunctionBuilder,
3725 values: &'a [ir::Value],
3726) -> &'a [ir::BlockArg] {
3727 debug_assert!(tmp_canonicalised.is_empty());
3728 for v in values {
3729 let value = if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
3730 builder.ins().bitcast(
3731 I8X16,
3732 MemFlagsData::new().with_endianness(ir::Endianness::Little),
3733 *v,
3734 )
3735 } else {
3736 *v
3737 };
3738 tmp_canonicalised.push(BlockArg::from(value));
3739 }
3740 tmp_canonicalised.as_slice()
3741}
3742
3743fn canonicalise_then_jump(
3747 builder: &mut FunctionBuilder,
3748 destination: ir::Block,
3749 params: &[ir::Value],
3750) -> ir::Inst {
3751 let mut tmp_canonicalised = SmallVec::<[_; 16]>::new();
3752 let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
3753 builder.ins().jump(destination, canonicalised)
3754}
3755
3756fn canonicalise_brif(
3758 builder: &mut FunctionBuilder,
3759 cond: ir::Value,
3760 block_then: ir::Block,
3761 params_then: &[ir::Value],
3762 block_else: ir::Block,
3763 params_else: &[ir::Value],
3764) -> ir::Inst {
3765 let mut tmp_canonicalised_then = SmallVec::<[_; 16]>::new();
3766 let canonicalised_then =
3767 canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
3768 let mut tmp_canonicalised_else = SmallVec::<[_; 16]>::new();
3769 let canonicalised_else =
3770 canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
3771 builder.ins().brif(
3772 cond,
3773 block_then,
3774 canonicalised_then,
3775 block_else,
3776 canonicalised_else,
3777 )
3778}
3779
3780fn pop1_with_bitcast(
3784 state: &mut FuncTranslationState,
3785 needed_type: Type,
3786 builder: &mut FunctionBuilder,
3787) -> Value {
3788 optionally_bitcast_vector(state.pop1(), needed_type, builder)
3789}
3790
3791fn pop2_with_bitcast(
3795 state: &mut FuncTranslationState,
3796 needed_type: Type,
3797 builder: &mut FunctionBuilder,
3798) -> (Value, Value) {
3799 let (a, b) = state.pop2();
3800 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3801 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3802 (bitcast_a, bitcast_b)
3803}
3804
3805pub fn bitcast_arguments<'a>(
3806 builder: &FunctionBuilder,
3807 arguments: &'a mut [Value],
3808 params: &[ir::AbiParam],
3809 param_predicate: impl Fn(usize) -> bool,
3810) -> Vec<(Type, &'a mut Value)> {
3811 let filtered_param_types = params
3812 .iter()
3813 .enumerate()
3814 .filter(|(i, _)| param_predicate(*i))
3815 .map(|(_, param)| param.value_type);
3816
3817 let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
3821
3822 pairs
3825 .filter(|(param_type, _)| param_type.is_vector())
3826 .filter(|(param_type, arg)| {
3827 let arg_type = builder.func.dfg.value_type(**arg);
3828 assert!(
3829 arg_type.is_vector(),
3830 "unexpected type mismatch: expected {}, argument {} was actually of type {}",
3831 param_type,
3832 *arg,
3833 arg_type
3834 );
3835
3836 arg_type != *param_type
3840 })
3841 .collect()
3842}
3843
3844pub fn bitcast_wasm_params(
3846 environ: &mut FuncEnvironment<'_>,
3847 callee_signature: ir::SigRef,
3848 arguments: &mut [Value],
3849 builder: &mut FunctionBuilder,
3850) {
3851 let callee_signature = &builder.func.dfg.signatures[callee_signature];
3852 let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
3853 environ.is_wasm_parameter(callee_signature, i)
3854 });
3855 for (t, arg) in changes {
3856 let mut flags = MemFlagsData::new();
3857 flags.set_endianness(ir::Endianness::Little);
3858 *arg = builder.ins().bitcast(t, flags, *arg);
3859 }
3860}
3861
3862#[derive(Debug, Clone)]
3863pub(crate) struct CatchClause {
3864 pub(crate) wasm_tag: Option<u32>,
3865 pub(crate) tag_value: i32,
3866 pub(crate) block: ir::Block,
3867}
3868
3869fn create_catch_block(
3870 builder: &mut FunctionBuilder,
3871 state: &mut FuncTranslationState,
3872 catch: &wasmparser::Catch,
3873 environ: &mut FuncEnvironment<'_>,
3874) -> WasmResult<CatchClause> {
3875 let (is_ref, wasm_tag, label) = match catch {
3876 wasmparser::Catch::One { tag, label } => (false, Some(*tag), *label),
3877 wasmparser::Catch::OneRef { tag, label } => (true, Some(*tag), *label),
3878 wasmparser::Catch::All { label } => (false, None, *label),
3879 wasmparser::Catch::AllRef { label } => (true, None, *label),
3880 };
3881
3882 let tag_value = wasm_tag.map_or(CATCH_ALL_TAG_VALUE, |t| t as i32);
3883
3884 let block = builder.create_block();
3885 let exnref = builder.append_block_param(block, EXN_REF_TYPE);
3886
3887 builder.switch_to_block(block);
3888
3889 let mut params = SmallVec::<[Value; 4]>::new();
3890 if let Some(tag) = wasm_tag {
3891 let tag_index = TagIndex::from_u32(tag);
3892 params.extend(environ.translate_exn_unbox(builder, tag_index, exnref)?);
3893 }
3894 if is_ref {
3895 params.push(exnref);
3896 }
3897
3898 let depth = label as usize;
3899 let idx = state.control_stack.len() - 1 - depth;
3900 let frame = &mut state.control_stack[idx];
3901 frame.set_branched_to_exit();
3902 canonicalise_then_jump(builder, frame.br_destination(), params.as_slice());
3903
3904 Ok(CatchClause {
3905 wasm_tag,
3906 tag_value,
3907 block,
3908 })
3909}
3910
3911fn create_dispatch_block(
3912 builder: &mut FunctionBuilder,
3913 environ: &mut FuncEnvironment<'_>,
3914 clauses: impl Iterator<Item = CatchClause>,
3915) -> WasmResult<ir::Block> {
3916 let clauses = clauses.collect_vec();
3917
3918 let catch_block = builder.create_block();
3919 let exn_ptr = builder.append_block_param(catch_block, environ.reference_type());
3920 let pre_selector = builder.append_block_param(catch_block, I64);
3921 let catch_all_block = builder.create_block();
3922 let catch_one_block = builder.create_block();
3923 let dispatch_block = builder.create_block();
3924
3925 builder.switch_to_block(catch_block);
3926 let catch_all_tag = builder.ins().iconst(I64, 0);
3927 let matches = builder
3928 .ins()
3929 .icmp(IntCC::Equal, pre_selector, catch_all_tag);
3930 canonicalise_brif(builder, matches, catch_all_block, &[], catch_one_block, &[]);
3931
3932 builder.switch_to_block(catch_all_block);
3933 let catch_all_tag = builder
3934 .ins()
3935 .iconst(TAG_TYPE, i64::from(CATCH_ALL_TAG_VALUE));
3936 canonicalise_then_jump(builder, dispatch_block, &[catch_all_tag]);
3937 builder.seal_block(catch_all_block);
3938
3939 builder.switch_to_block(catch_one_block);
3940 let selector = environ.translate_exn_personality_selector(builder, exn_ptr)?;
3941 canonicalise_then_jump(builder, dispatch_block, &[selector]);
3942 builder.seal_block(catch_one_block);
3943
3944 builder.switch_to_block(dispatch_block);
3945 let selector = builder.append_block_param(dispatch_block, TAG_TYPE);
3946 let exnref = environ.translate_exn_pointer_to_ref(builder, exn_ptr)?;
3947
3948 let rethrow_block = builder.create_block();
3949 builder.append_block_param(rethrow_block, EXN_REF_TYPE);
3950
3951 let mut current_selector = selector;
3952 let mut current_exn = exnref;
3953
3954 for (idx, clause) in clauses.iter().enumerate() {
3955 let tag_value = builder.ins().iconst(TAG_TYPE, i64::from(clause.tag_value));
3956 let matches = builder
3957 .ins()
3958 .icmp(IntCC::Equal, current_selector, tag_value);
3959
3960 if idx + 1 == clauses.len() {
3961 canonicalise_brif(
3962 builder,
3963 matches,
3964 clause.block,
3965 &[current_exn],
3966 rethrow_block,
3967 &[exnref],
3968 );
3969 } else {
3970 let continue_block = builder.create_block();
3971 builder.append_block_param(continue_block, TAG_TYPE);
3972 builder.append_block_param(continue_block, EXN_REF_TYPE);
3973
3974 canonicalise_brif(
3975 builder,
3976 matches,
3977 clause.block,
3978 &[current_exn],
3979 continue_block,
3980 &[current_selector, current_exn],
3981 );
3982
3983 builder.seal_block(continue_block);
3984 builder.switch_to_block(continue_block);
3985 let params = builder.func.dfg.block_params(continue_block);
3986 current_selector = params[0];
3987 current_exn = params[1];
3988 }
3989 }
3990 builder.seal_block(dispatch_block);
3991
3992 builder.switch_to_block(rethrow_block);
3993 let rethrow_exn = builder.func.dfg.block_params(rethrow_block)[0];
3994 environ.translate_exn_reraise_unmatched(builder, rethrow_exn)?;
3995 builder.seal_block(rethrow_block);
3996
3997 Ok(catch_block)
3998}