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