1use crate::Reachability;
75use crate::bounds_checks::{BoundsCheck, bounds_check_and_compute_addr};
76use crate::func_environ::{Extension, FuncEnvironment};
77use crate::translate::TargetEnvironment;
78use crate::translate::environ::StructFieldsVec;
79use crate::translate::stack::{ControlStackFrame, ElseData, FuncTranslationStacks};
80use crate::translate::translation_utils::{
81 block_with_params, blocktype_params_results, f32_translation, f64_translation,
82};
83use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
84use cranelift_codegen::ir::immediates::Offset32;
85use cranelift_codegen::ir::{
86 self, AtomicRmwOp, ExceptionTag, InstBuilder, JumpTableData, MemFlags, Value, ValueLabel,
87};
88use cranelift_codegen::ir::{BlockArg, types::*};
89use cranelift_codegen::packed_option::ReservedValue;
90use cranelift_frontend::{FunctionBuilder, Variable};
91use itertools::Itertools;
92use smallvec::{SmallVec, ToSmallVec};
93use std::collections::{HashMap, hash_map};
94use std::vec::Vec;
95use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
96use wasmtime_environ::{
97 DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TagIndex, TypeConvert,
98 TypeIndex, WasmHeapType, WasmRefType, WasmResult, WasmValType, wasm_unsupported,
99};
100
101macro_rules! unwrap_or_return_unreachable_state {
108 ($state:ident, $value:expr) => {
109 match $value {
110 Reachability::Reachable(x) => x,
111 Reachability::Unreachable => {
112 $state.reachable = false;
113 return Ok(());
114 }
115 }
116 };
117}
118
119pub fn translate_operator(
121 validator: &mut FuncValidator<impl WasmModuleResources>,
122 op: &Operator,
123 operand_types: Option<&[WasmValType]>,
124 builder: &mut FunctionBuilder,
125 stack: &mut FuncTranslationStacks,
126 environ: &mut FuncEnvironment<'_>,
127) -> WasmResult<()> {
128 log::trace!("Translating Wasm opcode: {op:?}");
129
130 if !stack.reachable {
131 translate_unreachable_operator(validator, &op, builder, stack, environ)?;
132 return Ok(());
133 }
134
135 debug_assert!(!builder.is_unreachable());
137
138 let operand_types = operand_types.unwrap_or_else(|| {
139 panic!("should always have operand types available for valid, reachable ops; op = {op:?}")
140 });
141
142 match op {
144 Operator::LocalGet { local_index } => {
149 let val = builder.use_var(Variable::from_u32(*local_index));
150 stack.push1(val);
151 let label = ValueLabel::from_u32(*local_index);
152 builder.set_val_label(val, label);
153 }
154 Operator::LocalSet { local_index } => {
155 let mut val = stack.pop1();
156
157 let ty = builder.func.dfg.value_type(val);
159 if ty.is_vector() {
160 val = optionally_bitcast_vector(val, I8X16, builder);
161 }
162
163 builder.def_var(Variable::from_u32(*local_index), val);
164 let label = ValueLabel::from_u32(*local_index);
165 builder.set_val_label(val, label);
166 }
167 Operator::LocalTee { local_index } => {
168 let mut val = stack.peek1();
169
170 let ty = builder.func.dfg.value_type(val);
172 if ty.is_vector() {
173 val = optionally_bitcast_vector(val, I8X16, builder);
174 }
175
176 builder.def_var(Variable::from_u32(*local_index), val);
177 let label = ValueLabel::from_u32(*local_index);
178 builder.set_val_label(val, label);
179 }
180 Operator::GlobalGet { global_index } => {
184 let global_index = GlobalIndex::from_u32(*global_index);
185 let val = environ.translate_global_get(builder, global_index)?;
186 stack.push1(val);
187 }
188 Operator::GlobalSet { global_index } => {
189 let global_index = GlobalIndex::from_u32(*global_index);
190 let mut val = stack.pop1();
191 if builder.func.dfg.value_type(val).is_vector() {
193 val = optionally_bitcast_vector(val, I8X16, builder);
194 }
195 environ.translate_global_set(builder, global_index, val)?;
196 }
197 Operator::Drop => {
201 stack.pop1();
202 }
203 Operator::Select => {
204 let (mut arg1, mut arg2, cond) = stack.pop3();
205 if builder.func.dfg.value_type(arg1).is_vector() {
206 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
207 }
208 if builder.func.dfg.value_type(arg2).is_vector() {
209 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
210 }
211 stack.push1(builder.ins().select(cond, arg1, arg2));
212 }
213 Operator::TypedSelect { ty: _ } => {
214 let (mut arg1, mut arg2, cond) = stack.pop3();
218 if builder.func.dfg.value_type(arg1).is_vector() {
219 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
220 }
221 if builder.func.dfg.value_type(arg2).is_vector() {
222 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
223 }
224 stack.push1(builder.ins().select(cond, arg1, arg2));
225 }
226 Operator::Nop => {
227 }
229 Operator::Unreachable => {
230 environ.trap(builder, crate::TRAP_UNREACHABLE);
231 stack.reachable = false;
232 }
233 Operator::Block { blockty } => {
245 let (params, results) = blocktype_params_results(validator, *blockty)?;
246 let next = block_with_params(builder, results.clone(), environ)?;
247 stack.push_block(next, params.len(), results.len());
248 }
249 Operator::Loop { blockty } => {
250 let (params, results) = blocktype_params_results(validator, *blockty)?;
251 let loop_body = block_with_params(builder, params.clone(), environ)?;
252 let next = block_with_params(builder, results.clone(), environ)?;
253 canonicalise_then_jump(builder, loop_body, stack.peekn(params.len()));
254 stack.push_loop(loop_body, next, params.len(), results.len());
255
256 stack.popn(params.len());
259 stack
260 .stack
261 .extend_from_slice(builder.block_params(loop_body));
262
263 builder.switch_to_block(loop_body);
264 environ.translate_loop_header(builder)?;
265 }
266 Operator::If { blockty } => {
267 let val = stack.pop1();
268
269 let next_block = builder.create_block();
270 let (params, results) = blocktype_params_results(validator, *blockty)?;
271 let (destination, else_data) = if params.clone().eq(results.clone()) {
272 let destination = block_with_params(builder, results.clone(), environ)?;
279 let branch_inst = canonicalise_brif(
280 builder,
281 val,
282 next_block,
283 &[],
284 destination,
285 stack.peekn(params.len()),
286 );
287 (
288 destination,
289 ElseData::NoElse {
290 branch_inst,
291 placeholder: destination,
292 },
293 )
294 } else {
295 let destination = block_with_params(builder, results.clone(), environ)?;
298 let else_block = block_with_params(builder, params.clone(), environ)?;
299 canonicalise_brif(
300 builder,
301 val,
302 next_block,
303 &[],
304 else_block,
305 stack.peekn(params.len()),
306 );
307 builder.seal_block(else_block);
308 (destination, ElseData::WithElse { else_block })
309 };
310
311 builder.seal_block(next_block); builder.switch_to_block(next_block);
313
314 stack.push_if(
321 destination,
322 else_data,
323 params.len(),
324 results.len(),
325 *blockty,
326 );
327 }
328 Operator::Else => {
329 let i = stack.control_stack.len() - 1;
330 match stack.control_stack[i] {
331 ControlStackFrame::If {
332 ref else_data,
333 head_is_reachable,
334 ref mut consequent_ends_reachable,
335 num_return_values,
336 blocktype,
337 destination,
338 ..
339 } => {
340 debug_assert!(consequent_ends_reachable.is_none());
343 *consequent_ends_reachable = Some(stack.reachable);
344
345 if head_is_reachable {
346 stack.reachable = true;
348
349 let else_block = match *else_data {
352 ElseData::NoElse {
353 branch_inst,
354 placeholder,
355 } => {
356 let (params, _results) =
357 blocktype_params_results(validator, blocktype)?;
358 debug_assert_eq!(params.len(), num_return_values);
359 let else_block =
360 block_with_params(builder, params.clone(), environ)?;
361 canonicalise_then_jump(
362 builder,
363 destination,
364 stack.peekn(params.len()),
365 );
366 stack.popn(params.len());
367
368 builder.change_jump_destination(
369 branch_inst,
370 placeholder,
371 else_block,
372 );
373 builder.seal_block(else_block);
374 else_block
375 }
376 ElseData::WithElse { else_block } => {
377 canonicalise_then_jump(
378 builder,
379 destination,
380 stack.peekn(num_return_values),
381 );
382 stack.popn(num_return_values);
383 else_block
384 }
385 };
386
387 builder.switch_to_block(else_block);
398
399 }
402 }
403 _ => unreachable!(),
404 }
405 }
406 Operator::End => {
407 let frame = stack.control_stack.pop().unwrap();
408 let next_block = frame.following_code();
409 let return_count = frame.num_return_values();
410 let return_args = stack.peekn_mut(return_count);
411
412 canonicalise_then_jump(builder, next_block, return_args);
413 builder.switch_to_block(next_block);
421 builder.seal_block(next_block);
422
423 if let ControlStackFrame::Loop { header, .. } = frame {
425 builder.seal_block(header)
426 }
427
428 frame.restore_catch_handlers(&mut stack.handlers, builder);
429
430 frame.truncate_value_stack_to_original_size(&mut stack.stack);
431 stack
432 .stack
433 .extend_from_slice(builder.block_params(next_block));
434 }
435 Operator::Br { relative_depth } => {
457 let i = stack.control_stack.len() - 1 - (*relative_depth as usize);
458 let (return_count, br_destination) = {
459 let frame = &mut stack.control_stack[i];
460 frame.set_branched_to_exit();
462 let return_count = if frame.is_loop() {
463 frame.num_param_values()
464 } else {
465 frame.num_return_values()
466 };
467 (return_count, frame.br_destination())
468 };
469 let destination_args = stack.peekn_mut(return_count);
470 canonicalise_then_jump(builder, br_destination, destination_args);
471 stack.popn(return_count);
472 stack.reachable = false;
473 }
474 Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, stack),
475 Operator::BrTable { targets } => {
476 let default = targets.default();
477 let mut min_depth = default;
478 for depth in targets.targets() {
479 let depth = depth?;
480 if depth < min_depth {
481 min_depth = depth;
482 }
483 }
484 let jump_args_count = {
485 let i = stack.control_stack.len() - 1 - (min_depth as usize);
486 let min_depth_frame = &stack.control_stack[i];
487 if min_depth_frame.is_loop() {
488 min_depth_frame.num_param_values()
489 } else {
490 min_depth_frame.num_return_values()
491 }
492 };
493 let val = stack.pop1();
494 let mut data = Vec::with_capacity(targets.len() as usize);
495 if jump_args_count == 0 {
496 for depth in targets.targets() {
498 let depth = depth?;
499 let block = {
500 let i = stack.control_stack.len() - 1 - (depth as usize);
501 let frame = &mut stack.control_stack[i];
502 frame.set_branched_to_exit();
503 frame.br_destination()
504 };
505 data.push(builder.func.dfg.block_call(block, &[]));
506 }
507 let block = {
508 let i = stack.control_stack.len() - 1 - (default as usize);
509 let frame = &mut stack.control_stack[i];
510 frame.set_branched_to_exit();
511 frame.br_destination()
512 };
513 let block = builder.func.dfg.block_call(block, &[]);
514 let jt = builder.create_jump_table(JumpTableData::new(block, &data));
515 builder.ins().br_table(val, jt);
516 } else {
517 let return_count = jump_args_count;
520 let mut dest_block_sequence = vec![];
521 let mut dest_block_map = HashMap::new();
522 for depth in targets.targets() {
523 let depth = depth?;
524 let branch_block = match dest_block_map.entry(depth as usize) {
525 hash_map::Entry::Occupied(entry) => *entry.get(),
526 hash_map::Entry::Vacant(entry) => {
527 let block = builder.create_block();
528 dest_block_sequence.push((depth as usize, block));
529 *entry.insert(block)
530 }
531 };
532 data.push(builder.func.dfg.block_call(branch_block, &[]));
533 }
534 let default_branch_block = match dest_block_map.entry(default as usize) {
535 hash_map::Entry::Occupied(entry) => *entry.get(),
536 hash_map::Entry::Vacant(entry) => {
537 let block = builder.create_block();
538 dest_block_sequence.push((default as usize, block));
539 *entry.insert(block)
540 }
541 };
542 let default_branch_block = builder.func.dfg.block_call(default_branch_block, &[]);
543 let jt = builder.create_jump_table(JumpTableData::new(default_branch_block, &data));
544 builder.ins().br_table(val, jt);
545 for (depth, dest_block) in dest_block_sequence {
546 builder.switch_to_block(dest_block);
547 builder.seal_block(dest_block);
548 let real_dest_block = {
549 let i = stack.control_stack.len() - 1 - depth;
550 let frame = &mut stack.control_stack[i];
551 frame.set_branched_to_exit();
552 frame.br_destination()
553 };
554 let destination_args = stack.peekn_mut(return_count);
555 canonicalise_then_jump(builder, real_dest_block, destination_args);
556 }
557 stack.popn(return_count);
558 }
559 stack.reachable = false;
560 }
561 Operator::Return => {
562 let return_count = {
563 let frame = &mut stack.control_stack[0];
564 frame.num_return_values()
565 };
566 {
567 let return_args = stack.peekn_mut(return_count);
568 environ.handle_before_return(&return_args, builder);
569 bitcast_wasm_returns(return_args, builder);
570 builder.ins().return_(return_args);
571 }
572 stack.popn(return_count);
573 stack.reachable = false;
574 }
575 Operator::Catch { .. }
577 | Operator::Rethrow { .. }
578 | Operator::Delegate { .. }
579 | Operator::CatchAll => {
580 return Err(wasm_unsupported!(
581 "legacy exception handling proposal is not supported"
582 ));
583 }
584
585 Operator::TryTable { try_table } => {
586 let body = builder.create_block();
590 let (params, results) = blocktype_params_results(validator, try_table.ty)?;
591 let next = block_with_params(builder, results.clone(), environ)?;
592 builder.ins().jump(body, []);
593 builder.seal_block(body);
594
595 let ckpt = stack.handlers.take_checkpoint();
600 let mut catch_blocks = vec![];
601 for catch in try_table.catches.iter().rev() {
607 catch_blocks.push(create_catch_block(builder, stack, catch, environ)?);
610 }
611
612 stack.push_try_table_block(next, catch_blocks, params.len(), results.len(), ckpt);
613
614 builder.switch_to_block(body);
616 }
617
618 Operator::Throw { tag_index } => {
619 let tag_index = TagIndex::from_u32(*tag_index);
620 let arity = environ.tag_param_arity(tag_index);
621 let args = stack.peekn(arity);
622 environ.translate_exn_throw(builder, tag_index, args, stack.handlers.handlers())?;
623 stack.popn(arity);
624 stack.reachable = false;
625 }
626
627 Operator::ThrowRef => {
628 let exnref = stack.pop1();
629 environ.translate_exn_throw_ref(builder, exnref, stack.handlers.handlers())?;
630 stack.reachable = false;
631 }
632
633 Operator::Call { function_index } => {
639 let function_index = FuncIndex::from_u32(*function_index);
640 let ty = environ.module.functions[function_index]
641 .signature
642 .unwrap_module_type_index();
643 let sig_ref = environ.get_or_create_interned_sig_ref(builder.func, ty);
644 let num_args = environ.num_params_for_func(function_index);
645
646 let args = stack.peekn_mut(num_args);
648 bitcast_wasm_params(environ, sig_ref, args, builder);
649 let args = stack.peekn(num_args); let inst_results = environ.translate_call(
652 builder,
653 function_index,
654 sig_ref,
655 args,
656 stack.handlers.handlers(),
657 )?;
658
659 debug_assert_eq!(
660 inst_results.len(),
661 builder.func.dfg.signatures[sig_ref].returns.len(),
662 "translate_call results should match the call signature"
663 );
664 stack.popn(num_args);
665 stack.pushn(&inst_results);
666 }
667 Operator::CallIndirect {
668 type_index,
669 table_index,
670 } => {
671 let type_index = TypeIndex::from_u32(*type_index);
675 let sigref = environ.get_or_create_sig_ref(builder.func, type_index);
676 let num_args = environ.num_params_for_function_type(type_index);
677 let callee = stack.pop1();
678
679 let args = stack.peekn_mut(num_args);
681 bitcast_wasm_params(environ, sigref, args, builder);
682
683 let inst_results = environ.translate_call_indirect(
684 builder,
685 validator.features(),
686 TableIndex::from_u32(*table_index),
687 type_index,
688 sigref,
689 callee,
690 stack.peekn(num_args),
691 stack.handlers.handlers(),
692 )?;
693 let inst_results = match inst_results {
694 Some(results) => results,
695 None => {
696 stack.reachable = false;
697 return Ok(());
698 }
699 };
700
701 debug_assert_eq!(
702 inst_results.len(),
703 builder.func.dfg.signatures[sigref].returns.len(),
704 "translate_call_indirect results should match the call signature"
705 );
706 stack.popn(num_args);
707 stack.pushn(&inst_results);
708 }
709 Operator::ReturnCall { function_index } => {
717 let function_index = FuncIndex::from_u32(*function_index);
718 let ty = environ.module.functions[function_index]
719 .signature
720 .unwrap_module_type_index();
721 let sig_ref = environ.get_or_create_interned_sig_ref(builder.func, ty);
722 let num_args = environ.num_params_for_func(function_index);
723
724 let args = stack.peekn_mut(num_args);
726 bitcast_wasm_params(environ, sig_ref, args, builder);
727
728 environ.translate_return_call(builder, function_index, sig_ref, args)?;
729
730 stack.popn(num_args);
731 stack.reachable = false;
732 }
733 Operator::ReturnCallIndirect {
734 type_index,
735 table_index,
736 } => {
737 let type_index = TypeIndex::from_u32(*type_index);
741 let sigref = environ.get_or_create_sig_ref(builder.func, type_index);
742 let num_args = environ.num_params_for_function_type(type_index);
743 let callee = stack.pop1();
744
745 let args = stack.peekn_mut(num_args);
747 bitcast_wasm_params(environ, sigref, args, builder);
748
749 environ.translate_return_call_indirect(
750 builder,
751 validator.features(),
752 TableIndex::from_u32(*table_index),
753 type_index,
754 sigref,
755 callee,
756 stack.peekn(num_args),
757 )?;
758
759 stack.popn(num_args);
760 stack.reachable = false;
761 }
762 Operator::ReturnCallRef { type_index } => {
763 let type_index = TypeIndex::from_u32(*type_index);
767 let sigref = environ.get_or_create_sig_ref(builder.func, type_index);
768 let num_args = environ.num_params_for_function_type(type_index);
769 let callee = stack.pop1();
770
771 let args = stack.peekn_mut(num_args);
773 bitcast_wasm_params(environ, sigref, args, builder);
774
775 environ.translate_return_call_ref(builder, sigref, callee, stack.peekn(num_args))?;
776
777 stack.popn(num_args);
778 stack.reachable = false;
779 }
780 Operator::MemoryGrow { mem } => {
785 let mem = MemoryIndex::from_u32(*mem);
788 let _heap = environ.get_or_create_heap(builder.func, mem);
789 let val = stack.pop1();
790 environ.before_memory_grow(builder, val, mem);
791 stack.push1(environ.translate_memory_grow(builder, mem, val)?)
792 }
793 Operator::MemorySize { mem } => {
794 let mem = MemoryIndex::from_u32(*mem);
795 let _heap = environ.get_or_create_heap(builder.func, mem);
796 stack.push1(environ.translate_memory_size(builder.cursor(), mem)?);
797 }
798 Operator::I32Load8U { memarg } => {
803 unwrap_or_return_unreachable_state!(
804 stack,
805 translate_load(memarg, ir::Opcode::Uload8, I32, builder, stack, environ)?
806 );
807 }
808 Operator::I32Load16U { memarg } => {
809 unwrap_or_return_unreachable_state!(
810 stack,
811 translate_load(memarg, ir::Opcode::Uload16, I32, builder, stack, environ)?
812 );
813 }
814 Operator::I32Load8S { memarg } => {
815 unwrap_or_return_unreachable_state!(
816 stack,
817 translate_load(memarg, ir::Opcode::Sload8, I32, builder, stack, environ)?
818 );
819 }
820 Operator::I32Load16S { memarg } => {
821 unwrap_or_return_unreachable_state!(
822 stack,
823 translate_load(memarg, ir::Opcode::Sload16, I32, builder, stack, environ)?
824 );
825 }
826 Operator::I64Load8U { memarg } => {
827 unwrap_or_return_unreachable_state!(
828 stack,
829 translate_load(memarg, ir::Opcode::Uload8, I64, builder, stack, environ)?
830 );
831 }
832 Operator::I64Load16U { memarg } => {
833 unwrap_or_return_unreachable_state!(
834 stack,
835 translate_load(memarg, ir::Opcode::Uload16, I64, builder, stack, environ)?
836 );
837 }
838 Operator::I64Load8S { memarg } => {
839 unwrap_or_return_unreachable_state!(
840 stack,
841 translate_load(memarg, ir::Opcode::Sload8, I64, builder, stack, environ)?
842 );
843 }
844 Operator::I64Load16S { memarg } => {
845 unwrap_or_return_unreachable_state!(
846 stack,
847 translate_load(memarg, ir::Opcode::Sload16, I64, builder, stack, environ)?
848 );
849 }
850 Operator::I64Load32S { memarg } => {
851 unwrap_or_return_unreachable_state!(
852 stack,
853 translate_load(memarg, ir::Opcode::Sload32, I64, builder, stack, environ)?
854 );
855 }
856 Operator::I64Load32U { memarg } => {
857 unwrap_or_return_unreachable_state!(
858 stack,
859 translate_load(memarg, ir::Opcode::Uload32, I64, builder, stack, environ)?
860 );
861 }
862 Operator::I32Load { memarg } => {
863 unwrap_or_return_unreachable_state!(
864 stack,
865 translate_load(memarg, ir::Opcode::Load, I32, builder, stack, environ)?
866 );
867 }
868 Operator::F32Load { memarg } => {
869 unwrap_or_return_unreachable_state!(
870 stack,
871 translate_load(memarg, ir::Opcode::Load, F32, builder, stack, environ)?
872 );
873 }
874 Operator::I64Load { memarg } => {
875 unwrap_or_return_unreachable_state!(
876 stack,
877 translate_load(memarg, ir::Opcode::Load, I64, builder, stack, environ)?
878 );
879 }
880 Operator::F64Load { memarg } => {
881 unwrap_or_return_unreachable_state!(
882 stack,
883 translate_load(memarg, ir::Opcode::Load, F64, builder, stack, environ)?
884 );
885 }
886 Operator::V128Load { memarg } => {
887 unwrap_or_return_unreachable_state!(
888 stack,
889 translate_load(memarg, ir::Opcode::Load, I8X16, builder, stack, environ)?
890 );
891 }
892 Operator::V128Load8x8S { memarg } => {
893 let (flags, _, base) = unwrap_or_return_unreachable_state!(
895 stack,
896 prepare_addr(memarg, 8, builder, stack, environ)?
897 );
898 let loaded = builder.ins().sload8x8(flags, base, 0);
899 stack.push1(loaded);
900 }
901 Operator::V128Load8x8U { memarg } => {
902 let (flags, _, base) = unwrap_or_return_unreachable_state!(
903 stack,
904 prepare_addr(memarg, 8, builder, stack, environ)?
905 );
906 let loaded = builder.ins().uload8x8(flags, base, 0);
907 stack.push1(loaded);
908 }
909 Operator::V128Load16x4S { memarg } => {
910 let (flags, _, base) = unwrap_or_return_unreachable_state!(
911 stack,
912 prepare_addr(memarg, 8, builder, stack, environ)?
913 );
914 let loaded = builder.ins().sload16x4(flags, base, 0);
915 stack.push1(loaded);
916 }
917 Operator::V128Load16x4U { memarg } => {
918 let (flags, _, base) = unwrap_or_return_unreachable_state!(
919 stack,
920 prepare_addr(memarg, 8, builder, stack, environ)?
921 );
922 let loaded = builder.ins().uload16x4(flags, base, 0);
923 stack.push1(loaded);
924 }
925 Operator::V128Load32x2S { memarg } => {
926 let (flags, _, base) = unwrap_or_return_unreachable_state!(
927 stack,
928 prepare_addr(memarg, 8, builder, stack, environ)?
929 );
930 let loaded = builder.ins().sload32x2(flags, base, 0);
931 stack.push1(loaded);
932 }
933 Operator::V128Load32x2U { memarg } => {
934 let (flags, _, base) = unwrap_or_return_unreachable_state!(
935 stack,
936 prepare_addr(memarg, 8, builder, stack, environ)?
937 );
938 let loaded = builder.ins().uload32x2(flags, base, 0);
939 stack.push1(loaded);
940 }
941 Operator::I32Store { memarg }
946 | Operator::I64Store { memarg }
947 | Operator::F32Store { memarg }
948 | Operator::F64Store { memarg } => {
949 translate_store(memarg, ir::Opcode::Store, builder, stack, environ)?;
950 }
951 Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
952 translate_store(memarg, ir::Opcode::Istore8, builder, stack, environ)?;
953 }
954 Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
955 translate_store(memarg, ir::Opcode::Istore16, builder, stack, environ)?;
956 }
957 Operator::I64Store32 { memarg } => {
958 translate_store(memarg, ir::Opcode::Istore32, builder, stack, environ)?;
959 }
960 Operator::V128Store { memarg } => {
961 translate_store(memarg, ir::Opcode::Store, builder, stack, environ)?;
962 }
963 Operator::I32Const { value } => {
965 stack.push1(builder.ins().iconst(I32, i64::from(value.cast_unsigned())));
966 }
967 Operator::I64Const { value } => stack.push1(builder.ins().iconst(I64, *value)),
968 Operator::F32Const { value } => {
969 stack.push1(builder.ins().f32const(f32_translation(*value)));
970 }
971 Operator::F64Const { value } => {
972 stack.push1(builder.ins().f64const(f64_translation(*value)));
973 }
974 Operator::I32Clz | Operator::I64Clz => {
976 let arg = stack.pop1();
977 stack.push1(builder.ins().clz(arg));
978 }
979 Operator::I32Ctz | Operator::I64Ctz => {
980 let arg = stack.pop1();
981 stack.push1(builder.ins().ctz(arg));
982 }
983 Operator::I32Popcnt | Operator::I64Popcnt => {
984 let arg = stack.pop1();
985 stack.push1(builder.ins().popcnt(arg));
986 }
987 Operator::I64ExtendI32S => {
988 let val = stack.pop1();
989 stack.push1(builder.ins().sextend(I64, val));
990 }
991 Operator::I64ExtendI32U => {
992 let val = stack.pop1();
993 stack.push1(builder.ins().uextend(I64, val));
994 }
995 Operator::I32WrapI64 => {
996 let val = stack.pop1();
997 stack.push1(builder.ins().ireduce(I32, val));
998 }
999 Operator::F32Sqrt | Operator::F64Sqrt => {
1000 let arg = stack.pop1();
1001 stack.push1(builder.ins().sqrt(arg));
1002 }
1003 Operator::F32Ceil => {
1004 let arg = stack.pop1();
1005 stack.push1(environ.ceil_f32(builder, arg));
1006 }
1007 Operator::F64Ceil => {
1008 let arg = stack.pop1();
1009 stack.push1(environ.ceil_f64(builder, arg));
1010 }
1011 Operator::F32Floor => {
1012 let arg = stack.pop1();
1013 stack.push1(environ.floor_f32(builder, arg));
1014 }
1015 Operator::F64Floor => {
1016 let arg = stack.pop1();
1017 stack.push1(environ.floor_f64(builder, arg));
1018 }
1019 Operator::F32Trunc => {
1020 let arg = stack.pop1();
1021 stack.push1(environ.trunc_f32(builder, arg));
1022 }
1023 Operator::F64Trunc => {
1024 let arg = stack.pop1();
1025 stack.push1(environ.trunc_f64(builder, arg));
1026 }
1027 Operator::F32Nearest => {
1028 let arg = stack.pop1();
1029 stack.push1(environ.nearest_f32(builder, arg));
1030 }
1031 Operator::F64Nearest => {
1032 let arg = stack.pop1();
1033 stack.push1(environ.nearest_f64(builder, arg));
1034 }
1035 Operator::F32Abs | Operator::F64Abs => {
1036 let val = stack.pop1();
1037 stack.push1(builder.ins().fabs(val));
1038 }
1039 Operator::F32Neg | Operator::F64Neg => {
1040 let arg = stack.pop1();
1041 stack.push1(builder.ins().fneg(arg));
1042 }
1043 Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
1044 let val = stack.pop1();
1045 stack.push1(builder.ins().fcvt_from_uint(F64, val));
1046 }
1047 Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
1048 let val = stack.pop1();
1049 stack.push1(builder.ins().fcvt_from_sint(F64, val));
1050 }
1051 Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
1052 let val = stack.pop1();
1053 stack.push1(builder.ins().fcvt_from_sint(F32, val));
1054 }
1055 Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
1056 let val = stack.pop1();
1057 stack.push1(builder.ins().fcvt_from_uint(F32, val));
1058 }
1059 Operator::F64PromoteF32 => {
1060 let val = stack.pop1();
1061 stack.push1(builder.ins().fpromote(F64, val));
1062 }
1063 Operator::F32DemoteF64 => {
1064 let val = stack.pop1();
1065 stack.push1(builder.ins().fdemote(F32, val));
1066 }
1067 Operator::I64TruncF64S | Operator::I64TruncF32S => {
1068 let val = stack.pop1();
1069 stack.push1(environ.translate_fcvt_to_sint(builder, I64, val));
1070 }
1071 Operator::I32TruncF64S | Operator::I32TruncF32S => {
1072 let val = stack.pop1();
1073 stack.push1(environ.translate_fcvt_to_sint(builder, I32, val));
1074 }
1075 Operator::I64TruncF64U | Operator::I64TruncF32U => {
1076 let val = stack.pop1();
1077 stack.push1(environ.translate_fcvt_to_uint(builder, I64, val));
1078 }
1079 Operator::I32TruncF64U | Operator::I32TruncF32U => {
1080 let val = stack.pop1();
1081 stack.push1(environ.translate_fcvt_to_uint(builder, I32, val));
1082 }
1083 Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
1084 let val = stack.pop1();
1085 stack.push1(builder.ins().fcvt_to_sint_sat(I64, val));
1086 }
1087 Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
1088 let val = stack.pop1();
1089 stack.push1(builder.ins().fcvt_to_sint_sat(I32, val));
1090 }
1091 Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
1092 let val = stack.pop1();
1093 stack.push1(builder.ins().fcvt_to_uint_sat(I64, val));
1094 }
1095 Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
1096 let val = stack.pop1();
1097 stack.push1(builder.ins().fcvt_to_uint_sat(I32, val));
1098 }
1099 Operator::F32ReinterpretI32 => {
1100 let val = stack.pop1();
1101 stack.push1(builder.ins().bitcast(F32, MemFlags::new(), val));
1102 }
1103 Operator::F64ReinterpretI64 => {
1104 let val = stack.pop1();
1105 stack.push1(builder.ins().bitcast(F64, MemFlags::new(), val));
1106 }
1107 Operator::I32ReinterpretF32 => {
1108 let val = stack.pop1();
1109 stack.push1(builder.ins().bitcast(I32, MemFlags::new(), val));
1110 }
1111 Operator::I64ReinterpretF64 => {
1112 let val = stack.pop1();
1113 stack.push1(builder.ins().bitcast(I64, MemFlags::new(), val));
1114 }
1115 Operator::I32Extend8S => {
1116 let val = stack.pop1();
1117 stack.push1(builder.ins().ireduce(I8, val));
1118 let val = stack.pop1();
1119 stack.push1(builder.ins().sextend(I32, val));
1120 }
1121 Operator::I32Extend16S => {
1122 let val = stack.pop1();
1123 stack.push1(builder.ins().ireduce(I16, val));
1124 let val = stack.pop1();
1125 stack.push1(builder.ins().sextend(I32, val));
1126 }
1127 Operator::I64Extend8S => {
1128 let val = stack.pop1();
1129 stack.push1(builder.ins().ireduce(I8, val));
1130 let val = stack.pop1();
1131 stack.push1(builder.ins().sextend(I64, val));
1132 }
1133 Operator::I64Extend16S => {
1134 let val = stack.pop1();
1135 stack.push1(builder.ins().ireduce(I16, val));
1136 let val = stack.pop1();
1137 stack.push1(builder.ins().sextend(I64, val));
1138 }
1139 Operator::I64Extend32S => {
1140 let val = stack.pop1();
1141 stack.push1(builder.ins().ireduce(I32, val));
1142 let val = stack.pop1();
1143 stack.push1(builder.ins().sextend(I64, val));
1144 }
1145 Operator::I32Add | Operator::I64Add => {
1147 let (arg1, arg2) = stack.pop2();
1148 stack.push1(builder.ins().iadd(arg1, arg2));
1149 }
1150 Operator::I32And | Operator::I64And => {
1151 let (arg1, arg2) = stack.pop2();
1152 stack.push1(builder.ins().band(arg1, arg2));
1153 }
1154 Operator::I32Or | Operator::I64Or => {
1155 let (arg1, arg2) = stack.pop2();
1156 stack.push1(builder.ins().bor(arg1, arg2));
1157 }
1158 Operator::I32Xor | Operator::I64Xor => {
1159 let (arg1, arg2) = stack.pop2();
1160 stack.push1(builder.ins().bxor(arg1, arg2));
1161 }
1162 Operator::I32Shl | Operator::I64Shl => {
1163 let (arg1, arg2) = stack.pop2();
1164 stack.push1(builder.ins().ishl(arg1, arg2));
1165 }
1166 Operator::I32ShrS | Operator::I64ShrS => {
1167 let (arg1, arg2) = stack.pop2();
1168 stack.push1(builder.ins().sshr(arg1, arg2));
1169 }
1170 Operator::I32ShrU | Operator::I64ShrU => {
1171 let (arg1, arg2) = stack.pop2();
1172 stack.push1(builder.ins().ushr(arg1, arg2));
1173 }
1174 Operator::I32Rotl | Operator::I64Rotl => {
1175 let (arg1, arg2) = stack.pop2();
1176 stack.push1(builder.ins().rotl(arg1, arg2));
1177 }
1178 Operator::I32Rotr | Operator::I64Rotr => {
1179 let (arg1, arg2) = stack.pop2();
1180 stack.push1(builder.ins().rotr(arg1, arg2));
1181 }
1182 Operator::F32Add | Operator::F64Add => {
1183 let (arg1, arg2) = stack.pop2();
1184 stack.push1(builder.ins().fadd(arg1, arg2));
1185 }
1186 Operator::I32Sub | Operator::I64Sub => {
1187 let (arg1, arg2) = stack.pop2();
1188 stack.push1(builder.ins().isub(arg1, arg2));
1189 }
1190 Operator::F32Sub | Operator::F64Sub => {
1191 let (arg1, arg2) = stack.pop2();
1192 stack.push1(builder.ins().fsub(arg1, arg2));
1193 }
1194 Operator::I32Mul | Operator::I64Mul => {
1195 let (arg1, arg2) = stack.pop2();
1196 stack.push1(builder.ins().imul(arg1, arg2));
1197 }
1198 Operator::F32Mul | Operator::F64Mul => {
1199 let (arg1, arg2) = stack.pop2();
1200 stack.push1(builder.ins().fmul(arg1, arg2));
1201 }
1202 Operator::F32Div | Operator::F64Div => {
1203 let (arg1, arg2) = stack.pop2();
1204 stack.push1(builder.ins().fdiv(arg1, arg2));
1205 }
1206 Operator::I32DivS | Operator::I64DivS => {
1207 let (arg1, arg2) = stack.pop2();
1208 stack.push1(environ.translate_sdiv(builder, arg1, arg2));
1209 }
1210 Operator::I32DivU | Operator::I64DivU => {
1211 let (arg1, arg2) = stack.pop2();
1212 stack.push1(environ.translate_udiv(builder, arg1, arg2));
1213 }
1214 Operator::I32RemS | Operator::I64RemS => {
1215 let (arg1, arg2) = stack.pop2();
1216 stack.push1(environ.translate_srem(builder, arg1, arg2));
1217 }
1218 Operator::I32RemU | Operator::I64RemU => {
1219 let (arg1, arg2) = stack.pop2();
1220 stack.push1(environ.translate_urem(builder, arg1, arg2));
1221 }
1222 Operator::F32Min | Operator::F64Min => {
1223 let (arg1, arg2) = stack.pop2();
1224 stack.push1(builder.ins().fmin(arg1, arg2));
1225 }
1226 Operator::F32Max | Operator::F64Max => {
1227 let (arg1, arg2) = stack.pop2();
1228 stack.push1(builder.ins().fmax(arg1, arg2));
1229 }
1230 Operator::F32Copysign | Operator::F64Copysign => {
1231 let (arg1, arg2) = stack.pop2();
1232 stack.push1(builder.ins().fcopysign(arg1, arg2));
1233 }
1234 Operator::I32LtS | Operator::I64LtS => {
1236 translate_icmp(IntCC::SignedLessThan, builder, stack)
1237 }
1238 Operator::I32LtU | Operator::I64LtU => {
1239 translate_icmp(IntCC::UnsignedLessThan, builder, stack)
1240 }
1241 Operator::I32LeS | Operator::I64LeS => {
1242 translate_icmp(IntCC::SignedLessThanOrEqual, builder, stack)
1243 }
1244 Operator::I32LeU | Operator::I64LeU => {
1245 translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, stack)
1246 }
1247 Operator::I32GtS | Operator::I64GtS => {
1248 translate_icmp(IntCC::SignedGreaterThan, builder, stack)
1249 }
1250 Operator::I32GtU | Operator::I64GtU => {
1251 translate_icmp(IntCC::UnsignedGreaterThan, builder, stack)
1252 }
1253 Operator::I32GeS | Operator::I64GeS => {
1254 translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, stack)
1255 }
1256 Operator::I32GeU | Operator::I64GeU => {
1257 translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, stack)
1258 }
1259 Operator::I32Eqz | Operator::I64Eqz => {
1260 let arg = stack.pop1();
1261 let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0);
1262 stack.push1(builder.ins().uextend(I32, val));
1263 }
1264 Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, stack),
1265 Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, stack),
1266 Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, stack),
1267 Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, stack),
1268 Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, stack),
1269 Operator::F32Ge | Operator::F64Ge => {
1270 translate_fcmp(FloatCC::GreaterThanOrEqual, builder, stack)
1271 }
1272 Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, stack),
1273 Operator::F32Le | Operator::F64Le => {
1274 translate_fcmp(FloatCC::LessThanOrEqual, builder, stack)
1275 }
1276 Operator::RefNull { hty } => {
1277 let hty = environ.convert_heap_type(*hty)?;
1278 stack.push1(environ.translate_ref_null(builder.cursor(), hty)?)
1279 }
1280 Operator::RefIsNull => {
1281 let value = stack.pop1();
1282 let [WasmValType::Ref(ty)] = operand_types else {
1283 unreachable!("validation")
1284 };
1285 stack.push1(environ.translate_ref_is_null(builder.cursor(), value, *ty)?);
1286 }
1287 Operator::RefFunc { function_index } => {
1288 let index = FuncIndex::from_u32(*function_index);
1289 stack.push1(environ.translate_ref_func(builder.cursor(), index)?);
1290 }
1291 Operator::MemoryAtomicWait32 { memarg } | Operator::MemoryAtomicWait64 { memarg } => {
1292 let implied_ty = match op {
1296 Operator::MemoryAtomicWait64 { .. } => I64,
1297 Operator::MemoryAtomicWait32 { .. } => I32,
1298 _ => unreachable!(),
1299 };
1300 let memory_index = MemoryIndex::from_u32(memarg.memory);
1301 let heap = environ.get_or_create_heap(builder.func, memory_index);
1302 let timeout = stack.pop1(); let expected = stack.pop1(); assert!(builder.func.dfg.value_type(expected) == implied_ty);
1305 let addr = stack.pop1();
1306 let effective_addr = if memarg.offset == 0 {
1307 addr
1308 } else {
1309 let index_type = environ.heaps()[heap].index_type();
1310 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1311 environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
1312 };
1313 let res = environ.translate_atomic_wait(
1316 builder,
1317 memory_index,
1318 heap,
1319 effective_addr,
1320 expected,
1321 timeout,
1322 )?;
1323 stack.push1(res);
1324 }
1325 Operator::MemoryAtomicNotify { memarg } => {
1326 let memory_index = MemoryIndex::from_u32(memarg.memory);
1327 let heap = environ.get_or_create_heap(builder.func, memory_index);
1328 let count = stack.pop1(); let addr = stack.pop1();
1330 let effective_addr = if memarg.offset == 0 {
1331 addr
1332 } else {
1333 let index_type = environ.heaps()[heap].index_type();
1334 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1335 environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
1336 };
1337 let res = environ.translate_atomic_notify(
1338 builder,
1339 memory_index,
1340 heap,
1341 effective_addr,
1342 count,
1343 )?;
1344 stack.push1(res);
1345 }
1346 Operator::I32AtomicLoad { memarg } => {
1347 translate_atomic_load(I32, I32, memarg, builder, stack, environ)?
1348 }
1349 Operator::I64AtomicLoad { memarg } => {
1350 translate_atomic_load(I64, I64, memarg, builder, stack, environ)?
1351 }
1352 Operator::I32AtomicLoad8U { memarg } => {
1353 translate_atomic_load(I32, I8, memarg, builder, stack, environ)?
1354 }
1355 Operator::I32AtomicLoad16U { memarg } => {
1356 translate_atomic_load(I32, I16, memarg, builder, stack, environ)?
1357 }
1358 Operator::I64AtomicLoad8U { memarg } => {
1359 translate_atomic_load(I64, I8, memarg, builder, stack, environ)?
1360 }
1361 Operator::I64AtomicLoad16U { memarg } => {
1362 translate_atomic_load(I64, I16, memarg, builder, stack, environ)?
1363 }
1364 Operator::I64AtomicLoad32U { memarg } => {
1365 translate_atomic_load(I64, I32, memarg, builder, stack, environ)?
1366 }
1367
1368 Operator::I32AtomicStore { memarg } => {
1369 translate_atomic_store(I32, memarg, builder, stack, environ)?
1370 }
1371 Operator::I64AtomicStore { memarg } => {
1372 translate_atomic_store(I64, memarg, builder, stack, environ)?
1373 }
1374 Operator::I32AtomicStore8 { memarg } => {
1375 translate_atomic_store(I8, memarg, builder, stack, environ)?
1376 }
1377 Operator::I32AtomicStore16 { memarg } => {
1378 translate_atomic_store(I16, memarg, builder, stack, environ)?
1379 }
1380 Operator::I64AtomicStore8 { memarg } => {
1381 translate_atomic_store(I8, memarg, builder, stack, environ)?
1382 }
1383 Operator::I64AtomicStore16 { memarg } => {
1384 translate_atomic_store(I16, memarg, builder, stack, environ)?
1385 }
1386 Operator::I64AtomicStore32 { memarg } => {
1387 translate_atomic_store(I32, memarg, builder, stack, environ)?
1388 }
1389
1390 Operator::I32AtomicRmwAdd { memarg } => {
1391 translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1392 }
1393 Operator::I64AtomicRmwAdd { memarg } => {
1394 translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1395 }
1396 Operator::I32AtomicRmw8AddU { memarg } => {
1397 translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1398 }
1399 Operator::I32AtomicRmw16AddU { memarg } => {
1400 translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1401 }
1402 Operator::I64AtomicRmw8AddU { memarg } => {
1403 translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1404 }
1405 Operator::I64AtomicRmw16AddU { memarg } => {
1406 translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1407 }
1408 Operator::I64AtomicRmw32AddU { memarg } => {
1409 translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, stack, environ)?
1410 }
1411
1412 Operator::I32AtomicRmwSub { memarg } => {
1413 translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1414 }
1415 Operator::I64AtomicRmwSub { memarg } => {
1416 translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1417 }
1418 Operator::I32AtomicRmw8SubU { memarg } => {
1419 translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1420 }
1421 Operator::I32AtomicRmw16SubU { memarg } => {
1422 translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1423 }
1424 Operator::I64AtomicRmw8SubU { memarg } => {
1425 translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1426 }
1427 Operator::I64AtomicRmw16SubU { memarg } => {
1428 translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1429 }
1430 Operator::I64AtomicRmw32SubU { memarg } => {
1431 translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, stack, environ)?
1432 }
1433
1434 Operator::I32AtomicRmwAnd { memarg } => {
1435 translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, stack, environ)?
1436 }
1437 Operator::I64AtomicRmwAnd { memarg } => {
1438 translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, stack, environ)?
1439 }
1440 Operator::I32AtomicRmw8AndU { memarg } => {
1441 translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, stack, environ)?
1442 }
1443 Operator::I32AtomicRmw16AndU { memarg } => {
1444 translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, stack, environ)?
1445 }
1446 Operator::I64AtomicRmw8AndU { memarg } => {
1447 translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, stack, environ)?
1448 }
1449 Operator::I64AtomicRmw16AndU { memarg } => {
1450 translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, stack, environ)?
1451 }
1452 Operator::I64AtomicRmw32AndU { memarg } => {
1453 translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, stack, environ)?
1454 }
1455
1456 Operator::I32AtomicRmwOr { memarg } => {
1457 translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1458 }
1459 Operator::I64AtomicRmwOr { memarg } => {
1460 translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1461 }
1462 Operator::I32AtomicRmw8OrU { memarg } => {
1463 translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1464 }
1465 Operator::I32AtomicRmw16OrU { memarg } => {
1466 translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1467 }
1468 Operator::I64AtomicRmw8OrU { memarg } => {
1469 translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1470 }
1471 Operator::I64AtomicRmw16OrU { memarg } => {
1472 translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1473 }
1474 Operator::I64AtomicRmw32OrU { memarg } => {
1475 translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, stack, environ)?
1476 }
1477
1478 Operator::I32AtomicRmwXor { memarg } => {
1479 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1480 }
1481 Operator::I64AtomicRmwXor { memarg } => {
1482 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1483 }
1484 Operator::I32AtomicRmw8XorU { memarg } => {
1485 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1486 }
1487 Operator::I32AtomicRmw16XorU { memarg } => {
1488 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1489 }
1490 Operator::I64AtomicRmw8XorU { memarg } => {
1491 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1492 }
1493 Operator::I64AtomicRmw16XorU { memarg } => {
1494 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1495 }
1496 Operator::I64AtomicRmw32XorU { memarg } => {
1497 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, stack, environ)?
1498 }
1499
1500 Operator::I32AtomicRmwXchg { memarg } => {
1501 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1502 }
1503 Operator::I64AtomicRmwXchg { memarg } => {
1504 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1505 }
1506 Operator::I32AtomicRmw8XchgU { memarg } => {
1507 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1508 }
1509 Operator::I32AtomicRmw16XchgU { memarg } => {
1510 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1511 }
1512 Operator::I64AtomicRmw8XchgU { memarg } => {
1513 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1514 }
1515 Operator::I64AtomicRmw16XchgU { memarg } => {
1516 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1517 }
1518 Operator::I64AtomicRmw32XchgU { memarg } => {
1519 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, stack, environ)?
1520 }
1521
1522 Operator::I32AtomicRmwCmpxchg { memarg } => {
1523 translate_atomic_cas(I32, I32, memarg, builder, stack, environ)?
1524 }
1525 Operator::I64AtomicRmwCmpxchg { memarg } => {
1526 translate_atomic_cas(I64, I64, memarg, builder, stack, environ)?
1527 }
1528 Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1529 translate_atomic_cas(I32, I8, memarg, builder, stack, environ)?
1530 }
1531 Operator::I32AtomicRmw16CmpxchgU { memarg } => {
1532 translate_atomic_cas(I32, I16, memarg, builder, stack, environ)?
1533 }
1534 Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1535 translate_atomic_cas(I64, I8, memarg, builder, stack, environ)?
1536 }
1537 Operator::I64AtomicRmw16CmpxchgU { memarg } => {
1538 translate_atomic_cas(I64, I16, memarg, builder, stack, environ)?
1539 }
1540 Operator::I64AtomicRmw32CmpxchgU { memarg } => {
1541 translate_atomic_cas(I64, I32, memarg, builder, stack, environ)?
1542 }
1543
1544 Operator::AtomicFence { .. } => {
1545 builder.ins().fence();
1546 }
1547 Operator::MemoryCopy { src_mem, dst_mem } => {
1548 let src_index = MemoryIndex::from_u32(*src_mem);
1549 let _src_heap = environ.get_or_create_heap(builder.func, src_index);
1550
1551 let dst_index = MemoryIndex::from_u32(*dst_mem);
1552 let _dst_heap = environ.get_or_create_heap(builder.func, dst_index);
1553
1554 let len = stack.pop1();
1555 let src_pos = stack.pop1();
1556 let dst_pos = stack.pop1();
1557 environ.translate_memory_copy(builder, src_index, dst_index, dst_pos, src_pos, len)?;
1558 }
1559 Operator::MemoryFill { mem } => {
1560 let mem = MemoryIndex::from_u32(*mem);
1561 let _heap = environ.get_or_create_heap(builder.func, mem);
1562 let len = stack.pop1();
1563 let val = stack.pop1();
1564 let dest = stack.pop1();
1565 environ.translate_memory_fill(builder, mem, dest, val, len)?;
1566 }
1567 Operator::MemoryInit { data_index, mem } => {
1568 let mem = MemoryIndex::from_u32(*mem);
1569 let _heap = environ.get_or_create_heap(builder.func, mem);
1570 let len = stack.pop1();
1571 let src = stack.pop1();
1572 let dest = stack.pop1();
1573 environ.translate_memory_init(builder, mem, *data_index, dest, src, len)?;
1574 }
1575 Operator::DataDrop { data_index } => {
1576 environ.translate_data_drop(builder.cursor(), *data_index)?;
1577 }
1578 Operator::TableSize { table: index } => {
1579 stack.push1(
1580 environ.translate_table_size(builder.cursor(), TableIndex::from_u32(*index))?,
1581 );
1582 }
1583 Operator::TableGrow { table: index } => {
1584 let table_index = TableIndex::from_u32(*index);
1585 let delta = stack.pop1();
1586 let init_value = stack.pop1();
1587 stack.push1(environ.translate_table_grow(builder, table_index, delta, init_value)?);
1588 }
1589 Operator::TableGet { table: index } => {
1590 let table_index = TableIndex::from_u32(*index);
1591 let index = stack.pop1();
1592 stack.push1(environ.translate_table_get(builder, table_index, index)?);
1593 }
1594 Operator::TableSet { table: index } => {
1595 let table_index = TableIndex::from_u32(*index);
1596 let value = stack.pop1();
1597 let index = stack.pop1();
1598 environ.translate_table_set(builder, table_index, value, index)?;
1599 }
1600 Operator::TableCopy {
1601 dst_table: dst_table_index,
1602 src_table: src_table_index,
1603 } => {
1604 let len = stack.pop1();
1605 let src = stack.pop1();
1606 let dest = stack.pop1();
1607 environ.translate_table_copy(
1608 builder,
1609 TableIndex::from_u32(*dst_table_index),
1610 TableIndex::from_u32(*src_table_index),
1611 dest,
1612 src,
1613 len,
1614 )?;
1615 }
1616 Operator::TableFill { table } => {
1617 let table_index = TableIndex::from_u32(*table);
1618 let len = stack.pop1();
1619 let val = stack.pop1();
1620 let dest = stack.pop1();
1621 environ.translate_table_fill(builder, table_index, dest, val, len)?;
1622 }
1623 Operator::TableInit {
1624 elem_index,
1625 table: table_index,
1626 } => {
1627 let len = stack.pop1();
1628 let src = stack.pop1();
1629 let dest = stack.pop1();
1630 environ.translate_table_init(
1631 builder,
1632 *elem_index,
1633 TableIndex::from_u32(*table_index),
1634 dest,
1635 src,
1636 len,
1637 )?;
1638 }
1639 Operator::ElemDrop { elem_index } => {
1640 environ.translate_elem_drop(builder.cursor(), *elem_index)?;
1641 }
1642 Operator::V128Const { value } => {
1643 let data = value.bytes().to_vec().into();
1644 let handle = builder.func.dfg.constants.insert(data);
1645 let value = builder.ins().vconst(I8X16, handle);
1646 stack.push1(value)
1649 }
1650 Operator::I8x16Splat | Operator::I16x8Splat => {
1651 let reduced = builder.ins().ireduce(type_of(op).lane_type(), stack.pop1());
1652 let splatted = builder.ins().splat(type_of(op), reduced);
1653 stack.push1(splatted)
1654 }
1655 Operator::I32x4Splat
1656 | Operator::I64x2Splat
1657 | Operator::F32x4Splat
1658 | Operator::F64x2Splat => {
1659 let splatted = builder.ins().splat(type_of(op), stack.pop1());
1660 stack.push1(splatted)
1661 }
1662 Operator::V128Load8Splat { memarg }
1663 | Operator::V128Load16Splat { memarg }
1664 | Operator::V128Load32Splat { memarg }
1665 | Operator::V128Load64Splat { memarg } => {
1666 unwrap_or_return_unreachable_state!(
1667 stack,
1668 translate_load(
1669 memarg,
1670 ir::Opcode::Load,
1671 type_of(op).lane_type(),
1672 builder,
1673 stack,
1674 environ,
1675 )?
1676 );
1677 let splatted = builder.ins().splat(type_of(op), stack.pop1());
1678 stack.push1(splatted)
1679 }
1680 Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
1681 unwrap_or_return_unreachable_state!(
1682 stack,
1683 translate_load(
1684 memarg,
1685 ir::Opcode::Load,
1686 type_of(op).lane_type(),
1687 builder,
1688 stack,
1689 environ,
1690 )?
1691 );
1692 let as_vector = builder.ins().scalar_to_vector(type_of(op), stack.pop1());
1693 stack.push1(as_vector)
1694 }
1695 Operator::V128Load8Lane { memarg, lane }
1696 | Operator::V128Load16Lane { memarg, lane }
1697 | Operator::V128Load32Lane { memarg, lane }
1698 | Operator::V128Load64Lane { memarg, lane } => {
1699 let vector = pop1_with_bitcast(stack, type_of(op), builder);
1700 unwrap_or_return_unreachable_state!(
1701 stack,
1702 translate_load(
1703 memarg,
1704 ir::Opcode::Load,
1705 type_of(op).lane_type(),
1706 builder,
1707 stack,
1708 environ,
1709 )?
1710 );
1711 let replacement = stack.pop1();
1712 stack.push1(builder.ins().insertlane(vector, replacement, *lane))
1713 }
1714 Operator::V128Store8Lane { memarg, lane }
1715 | Operator::V128Store16Lane { memarg, lane }
1716 | Operator::V128Store32Lane { memarg, lane }
1717 | Operator::V128Store64Lane { memarg, lane } => {
1718 let vector = pop1_with_bitcast(stack, type_of(op), builder);
1719 stack.push1(builder.ins().extractlane(vector, *lane));
1720 translate_store(memarg, ir::Opcode::Store, builder, stack, environ)?;
1721 }
1722 Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => {
1723 let vector = pop1_with_bitcast(stack, type_of(op), builder);
1724 let extracted = builder.ins().extractlane(vector, *lane);
1725 stack.push1(builder.ins().sextend(I32, extracted))
1726 }
1727 Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
1728 let vector = pop1_with_bitcast(stack, type_of(op), builder);
1729 let extracted = builder.ins().extractlane(vector, *lane);
1730 stack.push1(builder.ins().uextend(I32, extracted));
1731 }
1735 Operator::I32x4ExtractLane { lane }
1736 | Operator::I64x2ExtractLane { lane }
1737 | Operator::F32x4ExtractLane { lane }
1738 | Operator::F64x2ExtractLane { lane } => {
1739 let vector = pop1_with_bitcast(stack, type_of(op), builder);
1740 stack.push1(builder.ins().extractlane(vector, *lane))
1741 }
1742 Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => {
1743 let (vector, replacement) = stack.pop2();
1744 let ty = type_of(op);
1745 let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
1746 let vector = optionally_bitcast_vector(vector, ty, builder);
1747 stack.push1(builder.ins().insertlane(vector, reduced, *lane))
1748 }
1749 Operator::I32x4ReplaceLane { lane }
1750 | Operator::I64x2ReplaceLane { lane }
1751 | Operator::F32x4ReplaceLane { lane }
1752 | Operator::F64x2ReplaceLane { lane } => {
1753 let (vector, replacement) = stack.pop2();
1754 let vector = optionally_bitcast_vector(vector, type_of(op), builder);
1755 stack.push1(builder.ins().insertlane(vector, replacement, *lane))
1756 }
1757 Operator::I8x16Shuffle { lanes, .. } => {
1758 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
1759 stack.push1(environ.i8x16_shuffle(builder, a, b, lanes));
1760 }
1765 Operator::I8x16Swizzle => {
1766 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
1767 stack.push1(environ.swizzle(builder, a, b));
1768 }
1769 Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1770 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1771 stack.push1(builder.ins().iadd(a, b))
1772 }
1773 Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1774 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1775 stack.push1(builder.ins().sadd_sat(a, b))
1776 }
1777 Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1778 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1779 stack.push1(builder.ins().uadd_sat(a, b))
1780 }
1781 Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1782 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1783 stack.push1(builder.ins().isub(a, b))
1784 }
1785 Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1786 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1787 stack.push1(builder.ins().ssub_sat(a, b))
1788 }
1789 Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1790 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1791 stack.push1(builder.ins().usub_sat(a, b))
1792 }
1793 Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1794 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1795 stack.push1(builder.ins().smin(a, b))
1796 }
1797 Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1798 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1799 stack.push1(builder.ins().umin(a, b))
1800 }
1801 Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1802 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1803 stack.push1(builder.ins().smax(a, b))
1804 }
1805 Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1806 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1807 stack.push1(builder.ins().umax(a, b))
1808 }
1809 Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1810 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1811 stack.push1(builder.ins().avg_round(a, b))
1812 }
1813 Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1814 let a = pop1_with_bitcast(stack, type_of(op), builder);
1815 stack.push1(builder.ins().ineg(a))
1816 }
1817 Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1818 let a = pop1_with_bitcast(stack, type_of(op), builder);
1819 stack.push1(builder.ins().iabs(a))
1820 }
1821 Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1822 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1823 stack.push1(builder.ins().imul(a, b))
1824 }
1825 Operator::V128Or => {
1826 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1827 stack.push1(builder.ins().bor(a, b))
1828 }
1829 Operator::V128Xor => {
1830 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1831 stack.push1(builder.ins().bxor(a, b))
1832 }
1833 Operator::V128And => {
1834 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1835 stack.push1(builder.ins().band(a, b))
1836 }
1837 Operator::V128AndNot => {
1838 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1839 stack.push1(builder.ins().band_not(a, b))
1840 }
1841 Operator::V128Not => {
1842 let a = stack.pop1();
1843 stack.push1(builder.ins().bnot(a));
1844 }
1845 Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
1846 let (a, b) = stack.pop2();
1847 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1848 stack.push1(builder.ins().ishl(bitcast_a, b))
1851 }
1852 Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
1853 let (a, b) = stack.pop2();
1854 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1855 stack.push1(builder.ins().ushr(bitcast_a, b))
1858 }
1859 Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
1860 let (a, b) = stack.pop2();
1861 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1862 stack.push1(builder.ins().sshr(bitcast_a, b))
1865 }
1866 Operator::V128Bitselect => {
1867 let (a, b, c) = pop3_with_bitcast(stack, I8X16, builder);
1868 stack.push1(builder.ins().bitselect(c, a, b))
1871 }
1872 Operator::V128AnyTrue => {
1873 let a = pop1_with_bitcast(stack, type_of(op), builder);
1874 let bool_result = builder.ins().vany_true(a);
1875 stack.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(stack, type_of(op), builder);
1882 let bool_result = builder.ins().vall_true(a);
1883 stack.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(stack, type_of(op), builder);
1890 stack.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, stack)
1894 }
1895 Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
1896 translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, stack)
1897 }
1898 Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
1899 translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, stack)
1900 }
1901 Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
1902 translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, stack)
1903 }
1904 Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
1905 translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, stack)
1906 }
1907 Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
1908 translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, stack)
1909 }
1910 Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
1911 translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, stack)
1912 }
1913 Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
1914 translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, stack)
1915 }
1916 Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
1917 IntCC::UnsignedGreaterThanOrEqual,
1918 type_of(op),
1919 builder,
1920 stack,
1921 ),
1922 Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
1923 translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, stack)
1924 }
1925 Operator::F32x4Eq | Operator::F64x2Eq => {
1926 translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, stack)
1927 }
1928 Operator::F32x4Ne | Operator::F64x2Ne => {
1929 translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, stack)
1930 }
1931 Operator::F32x4Lt | Operator::F64x2Lt => {
1932 translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, stack)
1933 }
1934 Operator::F32x4Gt | Operator::F64x2Gt => {
1935 translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, stack)
1936 }
1937 Operator::F32x4Le | Operator::F64x2Le => {
1938 translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, stack)
1939 }
1940 Operator::F32x4Ge | Operator::F64x2Ge => {
1941 translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, stack)
1942 }
1943 Operator::F32x4Add | Operator::F64x2Add => {
1944 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1945 stack.push1(builder.ins().fadd(a, b))
1946 }
1947 Operator::F32x4Sub | Operator::F64x2Sub => {
1948 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1949 stack.push1(builder.ins().fsub(a, b))
1950 }
1951 Operator::F32x4Mul | Operator::F64x2Mul => {
1952 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1953 stack.push1(builder.ins().fmul(a, b))
1954 }
1955 Operator::F32x4Div | Operator::F64x2Div => {
1956 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1957 stack.push1(builder.ins().fdiv(a, b))
1958 }
1959 Operator::F32x4Max | Operator::F64x2Max => {
1960 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1961 stack.push1(builder.ins().fmax(a, b))
1962 }
1963 Operator::F32x4Min | Operator::F64x2Min => {
1964 let (a, b) = pop2_with_bitcast(stack, type_of(op), builder);
1965 stack.push1(builder.ins().fmin(a, b))
1966 }
1967 Operator::F32x4PMax | Operator::F64x2PMax => {
1968 let ty = type_of(op);
1975 let (a, b) = pop2_with_bitcast(stack, ty, builder);
1976 let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
1977 let cmp = optionally_bitcast_vector(cmp, ty, builder);
1978 stack.push1(builder.ins().bitselect(cmp, b, a))
1979 }
1980 Operator::F32x4PMin | Operator::F64x2PMin => {
1981 let ty = type_of(op);
1987 let (a, b) = pop2_with_bitcast(stack, ty, builder);
1988 let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
1989 let cmp = optionally_bitcast_vector(cmp, ty, builder);
1990 stack.push1(builder.ins().bitselect(cmp, b, a))
1991 }
1992 Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
1993 let a = pop1_with_bitcast(stack, type_of(op), builder);
1994 stack.push1(builder.ins().sqrt(a))
1995 }
1996 Operator::F32x4Neg | Operator::F64x2Neg => {
1997 let a = pop1_with_bitcast(stack, type_of(op), builder);
1998 stack.push1(builder.ins().fneg(a))
1999 }
2000 Operator::F32x4Abs | Operator::F64x2Abs => {
2001 let a = pop1_with_bitcast(stack, type_of(op), builder);
2002 stack.push1(builder.ins().fabs(a))
2003 }
2004 Operator::F32x4ConvertI32x4S => {
2005 let a = pop1_with_bitcast(stack, I32X4, builder);
2006 stack.push1(builder.ins().fcvt_from_sint(F32X4, a))
2007 }
2008 Operator::F32x4ConvertI32x4U => {
2009 let a = pop1_with_bitcast(stack, I32X4, builder);
2010 stack.push1(builder.ins().fcvt_from_uint(F32X4, a))
2011 }
2012 Operator::F64x2ConvertLowI32x4S => {
2013 let a = pop1_with_bitcast(stack, I32X4, builder);
2014 let widened_a = builder.ins().swiden_low(a);
2015 stack.push1(builder.ins().fcvt_from_sint(F64X2, widened_a));
2016 }
2017 Operator::F64x2ConvertLowI32x4U => {
2018 let a = pop1_with_bitcast(stack, I32X4, builder);
2019 let widened_a = builder.ins().uwiden_low(a);
2020 stack.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
2021 }
2022 Operator::F64x2PromoteLowF32x4 => {
2023 let a = pop1_with_bitcast(stack, F32X4, builder);
2024 stack.push1(builder.ins().fvpromote_low(a));
2025 }
2026 Operator::F32x4DemoteF64x2Zero => {
2027 let a = pop1_with_bitcast(stack, F64X2, builder);
2028 stack.push1(builder.ins().fvdemote(a));
2029 }
2030 Operator::I32x4TruncSatF32x4S => {
2031 let a = pop1_with_bitcast(stack, F32X4, builder);
2032 stack.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2033 }
2034 Operator::I32x4TruncSatF64x2SZero => {
2035 let a = pop1_with_bitcast(stack, F64X2, builder);
2036 let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2037 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2038 let zero = builder.ins().vconst(I64X2, handle);
2039
2040 stack.push1(builder.ins().snarrow(converted_a, zero));
2041 }
2042
2043 Operator::I32x4RelaxedTruncF32x4U | Operator::I32x4TruncSatF32x4U => {
2055 let a = pop1_with_bitcast(stack, F32X4, builder);
2056 stack.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2057 }
2058 Operator::I32x4RelaxedTruncF64x2UZero | Operator::I32x4TruncSatF64x2UZero => {
2059 let a = pop1_with_bitcast(stack, F64X2, builder);
2060 let zero_constant = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2061 let result = if environ.is_x86() && !environ.isa().has_round() {
2062 let lane0 = builder.ins().extractlane(a, 0);
2068 let lane1 = builder.ins().extractlane(a, 1);
2069 let lane0_rounded = builder.ins().fcvt_to_uint_sat(I32, lane0);
2070 let lane1_rounded = builder.ins().fcvt_to_uint_sat(I32, lane1);
2071 let result = builder.ins().vconst(I32X4, zero_constant);
2072 let result = builder.ins().insertlane(result, lane0_rounded, 0);
2073 builder.ins().insertlane(result, lane1_rounded, 1)
2074 } else {
2075 let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2076 let zero = builder.ins().vconst(I64X2, zero_constant);
2077 builder.ins().uunarrow(converted_a, zero)
2078 };
2079 stack.push1(result);
2080 }
2081
2082 Operator::I8x16NarrowI16x8S => {
2083 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2084 stack.push1(builder.ins().snarrow(a, b))
2085 }
2086 Operator::I16x8NarrowI32x4S => {
2087 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2088 stack.push1(builder.ins().snarrow(a, b))
2089 }
2090 Operator::I8x16NarrowI16x8U => {
2091 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2092 stack.push1(builder.ins().unarrow(a, b))
2093 }
2094 Operator::I16x8NarrowI32x4U => {
2095 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2096 stack.push1(builder.ins().unarrow(a, b))
2097 }
2098 Operator::I16x8ExtendLowI8x16S => {
2099 let a = pop1_with_bitcast(stack, I8X16, builder);
2100 stack.push1(builder.ins().swiden_low(a))
2101 }
2102 Operator::I16x8ExtendHighI8x16S => {
2103 let a = pop1_with_bitcast(stack, I8X16, builder);
2104 stack.push1(builder.ins().swiden_high(a))
2105 }
2106 Operator::I16x8ExtendLowI8x16U => {
2107 let a = pop1_with_bitcast(stack, I8X16, builder);
2108 stack.push1(builder.ins().uwiden_low(a))
2109 }
2110 Operator::I16x8ExtendHighI8x16U => {
2111 let a = pop1_with_bitcast(stack, I8X16, builder);
2112 stack.push1(builder.ins().uwiden_high(a))
2113 }
2114 Operator::I32x4ExtendLowI16x8S => {
2115 let a = pop1_with_bitcast(stack, I16X8, builder);
2116 stack.push1(builder.ins().swiden_low(a))
2117 }
2118 Operator::I32x4ExtendHighI16x8S => {
2119 let a = pop1_with_bitcast(stack, I16X8, builder);
2120 stack.push1(builder.ins().swiden_high(a))
2121 }
2122 Operator::I32x4ExtendLowI16x8U => {
2123 let a = pop1_with_bitcast(stack, I16X8, builder);
2124 stack.push1(builder.ins().uwiden_low(a))
2125 }
2126 Operator::I32x4ExtendHighI16x8U => {
2127 let a = pop1_with_bitcast(stack, I16X8, builder);
2128 stack.push1(builder.ins().uwiden_high(a))
2129 }
2130 Operator::I64x2ExtendLowI32x4S => {
2131 let a = pop1_with_bitcast(stack, I32X4, builder);
2132 stack.push1(builder.ins().swiden_low(a))
2133 }
2134 Operator::I64x2ExtendHighI32x4S => {
2135 let a = pop1_with_bitcast(stack, I32X4, builder);
2136 stack.push1(builder.ins().swiden_high(a))
2137 }
2138 Operator::I64x2ExtendLowI32x4U => {
2139 let a = pop1_with_bitcast(stack, I32X4, builder);
2140 stack.push1(builder.ins().uwiden_low(a))
2141 }
2142 Operator::I64x2ExtendHighI32x4U => {
2143 let a = pop1_with_bitcast(stack, I32X4, builder);
2144 stack.push1(builder.ins().uwiden_high(a))
2145 }
2146 Operator::I16x8ExtAddPairwiseI8x16S => {
2147 let a = pop1_with_bitcast(stack, I8X16, builder);
2148 let widen_low = builder.ins().swiden_low(a);
2149 let widen_high = builder.ins().swiden_high(a);
2150 stack.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2151 }
2152 Operator::I32x4ExtAddPairwiseI16x8S => {
2153 let a = pop1_with_bitcast(stack, I16X8, builder);
2154 let widen_low = builder.ins().swiden_low(a);
2155 let widen_high = builder.ins().swiden_high(a);
2156 stack.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2157 }
2158 Operator::I16x8ExtAddPairwiseI8x16U => {
2159 let a = pop1_with_bitcast(stack, I8X16, builder);
2160 let widen_low = builder.ins().uwiden_low(a);
2161 let widen_high = builder.ins().uwiden_high(a);
2162 stack.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2163 }
2164 Operator::I32x4ExtAddPairwiseI16x8U => {
2165 let a = pop1_with_bitcast(stack, I16X8, builder);
2166 let widen_low = builder.ins().uwiden_low(a);
2167 let widen_high = builder.ins().uwiden_high(a);
2168 stack.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2169 }
2170 Operator::F32x4Ceil => {
2171 let arg = pop1_with_bitcast(stack, F32X4, builder);
2172 stack.push1(environ.ceil_f32x4(builder, arg));
2173 }
2174 Operator::F64x2Ceil => {
2175 let arg = pop1_with_bitcast(stack, F64X2, builder);
2176 stack.push1(environ.ceil_f64x2(builder, arg));
2177 }
2178 Operator::F32x4Floor => {
2179 let arg = pop1_with_bitcast(stack, F32X4, builder);
2180 stack.push1(environ.floor_f32x4(builder, arg));
2181 }
2182 Operator::F64x2Floor => {
2183 let arg = pop1_with_bitcast(stack, F64X2, builder);
2184 stack.push1(environ.floor_f64x2(builder, arg));
2185 }
2186 Operator::F32x4Trunc => {
2187 let arg = pop1_with_bitcast(stack, F32X4, builder);
2188 stack.push1(environ.trunc_f32x4(builder, arg));
2189 }
2190 Operator::F64x2Trunc => {
2191 let arg = pop1_with_bitcast(stack, F64X2, builder);
2192 stack.push1(environ.trunc_f64x2(builder, arg));
2193 }
2194 Operator::F32x4Nearest => {
2195 let arg = pop1_with_bitcast(stack, F32X4, builder);
2196 stack.push1(environ.nearest_f32x4(builder, arg));
2197 }
2198 Operator::F64x2Nearest => {
2199 let arg = pop1_with_bitcast(stack, F64X2, builder);
2200 stack.push1(environ.nearest_f64x2(builder, arg));
2201 }
2202 Operator::I32x4DotI16x8S => {
2203 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2204 let alow = builder.ins().swiden_low(a);
2205 let blow = builder.ins().swiden_low(b);
2206 let low = builder.ins().imul(alow, blow);
2207 let ahigh = builder.ins().swiden_high(a);
2208 let bhigh = builder.ins().swiden_high(b);
2209 let high = builder.ins().imul(ahigh, bhigh);
2210 stack.push1(builder.ins().iadd_pairwise(low, high));
2211 }
2212 Operator::I8x16Popcnt => {
2213 let arg = pop1_with_bitcast(stack, type_of(op), builder);
2214 stack.push1(builder.ins().popcnt(arg));
2215 }
2216 Operator::I16x8Q15MulrSatS => {
2217 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2218 stack.push1(builder.ins().sqmul_round_sat(a, b))
2219 }
2220 Operator::I16x8ExtMulLowI8x16S => {
2221 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2222 let a_low = builder.ins().swiden_low(a);
2223 let b_low = builder.ins().swiden_low(b);
2224 stack.push1(builder.ins().imul(a_low, b_low));
2225 }
2226 Operator::I16x8ExtMulHighI8x16S => {
2227 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2228 let a_high = builder.ins().swiden_high(a);
2229 let b_high = builder.ins().swiden_high(b);
2230 stack.push1(builder.ins().imul(a_high, b_high));
2231 }
2232 Operator::I16x8ExtMulLowI8x16U => {
2233 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2234 let a_low = builder.ins().uwiden_low(a);
2235 let b_low = builder.ins().uwiden_low(b);
2236 stack.push1(builder.ins().imul(a_low, b_low));
2237 }
2238 Operator::I16x8ExtMulHighI8x16U => {
2239 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2240 let a_high = builder.ins().uwiden_high(a);
2241 let b_high = builder.ins().uwiden_high(b);
2242 stack.push1(builder.ins().imul(a_high, b_high));
2243 }
2244 Operator::I32x4ExtMulLowI16x8S => {
2245 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2246 let a_low = builder.ins().swiden_low(a);
2247 let b_low = builder.ins().swiden_low(b);
2248 stack.push1(builder.ins().imul(a_low, b_low));
2249 }
2250 Operator::I32x4ExtMulHighI16x8S => {
2251 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2252 let a_high = builder.ins().swiden_high(a);
2253 let b_high = builder.ins().swiden_high(b);
2254 stack.push1(builder.ins().imul(a_high, b_high));
2255 }
2256 Operator::I32x4ExtMulLowI16x8U => {
2257 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2258 let a_low = builder.ins().uwiden_low(a);
2259 let b_low = builder.ins().uwiden_low(b);
2260 stack.push1(builder.ins().imul(a_low, b_low));
2261 }
2262 Operator::I32x4ExtMulHighI16x8U => {
2263 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2264 let a_high = builder.ins().uwiden_high(a);
2265 let b_high = builder.ins().uwiden_high(b);
2266 stack.push1(builder.ins().imul(a_high, b_high));
2267 }
2268 Operator::I64x2ExtMulLowI32x4S => {
2269 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2270 let a_low = builder.ins().swiden_low(a);
2271 let b_low = builder.ins().swiden_low(b);
2272 stack.push1(builder.ins().imul(a_low, b_low));
2273 }
2274 Operator::I64x2ExtMulHighI32x4S => {
2275 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2276 let a_high = builder.ins().swiden_high(a);
2277 let b_high = builder.ins().swiden_high(b);
2278 stack.push1(builder.ins().imul(a_high, b_high));
2279 }
2280 Operator::I64x2ExtMulLowI32x4U => {
2281 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2282 let a_low = builder.ins().uwiden_low(a);
2283 let b_low = builder.ins().uwiden_low(b);
2284 stack.push1(builder.ins().imul(a_low, b_low));
2285 }
2286 Operator::I64x2ExtMulHighI32x4U => {
2287 let (a, b) = pop2_with_bitcast(stack, I32X4, builder);
2288 let a_high = builder.ins().uwiden_high(a);
2289 let b_high = builder.ins().uwiden_high(b);
2290 stack.push1(builder.ins().imul(a_high, b_high));
2291 }
2292 Operator::MemoryDiscard { .. } => {
2293 return Err(wasm_unsupported!(
2294 "proposed memory-control operator {:?}",
2295 op
2296 ));
2297 }
2298
2299 Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => {
2300 let ty = type_of(op);
2301 let (a, b) = pop2_with_bitcast(stack, ty, builder);
2302 stack.push1(
2303 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2304 builder.ins().fmax(a, b)
2307 } else {
2308 let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
2312 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2313 builder.ins().bitselect(cmp, b, a)
2314 },
2315 )
2316 }
2317
2318 Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => {
2319 let ty = type_of(op);
2320 let (a, b) = pop2_with_bitcast(stack, ty, builder);
2321 stack.push1(
2322 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2323 builder.ins().fmin(a, b)
2326 } else {
2327 let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
2331 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2332 builder.ins().bitselect(cmp, b, a)
2333 },
2334 );
2335 }
2336
2337 Operator::I8x16RelaxedSwizzle => {
2338 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2339 stack.push1(environ.relaxed_swizzle(builder, a, b));
2340 }
2341
2342 Operator::F32x4RelaxedMadd => {
2343 let (a, b, c) = pop3_with_bitcast(stack, type_of(op), builder);
2344 stack.push1(environ.fma_f32x4(builder, a, b, c));
2345 }
2346 Operator::F64x2RelaxedMadd => {
2347 let (a, b, c) = pop3_with_bitcast(stack, type_of(op), builder);
2348 stack.push1(environ.fma_f64x2(builder, a, b, c));
2349 }
2350 Operator::F32x4RelaxedNmadd => {
2351 let (a, b, c) = pop3_with_bitcast(stack, type_of(op), builder);
2352 let a = builder.ins().fneg(a);
2353 stack.push1(environ.fma_f32x4(builder, a, b, c));
2354 }
2355 Operator::F64x2RelaxedNmadd => {
2356 let (a, b, c) = pop3_with_bitcast(stack, type_of(op), builder);
2357 let a = builder.ins().fneg(a);
2358 stack.push1(environ.fma_f64x2(builder, a, b, c));
2359 }
2360
2361 Operator::I8x16RelaxedLaneselect
2362 | Operator::I16x8RelaxedLaneselect
2363 | Operator::I32x4RelaxedLaneselect
2364 | Operator::I64x2RelaxedLaneselect => {
2365 let ty = type_of(op);
2366 let (a, b, c) = pop3_with_bitcast(stack, ty, builder);
2367 stack.push1(
2371 if environ.relaxed_simd_deterministic()
2372 || !environ.use_x86_blendv_for_relaxed_laneselect(ty)
2373 {
2374 builder.ins().bitselect(c, a, b)
2377 } else {
2378 builder.ins().x86_blendv(c, a, b)
2379 },
2380 );
2381 }
2382
2383 Operator::I32x4RelaxedTruncF32x4S => {
2384 let a = pop1_with_bitcast(stack, F32X4, builder);
2385 stack.push1(
2386 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2387 builder.ins().fcvt_to_sint_sat(I32X4, a)
2390 } else {
2391 builder.ins().x86_cvtt2dq(I32X4, a)
2392 },
2393 )
2394 }
2395 Operator::I32x4RelaxedTruncF64x2SZero => {
2396 let a = pop1_with_bitcast(stack, F64X2, builder);
2397 let converted_a = if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2398 builder.ins().fcvt_to_sint_sat(I64X2, a)
2401 } else {
2402 builder.ins().x86_cvtt2dq(I64X2, a)
2403 };
2404 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2405 let zero = builder.ins().vconst(I64X2, handle);
2406
2407 stack.push1(builder.ins().snarrow(converted_a, zero));
2408 }
2409 Operator::I16x8RelaxedQ15mulrS => {
2410 let (a, b) = pop2_with_bitcast(stack, I16X8, builder);
2411 stack.push1(
2412 if environ.relaxed_simd_deterministic()
2413 || !environ.use_x86_pmulhrsw_for_relaxed_q15mul()
2414 {
2415 builder.ins().sqmul_round_sat(a, b)
2418 } else {
2419 builder.ins().x86_pmulhrsw(a, b)
2420 },
2421 );
2422 }
2423 Operator::I16x8RelaxedDotI8x16I7x16S => {
2424 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2425 stack.push1(
2426 if environ.relaxed_simd_deterministic() || !environ.use_x86_pmaddubsw_for_dot() {
2427 let alo = builder.ins().swiden_low(a);
2430 let blo = builder.ins().swiden_low(b);
2431 let lo = builder.ins().imul(alo, blo);
2432 let ahi = builder.ins().swiden_high(a);
2433 let bhi = builder.ins().swiden_high(b);
2434 let hi = builder.ins().imul(ahi, bhi);
2435 builder.ins().iadd_pairwise(lo, hi)
2436 } else {
2437 builder.ins().x86_pmaddubsw(a, b)
2438 },
2439 );
2440 }
2441
2442 Operator::I32x4RelaxedDotI8x16I7x16AddS => {
2443 let c = pop1_with_bitcast(stack, I32X4, builder);
2444 let (a, b) = pop2_with_bitcast(stack, I8X16, builder);
2445 let dot =
2446 if environ.relaxed_simd_deterministic() || !environ.use_x86_pmaddubsw_for_dot() {
2447 let alo = builder.ins().swiden_low(a);
2450 let blo = builder.ins().swiden_low(b);
2451 let lo = builder.ins().imul(alo, blo);
2452 let ahi = builder.ins().swiden_high(a);
2453 let bhi = builder.ins().swiden_high(b);
2454 let hi = builder.ins().imul(ahi, bhi);
2455 builder.ins().iadd_pairwise(lo, hi)
2456 } else {
2457 builder.ins().x86_pmaddubsw(a, b)
2458 };
2459 let dotlo = builder.ins().swiden_low(dot);
2460 let dothi = builder.ins().swiden_high(dot);
2461 let dot32 = builder.ins().iadd_pairwise(dotlo, dothi);
2462 stack.push1(builder.ins().iadd(dot32, c));
2463 }
2464
2465 Operator::BrOnNull { relative_depth } => {
2466 let r = stack.pop1();
2467 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2468 unreachable!("validation")
2469 };
2470 let (br_destination, inputs) = translate_br_if_args(*relative_depth, stack);
2471 let is_null = environ.translate_ref_is_null(builder.cursor(), r, *r_ty)?;
2472 let else_block = builder.create_block();
2473 canonicalise_brif(builder, is_null, br_destination, inputs, else_block, &[]);
2474
2475 builder.seal_block(else_block); builder.switch_to_block(else_block);
2477 stack.push1(r);
2478 }
2479 Operator::BrOnNonNull { relative_depth } => {
2480 let r = stack.peek1();
2487 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2488 unreachable!("validation")
2489 };
2490 let is_null = environ.translate_ref_is_null(builder.cursor(), r, *r_ty)?;
2491 let (br_destination, inputs) = translate_br_if_args(*relative_depth, stack);
2492 let else_block = builder.create_block();
2493 canonicalise_brif(builder, is_null, else_block, &[], br_destination, inputs);
2494
2495 stack.pop1();
2497
2498 builder.seal_block(else_block); builder.switch_to_block(else_block);
2503 }
2504 Operator::CallRef { type_index } => {
2505 let type_index = TypeIndex::from_u32(*type_index);
2509 let sigref = environ.get_or_create_sig_ref(builder.func, type_index);
2510 let num_args = environ.num_params_for_function_type(type_index);
2511 let callee = stack.pop1();
2512
2513 let args = stack.peekn_mut(num_args);
2515 bitcast_wasm_params(environ, sigref, args, builder);
2516
2517 let inst_results = environ.translate_call_ref(
2518 builder,
2519 sigref,
2520 callee,
2521 stack.peekn(num_args),
2522 stack.handlers.handlers(),
2523 )?;
2524
2525 debug_assert_eq!(
2526 inst_results.len(),
2527 builder.func.dfg.signatures[sigref].returns.len(),
2528 "translate_call_ref results should match the call signature"
2529 );
2530 stack.popn(num_args);
2531 stack.pushn(&inst_results);
2532 }
2533 Operator::RefAsNonNull => {
2534 let r = stack.pop1();
2535 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2536 unreachable!("validation")
2537 };
2538 let is_null = environ.translate_ref_is_null(builder.cursor(), r, *r_ty)?;
2539 environ.trapnz(builder, is_null, crate::TRAP_NULL_REFERENCE);
2540 stack.push1(r);
2541 }
2542
2543 Operator::RefI31 => {
2544 let val = stack.pop1();
2545 let i31ref = environ.translate_ref_i31(builder.cursor(), val)?;
2546 stack.push1(i31ref);
2547 }
2548 Operator::I31GetS => {
2549 let i31ref = stack.pop1();
2550 let val = environ.translate_i31_get_s(builder, i31ref)?;
2551 stack.push1(val);
2552 }
2553 Operator::I31GetU => {
2554 let i31ref = stack.pop1();
2555 let val = environ.translate_i31_get_u(builder, i31ref)?;
2556 stack.push1(val);
2557 }
2558
2559 Operator::StructNew { struct_type_index } => {
2560 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2561 let arity = environ.struct_fields_len(struct_type_index)?;
2562 let fields: StructFieldsVec = stack.peekn(arity).iter().copied().collect();
2563 stack.popn(arity);
2564 let struct_ref = environ.translate_struct_new(builder, struct_type_index, fields)?;
2565 stack.push1(struct_ref);
2566 }
2567
2568 Operator::StructNewDefault { struct_type_index } => {
2569 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2570 let struct_ref = environ.translate_struct_new_default(builder, struct_type_index)?;
2571 stack.push1(struct_ref);
2572 }
2573
2574 Operator::StructSet {
2575 struct_type_index,
2576 field_index,
2577 } => {
2578 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2579 let val = stack.pop1();
2580 let struct_ref = stack.pop1();
2581 environ.translate_struct_set(
2582 builder,
2583 struct_type_index,
2584 *field_index,
2585 struct_ref,
2586 val,
2587 )?;
2588 }
2589
2590 Operator::StructGetS {
2591 struct_type_index,
2592 field_index,
2593 } => {
2594 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2595 let struct_ref = stack.pop1();
2596 let val = environ.translate_struct_get(
2597 builder,
2598 struct_type_index,
2599 *field_index,
2600 struct_ref,
2601 Some(Extension::Sign),
2602 )?;
2603 stack.push1(val);
2604 }
2605
2606 Operator::StructGetU {
2607 struct_type_index,
2608 field_index,
2609 } => {
2610 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2611 let struct_ref = stack.pop1();
2612 let val = environ.translate_struct_get(
2613 builder,
2614 struct_type_index,
2615 *field_index,
2616 struct_ref,
2617 Some(Extension::Zero),
2618 )?;
2619 stack.push1(val);
2620 }
2621
2622 Operator::StructGet {
2623 struct_type_index,
2624 field_index,
2625 } => {
2626 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2627 let struct_ref = stack.pop1();
2628 let val = environ.translate_struct_get(
2629 builder,
2630 struct_type_index,
2631 *field_index,
2632 struct_ref,
2633 None,
2634 )?;
2635 stack.push1(val);
2636 }
2637
2638 Operator::ArrayNew { array_type_index } => {
2639 let array_type_index = TypeIndex::from_u32(*array_type_index);
2640 let (elem, len) = stack.pop2();
2641 let array_ref = environ.translate_array_new(builder, array_type_index, elem, len)?;
2642 stack.push1(array_ref);
2643 }
2644 Operator::ArrayNewDefault { array_type_index } => {
2645 let array_type_index = TypeIndex::from_u32(*array_type_index);
2646 let len = stack.pop1();
2647 let array_ref = environ.translate_array_new_default(builder, array_type_index, len)?;
2648 stack.push1(array_ref);
2649 }
2650 Operator::ArrayNewFixed {
2651 array_type_index,
2652 array_size,
2653 } => {
2654 let array_type_index = TypeIndex::from_u32(*array_type_index);
2655 let array_size = usize::try_from(*array_size).unwrap();
2656 let elems = stack.peekn(array_size);
2657 let array_ref = environ.translate_array_new_fixed(builder, array_type_index, elems)?;
2658 stack.popn(array_size);
2659 stack.push1(array_ref);
2660 }
2661 Operator::ArrayNewData {
2662 array_type_index,
2663 array_data_index,
2664 } => {
2665 let array_type_index = TypeIndex::from_u32(*array_type_index);
2666 let array_data_index = DataIndex::from_u32(*array_data_index);
2667 let (data_offset, len) = stack.pop2();
2668 let array_ref = environ.translate_array_new_data(
2669 builder,
2670 array_type_index,
2671 array_data_index,
2672 data_offset,
2673 len,
2674 )?;
2675 stack.push1(array_ref);
2676 }
2677 Operator::ArrayNewElem {
2678 array_type_index,
2679 array_elem_index,
2680 } => {
2681 let array_type_index = TypeIndex::from_u32(*array_type_index);
2682 let array_elem_index = ElemIndex::from_u32(*array_elem_index);
2683 let (elem_offset, len) = stack.pop2();
2684 let array_ref = environ.translate_array_new_elem(
2685 builder,
2686 array_type_index,
2687 array_elem_index,
2688 elem_offset,
2689 len,
2690 )?;
2691 stack.push1(array_ref);
2692 }
2693 Operator::ArrayCopy {
2694 array_type_index_dst,
2695 array_type_index_src,
2696 } => {
2697 let array_type_index_dst = TypeIndex::from_u32(*array_type_index_dst);
2698 let array_type_index_src = TypeIndex::from_u32(*array_type_index_src);
2699 let (dst_array, dst_index, src_array, src_index, len) = stack.pop5();
2700 environ.translate_array_copy(
2701 builder,
2702 array_type_index_dst,
2703 dst_array,
2704 dst_index,
2705 array_type_index_src,
2706 src_array,
2707 src_index,
2708 len,
2709 )?;
2710 }
2711 Operator::ArrayFill { array_type_index } => {
2712 let array_type_index = TypeIndex::from_u32(*array_type_index);
2713 let (array, index, val, len) = stack.pop4();
2714 environ.translate_array_fill(builder, array_type_index, array, index, val, len)?;
2715 }
2716 Operator::ArrayInitData {
2717 array_type_index,
2718 array_data_index,
2719 } => {
2720 let array_type_index = TypeIndex::from_u32(*array_type_index);
2721 let array_data_index = DataIndex::from_u32(*array_data_index);
2722 let (array, dst_index, src_index, len) = stack.pop4();
2723 environ.translate_array_init_data(
2724 builder,
2725 array_type_index,
2726 array,
2727 dst_index,
2728 array_data_index,
2729 src_index,
2730 len,
2731 )?;
2732 }
2733 Operator::ArrayInitElem {
2734 array_type_index,
2735 array_elem_index,
2736 } => {
2737 let array_type_index = TypeIndex::from_u32(*array_type_index);
2738 let array_elem_index = ElemIndex::from_u32(*array_elem_index);
2739 let (array, dst_index, src_index, len) = stack.pop4();
2740 environ.translate_array_init_elem(
2741 builder,
2742 array_type_index,
2743 array,
2744 dst_index,
2745 array_elem_index,
2746 src_index,
2747 len,
2748 )?;
2749 }
2750 Operator::ArrayLen => {
2751 let array = stack.pop1();
2752 let len = environ.translate_array_len(builder, array)?;
2753 stack.push1(len);
2754 }
2755 Operator::ArrayGet { array_type_index } => {
2756 let array_type_index = TypeIndex::from_u32(*array_type_index);
2757 let (array, index) = stack.pop2();
2758 let elem =
2759 environ.translate_array_get(builder, array_type_index, array, index, None)?;
2760 stack.push1(elem);
2761 }
2762 Operator::ArrayGetS { array_type_index } => {
2763 let array_type_index = TypeIndex::from_u32(*array_type_index);
2764 let (array, index) = stack.pop2();
2765 let elem = environ.translate_array_get(
2766 builder,
2767 array_type_index,
2768 array,
2769 index,
2770 Some(Extension::Sign),
2771 )?;
2772 stack.push1(elem);
2773 }
2774 Operator::ArrayGetU { array_type_index } => {
2775 let array_type_index = TypeIndex::from_u32(*array_type_index);
2776 let (array, index) = stack.pop2();
2777 let elem = environ.translate_array_get(
2778 builder,
2779 array_type_index,
2780 array,
2781 index,
2782 Some(Extension::Zero),
2783 )?;
2784 stack.push1(elem);
2785 }
2786 Operator::ArraySet { array_type_index } => {
2787 let array_type_index = TypeIndex::from_u32(*array_type_index);
2788 let (array, index, elem) = stack.pop3();
2789 environ.translate_array_set(builder, array_type_index, array, index, elem)?;
2790 }
2791 Operator::RefEq => {
2792 let (r1, r2) = stack.pop2();
2793 let eq = builder.ins().icmp(ir::condcodes::IntCC::Equal, r1, r2);
2794 let eq = builder.ins().uextend(ir::types::I32, eq);
2795 stack.push1(eq);
2796 }
2797 Operator::RefTestNonNull { hty } => {
2798 let r = stack.pop1();
2799 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2800 unreachable!("validation")
2801 };
2802 let heap_type = environ.convert_heap_type(*hty)?;
2803 let result = environ.translate_ref_test(
2804 builder,
2805 WasmRefType {
2806 heap_type,
2807 nullable: false,
2808 },
2809 r,
2810 *r_ty,
2811 )?;
2812 stack.push1(result);
2813 }
2814 Operator::RefTestNullable { hty } => {
2815 let r = stack.pop1();
2816 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2817 unreachable!("validation")
2818 };
2819 let heap_type = environ.convert_heap_type(*hty)?;
2820 let result = environ.translate_ref_test(
2821 builder,
2822 WasmRefType {
2823 heap_type,
2824 nullable: true,
2825 },
2826 r,
2827 *r_ty,
2828 )?;
2829 stack.push1(result);
2830 }
2831 Operator::RefCastNonNull { hty } => {
2832 let r = stack.pop1();
2833 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2834 unreachable!("validation")
2835 };
2836 let heap_type = environ.convert_heap_type(*hty)?;
2837 let cast_okay = environ.translate_ref_test(
2838 builder,
2839 WasmRefType {
2840 heap_type,
2841 nullable: false,
2842 },
2843 r,
2844 *r_ty,
2845 )?;
2846 environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
2847 stack.push1(r);
2848 }
2849 Operator::RefCastNullable { hty } => {
2850 let r = stack.pop1();
2851 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2852 unreachable!("validation")
2853 };
2854 let heap_type = environ.convert_heap_type(*hty)?;
2855 let cast_okay = environ.translate_ref_test(
2856 builder,
2857 WasmRefType {
2858 heap_type,
2859 nullable: true,
2860 },
2861 r,
2862 *r_ty,
2863 )?;
2864 environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
2865 stack.push1(r);
2866 }
2867 Operator::BrOnCast {
2868 relative_depth,
2869 to_ref_type,
2870 from_ref_type: _,
2871 } => {
2872 let r = stack.peek1();
2873 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2874 unreachable!("validation")
2875 };
2876
2877 let to_ref_type = environ.convert_ref_type(*to_ref_type)?;
2878 let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r, *r_ty)?;
2879
2880 let (cast_succeeds_block, inputs) = translate_br_if_args(*relative_depth, stack);
2881 let cast_fails_block = builder.create_block();
2882 canonicalise_brif(
2883 builder,
2884 cast_is_okay,
2885 cast_succeeds_block,
2886 inputs,
2887 cast_fails_block,
2888 &[
2889 ],
2892 );
2893
2894 builder.seal_block(cast_fails_block);
2896
2897 builder.switch_to_block(cast_fails_block);
2900 }
2901 Operator::BrOnCastFail {
2902 relative_depth,
2903 to_ref_type,
2904 from_ref_type: _,
2905 } => {
2906 let r = stack.peek1();
2907 let [.., WasmValType::Ref(r_ty)] = operand_types else {
2908 unreachable!("validation")
2909 };
2910
2911 let to_ref_type = environ.convert_ref_type(*to_ref_type)?;
2912 let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r, *r_ty)?;
2913
2914 let (cast_fails_block, inputs) = translate_br_if_args(*relative_depth, stack);
2915 let cast_succeeds_block = builder.create_block();
2916 canonicalise_brif(
2917 builder,
2918 cast_is_okay,
2919 cast_succeeds_block,
2920 &[
2921 ],
2924 cast_fails_block,
2925 inputs,
2926 );
2927
2928 builder.seal_block(cast_succeeds_block);
2930
2931 builder.switch_to_block(cast_succeeds_block);
2934 }
2935
2936 Operator::AnyConvertExtern => {
2937 }
2940 Operator::ExternConvertAny => {
2941 }
2944
2945 Operator::ContNew { cont_type_index } => {
2946 let cont_type_index = TypeIndex::from_u32(*cont_type_index);
2947 let arg_types: SmallVec<[_; 8]> = environ
2948 .continuation_arguments(cont_type_index)
2949 .to_smallvec();
2950 let result_types: SmallVec<[_; 8]> =
2951 environ.continuation_returns(cont_type_index).to_smallvec();
2952 let r = stack.pop1();
2953 let contobj = environ.translate_cont_new(builder, r, &arg_types, &result_types)?;
2954 stack.push1(contobj);
2955 }
2956 Operator::ContBind {
2957 argument_index,
2958 result_index,
2959 } => {
2960 let src_types = environ.continuation_arguments(TypeIndex::from_u32(*argument_index));
2961 let dst_arity = environ
2962 .continuation_arguments(TypeIndex::from_u32(*result_index))
2963 .len();
2964 let arg_count = src_types.len() - dst_arity;
2965
2966 let arg_types = &src_types[0..arg_count];
2967 for arg_type in arg_types {
2968 if arg_type.is_vmgcref_type_and_not_i31() {
2974 return Err(wasmtime_environ::WasmError::Unsupported(
2975 "cont.bind does not support GC types at the moment".into(),
2976 ));
2977 }
2978 }
2979
2980 let (original_contobj, args) = stack.peekn(arg_count + 1).split_last().unwrap();
2981
2982 let new_contobj = environ.translate_cont_bind(builder, *original_contobj, args);
2983
2984 stack.popn(arg_count + 1);
2985 stack.push1(new_contobj);
2986 }
2987 Operator::Suspend { tag_index } => {
2988 let tag_index = TagIndex::from_u32(*tag_index);
2989 let param_types = environ.tag_params(tag_index).to_vec();
2990 let return_types: SmallVec<[_; 8]> = environ
2991 .tag_returns(tag_index)
2992 .iter()
2993 .map(|ty| crate::value_type(environ.isa(), *ty))
2994 .collect();
2995
2996 let params = stack.peekn(param_types.len());
2997 let param_count = params.len();
2998
2999 let return_values =
3000 environ.translate_suspend(builder, tag_index.as_u32(), params, &return_types);
3001
3002 stack.popn(param_count);
3003 stack.pushn(&return_values);
3004 }
3005 Operator::Resume {
3006 cont_type_index,
3007 resume_table: wasm_resume_table,
3008 } => {
3009 let mut clif_resume_table = vec![];
3011 for handle in &wasm_resume_table.handlers {
3012 match handle {
3013 wasmparser::Handle::OnLabel { tag, label } => {
3014 let i = stack.control_stack.len() - 1 - (*label as usize);
3015 let frame = &mut stack.control_stack[i];
3016 frame.set_branched_to_exit();
3018 clif_resume_table.push((*tag, Some(frame.br_destination())));
3019 }
3020 wasmparser::Handle::OnSwitch { tag } => {
3021 clif_resume_table.push((*tag, None));
3022 }
3023 }
3024 }
3025
3026 let cont_type_index = TypeIndex::from_u32(*cont_type_index);
3027 let arity = environ.continuation_arguments(cont_type_index).len();
3028 let (contobj, call_args) = stack.peekn(arity + 1).split_last().unwrap();
3029
3030 let cont_return_vals = environ.translate_resume(
3031 builder,
3032 cont_type_index.as_u32(),
3033 *contobj,
3034 call_args,
3035 &clif_resume_table,
3036 )?;
3037
3038 stack.popn(arity + 1); stack.pushn(&cont_return_vals);
3040 }
3041 Operator::ResumeThrow {
3042 cont_type_index: _,
3043 tag_index: _,
3044 resume_table: _,
3045 } => {
3046 return Err(wasmtime_environ::WasmError::Unsupported(
3048 "resume.throw instructions not supported, yet".to_string(),
3049 ));
3050 }
3051 Operator::Switch {
3052 cont_type_index,
3053 tag_index,
3054 } => {
3055 let continuation_argument_types: SmallVec<[_; 8]> = environ
3057 .continuation_arguments(TypeIndex::from_u32(*cont_type_index))
3058 .to_smallvec();
3059 let arity = continuation_argument_types.len();
3061 let (contobj, switch_args) = stack.peekn(arity).split_last().unwrap();
3062
3063 let current_continuation_type = continuation_argument_types.last().unwrap();
3066 let current_continuation_type = current_continuation_type.unwrap_ref_type();
3067
3068 let current_continuation_arg_types: SmallVec<[_; 8]> =
3072 match current_continuation_type.heap_type {
3073 WasmHeapType::ConcreteCont(index) => {
3074 let mti = index
3075 .as_module_type_index()
3076 .expect("Only supporting module type indices on switch for now");
3077
3078 environ
3079 .continuation_arguments(TypeIndex::from_u32(mti.as_u32()))
3080 .iter()
3081 .map(|ty| crate::value_type(environ.isa(), *ty))
3082 .collect()
3083 }
3084 _ => panic!("Invalid type on switch"),
3085 };
3086
3087 let switch_return_values = environ.translate_switch(
3088 builder,
3089 *tag_index,
3090 *contobj,
3091 switch_args,
3092 ¤t_continuation_arg_types,
3093 )?;
3094
3095 stack.popn(arity);
3096 stack.pushn(&switch_return_values)
3097 }
3098
3099 Operator::GlobalAtomicGet { .. }
3100 | Operator::GlobalAtomicSet { .. }
3101 | Operator::GlobalAtomicRmwAdd { .. }
3102 | Operator::GlobalAtomicRmwSub { .. }
3103 | Operator::GlobalAtomicRmwOr { .. }
3104 | Operator::GlobalAtomicRmwXor { .. }
3105 | Operator::GlobalAtomicRmwAnd { .. }
3106 | Operator::GlobalAtomicRmwXchg { .. }
3107 | Operator::GlobalAtomicRmwCmpxchg { .. }
3108 | Operator::TableAtomicGet { .. }
3109 | Operator::TableAtomicSet { .. }
3110 | Operator::TableAtomicRmwXchg { .. }
3111 | Operator::TableAtomicRmwCmpxchg { .. }
3112 | Operator::StructAtomicGet { .. }
3113 | Operator::StructAtomicGetS { .. }
3114 | Operator::StructAtomicGetU { .. }
3115 | Operator::StructAtomicSet { .. }
3116 | Operator::StructAtomicRmwAdd { .. }
3117 | Operator::StructAtomicRmwSub { .. }
3118 | Operator::StructAtomicRmwOr { .. }
3119 | Operator::StructAtomicRmwXor { .. }
3120 | Operator::StructAtomicRmwAnd { .. }
3121 | Operator::StructAtomicRmwXchg { .. }
3122 | Operator::StructAtomicRmwCmpxchg { .. }
3123 | Operator::ArrayAtomicGet { .. }
3124 | Operator::ArrayAtomicGetS { .. }
3125 | Operator::ArrayAtomicGetU { .. }
3126 | Operator::ArrayAtomicSet { .. }
3127 | Operator::ArrayAtomicRmwAdd { .. }
3128 | Operator::ArrayAtomicRmwSub { .. }
3129 | Operator::ArrayAtomicRmwOr { .. }
3130 | Operator::ArrayAtomicRmwXor { .. }
3131 | Operator::ArrayAtomicRmwAnd { .. }
3132 | Operator::ArrayAtomicRmwXchg { .. }
3133 | Operator::ArrayAtomicRmwCmpxchg { .. }
3134 | Operator::RefI31Shared { .. } => {
3135 return Err(wasm_unsupported!(
3136 "shared-everything-threads operators are not yet implemented"
3137 ));
3138 }
3139
3140 Operator::I64MulWideS => {
3141 let (arg1, arg2) = stack.pop2();
3142 let arg1 = builder.ins().sextend(I128, arg1);
3143 let arg2 = builder.ins().sextend(I128, arg2);
3144 let result = builder.ins().imul(arg1, arg2);
3145 let (lo, hi) = builder.ins().isplit(result);
3146 stack.push2(lo, hi);
3147 }
3148 Operator::I64MulWideU => {
3149 let (arg1, arg2) = stack.pop2();
3150 let arg1 = builder.ins().uextend(I128, arg1);
3151 let arg2 = builder.ins().uextend(I128, arg2);
3152 let result = builder.ins().imul(arg1, arg2);
3153 let (lo, hi) = builder.ins().isplit(result);
3154 stack.push2(lo, hi);
3155 }
3156 Operator::I64Add128 => {
3157 let (arg1, arg2, arg3, arg4) = stack.pop4();
3158 let arg1 = builder.ins().iconcat(arg1, arg2);
3159 let arg2 = builder.ins().iconcat(arg3, arg4);
3160 let result = builder.ins().iadd(arg1, arg2);
3161 let (res1, res2) = builder.ins().isplit(result);
3162 stack.push2(res1, res2);
3163 }
3164 Operator::I64Sub128 => {
3165 let (arg1, arg2, arg3, arg4) = stack.pop4();
3166 let arg1 = builder.ins().iconcat(arg1, arg2);
3167 let arg2 = builder.ins().iconcat(arg3, arg4);
3168 let result = builder.ins().isub(arg1, arg2);
3169 let (res1, res2) = builder.ins().isplit(result);
3170 stack.push2(res1, res2);
3171 }
3172
3173 op => return Err(wasm_unsupported!("operator {op:?}")),
3175 };
3176 Ok(())
3177}
3178
3179fn translate_unreachable_operator(
3183 validator: &FuncValidator<impl WasmModuleResources>,
3184 op: &Operator,
3185 builder: &mut FunctionBuilder,
3186 stack: &mut FuncTranslationStacks,
3187 environ: &mut FuncEnvironment<'_>,
3188) -> WasmResult<()> {
3189 debug_assert!(!stack.reachable);
3190 match *op {
3191 Operator::If { blockty } => {
3192 stack.push_if(
3195 ir::Block::reserved_value(),
3196 ElseData::NoElse {
3197 branch_inst: ir::Inst::reserved_value(),
3198 placeholder: ir::Block::reserved_value(),
3199 },
3200 0,
3201 0,
3202 blockty,
3203 );
3204 }
3205 Operator::Loop { blockty: _ }
3206 | Operator::Block { blockty: _ }
3207 | Operator::TryTable { try_table: _ } => {
3208 stack.push_block(ir::Block::reserved_value(), 0, 0);
3209 }
3210 Operator::Else => {
3211 let i = stack.control_stack.len() - 1;
3212 match stack.control_stack[i] {
3213 ControlStackFrame::If {
3214 ref else_data,
3215 head_is_reachable,
3216 ref mut consequent_ends_reachable,
3217 blocktype,
3218 ..
3219 } => {
3220 debug_assert!(consequent_ends_reachable.is_none());
3221 *consequent_ends_reachable = Some(stack.reachable);
3222
3223 if head_is_reachable {
3224 stack.reachable = true;
3226
3227 let else_block = match *else_data {
3228 ElseData::NoElse {
3229 branch_inst,
3230 placeholder,
3231 } => {
3232 let (params, _results) =
3233 blocktype_params_results(validator, blocktype)?;
3234 let else_block = block_with_params(builder, params, environ)?;
3235 let frame = stack.control_stack.last().unwrap();
3236 frame.truncate_value_stack_to_else_params(&mut stack.stack);
3237
3238 builder.change_jump_destination(
3240 branch_inst,
3241 placeholder,
3242 else_block,
3243 );
3244 builder.seal_block(else_block);
3245 else_block
3246 }
3247 ElseData::WithElse { else_block } => {
3248 let frame = stack.control_stack.last().unwrap();
3249 frame.truncate_value_stack_to_else_params(&mut stack.stack);
3250 else_block
3251 }
3252 };
3253
3254 builder.switch_to_block(else_block);
3255
3256 }
3261 }
3262 _ => unreachable!(),
3263 }
3264 }
3265 Operator::End => {
3266 let value_stack = &mut stack.stack;
3267 let control_stack = &mut stack.control_stack;
3268 let frame = control_stack.pop().unwrap();
3269
3270 frame.restore_catch_handlers(&mut stack.handlers, builder);
3271
3272 frame.truncate_value_stack_to_original_size(value_stack);
3274
3275 let reachable_anyway = match frame {
3276 ControlStackFrame::Loop { header, .. } => {
3278 builder.seal_block(header);
3279 false
3281 }
3282 ControlStackFrame::If {
3287 head_is_reachable,
3288 consequent_ends_reachable: None,
3289 ..
3290 } => head_is_reachable,
3291 ControlStackFrame::If {
3296 head_is_reachable,
3297 consequent_ends_reachable: Some(consequent_ends_reachable),
3298 ..
3299 } => head_is_reachable && consequent_ends_reachable,
3300 _ => false,
3302 };
3303
3304 if frame.exit_is_branched_to() || reachable_anyway {
3305 builder.switch_to_block(frame.following_code());
3306 builder.seal_block(frame.following_code());
3307
3308 value_stack.extend_from_slice(builder.block_params(frame.following_code()));
3311 stack.reachable = true;
3312 }
3313 }
3314 _ => {
3315 }
3317 }
3318
3319 Ok(())
3320}
3321
3322fn prepare_addr(
3335 memarg: &MemArg,
3336 access_size: u8,
3337 builder: &mut FunctionBuilder,
3338 stack: &mut FuncTranslationStacks,
3339 environ: &mut FuncEnvironment<'_>,
3340) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
3341 let index = stack.pop1();
3342
3343 let memory_index = MemoryIndex::from_u32(memarg.memory);
3344 let heap = environ.get_or_create_heap(builder.func, memory_index);
3345
3346 let heap = environ.heaps()[heap].clone();
3417 let addr = match u32::try_from(memarg.offset) {
3418 Ok(offset) => bounds_check_and_compute_addr(
3421 builder,
3422 environ,
3423 &heap,
3424 index,
3425 BoundsCheck::StaticOffset {
3426 offset,
3427 access_size,
3428 },
3429 ir::TrapCode::HEAP_OUT_OF_BOUNDS,
3430 ),
3431
3432 Err(_) => {
3459 let offset = builder
3460 .ins()
3461 .iconst(heap.index_type(), memarg.offset.cast_signed());
3462 let adjusted_index = environ.uadd_overflow_trap(
3463 builder,
3464 index,
3465 offset,
3466 ir::TrapCode::HEAP_OUT_OF_BOUNDS,
3467 );
3468 bounds_check_and_compute_addr(
3469 builder,
3470 environ,
3471 &heap,
3472 adjusted_index,
3473 BoundsCheck::StaticOffset {
3474 offset: 0,
3475 access_size,
3476 },
3477 ir::TrapCode::HEAP_OUT_OF_BOUNDS,
3478 )
3479 }
3480 };
3481 let addr = match addr {
3482 Reachability::Unreachable => return Ok(Reachability::Unreachable),
3483 Reachability::Reachable(a) => a,
3484 };
3485
3486 let mut flags = MemFlags::new();
3491 flags.set_endianness(ir::Endianness::Little);
3492
3493 if heap.pcc_memory_type.is_some() {
3494 flags.set_checked();
3496 }
3497
3498 flags.set_alias_region(Some(ir::AliasRegion::Heap));
3503
3504 Ok(Reachability::Reachable((flags, index, addr)))
3505}
3506
3507fn align_atomic_addr(
3508 memarg: &MemArg,
3509 loaded_bytes: u8,
3510 builder: &mut FunctionBuilder,
3511 stack: &mut FuncTranslationStacks,
3512 environ: &mut FuncEnvironment<'_>,
3513) {
3514 if loaded_bytes > 1 {
3525 let addr = stack.pop1(); stack.push1(addr);
3527 let effective_addr = if memarg.offset == 0 {
3528 addr
3529 } else {
3530 builder.ins().iadd_imm(addr, memarg.offset.cast_signed())
3531 };
3532 debug_assert!(loaded_bytes.is_power_of_two());
3533 let misalignment = builder
3534 .ins()
3535 .band_imm(effective_addr, i64::from(loaded_bytes - 1));
3536 let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0);
3537 environ.trapnz(builder, f, crate::TRAP_HEAP_MISALIGNED);
3538 }
3539}
3540
3541fn prepare_atomic_addr(
3545 memarg: &MemArg,
3546 loaded_bytes: u8,
3547 builder: &mut FunctionBuilder,
3548 stack: &mut FuncTranslationStacks,
3549 environ: &mut FuncEnvironment<'_>,
3550) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
3551 align_atomic_addr(memarg, loaded_bytes, builder, stack, environ);
3552 prepare_addr(memarg, loaded_bytes, builder, stack, environ)
3553}
3554
3555fn translate_load(
3559 memarg: &MemArg,
3560 opcode: ir::Opcode,
3561 result_ty: Type,
3562 builder: &mut FunctionBuilder,
3563 stack: &mut FuncTranslationStacks,
3564 environ: &mut FuncEnvironment<'_>,
3565) -> WasmResult<Reachability<()>> {
3566 let mem_op_size = mem_op_size(opcode, result_ty);
3567 let (flags, wasm_index, base) =
3568 match prepare_addr(memarg, mem_op_size, builder, stack, environ)? {
3569 Reachability::Unreachable => return Ok(Reachability::Unreachable),
3570 Reachability::Reachable((f, i, b)) => (f, i, b),
3571 };
3572
3573 environ.before_load(builder, mem_op_size, wasm_index, memarg.offset);
3574
3575 let (load, dfg) = builder
3576 .ins()
3577 .Load(opcode, result_ty, flags, Offset32::new(0), base);
3578 stack.push1(dfg.first_result(load));
3579 Ok(Reachability::Reachable(()))
3580}
3581
3582fn translate_store(
3584 memarg: &MemArg,
3585 opcode: ir::Opcode,
3586 builder: &mut FunctionBuilder,
3587 stack: &mut FuncTranslationStacks,
3588 environ: &mut FuncEnvironment<'_>,
3589) -> WasmResult<()> {
3590 let val = stack.pop1();
3591 let val_ty = builder.func.dfg.value_type(val);
3592 let mem_op_size = mem_op_size(opcode, val_ty);
3593
3594 let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!(
3595 stack,
3596 prepare_addr(memarg, mem_op_size, builder, stack, environ)?
3597 );
3598
3599 environ.before_store(builder, mem_op_size, wasm_index, memarg.offset);
3600
3601 builder
3602 .ins()
3603 .Store(opcode, val_ty, flags, Offset32::new(0), val, base);
3604 Ok(())
3605}
3606
3607fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
3608 match opcode {
3609 ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
3610 ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
3611 ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
3612 ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
3613 _ => panic!("unknown size of mem op for {opcode:?}"),
3614 }
3615}
3616
3617fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, stack: &mut FuncTranslationStacks) {
3618 let (arg0, arg1) = stack.pop2();
3619 let val = builder.ins().icmp(cc, arg0, arg1);
3620 stack.push1(builder.ins().uextend(I32, val));
3621}
3622
3623fn translate_atomic_rmw(
3624 widened_ty: Type,
3625 access_ty: Type,
3626 op: AtomicRmwOp,
3627 memarg: &MemArg,
3628 builder: &mut FunctionBuilder,
3629 stack: &mut FuncTranslationStacks,
3630 environ: &mut FuncEnvironment<'_>,
3631) -> WasmResult<()> {
3632 let mut arg2 = stack.pop1();
3633 let arg2_ty = builder.func.dfg.value_type(arg2);
3634
3635 match access_ty {
3638 I8 | I16 | I32 | I64 => {}
3639 _ => {
3640 return Err(wasm_unsupported!(
3641 "atomic_rmw: unsupported access type {:?}",
3642 access_ty
3643 ));
3644 }
3645 };
3646 let w_ty_ok = match widened_ty {
3647 I32 | I64 => true,
3648 _ => false,
3649 };
3650 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3651
3652 assert!(arg2_ty.bytes() >= access_ty.bytes());
3653 if arg2_ty.bytes() > access_ty.bytes() {
3654 arg2 = builder.ins().ireduce(access_ty, arg2);
3655 }
3656
3657 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3658 stack,
3659 prepare_atomic_addr(
3660 memarg,
3661 u8::try_from(access_ty.bytes()).unwrap(),
3662 builder,
3663 stack,
3664 environ,
3665 )?
3666 );
3667
3668 let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
3669 if access_ty != widened_ty {
3670 res = builder.ins().uextend(widened_ty, res);
3671 }
3672 stack.push1(res);
3673 Ok(())
3674}
3675
3676fn translate_atomic_cas(
3677 widened_ty: Type,
3678 access_ty: Type,
3679 memarg: &MemArg,
3680 builder: &mut FunctionBuilder,
3681 stack: &mut FuncTranslationStacks,
3682 environ: &mut FuncEnvironment<'_>,
3683) -> WasmResult<()> {
3684 let (mut expected, mut replacement) = stack.pop2();
3685 let expected_ty = builder.func.dfg.value_type(expected);
3686 let replacement_ty = builder.func.dfg.value_type(replacement);
3687
3688 match access_ty {
3691 I8 | I16 | I32 | I64 => {}
3692 _ => {
3693 return Err(wasm_unsupported!(
3694 "atomic_cas: unsupported access type {:?}",
3695 access_ty
3696 ));
3697 }
3698 };
3699 let w_ty_ok = match widened_ty {
3700 I32 | I64 => true,
3701 _ => false,
3702 };
3703 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3704
3705 assert!(expected_ty.bytes() >= access_ty.bytes());
3706 if expected_ty.bytes() > access_ty.bytes() {
3707 expected = builder.ins().ireduce(access_ty, expected);
3708 }
3709 assert!(replacement_ty.bytes() >= access_ty.bytes());
3710 if replacement_ty.bytes() > access_ty.bytes() {
3711 replacement = builder.ins().ireduce(access_ty, replacement);
3712 }
3713
3714 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3715 stack,
3716 prepare_atomic_addr(
3717 memarg,
3718 u8::try_from(access_ty.bytes()).unwrap(),
3719 builder,
3720 stack,
3721 environ,
3722 )?
3723 );
3724 let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
3725 if access_ty != widened_ty {
3726 res = builder.ins().uextend(widened_ty, res);
3727 }
3728 stack.push1(res);
3729 Ok(())
3730}
3731
3732fn translate_atomic_load(
3733 widened_ty: Type,
3734 access_ty: Type,
3735 memarg: &MemArg,
3736 builder: &mut FunctionBuilder,
3737 stack: &mut FuncTranslationStacks,
3738 environ: &mut FuncEnvironment<'_>,
3739) -> WasmResult<()> {
3740 match access_ty {
3743 I8 | I16 | I32 | I64 => {}
3744 _ => {
3745 return Err(wasm_unsupported!(
3746 "atomic_load: unsupported access type {:?}",
3747 access_ty
3748 ));
3749 }
3750 };
3751 let w_ty_ok = match widened_ty {
3752 I32 | I64 => true,
3753 _ => false,
3754 };
3755 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3756
3757 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3758 stack,
3759 prepare_atomic_addr(
3760 memarg,
3761 u8::try_from(access_ty.bytes()).unwrap(),
3762 builder,
3763 stack,
3764 environ,
3765 )?
3766 );
3767 let mut res = builder.ins().atomic_load(access_ty, flags, addr);
3768 if access_ty != widened_ty {
3769 res = builder.ins().uextend(widened_ty, res);
3770 }
3771 stack.push1(res);
3772 Ok(())
3773}
3774
3775fn translate_atomic_store(
3776 access_ty: Type,
3777 memarg: &MemArg,
3778 builder: &mut FunctionBuilder,
3779 stack: &mut FuncTranslationStacks,
3780 environ: &mut FuncEnvironment<'_>,
3781) -> WasmResult<()> {
3782 let mut data = stack.pop1();
3783 let data_ty = builder.func.dfg.value_type(data);
3784
3785 match access_ty {
3788 I8 | I16 | I32 | I64 => {}
3789 _ => {
3790 return Err(wasm_unsupported!(
3791 "atomic_store: unsupported access type {:?}",
3792 access_ty
3793 ));
3794 }
3795 };
3796 let d_ty_ok = match data_ty {
3797 I32 | I64 => true,
3798 _ => false,
3799 };
3800 assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
3801
3802 if data_ty.bytes() > access_ty.bytes() {
3803 data = builder.ins().ireduce(access_ty, data);
3804 }
3805
3806 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3807 stack,
3808 prepare_atomic_addr(
3809 memarg,
3810 u8::try_from(access_ty.bytes()).unwrap(),
3811 builder,
3812 stack,
3813 environ,
3814 )?
3815 );
3816 builder.ins().atomic_store(flags, data, addr);
3817 Ok(())
3818}
3819
3820fn translate_vector_icmp(
3821 cc: IntCC,
3822 needed_type: Type,
3823 builder: &mut FunctionBuilder,
3824 stack: &mut FuncTranslationStacks,
3825) {
3826 let (a, b) = stack.pop2();
3827 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3828 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3829 stack.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3830}
3831
3832fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, stack: &mut FuncTranslationStacks) {
3833 let (arg0, arg1) = stack.pop2();
3834 let val = builder.ins().fcmp(cc, arg0, arg1);
3835 stack.push1(builder.ins().uextend(I32, val));
3836}
3837
3838fn translate_vector_fcmp(
3839 cc: FloatCC,
3840 needed_type: Type,
3841 builder: &mut FunctionBuilder,
3842 stack: &mut FuncTranslationStacks,
3843) {
3844 let (a, b) = stack.pop2();
3845 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3846 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3847 stack.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3848}
3849
3850fn translate_br_if(
3851 relative_depth: u32,
3852 builder: &mut FunctionBuilder,
3853 stack: &mut FuncTranslationStacks,
3854) {
3855 let val = stack.pop1();
3856 let (br_destination, inputs) = translate_br_if_args(relative_depth, stack);
3857 let next_block = builder.create_block();
3858 canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3859
3860 builder.seal_block(next_block); builder.switch_to_block(next_block);
3862}
3863
3864fn translate_br_if_args(
3865 relative_depth: u32,
3866 stack: &mut FuncTranslationStacks,
3867) -> (ir::Block, &mut [ir::Value]) {
3868 let i = stack.control_stack.len() - 1 - (relative_depth as usize);
3869 let (return_count, br_destination) = {
3870 let frame = &mut stack.control_stack[i];
3871 frame.set_branched_to_exit();
3874 let return_count = if frame.is_loop() {
3875 frame.num_param_values()
3876 } else {
3877 frame.num_return_values()
3878 };
3879 (return_count, frame.br_destination())
3880 };
3881 let inputs = stack.peekn_mut(return_count);
3882 (br_destination, inputs)
3883}
3884
3885fn type_of(operator: &Operator) -> Type {
3887 match operator {
3888 Operator::V128Load { .. }
3889 | Operator::V128Store { .. }
3890 | Operator::V128Const { .. }
3891 | Operator::V128Not
3892 | Operator::V128And
3893 | Operator::V128AndNot
3894 | Operator::V128Or
3895 | Operator::V128Xor
3896 | Operator::V128AnyTrue
3897 | Operator::V128Bitselect => I8X16, Operator::I8x16Shuffle { .. }
3900 | Operator::I8x16Splat
3901 | Operator::V128Load8Splat { .. }
3902 | Operator::V128Load8Lane { .. }
3903 | Operator::V128Store8Lane { .. }
3904 | Operator::I8x16ExtractLaneS { .. }
3905 | Operator::I8x16ExtractLaneU { .. }
3906 | Operator::I8x16ReplaceLane { .. }
3907 | Operator::I8x16Eq
3908 | Operator::I8x16Ne
3909 | Operator::I8x16LtS
3910 | Operator::I8x16LtU
3911 | Operator::I8x16GtS
3912 | Operator::I8x16GtU
3913 | Operator::I8x16LeS
3914 | Operator::I8x16LeU
3915 | Operator::I8x16GeS
3916 | Operator::I8x16GeU
3917 | Operator::I8x16Neg
3918 | Operator::I8x16Abs
3919 | Operator::I8x16AllTrue
3920 | Operator::I8x16Shl
3921 | Operator::I8x16ShrS
3922 | Operator::I8x16ShrU
3923 | Operator::I8x16Add
3924 | Operator::I8x16AddSatS
3925 | Operator::I8x16AddSatU
3926 | Operator::I8x16Sub
3927 | Operator::I8x16SubSatS
3928 | Operator::I8x16SubSatU
3929 | Operator::I8x16MinS
3930 | Operator::I8x16MinU
3931 | Operator::I8x16MaxS
3932 | Operator::I8x16MaxU
3933 | Operator::I8x16AvgrU
3934 | Operator::I8x16Bitmask
3935 | Operator::I8x16Popcnt
3936 | Operator::I8x16RelaxedLaneselect => I8X16,
3937
3938 Operator::I16x8Splat
3939 | Operator::V128Load16Splat { .. }
3940 | Operator::V128Load16Lane { .. }
3941 | Operator::V128Store16Lane { .. }
3942 | Operator::I16x8ExtractLaneS { .. }
3943 | Operator::I16x8ExtractLaneU { .. }
3944 | Operator::I16x8ReplaceLane { .. }
3945 | Operator::I16x8Eq
3946 | Operator::I16x8Ne
3947 | Operator::I16x8LtS
3948 | Operator::I16x8LtU
3949 | Operator::I16x8GtS
3950 | Operator::I16x8GtU
3951 | Operator::I16x8LeS
3952 | Operator::I16x8LeU
3953 | Operator::I16x8GeS
3954 | Operator::I16x8GeU
3955 | Operator::I16x8Neg
3956 | Operator::I16x8Abs
3957 | Operator::I16x8AllTrue
3958 | Operator::I16x8Shl
3959 | Operator::I16x8ShrS
3960 | Operator::I16x8ShrU
3961 | Operator::I16x8Add
3962 | Operator::I16x8AddSatS
3963 | Operator::I16x8AddSatU
3964 | Operator::I16x8Sub
3965 | Operator::I16x8SubSatS
3966 | Operator::I16x8SubSatU
3967 | Operator::I16x8MinS
3968 | Operator::I16x8MinU
3969 | Operator::I16x8MaxS
3970 | Operator::I16x8MaxU
3971 | Operator::I16x8AvgrU
3972 | Operator::I16x8Mul
3973 | Operator::I16x8Bitmask
3974 | Operator::I16x8RelaxedLaneselect => I16X8,
3975
3976 Operator::I32x4Splat
3977 | Operator::V128Load32Splat { .. }
3978 | Operator::V128Load32Lane { .. }
3979 | Operator::V128Store32Lane { .. }
3980 | Operator::I32x4ExtractLane { .. }
3981 | Operator::I32x4ReplaceLane { .. }
3982 | Operator::I32x4Eq
3983 | Operator::I32x4Ne
3984 | Operator::I32x4LtS
3985 | Operator::I32x4LtU
3986 | Operator::I32x4GtS
3987 | Operator::I32x4GtU
3988 | Operator::I32x4LeS
3989 | Operator::I32x4LeU
3990 | Operator::I32x4GeS
3991 | Operator::I32x4GeU
3992 | Operator::I32x4Neg
3993 | Operator::I32x4Abs
3994 | Operator::I32x4AllTrue
3995 | Operator::I32x4Shl
3996 | Operator::I32x4ShrS
3997 | Operator::I32x4ShrU
3998 | Operator::I32x4Add
3999 | Operator::I32x4Sub
4000 | Operator::I32x4Mul
4001 | Operator::I32x4MinS
4002 | Operator::I32x4MinU
4003 | Operator::I32x4MaxS
4004 | Operator::I32x4MaxU
4005 | Operator::I32x4Bitmask
4006 | Operator::I32x4TruncSatF32x4S
4007 | Operator::I32x4TruncSatF32x4U
4008 | Operator::I32x4RelaxedLaneselect
4009 | Operator::V128Load32Zero { .. } => I32X4,
4010
4011 Operator::I64x2Splat
4012 | Operator::V128Load64Splat { .. }
4013 | Operator::V128Load64Lane { .. }
4014 | Operator::V128Store64Lane { .. }
4015 | Operator::I64x2ExtractLane { .. }
4016 | Operator::I64x2ReplaceLane { .. }
4017 | Operator::I64x2Eq
4018 | Operator::I64x2Ne
4019 | Operator::I64x2LtS
4020 | Operator::I64x2GtS
4021 | Operator::I64x2LeS
4022 | Operator::I64x2GeS
4023 | Operator::I64x2Neg
4024 | Operator::I64x2Abs
4025 | Operator::I64x2AllTrue
4026 | Operator::I64x2Shl
4027 | Operator::I64x2ShrS
4028 | Operator::I64x2ShrU
4029 | Operator::I64x2Add
4030 | Operator::I64x2Sub
4031 | Operator::I64x2Mul
4032 | Operator::I64x2Bitmask
4033 | Operator::I64x2RelaxedLaneselect
4034 | Operator::V128Load64Zero { .. } => I64X2,
4035
4036 Operator::F32x4Splat
4037 | Operator::F32x4ExtractLane { .. }
4038 | Operator::F32x4ReplaceLane { .. }
4039 | Operator::F32x4Eq
4040 | Operator::F32x4Ne
4041 | Operator::F32x4Lt
4042 | Operator::F32x4Gt
4043 | Operator::F32x4Le
4044 | Operator::F32x4Ge
4045 | Operator::F32x4Abs
4046 | Operator::F32x4Neg
4047 | Operator::F32x4Sqrt
4048 | Operator::F32x4Add
4049 | Operator::F32x4Sub
4050 | Operator::F32x4Mul
4051 | Operator::F32x4Div
4052 | Operator::F32x4Min
4053 | Operator::F32x4Max
4054 | Operator::F32x4PMin
4055 | Operator::F32x4PMax
4056 | Operator::F32x4ConvertI32x4S
4057 | Operator::F32x4ConvertI32x4U
4058 | Operator::F32x4Ceil
4059 | Operator::F32x4Floor
4060 | Operator::F32x4Trunc
4061 | Operator::F32x4Nearest
4062 | Operator::F32x4RelaxedMax
4063 | Operator::F32x4RelaxedMin
4064 | Operator::F32x4RelaxedMadd
4065 | Operator::F32x4RelaxedNmadd => F32X4,
4066
4067 Operator::F64x2Splat
4068 | Operator::F64x2ExtractLane { .. }
4069 | Operator::F64x2ReplaceLane { .. }
4070 | Operator::F64x2Eq
4071 | Operator::F64x2Ne
4072 | Operator::F64x2Lt
4073 | Operator::F64x2Gt
4074 | Operator::F64x2Le
4075 | Operator::F64x2Ge
4076 | Operator::F64x2Abs
4077 | Operator::F64x2Neg
4078 | Operator::F64x2Sqrt
4079 | Operator::F64x2Add
4080 | Operator::F64x2Sub
4081 | Operator::F64x2Mul
4082 | Operator::F64x2Div
4083 | Operator::F64x2Min
4084 | Operator::F64x2Max
4085 | Operator::F64x2PMin
4086 | Operator::F64x2PMax
4087 | Operator::F64x2Ceil
4088 | Operator::F64x2Floor
4089 | Operator::F64x2Trunc
4090 | Operator::F64x2Nearest
4091 | Operator::F64x2RelaxedMax
4092 | Operator::F64x2RelaxedMin
4093 | Operator::F64x2RelaxedMadd
4094 | Operator::F64x2RelaxedNmadd => F64X2,
4095
4096 _ => unimplemented!(
4097 "Currently only SIMD instructions are mapped to their return type; the \
4098 following instruction is not mapped: {:?}",
4099 operator
4100 ),
4101 }
4102}
4103
4104fn optionally_bitcast_vector(
4107 value: Value,
4108 needed_type: Type,
4109 builder: &mut FunctionBuilder,
4110) -> Value {
4111 if builder.func.dfg.value_type(value) != needed_type {
4112 let mut flags = MemFlags::new();
4113 flags.set_endianness(ir::Endianness::Little);
4114 builder.ins().bitcast(needed_type, flags, value)
4115 } else {
4116 value
4117 }
4118}
4119
4120#[inline(always)]
4121fn is_non_canonical_v128(ty: ir::Type) -> bool {
4122 match ty {
4123 I64X2 | I32X4 | I16X8 | F32X4 | F64X2 => true,
4124 _ => false,
4125 }
4126}
4127
4128fn canonicalise_v128_values<'a>(
4133 tmp_canonicalised: &'a mut SmallVec<[BlockArg; 16]>,
4134 builder: &mut FunctionBuilder,
4135 values: &'a [ir::Value],
4136) -> &'a [BlockArg] {
4137 debug_assert!(tmp_canonicalised.is_empty());
4138 for v in values {
4140 let value = if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
4141 let mut flags = MemFlags::new();
4142 flags.set_endianness(ir::Endianness::Little);
4143 builder.ins().bitcast(I8X16, flags, *v)
4144 } else {
4145 *v
4146 };
4147 tmp_canonicalised.push(BlockArg::from(value));
4148 }
4149 tmp_canonicalised.as_slice()
4150}
4151
4152fn canonicalise_then_jump(
4156 builder: &mut FunctionBuilder,
4157 destination: ir::Block,
4158 params: &[ir::Value],
4159) -> ir::Inst {
4160 let mut tmp_canonicalised = SmallVec::<[_; 16]>::new();
4161 let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
4162 builder.ins().jump(destination, canonicalised)
4163}
4164
4165fn canonicalise_brif(
4167 builder: &mut FunctionBuilder,
4168 cond: ir::Value,
4169 block_then: ir::Block,
4170 params_then: &[ir::Value],
4171 block_else: ir::Block,
4172 params_else: &[ir::Value],
4173) -> ir::Inst {
4174 let mut tmp_canonicalised_then = SmallVec::<[_; 16]>::new();
4175 let canonicalised_then =
4176 canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
4177 let mut tmp_canonicalised_else = SmallVec::<[_; 16]>::new();
4178 let canonicalised_else =
4179 canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
4180 builder.ins().brif(
4181 cond,
4182 block_then,
4183 canonicalised_then,
4184 block_else,
4185 canonicalised_else,
4186 )
4187}
4188
4189fn pop1_with_bitcast(
4193 stack: &mut FuncTranslationStacks,
4194 needed_type: Type,
4195 builder: &mut FunctionBuilder,
4196) -> Value {
4197 optionally_bitcast_vector(stack.pop1(), needed_type, builder)
4198}
4199
4200fn pop2_with_bitcast(
4204 stack: &mut FuncTranslationStacks,
4205 needed_type: Type,
4206 builder: &mut FunctionBuilder,
4207) -> (Value, Value) {
4208 let (a, b) = stack.pop2();
4209 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
4210 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
4211 (bitcast_a, bitcast_b)
4212}
4213
4214fn pop3_with_bitcast(
4215 stack: &mut FuncTranslationStacks,
4216 needed_type: Type,
4217 builder: &mut FunctionBuilder,
4218) -> (Value, Value, Value) {
4219 let (a, b, c) = stack.pop3();
4220 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
4221 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
4222 let bitcast_c = optionally_bitcast_vector(c, needed_type, builder);
4223 (bitcast_a, bitcast_b, bitcast_c)
4224}
4225
4226fn bitcast_arguments<'a>(
4227 builder: &FunctionBuilder,
4228 arguments: &'a mut [Value],
4229 params: &[ir::AbiParam],
4230 param_predicate: impl Fn(usize) -> bool,
4231) -> Vec<(Type, &'a mut Value)> {
4232 let filtered_param_types = params
4233 .iter()
4234 .enumerate()
4235 .filter(|(i, _)| param_predicate(*i))
4236 .map(|(_, param)| param.value_type);
4237
4238 let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
4242
4243 pairs
4246 .filter(|(param_type, _)| param_type.is_vector())
4247 .filter(|(param_type, arg)| {
4248 let arg_type = builder.func.dfg.value_type(**arg);
4249 assert!(
4250 arg_type.is_vector(),
4251 "unexpected type mismatch: expected {}, argument {} was actually of type {}",
4252 param_type,
4253 *arg,
4254 arg_type
4255 );
4256
4257 arg_type != *param_type
4261 })
4262 .collect()
4263}
4264
4265pub fn bitcast_wasm_returns(arguments: &mut [Value], builder: &mut FunctionBuilder) {
4271 let changes = bitcast_arguments(builder, arguments, &builder.func.signature.returns, |i| {
4272 builder.func.signature.returns[i].purpose == ir::ArgumentPurpose::Normal
4273 });
4274 for (t, arg) in changes {
4275 let mut flags = MemFlags::new();
4276 flags.set_endianness(ir::Endianness::Little);
4277 *arg = builder.ins().bitcast(t, flags, *arg);
4278 }
4279}
4280
4281fn bitcast_wasm_params(
4283 environ: &mut FuncEnvironment<'_>,
4284 callee_signature: ir::SigRef,
4285 arguments: &mut [Value],
4286 builder: &mut FunctionBuilder,
4287) {
4288 let callee_signature = &builder.func.dfg.signatures[callee_signature];
4289 let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
4290 environ.is_wasm_parameter(&callee_signature, i)
4291 });
4292 for (t, arg) in changes {
4293 let mut flags = MemFlags::new();
4294 flags.set_endianness(ir::Endianness::Little);
4295 *arg = builder.ins().bitcast(t, flags, *arg);
4296 }
4297}
4298
4299fn create_catch_block(
4300 builder: &mut FunctionBuilder,
4301 stacks: &mut FuncTranslationStacks,
4302 catch: &wasmparser::Catch,
4303 environ: &mut FuncEnvironment<'_>,
4304) -> WasmResult<ir::Block> {
4305 let (is_ref, tag, label) = match catch {
4306 wasmparser::Catch::One { tag, label } => (false, Some(*tag), *label),
4307 wasmparser::Catch::OneRef { tag, label } => (true, Some(*tag), *label),
4308 wasmparser::Catch::All { label } => (false, None, *label),
4309 wasmparser::Catch::AllRef { label } => (true, None, *label),
4310 };
4311
4312 let (exn_ref_ty, needs_stack_map) = environ.reference_type(WasmHeapType::Exn);
4324 let (exn_payload_wasm_ty, exn_payload_ty) = match environ.pointer_type().bits() {
4325 32 => (wasmparser::ValType::I32, I32),
4326 64 => (wasmparser::ValType::I64, I64),
4327 _ => panic!("Unsupported pointer width"),
4328 };
4329 let block = block_with_params(builder, [exn_payload_wasm_ty], environ)?;
4330 builder.switch_to_block(block);
4331 let exn_ref = builder.func.dfg.block_params(block)[0];
4332 debug_assert!(exn_ref_ty.bits() <= exn_payload_ty.bits());
4333 let exn_ref = if exn_ref_ty.bits() < exn_payload_ty.bits() {
4334 builder.ins().ireduce(exn_ref_ty, exn_ref)
4335 } else {
4336 exn_ref
4337 };
4338
4339 if needs_stack_map {
4340 builder.declare_value_needs_stack_map(exn_ref);
4341 }
4342
4343 let clif_tag = tag.map(|t| ExceptionTag::from_u32(t));
4349
4350 stacks.handlers.add_handler(clif_tag, block);
4351
4352 let mut params = vec![];
4353
4354 if let Some(tag) = tag {
4355 let tag = TagIndex::from_u32(tag);
4356 params.extend(environ.translate_exn_unbox(builder, tag, exn_ref)?);
4357 }
4358 if is_ref {
4359 params.push(exn_ref);
4360 }
4361
4362 let i = stacks.control_stack.len() - 1 - (label as usize);
4364 let frame = &mut stacks.control_stack[i];
4365 frame.set_branched_to_exit();
4366 canonicalise_then_jump(builder, frame.br_destination(), ¶ms);
4367
4368 Ok(block)
4369}