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