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