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