1mod bounds_checks;
75
76use crate::func_environ::{Extension, FuncEnvironment};
77use crate::translate::environ::{GlobalVariable, StructFieldsVec};
78use crate::translate::state::{ControlStackFrame, ElseData, FuncTranslationState};
79use crate::translate::translation_utils::{
80 block_with_params, blocktype_params_results, f32_translation, f64_translation,
81};
82use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
83use cranelift_codegen::ir::immediates::Offset32;
84use cranelift_codegen::ir::types::*;
85use cranelift_codegen::ir::{
86 self, AtomicRmwOp, ConstantData, InstBuilder, JumpTableData, MemFlags, Value, ValueLabel,
87};
88use cranelift_codegen::packed_option::ReservedValue;
89use cranelift_frontend::{FunctionBuilder, Variable};
90use itertools::Itertools;
91use smallvec::SmallVec;
92use std::collections::{hash_map, HashMap};
93use std::vec::Vec;
94use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
95use wasmtime_environ::{
96 wasm_unsupported, DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, Signed,
97 TableIndex, TypeConvert, TypeIndex, Unsigned, WasmRefType, WasmResult,
98};
99
100macro_rules! unwrap_or_return_unreachable_state {
107 ($state:ident, $value:expr) => {
108 match $value {
109 Reachability::Reachable(x) => x,
110 Reachability::Unreachable => {
111 $state.reachable = false;
112 return Ok(());
113 }
114 }
115 };
116}
117
118pub fn translate_operator(
120 validator: &mut FuncValidator<impl WasmModuleResources>,
121 op: &Operator,
122 builder: &mut FunctionBuilder,
123 state: &mut FuncTranslationState,
124 environ: &mut FuncEnvironment<'_>,
125) -> WasmResult<()> {
126 if !state.reachable {
127 translate_unreachable_operator(validator, &op, builder, state, environ)?;
128 return Ok(());
129 }
130
131 debug_assert!(!builder.is_unreachable());
133
134 log::trace!("Translating Wasm opcode: {op:?}");
136 match op {
137 Operator::LocalGet { local_index } => {
142 let val = builder.use_var(Variable::from_u32(*local_index));
143 state.push1(val);
144 let label = ValueLabel::from_u32(*local_index);
145 builder.set_val_label(val, label);
146 }
147 Operator::LocalSet { local_index } => {
148 let mut val = state.pop1();
149
150 let ty = builder.func.dfg.value_type(val);
152 if ty.is_vector() {
153 val = optionally_bitcast_vector(val, I8X16, builder);
154 }
155
156 builder.def_var(Variable::from_u32(*local_index), val);
157 let label = ValueLabel::from_u32(*local_index);
158 builder.set_val_label(val, label);
159 }
160 Operator::LocalTee { local_index } => {
161 let mut val = state.peek1();
162
163 let ty = builder.func.dfg.value_type(val);
165 if ty.is_vector() {
166 val = optionally_bitcast_vector(val, I8X16, builder);
167 }
168
169 builder.def_var(Variable::from_u32(*local_index), val);
170 let label = ValueLabel::from_u32(*local_index);
171 builder.set_val_label(val, label);
172 }
173 Operator::GlobalGet { global_index } => {
177 let val = match state.get_global(builder.func, *global_index, environ)? {
178 GlobalVariable::Memory { gv, offset, ty } => {
179 let addr = builder.ins().global_value(environ.pointer_type(), gv);
180 let mut flags = ir::MemFlags::trusted();
181 if ty.is_vector() {
185 flags.set_endianness(ir::Endianness::Little);
186 }
187 flags.set_alias_region(Some(ir::AliasRegion::Table));
189 builder.ins().load(ty, flags, addr, offset)
190 }
191 GlobalVariable::Custom => environ
192 .translate_custom_global_get(builder, GlobalIndex::from_u32(*global_index))?,
193 };
194 state.push1(val);
195 }
196 Operator::GlobalSet { global_index } => {
197 match state.get_global(builder.func, *global_index, environ)? {
198 GlobalVariable::Memory { gv, offset, ty } => {
199 let addr = builder.ins().global_value(environ.pointer_type(), gv);
200 let mut flags = ir::MemFlags::trusted();
201 if ty.is_vector() {
203 flags.set_endianness(ir::Endianness::Little);
204 }
205 flags.set_alias_region(Some(ir::AliasRegion::Table));
207 let mut val = state.pop1();
208 if ty.is_vector() {
210 val = optionally_bitcast_vector(val, I8X16, builder);
211 }
212 debug_assert_eq!(ty, builder.func.dfg.value_type(val));
213 builder.ins().store(flags, val, addr, offset);
214 environ.update_global(builder, *global_index, val);
215 }
216 GlobalVariable::Custom => {
217 let val = state.pop1();
218 environ.translate_custom_global_set(
219 builder,
220 GlobalIndex::from_u32(*global_index),
221 val,
222 )?;
223 }
224 }
225 }
226 Operator::Drop => {
230 state.pop1();
231 }
232 Operator::Select => {
233 let (mut arg1, mut arg2, cond) = state.pop3();
234 if builder.func.dfg.value_type(arg1).is_vector() {
235 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
236 }
237 if builder.func.dfg.value_type(arg2).is_vector() {
238 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
239 }
240 state.push1(builder.ins().select(cond, arg1, arg2));
241 }
242 Operator::TypedSelect { ty: _ } => {
243 let (mut arg1, mut arg2, cond) = state.pop3();
247 if builder.func.dfg.value_type(arg1).is_vector() {
248 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
249 }
250 if builder.func.dfg.value_type(arg2).is_vector() {
251 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
252 }
253 state.push1(builder.ins().select(cond, arg1, arg2));
254 }
255 Operator::Nop => {
256 }
258 Operator::Unreachable => {
259 environ.trap(builder, crate::TRAP_UNREACHABLE);
260 state.reachable = false;
261 }
262 Operator::Block { blockty } => {
274 let (params, results) = blocktype_params_results(validator, *blockty)?;
275 let next = block_with_params(builder, results.clone(), environ)?;
276 state.push_block(next, params.len(), results.len());
277 }
278 Operator::Loop { blockty } => {
279 let (params, results) = blocktype_params_results(validator, *blockty)?;
280 let loop_body = block_with_params(builder, params.clone(), environ)?;
281 let next = block_with_params(builder, results.clone(), environ)?;
282 canonicalise_then_jump(builder, loop_body, state.peekn(params.len()));
283 state.push_loop(loop_body, next, params.len(), results.len());
284
285 state.popn(params.len());
288 state
289 .stack
290 .extend_from_slice(builder.block_params(loop_body));
291
292 builder.switch_to_block(loop_body);
293 environ.translate_loop_header(builder)?;
294 }
295 Operator::If { blockty } => {
296 let val = state.pop1();
297
298 let next_block = builder.create_block();
299 let (params, results) = blocktype_params_results(validator, *blockty)?;
300 let (destination, else_data) = if params.clone().eq(results.clone()) {
301 let destination = block_with_params(builder, results.clone(), environ)?;
308 let branch_inst = canonicalise_brif(
309 builder,
310 val,
311 next_block,
312 &[],
313 destination,
314 state.peekn(params.len()),
315 );
316 (
317 destination,
318 ElseData::NoElse {
319 branch_inst,
320 placeholder: destination,
321 },
322 )
323 } else {
324 let destination = block_with_params(builder, results.clone(), environ)?;
327 let else_block = block_with_params(builder, params.clone(), environ)?;
328 canonicalise_brif(
329 builder,
330 val,
331 next_block,
332 &[],
333 else_block,
334 state.peekn(params.len()),
335 );
336 builder.seal_block(else_block);
337 (destination, ElseData::WithElse { else_block })
338 };
339
340 builder.seal_block(next_block); builder.switch_to_block(next_block);
342
343 state.push_if(
350 destination,
351 else_data,
352 params.len(),
353 results.len(),
354 *blockty,
355 );
356 }
357 Operator::Else => {
358 let i = state.control_stack.len() - 1;
359 match state.control_stack[i] {
360 ControlStackFrame::If {
361 ref else_data,
362 head_is_reachable,
363 ref mut consequent_ends_reachable,
364 num_return_values,
365 blocktype,
366 destination,
367 ..
368 } => {
369 debug_assert!(consequent_ends_reachable.is_none());
372 *consequent_ends_reachable = Some(state.reachable);
373
374 if head_is_reachable {
375 state.reachable = true;
377
378 let else_block = match *else_data {
381 ElseData::NoElse {
382 branch_inst,
383 placeholder,
384 } => {
385 let (params, _results) =
386 blocktype_params_results(validator, blocktype)?;
387 debug_assert_eq!(params.len(), num_return_values);
388 let else_block =
389 block_with_params(builder, params.clone(), environ)?;
390 canonicalise_then_jump(
391 builder,
392 destination,
393 state.peekn(params.len()),
394 );
395 state.popn(params.len());
396
397 builder.change_jump_destination(
398 branch_inst,
399 placeholder,
400 else_block,
401 );
402 builder.seal_block(else_block);
403 else_block
404 }
405 ElseData::WithElse { else_block } => {
406 canonicalise_then_jump(
407 builder,
408 destination,
409 state.peekn(num_return_values),
410 );
411 state.popn(num_return_values);
412 else_block
413 }
414 };
415
416 builder.switch_to_block(else_block);
427
428 }
431 }
432 _ => unreachable!(),
433 }
434 }
435 Operator::End => {
436 let frame = state.control_stack.pop().unwrap();
437 let next_block = frame.following_code();
438 let return_count = frame.num_return_values();
439 let return_args = state.peekn_mut(return_count);
440
441 canonicalise_then_jump(builder, next_block, return_args);
442 builder.switch_to_block(next_block);
450 builder.seal_block(next_block);
451
452 if let ControlStackFrame::Loop { header, .. } = frame {
454 builder.seal_block(header)
455 }
456
457 frame.truncate_value_stack_to_original_size(&mut state.stack);
458 state
459 .stack
460 .extend_from_slice(builder.block_params(next_block));
461 }
462 Operator::Br { relative_depth } => {
484 let i = state.control_stack.len() - 1 - (*relative_depth as usize);
485 let (return_count, br_destination) = {
486 let frame = &mut state.control_stack[i];
487 frame.set_branched_to_exit();
489 let return_count = if frame.is_loop() {
490 frame.num_param_values()
491 } else {
492 frame.num_return_values()
493 };
494 (return_count, frame.br_destination())
495 };
496 let destination_args = state.peekn_mut(return_count);
497 canonicalise_then_jump(builder, br_destination, destination_args);
498 state.popn(return_count);
499 state.reachable = false;
500 }
501 Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, state),
502 Operator::BrTable { targets } => {
503 let default = targets.default();
504 let mut min_depth = default;
505 for depth in targets.targets() {
506 let depth = depth?;
507 if depth < min_depth {
508 min_depth = depth;
509 }
510 }
511 let jump_args_count = {
512 let i = state.control_stack.len() - 1 - (min_depth as usize);
513 let min_depth_frame = &state.control_stack[i];
514 if min_depth_frame.is_loop() {
515 min_depth_frame.num_param_values()
516 } else {
517 min_depth_frame.num_return_values()
518 }
519 };
520 let val = state.pop1();
521 let mut data = Vec::with_capacity(targets.len() as usize);
522 if jump_args_count == 0 {
523 for depth in targets.targets() {
525 let depth = depth?;
526 let block = {
527 let i = state.control_stack.len() - 1 - (depth as usize);
528 let frame = &mut state.control_stack[i];
529 frame.set_branched_to_exit();
530 frame.br_destination()
531 };
532 data.push(builder.func.dfg.block_call(block, &[]));
533 }
534 let block = {
535 let i = state.control_stack.len() - 1 - (default as usize);
536 let frame = &mut state.control_stack[i];
537 frame.set_branched_to_exit();
538 frame.br_destination()
539 };
540 let block = builder.func.dfg.block_call(block, &[]);
541 let jt = builder.create_jump_table(JumpTableData::new(block, &data));
542 builder.ins().br_table(val, jt);
543 } else {
544 let return_count = jump_args_count;
547 let mut dest_block_sequence = vec![];
548 let mut dest_block_map = HashMap::new();
549 for depth in targets.targets() {
550 let depth = depth?;
551 let branch_block = match dest_block_map.entry(depth as usize) {
552 hash_map::Entry::Occupied(entry) => *entry.get(),
553 hash_map::Entry::Vacant(entry) => {
554 let block = builder.create_block();
555 dest_block_sequence.push((depth as usize, block));
556 *entry.insert(block)
557 }
558 };
559 data.push(builder.func.dfg.block_call(branch_block, &[]));
560 }
561 let default_branch_block = match dest_block_map.entry(default as usize) {
562 hash_map::Entry::Occupied(entry) => *entry.get(),
563 hash_map::Entry::Vacant(entry) => {
564 let block = builder.create_block();
565 dest_block_sequence.push((default as usize, block));
566 *entry.insert(block)
567 }
568 };
569 let default_branch_block = builder.func.dfg.block_call(default_branch_block, &[]);
570 let jt = builder.create_jump_table(JumpTableData::new(default_branch_block, &data));
571 builder.ins().br_table(val, jt);
572 for (depth, dest_block) in dest_block_sequence {
573 builder.switch_to_block(dest_block);
574 builder.seal_block(dest_block);
575 let real_dest_block = {
576 let i = state.control_stack.len() - 1 - depth;
577 let frame = &mut state.control_stack[i];
578 frame.set_branched_to_exit();
579 frame.br_destination()
580 };
581 let destination_args = state.peekn_mut(return_count);
582 canonicalise_then_jump(builder, real_dest_block, destination_args);
583 }
584 state.popn(return_count);
585 }
586 state.reachable = false;
587 }
588 Operator::Return => {
589 let return_count = {
590 let frame = &mut state.control_stack[0];
591 frame.num_return_values()
592 };
593 {
594 let return_args = state.peekn_mut(return_count);
595 environ.handle_before_return(&return_args, builder);
596 bitcast_wasm_returns(return_args, builder);
597 builder.ins().return_(return_args);
598 }
599 state.popn(return_count);
600 state.reachable = false;
601 }
602 Operator::Try { .. }
604 | Operator::Catch { .. }
605 | Operator::Throw { .. }
606 | Operator::Rethrow { .. }
607 | Operator::Delegate { .. }
608 | Operator::CatchAll => {
609 return Err(wasm_unsupported!(
610 "proposed exception handling operator {:?}",
611 op
612 ));
613 }
614 Operator::Call { function_index } => {
620 let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
621
622 let args = state.peekn_mut(num_args);
624 bitcast_wasm_params(
625 environ,
626 builder.func.dfg.ext_funcs[fref].signature,
627 args,
628 builder,
629 );
630
631 let call = environ.translate_call(
632 builder,
633 FuncIndex::from_u32(*function_index),
634 fref,
635 args,
636 )?;
637 let inst_results = builder.inst_results(call);
638 debug_assert_eq!(
639 inst_results.len(),
640 builder.func.dfg.signatures[builder.func.dfg.ext_funcs[fref].signature]
641 .returns
642 .len(),
643 "translate_call results should match the call signature"
644 );
645 state.popn(num_args);
646 state.pushn(inst_results);
647 }
648 Operator::CallIndirect {
649 type_index,
650 table_index,
651 } => {
652 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
656 let callee = state.pop1();
657
658 let args = state.peekn_mut(num_args);
660 bitcast_wasm_params(environ, sigref, args, builder);
661
662 let call = environ.translate_call_indirect(
663 builder,
664 validator.features(),
665 TableIndex::from_u32(*table_index),
666 TypeIndex::from_u32(*type_index),
667 sigref,
668 callee,
669 state.peekn(num_args),
670 )?;
671 let call = match call {
672 Some(call) => call,
673 None => {
674 state.reachable = false;
675 return Ok(());
676 }
677 };
678 let inst_results = builder.inst_results(call);
679 debug_assert_eq!(
680 inst_results.len(),
681 builder.func.dfg.signatures[sigref].returns.len(),
682 "translate_call_indirect results should match the call signature"
683 );
684 state.popn(num_args);
685 state.pushn(inst_results);
686 }
687 Operator::ReturnCall { function_index } => {
695 let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
696
697 let args = state.peekn_mut(num_args);
699 bitcast_wasm_params(
700 environ,
701 builder.func.dfg.ext_funcs[fref].signature,
702 args,
703 builder,
704 );
705
706 environ.translate_return_call(
707 builder,
708 FuncIndex::from_u32(*function_index),
709 fref,
710 args,
711 )?;
712
713 state.popn(num_args);
714 state.reachable = false;
715 }
716 Operator::ReturnCallIndirect {
717 type_index,
718 table_index,
719 } => {
720 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
724 let callee = state.pop1();
725
726 let args = state.peekn_mut(num_args);
728 bitcast_wasm_params(environ, sigref, args, builder);
729
730 environ.translate_return_call_indirect(
731 builder,
732 validator.features(),
733 TableIndex::from_u32(*table_index),
734 TypeIndex::from_u32(*type_index),
735 sigref,
736 callee,
737 state.peekn(num_args),
738 )?;
739
740 state.popn(num_args);
741 state.reachable = false;
742 }
743 Operator::ReturnCallRef { type_index } => {
744 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
748 let callee = state.pop1();
749
750 let args = state.peekn_mut(num_args);
752 bitcast_wasm_params(environ, sigref, args, builder);
753
754 environ.translate_return_call_ref(builder, sigref, callee, state.peekn(num_args))?;
755
756 state.popn(num_args);
757 state.reachable = false;
758 }
759 Operator::MemoryGrow { mem } => {
764 let heap_index = MemoryIndex::from_u32(*mem);
767 let heap = state.get_heap(builder.func, *mem, environ)?;
768 let val = state.pop1();
769 environ.before_memory_grow(builder, val, heap_index);
770 state.push1(environ.translate_memory_grow(builder, heap_index, heap, val)?)
771 }
772 Operator::MemorySize { mem } => {
773 let heap_index = MemoryIndex::from_u32(*mem);
774 let heap = state.get_heap(builder.func, *mem, environ)?;
775 state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
776 }
777 Operator::I32Load8U { memarg } => {
782 unwrap_or_return_unreachable_state!(
783 state,
784 translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?
785 );
786 }
787 Operator::I32Load16U { memarg } => {
788 unwrap_or_return_unreachable_state!(
789 state,
790 translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?
791 );
792 }
793 Operator::I32Load8S { memarg } => {
794 unwrap_or_return_unreachable_state!(
795 state,
796 translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?
797 );
798 }
799 Operator::I32Load16S { memarg } => {
800 unwrap_or_return_unreachable_state!(
801 state,
802 translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?
803 );
804 }
805 Operator::I64Load8U { memarg } => {
806 unwrap_or_return_unreachable_state!(
807 state,
808 translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?
809 );
810 }
811 Operator::I64Load16U { memarg } => {
812 unwrap_or_return_unreachable_state!(
813 state,
814 translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?
815 );
816 }
817 Operator::I64Load8S { memarg } => {
818 unwrap_or_return_unreachable_state!(
819 state,
820 translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?
821 );
822 }
823 Operator::I64Load16S { memarg } => {
824 unwrap_or_return_unreachable_state!(
825 state,
826 translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?
827 );
828 }
829 Operator::I64Load32S { memarg } => {
830 unwrap_or_return_unreachable_state!(
831 state,
832 translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?
833 );
834 }
835 Operator::I64Load32U { memarg } => {
836 unwrap_or_return_unreachable_state!(
837 state,
838 translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?
839 );
840 }
841 Operator::I32Load { memarg } => {
842 unwrap_or_return_unreachable_state!(
843 state,
844 translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?
845 );
846 }
847 Operator::F32Load { memarg } => {
848 unwrap_or_return_unreachable_state!(
849 state,
850 translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?
851 );
852 }
853 Operator::I64Load { memarg } => {
854 unwrap_or_return_unreachable_state!(
855 state,
856 translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?
857 );
858 }
859 Operator::F64Load { memarg } => {
860 unwrap_or_return_unreachable_state!(
861 state,
862 translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?
863 );
864 }
865 Operator::V128Load { memarg } => {
866 unwrap_or_return_unreachable_state!(
867 state,
868 translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?
869 );
870 }
871 Operator::V128Load8x8S { memarg } => {
872 let (flags, _, base) = unwrap_or_return_unreachable_state!(
874 state,
875 prepare_addr(memarg, 8, builder, state, environ)?
876 );
877 let loaded = builder.ins().sload8x8(flags, base, 0);
878 state.push1(loaded);
879 }
880 Operator::V128Load8x8U { memarg } => {
881 let (flags, _, base) = unwrap_or_return_unreachable_state!(
882 state,
883 prepare_addr(memarg, 8, builder, state, environ)?
884 );
885 let loaded = builder.ins().uload8x8(flags, base, 0);
886 state.push1(loaded);
887 }
888 Operator::V128Load16x4S { memarg } => {
889 let (flags, _, base) = unwrap_or_return_unreachable_state!(
890 state,
891 prepare_addr(memarg, 8, builder, state, environ)?
892 );
893 let loaded = builder.ins().sload16x4(flags, base, 0);
894 state.push1(loaded);
895 }
896 Operator::V128Load16x4U { memarg } => {
897 let (flags, _, base) = unwrap_or_return_unreachable_state!(
898 state,
899 prepare_addr(memarg, 8, builder, state, environ)?
900 );
901 let loaded = builder.ins().uload16x4(flags, base, 0);
902 state.push1(loaded);
903 }
904 Operator::V128Load32x2S { memarg } => {
905 let (flags, _, base) = unwrap_or_return_unreachable_state!(
906 state,
907 prepare_addr(memarg, 8, builder, state, environ)?
908 );
909 let loaded = builder.ins().sload32x2(flags, base, 0);
910 state.push1(loaded);
911 }
912 Operator::V128Load32x2U { memarg } => {
913 let (flags, _, base) = unwrap_or_return_unreachable_state!(
914 state,
915 prepare_addr(memarg, 8, builder, state, environ)?
916 );
917 let loaded = builder.ins().uload32x2(flags, base, 0);
918 state.push1(loaded);
919 }
920 Operator::I32Store { memarg }
925 | Operator::I64Store { memarg }
926 | Operator::F32Store { memarg }
927 | Operator::F64Store { memarg } => {
928 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
929 }
930 Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
931 translate_store(memarg, ir::Opcode::Istore8, builder, state, environ)?;
932 }
933 Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
934 translate_store(memarg, ir::Opcode::Istore16, builder, state, environ)?;
935 }
936 Operator::I64Store32 { memarg } => {
937 translate_store(memarg, ir::Opcode::Istore32, builder, state, environ)?;
938 }
939 Operator::V128Store { memarg } => {
940 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
941 }
942 Operator::I32Const { value } => {
944 state.push1(builder.ins().iconst(I32, i64::from(value.unsigned())));
945 }
946 Operator::I64Const { value } => state.push1(builder.ins().iconst(I64, *value)),
947 Operator::F32Const { value } => {
948 state.push1(builder.ins().f32const(f32_translation(*value)));
949 }
950 Operator::F64Const { value } => {
951 state.push1(builder.ins().f64const(f64_translation(*value)));
952 }
953 Operator::I32Clz | Operator::I64Clz => {
955 let arg = state.pop1();
956 state.push1(builder.ins().clz(arg));
957 }
958 Operator::I32Ctz | Operator::I64Ctz => {
959 let arg = state.pop1();
960 state.push1(builder.ins().ctz(arg));
961 }
962 Operator::I32Popcnt | Operator::I64Popcnt => {
963 let arg = state.pop1();
964 state.push1(builder.ins().popcnt(arg));
965 }
966 Operator::I64ExtendI32S => {
967 let val = state.pop1();
968 state.push1(builder.ins().sextend(I64, val));
969 }
970 Operator::I64ExtendI32U => {
971 let val = state.pop1();
972 state.push1(builder.ins().uextend(I64, val));
973 }
974 Operator::I32WrapI64 => {
975 let val = state.pop1();
976 state.push1(builder.ins().ireduce(I32, val));
977 }
978 Operator::F32Sqrt | Operator::F64Sqrt => {
979 let arg = state.pop1();
980 state.push1(builder.ins().sqrt(arg));
981 }
982 Operator::F32Ceil | Operator::F64Ceil => {
983 let arg = state.pop1();
984 state.push1(builder.ins().ceil(arg));
985 }
986 Operator::F32Floor | Operator::F64Floor => {
987 let arg = state.pop1();
988 state.push1(builder.ins().floor(arg));
989 }
990 Operator::F32Trunc | Operator::F64Trunc => {
991 let arg = state.pop1();
992 state.push1(builder.ins().trunc(arg));
993 }
994 Operator::F32Nearest | Operator::F64Nearest => {
995 let arg = state.pop1();
996 state.push1(builder.ins().nearest(arg));
997 }
998 Operator::F32Abs | Operator::F64Abs => {
999 let val = state.pop1();
1000 state.push1(builder.ins().fabs(val));
1001 }
1002 Operator::F32Neg | Operator::F64Neg => {
1003 let arg = state.pop1();
1004 state.push1(builder.ins().fneg(arg));
1005 }
1006 Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
1007 let val = state.pop1();
1008 state.push1(builder.ins().fcvt_from_uint(F64, val));
1009 }
1010 Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
1011 let val = state.pop1();
1012 state.push1(builder.ins().fcvt_from_sint(F64, val));
1013 }
1014 Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
1015 let val = state.pop1();
1016 state.push1(builder.ins().fcvt_from_sint(F32, val));
1017 }
1018 Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
1019 let val = state.pop1();
1020 state.push1(builder.ins().fcvt_from_uint(F32, val));
1021 }
1022 Operator::F64PromoteF32 => {
1023 let val = state.pop1();
1024 state.push1(builder.ins().fpromote(F64, val));
1025 }
1026 Operator::F32DemoteF64 => {
1027 let val = state.pop1();
1028 state.push1(builder.ins().fdemote(F32, val));
1029 }
1030 Operator::I64TruncF64S | Operator::I64TruncF32S => {
1031 let val = state.pop1();
1032 state.push1(environ.translate_fcvt_to_sint(builder, I64, val));
1033 }
1034 Operator::I32TruncF64S | Operator::I32TruncF32S => {
1035 let val = state.pop1();
1036 state.push1(environ.translate_fcvt_to_sint(builder, I32, val));
1037 }
1038 Operator::I64TruncF64U | Operator::I64TruncF32U => {
1039 let val = state.pop1();
1040 state.push1(environ.translate_fcvt_to_uint(builder, I64, val));
1041 }
1042 Operator::I32TruncF64U | Operator::I32TruncF32U => {
1043 let val = state.pop1();
1044 state.push1(environ.translate_fcvt_to_uint(builder, I32, val));
1045 }
1046 Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
1047 let val = state.pop1();
1048 state.push1(builder.ins().fcvt_to_sint_sat(I64, val));
1049 }
1050 Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
1051 let val = state.pop1();
1052 state.push1(builder.ins().fcvt_to_sint_sat(I32, val));
1053 }
1054 Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
1055 let val = state.pop1();
1056 state.push1(builder.ins().fcvt_to_uint_sat(I64, val));
1057 }
1058 Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
1059 let val = state.pop1();
1060 state.push1(builder.ins().fcvt_to_uint_sat(I32, val));
1061 }
1062 Operator::F32ReinterpretI32 => {
1063 let val = state.pop1();
1064 state.push1(builder.ins().bitcast(F32, MemFlags::new(), val));
1065 }
1066 Operator::F64ReinterpretI64 => {
1067 let val = state.pop1();
1068 state.push1(builder.ins().bitcast(F64, MemFlags::new(), val));
1069 }
1070 Operator::I32ReinterpretF32 => {
1071 let val = state.pop1();
1072 state.push1(builder.ins().bitcast(I32, MemFlags::new(), val));
1073 }
1074 Operator::I64ReinterpretF64 => {
1075 let val = state.pop1();
1076 state.push1(builder.ins().bitcast(I64, MemFlags::new(), val));
1077 }
1078 Operator::I32Extend8S => {
1079 let val = state.pop1();
1080 state.push1(builder.ins().ireduce(I8, val));
1081 let val = state.pop1();
1082 state.push1(builder.ins().sextend(I32, val));
1083 }
1084 Operator::I32Extend16S => {
1085 let val = state.pop1();
1086 state.push1(builder.ins().ireduce(I16, val));
1087 let val = state.pop1();
1088 state.push1(builder.ins().sextend(I32, val));
1089 }
1090 Operator::I64Extend8S => {
1091 let val = state.pop1();
1092 state.push1(builder.ins().ireduce(I8, val));
1093 let val = state.pop1();
1094 state.push1(builder.ins().sextend(I64, val));
1095 }
1096 Operator::I64Extend16S => {
1097 let val = state.pop1();
1098 state.push1(builder.ins().ireduce(I16, val));
1099 let val = state.pop1();
1100 state.push1(builder.ins().sextend(I64, val));
1101 }
1102 Operator::I64Extend32S => {
1103 let val = state.pop1();
1104 state.push1(builder.ins().ireduce(I32, val));
1105 let val = state.pop1();
1106 state.push1(builder.ins().sextend(I64, val));
1107 }
1108 Operator::I32Add | Operator::I64Add => {
1110 let (arg1, arg2) = state.pop2();
1111 state.push1(builder.ins().iadd(arg1, arg2));
1112 }
1113 Operator::I32And | Operator::I64And => {
1114 let (arg1, arg2) = state.pop2();
1115 state.push1(builder.ins().band(arg1, arg2));
1116 }
1117 Operator::I32Or | Operator::I64Or => {
1118 let (arg1, arg2) = state.pop2();
1119 state.push1(builder.ins().bor(arg1, arg2));
1120 }
1121 Operator::I32Xor | Operator::I64Xor => {
1122 let (arg1, arg2) = state.pop2();
1123 state.push1(builder.ins().bxor(arg1, arg2));
1124 }
1125 Operator::I32Shl | Operator::I64Shl => {
1126 let (arg1, arg2) = state.pop2();
1127 state.push1(builder.ins().ishl(arg1, arg2));
1128 }
1129 Operator::I32ShrS | Operator::I64ShrS => {
1130 let (arg1, arg2) = state.pop2();
1131 state.push1(builder.ins().sshr(arg1, arg2));
1132 }
1133 Operator::I32ShrU | Operator::I64ShrU => {
1134 let (arg1, arg2) = state.pop2();
1135 state.push1(builder.ins().ushr(arg1, arg2));
1136 }
1137 Operator::I32Rotl | Operator::I64Rotl => {
1138 let (arg1, arg2) = state.pop2();
1139 state.push1(builder.ins().rotl(arg1, arg2));
1140 }
1141 Operator::I32Rotr | Operator::I64Rotr => {
1142 let (arg1, arg2) = state.pop2();
1143 state.push1(builder.ins().rotr(arg1, arg2));
1144 }
1145 Operator::F32Add | Operator::F64Add => {
1146 let (arg1, arg2) = state.pop2();
1147 state.push1(builder.ins().fadd(arg1, arg2));
1148 }
1149 Operator::I32Sub | Operator::I64Sub => {
1150 let (arg1, arg2) = state.pop2();
1151 state.push1(builder.ins().isub(arg1, arg2));
1152 }
1153 Operator::F32Sub | Operator::F64Sub => {
1154 let (arg1, arg2) = state.pop2();
1155 state.push1(builder.ins().fsub(arg1, arg2));
1156 }
1157 Operator::I32Mul | Operator::I64Mul => {
1158 let (arg1, arg2) = state.pop2();
1159 state.push1(builder.ins().imul(arg1, arg2));
1160 }
1161 Operator::F32Mul | Operator::F64Mul => {
1162 let (arg1, arg2) = state.pop2();
1163 state.push1(builder.ins().fmul(arg1, arg2));
1164 }
1165 Operator::F32Div | Operator::F64Div => {
1166 let (arg1, arg2) = state.pop2();
1167 state.push1(builder.ins().fdiv(arg1, arg2));
1168 }
1169 Operator::I32DivS | Operator::I64DivS => {
1170 let (arg1, arg2) = state.pop2();
1171 state.push1(environ.translate_sdiv(builder, arg1, arg2));
1172 }
1173 Operator::I32DivU | Operator::I64DivU => {
1174 let (arg1, arg2) = state.pop2();
1175 state.push1(environ.translate_udiv(builder, arg1, arg2));
1176 }
1177 Operator::I32RemS | Operator::I64RemS => {
1178 let (arg1, arg2) = state.pop2();
1179 state.push1(environ.translate_srem(builder, arg1, arg2));
1180 }
1181 Operator::I32RemU | Operator::I64RemU => {
1182 let (arg1, arg2) = state.pop2();
1183 state.push1(environ.translate_urem(builder, arg1, arg2));
1184 }
1185 Operator::F32Min | Operator::F64Min => {
1186 let (arg1, arg2) = state.pop2();
1187 state.push1(builder.ins().fmin(arg1, arg2));
1188 }
1189 Operator::F32Max | Operator::F64Max => {
1190 let (arg1, arg2) = state.pop2();
1191 state.push1(builder.ins().fmax(arg1, arg2));
1192 }
1193 Operator::F32Copysign | Operator::F64Copysign => {
1194 let (arg1, arg2) = state.pop2();
1195 state.push1(builder.ins().fcopysign(arg1, arg2));
1196 }
1197 Operator::I32LtS | Operator::I64LtS => {
1199 translate_icmp(IntCC::SignedLessThan, builder, state)
1200 }
1201 Operator::I32LtU | Operator::I64LtU => {
1202 translate_icmp(IntCC::UnsignedLessThan, builder, state)
1203 }
1204 Operator::I32LeS | Operator::I64LeS => {
1205 translate_icmp(IntCC::SignedLessThanOrEqual, builder, state)
1206 }
1207 Operator::I32LeU | Operator::I64LeU => {
1208 translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, state)
1209 }
1210 Operator::I32GtS | Operator::I64GtS => {
1211 translate_icmp(IntCC::SignedGreaterThan, builder, state)
1212 }
1213 Operator::I32GtU | Operator::I64GtU => {
1214 translate_icmp(IntCC::UnsignedGreaterThan, builder, state)
1215 }
1216 Operator::I32GeS | Operator::I64GeS => {
1217 translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, state)
1218 }
1219 Operator::I32GeU | Operator::I64GeU => {
1220 translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, state)
1221 }
1222 Operator::I32Eqz | Operator::I64Eqz => {
1223 let arg = state.pop1();
1224 let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0);
1225 state.push1(builder.ins().uextend(I32, val));
1226 }
1227 Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, state),
1228 Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, state),
1229 Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, state),
1230 Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, state),
1231 Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, state),
1232 Operator::F32Ge | Operator::F64Ge => {
1233 translate_fcmp(FloatCC::GreaterThanOrEqual, builder, state)
1234 }
1235 Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, state),
1236 Operator::F32Le | Operator::F64Le => {
1237 translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
1238 }
1239 Operator::RefNull { hty } => {
1240 let hty = environ.convert_heap_type(*hty);
1241 state.push1(environ.translate_ref_null(builder.cursor(), hty)?)
1242 }
1243 Operator::RefIsNull => {
1244 let value = state.pop1();
1245 state.push1(environ.translate_ref_is_null(builder.cursor(), value)?);
1246 }
1247 Operator::RefFunc { function_index } => {
1248 let index = FuncIndex::from_u32(*function_index);
1249 state.push1(environ.translate_ref_func(builder.cursor(), index)?);
1250 }
1251 Operator::MemoryAtomicWait32 { memarg } | Operator::MemoryAtomicWait64 { memarg } => {
1252 let implied_ty = match op {
1256 Operator::MemoryAtomicWait64 { .. } => I64,
1257 Operator::MemoryAtomicWait32 { .. } => I32,
1258 _ => unreachable!(),
1259 };
1260 let heap_index = MemoryIndex::from_u32(memarg.memory);
1261 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1262 let timeout = state.pop1(); let expected = state.pop1(); assert!(builder.func.dfg.value_type(expected) == implied_ty);
1265 let addr = state.pop1();
1266 let effective_addr = if memarg.offset == 0 {
1267 addr
1268 } else {
1269 let index_type = environ.heaps()[heap].index_type();
1270 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1271 environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
1272 };
1273 let res = environ.translate_atomic_wait(
1276 builder,
1277 heap_index,
1278 heap,
1279 effective_addr,
1280 expected,
1281 timeout,
1282 )?;
1283 state.push1(res);
1284 }
1285 Operator::MemoryAtomicNotify { memarg } => {
1286 let heap_index = MemoryIndex::from_u32(memarg.memory);
1287 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1288 let count = state.pop1(); let addr = state.pop1();
1290 let effective_addr = if memarg.offset == 0 {
1291 addr
1292 } else {
1293 let index_type = environ.heaps()[heap].index_type();
1294 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1295 environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
1296 };
1297 let res = environ.translate_atomic_notify(
1298 builder,
1299 heap_index,
1300 heap,
1301 effective_addr,
1302 count,
1303 )?;
1304 state.push1(res);
1305 }
1306 Operator::I32AtomicLoad { memarg } => {
1307 translate_atomic_load(I32, I32, memarg, builder, state, environ)?
1308 }
1309 Operator::I64AtomicLoad { memarg } => {
1310 translate_atomic_load(I64, I64, memarg, builder, state, environ)?
1311 }
1312 Operator::I32AtomicLoad8U { memarg } => {
1313 translate_atomic_load(I32, I8, memarg, builder, state, environ)?
1314 }
1315 Operator::I32AtomicLoad16U { memarg } => {
1316 translate_atomic_load(I32, I16, memarg, builder, state, environ)?
1317 }
1318 Operator::I64AtomicLoad8U { memarg } => {
1319 translate_atomic_load(I64, I8, memarg, builder, state, environ)?
1320 }
1321 Operator::I64AtomicLoad16U { memarg } => {
1322 translate_atomic_load(I64, I16, memarg, builder, state, environ)?
1323 }
1324 Operator::I64AtomicLoad32U { memarg } => {
1325 translate_atomic_load(I64, I32, memarg, builder, state, environ)?
1326 }
1327
1328 Operator::I32AtomicStore { memarg } => {
1329 translate_atomic_store(I32, memarg, builder, state, environ)?
1330 }
1331 Operator::I64AtomicStore { memarg } => {
1332 translate_atomic_store(I64, memarg, builder, state, environ)?
1333 }
1334 Operator::I32AtomicStore8 { memarg } => {
1335 translate_atomic_store(I8, memarg, builder, state, environ)?
1336 }
1337 Operator::I32AtomicStore16 { memarg } => {
1338 translate_atomic_store(I16, memarg, builder, state, environ)?
1339 }
1340 Operator::I64AtomicStore8 { memarg } => {
1341 translate_atomic_store(I8, memarg, builder, state, environ)?
1342 }
1343 Operator::I64AtomicStore16 { memarg } => {
1344 translate_atomic_store(I16, memarg, builder, state, environ)?
1345 }
1346 Operator::I64AtomicStore32 { memarg } => {
1347 translate_atomic_store(I32, memarg, builder, state, environ)?
1348 }
1349
1350 Operator::I32AtomicRmwAdd { memarg } => {
1351 translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1352 }
1353 Operator::I64AtomicRmwAdd { memarg } => {
1354 translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, state, environ)?
1355 }
1356 Operator::I32AtomicRmw8AddU { memarg } => {
1357 translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1358 }
1359 Operator::I32AtomicRmw16AddU { memarg } => {
1360 translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1361 }
1362 Operator::I64AtomicRmw8AddU { memarg } => {
1363 translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1364 }
1365 Operator::I64AtomicRmw16AddU { memarg } => {
1366 translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1367 }
1368 Operator::I64AtomicRmw32AddU { memarg } => {
1369 translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1370 }
1371
1372 Operator::I32AtomicRmwSub { memarg } => {
1373 translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1374 }
1375 Operator::I64AtomicRmwSub { memarg } => {
1376 translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1377 }
1378 Operator::I32AtomicRmw8SubU { memarg } => {
1379 translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1380 }
1381 Operator::I32AtomicRmw16SubU { memarg } => {
1382 translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1383 }
1384 Operator::I64AtomicRmw8SubU { memarg } => {
1385 translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1386 }
1387 Operator::I64AtomicRmw16SubU { memarg } => {
1388 translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1389 }
1390 Operator::I64AtomicRmw32SubU { memarg } => {
1391 translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1392 }
1393
1394 Operator::I32AtomicRmwAnd { memarg } => {
1395 translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1396 }
1397 Operator::I64AtomicRmwAnd { memarg } => {
1398 translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, state, environ)?
1399 }
1400 Operator::I32AtomicRmw8AndU { memarg } => {
1401 translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1402 }
1403 Operator::I32AtomicRmw16AndU { memarg } => {
1404 translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1405 }
1406 Operator::I64AtomicRmw8AndU { memarg } => {
1407 translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1408 }
1409 Operator::I64AtomicRmw16AndU { memarg } => {
1410 translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1411 }
1412 Operator::I64AtomicRmw32AndU { memarg } => {
1413 translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1414 }
1415
1416 Operator::I32AtomicRmwOr { memarg } => {
1417 translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1418 }
1419 Operator::I64AtomicRmwOr { memarg } => {
1420 translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, state, environ)?
1421 }
1422 Operator::I32AtomicRmw8OrU { memarg } => {
1423 translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1424 }
1425 Operator::I32AtomicRmw16OrU { memarg } => {
1426 translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1427 }
1428 Operator::I64AtomicRmw8OrU { memarg } => {
1429 translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1430 }
1431 Operator::I64AtomicRmw16OrU { memarg } => {
1432 translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1433 }
1434 Operator::I64AtomicRmw32OrU { memarg } => {
1435 translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1436 }
1437
1438 Operator::I32AtomicRmwXor { memarg } => {
1439 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1440 }
1441 Operator::I64AtomicRmwXor { memarg } => {
1442 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1443 }
1444 Operator::I32AtomicRmw8XorU { memarg } => {
1445 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1446 }
1447 Operator::I32AtomicRmw16XorU { memarg } => {
1448 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1449 }
1450 Operator::I64AtomicRmw8XorU { memarg } => {
1451 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1452 }
1453 Operator::I64AtomicRmw16XorU { memarg } => {
1454 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1455 }
1456 Operator::I64AtomicRmw32XorU { memarg } => {
1457 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1458 }
1459
1460 Operator::I32AtomicRmwXchg { memarg } => {
1461 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1462 }
1463 Operator::I64AtomicRmwXchg { memarg } => {
1464 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1465 }
1466 Operator::I32AtomicRmw8XchgU { memarg } => {
1467 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1468 }
1469 Operator::I32AtomicRmw16XchgU { memarg } => {
1470 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1471 }
1472 Operator::I64AtomicRmw8XchgU { memarg } => {
1473 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1474 }
1475 Operator::I64AtomicRmw16XchgU { memarg } => {
1476 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1477 }
1478 Operator::I64AtomicRmw32XchgU { memarg } => {
1479 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1480 }
1481
1482 Operator::I32AtomicRmwCmpxchg { memarg } => {
1483 translate_atomic_cas(I32, I32, memarg, builder, state, environ)?
1484 }
1485 Operator::I64AtomicRmwCmpxchg { memarg } => {
1486 translate_atomic_cas(I64, I64, memarg, builder, state, environ)?
1487 }
1488 Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1489 translate_atomic_cas(I32, I8, memarg, builder, state, environ)?
1490 }
1491 Operator::I32AtomicRmw16CmpxchgU { memarg } => {
1492 translate_atomic_cas(I32, I16, memarg, builder, state, environ)?
1493 }
1494 Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1495 translate_atomic_cas(I64, I8, memarg, builder, state, environ)?
1496 }
1497 Operator::I64AtomicRmw16CmpxchgU { memarg } => {
1498 translate_atomic_cas(I64, I16, memarg, builder, state, environ)?
1499 }
1500 Operator::I64AtomicRmw32CmpxchgU { memarg } => {
1501 translate_atomic_cas(I64, I32, memarg, builder, state, environ)?
1502 }
1503
1504 Operator::AtomicFence { .. } => {
1505 builder.ins().fence();
1506 }
1507 Operator::MemoryCopy { src_mem, dst_mem } => {
1508 let src_index = MemoryIndex::from_u32(*src_mem);
1509 let dst_index = MemoryIndex::from_u32(*dst_mem);
1510 let src_heap = state.get_heap(builder.func, *src_mem, environ)?;
1511 let dst_heap = state.get_heap(builder.func, *dst_mem, environ)?;
1512 let len = state.pop1();
1513 let src_pos = state.pop1();
1514 let dst_pos = state.pop1();
1515 environ.translate_memory_copy(
1516 builder, src_index, src_heap, dst_index, dst_heap, dst_pos, src_pos, len,
1517 )?;
1518 }
1519 Operator::MemoryFill { mem } => {
1520 let heap_index = MemoryIndex::from_u32(*mem);
1521 let heap = state.get_heap(builder.func, *mem, environ)?;
1522 let len = state.pop1();
1523 let val = state.pop1();
1524 let dest = state.pop1();
1525 environ.translate_memory_fill(builder, heap_index, heap, dest, val, len)?;
1526 }
1527 Operator::MemoryInit { data_index, mem } => {
1528 let heap_index = MemoryIndex::from_u32(*mem);
1529 let heap = state.get_heap(builder.func, *mem, environ)?;
1530 let len = state.pop1();
1531 let src = state.pop1();
1532 let dest = state.pop1();
1533 environ.translate_memory_init(
1534 builder,
1535 heap_index,
1536 heap,
1537 *data_index,
1538 dest,
1539 src,
1540 len,
1541 )?;
1542 }
1543 Operator::DataDrop { data_index } => {
1544 environ.translate_data_drop(builder.cursor(), *data_index)?;
1545 }
1546 Operator::TableSize { table: index } => {
1547 state.push1(
1548 environ.translate_table_size(builder.cursor(), TableIndex::from_u32(*index))?,
1549 );
1550 }
1551 Operator::TableGrow { table: index } => {
1552 let table_index = TableIndex::from_u32(*index);
1553 let delta = state.pop1();
1554 let init_value = state.pop1();
1555 state.push1(environ.translate_table_grow(builder, table_index, delta, init_value)?);
1556 }
1557 Operator::TableGet { table: index } => {
1558 let table_index = TableIndex::from_u32(*index);
1559 let index = state.pop1();
1560 state.push1(environ.translate_table_get(builder, table_index, index)?);
1561 }
1562 Operator::TableSet { table: index } => {
1563 let table_index = TableIndex::from_u32(*index);
1564 let value = state.pop1();
1565 let index = state.pop1();
1566 environ.translate_table_set(builder, table_index, value, index)?;
1567 }
1568 Operator::TableCopy {
1569 dst_table: dst_table_index,
1570 src_table: src_table_index,
1571 } => {
1572 let len = state.pop1();
1573 let src = state.pop1();
1574 let dest = state.pop1();
1575 environ.translate_table_copy(
1576 builder,
1577 TableIndex::from_u32(*dst_table_index),
1578 TableIndex::from_u32(*src_table_index),
1579 dest,
1580 src,
1581 len,
1582 )?;
1583 }
1584 Operator::TableFill { table } => {
1585 let table_index = TableIndex::from_u32(*table);
1586 let len = state.pop1();
1587 let val = state.pop1();
1588 let dest = state.pop1();
1589 environ.translate_table_fill(builder, table_index, dest, val, len)?;
1590 }
1591 Operator::TableInit {
1592 elem_index,
1593 table: table_index,
1594 } => {
1595 let len = state.pop1();
1596 let src = state.pop1();
1597 let dest = state.pop1();
1598 environ.translate_table_init(
1599 builder,
1600 *elem_index,
1601 TableIndex::from_u32(*table_index),
1602 dest,
1603 src,
1604 len,
1605 )?;
1606 }
1607 Operator::ElemDrop { elem_index } => {
1608 environ.translate_elem_drop(builder.cursor(), *elem_index)?;
1609 }
1610 Operator::V128Const { value } => {
1611 let data = value.bytes().to_vec().into();
1612 let handle = builder.func.dfg.constants.insert(data);
1613 let value = builder.ins().vconst(I8X16, handle);
1614 state.push1(value)
1617 }
1618 Operator::I8x16Splat | Operator::I16x8Splat => {
1619 let reduced = builder.ins().ireduce(type_of(op).lane_type(), state.pop1());
1620 let splatted = builder.ins().splat(type_of(op), reduced);
1621 state.push1(splatted)
1622 }
1623 Operator::I32x4Splat
1624 | Operator::I64x2Splat
1625 | Operator::F32x4Splat
1626 | Operator::F64x2Splat => {
1627 let splatted = builder.ins().splat(type_of(op), state.pop1());
1628 state.push1(splatted)
1629 }
1630 Operator::V128Load8Splat { memarg }
1631 | Operator::V128Load16Splat { memarg }
1632 | Operator::V128Load32Splat { memarg }
1633 | Operator::V128Load64Splat { memarg } => {
1634 unwrap_or_return_unreachable_state!(
1635 state,
1636 translate_load(
1637 memarg,
1638 ir::Opcode::Load,
1639 type_of(op).lane_type(),
1640 builder,
1641 state,
1642 environ,
1643 )?
1644 );
1645 let splatted = builder.ins().splat(type_of(op), state.pop1());
1646 state.push1(splatted)
1647 }
1648 Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
1649 unwrap_or_return_unreachable_state!(
1650 state,
1651 translate_load(
1652 memarg,
1653 ir::Opcode::Load,
1654 type_of(op).lane_type(),
1655 builder,
1656 state,
1657 environ,
1658 )?
1659 );
1660 let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
1661 state.push1(as_vector)
1662 }
1663 Operator::V128Load8Lane { memarg, lane }
1664 | Operator::V128Load16Lane { memarg, lane }
1665 | Operator::V128Load32Lane { memarg, lane }
1666 | Operator::V128Load64Lane { memarg, lane } => {
1667 let vector = pop1_with_bitcast(state, type_of(op), builder);
1668 unwrap_or_return_unreachable_state!(
1669 state,
1670 translate_load(
1671 memarg,
1672 ir::Opcode::Load,
1673 type_of(op).lane_type(),
1674 builder,
1675 state,
1676 environ,
1677 )?
1678 );
1679 let replacement = state.pop1();
1680 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1681 }
1682 Operator::V128Store8Lane { memarg, lane }
1683 | Operator::V128Store16Lane { memarg, lane }
1684 | Operator::V128Store32Lane { memarg, lane }
1685 | Operator::V128Store64Lane { memarg, lane } => {
1686 let vector = pop1_with_bitcast(state, type_of(op), builder);
1687 state.push1(builder.ins().extractlane(vector, *lane));
1688 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
1689 }
1690 Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => {
1691 let vector = pop1_with_bitcast(state, type_of(op), builder);
1692 let extracted = builder.ins().extractlane(vector, *lane);
1693 state.push1(builder.ins().sextend(I32, extracted))
1694 }
1695 Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
1696 let vector = pop1_with_bitcast(state, type_of(op), builder);
1697 let extracted = builder.ins().extractlane(vector, *lane);
1698 state.push1(builder.ins().uextend(I32, extracted));
1699 }
1703 Operator::I32x4ExtractLane { lane }
1704 | Operator::I64x2ExtractLane { lane }
1705 | Operator::F32x4ExtractLane { lane }
1706 | Operator::F64x2ExtractLane { lane } => {
1707 let vector = pop1_with_bitcast(state, type_of(op), builder);
1708 state.push1(builder.ins().extractlane(vector, *lane))
1709 }
1710 Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => {
1711 let (vector, replacement) = state.pop2();
1712 let ty = type_of(op);
1713 let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
1714 let vector = optionally_bitcast_vector(vector, ty, builder);
1715 state.push1(builder.ins().insertlane(vector, reduced, *lane))
1716 }
1717 Operator::I32x4ReplaceLane { lane }
1718 | Operator::I64x2ReplaceLane { lane }
1719 | Operator::F32x4ReplaceLane { lane }
1720 | Operator::F64x2ReplaceLane { lane } => {
1721 let (vector, replacement) = state.pop2();
1722 let vector = optionally_bitcast_vector(vector, type_of(op), builder);
1723 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1724 }
1725 Operator::I8x16Shuffle { lanes, .. } => {
1726 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1727 let lanes = ConstantData::from(lanes.as_ref());
1728 let mask = builder.func.dfg.immediates.push(lanes);
1729 let shuffled = builder.ins().shuffle(a, b, mask);
1730 state.push1(shuffled)
1731 }
1736 Operator::I8x16Swizzle => {
1737 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1738 state.push1(builder.ins().swizzle(a, b))
1739 }
1740 Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1741 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1742 state.push1(builder.ins().iadd(a, b))
1743 }
1744 Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1745 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1746 state.push1(builder.ins().sadd_sat(a, b))
1747 }
1748 Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1749 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1750 state.push1(builder.ins().uadd_sat(a, b))
1751 }
1752 Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1753 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1754 state.push1(builder.ins().isub(a, b))
1755 }
1756 Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1757 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1758 state.push1(builder.ins().ssub_sat(a, b))
1759 }
1760 Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1761 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1762 state.push1(builder.ins().usub_sat(a, b))
1763 }
1764 Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1765 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1766 state.push1(builder.ins().smin(a, b))
1767 }
1768 Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1769 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1770 state.push1(builder.ins().umin(a, b))
1771 }
1772 Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1773 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1774 state.push1(builder.ins().smax(a, b))
1775 }
1776 Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1777 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1778 state.push1(builder.ins().umax(a, b))
1779 }
1780 Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1781 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1782 state.push1(builder.ins().avg_round(a, b))
1783 }
1784 Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1785 let a = pop1_with_bitcast(state, type_of(op), builder);
1786 state.push1(builder.ins().ineg(a))
1787 }
1788 Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1789 let a = pop1_with_bitcast(state, type_of(op), builder);
1790 state.push1(builder.ins().iabs(a))
1791 }
1792 Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1793 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1794 state.push1(builder.ins().imul(a, b))
1795 }
1796 Operator::V128Or => {
1797 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1798 state.push1(builder.ins().bor(a, b))
1799 }
1800 Operator::V128Xor => {
1801 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1802 state.push1(builder.ins().bxor(a, b))
1803 }
1804 Operator::V128And => {
1805 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1806 state.push1(builder.ins().band(a, b))
1807 }
1808 Operator::V128AndNot => {
1809 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1810 state.push1(builder.ins().band_not(a, b))
1811 }
1812 Operator::V128Not => {
1813 let a = state.pop1();
1814 state.push1(builder.ins().bnot(a));
1815 }
1816 Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
1817 let (a, b) = state.pop2();
1818 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1819 state.push1(builder.ins().ishl(bitcast_a, b))
1822 }
1823 Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
1824 let (a, b) = state.pop2();
1825 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1826 state.push1(builder.ins().ushr(bitcast_a, b))
1829 }
1830 Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
1831 let (a, b) = state.pop2();
1832 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1833 state.push1(builder.ins().sshr(bitcast_a, b))
1836 }
1837 Operator::V128Bitselect => {
1838 let (a, b, c) = pop3_with_bitcast(state, I8X16, builder);
1839 state.push1(builder.ins().bitselect(c, a, b))
1842 }
1843 Operator::V128AnyTrue => {
1844 let a = pop1_with_bitcast(state, type_of(op), builder);
1845 let bool_result = builder.ins().vany_true(a);
1846 state.push1(builder.ins().uextend(I32, bool_result))
1847 }
1848 Operator::I8x16AllTrue
1849 | Operator::I16x8AllTrue
1850 | Operator::I32x4AllTrue
1851 | Operator::I64x2AllTrue => {
1852 let a = pop1_with_bitcast(state, type_of(op), builder);
1853 let bool_result = builder.ins().vall_true(a);
1854 state.push1(builder.ins().uextend(I32, bool_result))
1855 }
1856 Operator::I8x16Bitmask
1857 | Operator::I16x8Bitmask
1858 | Operator::I32x4Bitmask
1859 | Operator::I64x2Bitmask => {
1860 let a = pop1_with_bitcast(state, type_of(op), builder);
1861 state.push1(builder.ins().vhigh_bits(I32, a));
1862 }
1863 Operator::I8x16Eq | Operator::I16x8Eq | Operator::I32x4Eq | Operator::I64x2Eq => {
1864 translate_vector_icmp(IntCC::Equal, type_of(op), builder, state)
1865 }
1866 Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
1867 translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, state)
1868 }
1869 Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
1870 translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, state)
1871 }
1872 Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
1873 translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, state)
1874 }
1875 Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
1876 translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, state)
1877 }
1878 Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
1879 translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, state)
1880 }
1881 Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
1882 translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, state)
1883 }
1884 Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
1885 translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, state)
1886 }
1887 Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
1888 IntCC::UnsignedGreaterThanOrEqual,
1889 type_of(op),
1890 builder,
1891 state,
1892 ),
1893 Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
1894 translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, state)
1895 }
1896 Operator::F32x4Eq | Operator::F64x2Eq => {
1897 translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, state)
1898 }
1899 Operator::F32x4Ne | Operator::F64x2Ne => {
1900 translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, state)
1901 }
1902 Operator::F32x4Lt | Operator::F64x2Lt => {
1903 translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, state)
1904 }
1905 Operator::F32x4Gt | Operator::F64x2Gt => {
1906 translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, state)
1907 }
1908 Operator::F32x4Le | Operator::F64x2Le => {
1909 translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, state)
1910 }
1911 Operator::F32x4Ge | Operator::F64x2Ge => {
1912 translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, state)
1913 }
1914 Operator::F32x4Add | Operator::F64x2Add => {
1915 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1916 state.push1(builder.ins().fadd(a, b))
1917 }
1918 Operator::F32x4Sub | Operator::F64x2Sub => {
1919 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1920 state.push1(builder.ins().fsub(a, b))
1921 }
1922 Operator::F32x4Mul | Operator::F64x2Mul => {
1923 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1924 state.push1(builder.ins().fmul(a, b))
1925 }
1926 Operator::F32x4Div | Operator::F64x2Div => {
1927 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1928 state.push1(builder.ins().fdiv(a, b))
1929 }
1930 Operator::F32x4Max | Operator::F64x2Max => {
1931 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1932 state.push1(builder.ins().fmax(a, b))
1933 }
1934 Operator::F32x4Min | Operator::F64x2Min => {
1935 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1936 state.push1(builder.ins().fmin(a, b))
1937 }
1938 Operator::F32x4PMax | Operator::F64x2PMax => {
1939 let ty = type_of(op);
1946 let (a, b) = pop2_with_bitcast(state, ty, builder);
1947 let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
1948 let cmp = optionally_bitcast_vector(cmp, ty, builder);
1949 state.push1(builder.ins().bitselect(cmp, b, a))
1950 }
1951 Operator::F32x4PMin | Operator::F64x2PMin => {
1952 let ty = type_of(op);
1958 let (a, b) = pop2_with_bitcast(state, ty, builder);
1959 let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
1960 let cmp = optionally_bitcast_vector(cmp, ty, builder);
1961 state.push1(builder.ins().bitselect(cmp, b, a))
1962 }
1963 Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
1964 let a = pop1_with_bitcast(state, type_of(op), builder);
1965 state.push1(builder.ins().sqrt(a))
1966 }
1967 Operator::F32x4Neg | Operator::F64x2Neg => {
1968 let a = pop1_with_bitcast(state, type_of(op), builder);
1969 state.push1(builder.ins().fneg(a))
1970 }
1971 Operator::F32x4Abs | Operator::F64x2Abs => {
1972 let a = pop1_with_bitcast(state, type_of(op), builder);
1973 state.push1(builder.ins().fabs(a))
1974 }
1975 Operator::F32x4ConvertI32x4S => {
1976 let a = pop1_with_bitcast(state, I32X4, builder);
1977 state.push1(builder.ins().fcvt_from_sint(F32X4, a))
1978 }
1979 Operator::F32x4ConvertI32x4U => {
1980 let a = pop1_with_bitcast(state, I32X4, builder);
1981 state.push1(builder.ins().fcvt_from_uint(F32X4, a))
1982 }
1983 Operator::F64x2ConvertLowI32x4S => {
1984 let a = pop1_with_bitcast(state, I32X4, builder);
1985 let widened_a = builder.ins().swiden_low(a);
1986 state.push1(builder.ins().fcvt_from_sint(F64X2, widened_a));
1987 }
1988 Operator::F64x2ConvertLowI32x4U => {
1989 let a = pop1_with_bitcast(state, I32X4, builder);
1990 let widened_a = builder.ins().uwiden_low(a);
1991 state.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
1992 }
1993 Operator::F64x2PromoteLowF32x4 => {
1994 let a = pop1_with_bitcast(state, F32X4, builder);
1995 state.push1(builder.ins().fvpromote_low(a));
1996 }
1997 Operator::F32x4DemoteF64x2Zero => {
1998 let a = pop1_with_bitcast(state, F64X2, builder);
1999 state.push1(builder.ins().fvdemote(a));
2000 }
2001 Operator::I32x4TruncSatF32x4S => {
2002 let a = pop1_with_bitcast(state, F32X4, builder);
2003 state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
2004 }
2005 Operator::I32x4TruncSatF64x2SZero => {
2006 let a = pop1_with_bitcast(state, F64X2, builder);
2007 let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
2008 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2009 let zero = builder.ins().vconst(I64X2, handle);
2010
2011 state.push1(builder.ins().snarrow(converted_a, zero));
2012 }
2013
2014 Operator::I32x4RelaxedTruncF32x4U | Operator::I32x4TruncSatF32x4U => {
2026 let a = pop1_with_bitcast(state, F32X4, builder);
2027 state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
2028 }
2029 Operator::I32x4RelaxedTruncF64x2UZero | Operator::I32x4TruncSatF64x2UZero => {
2030 let a = pop1_with_bitcast(state, F64X2, builder);
2031 let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
2032 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2033 let zero = builder.ins().vconst(I64X2, handle);
2034
2035 state.push1(builder.ins().uunarrow(converted_a, zero));
2036 }
2037
2038 Operator::I8x16NarrowI16x8S => {
2039 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2040 state.push1(builder.ins().snarrow(a, b))
2041 }
2042 Operator::I16x8NarrowI32x4S => {
2043 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2044 state.push1(builder.ins().snarrow(a, b))
2045 }
2046 Operator::I8x16NarrowI16x8U => {
2047 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2048 state.push1(builder.ins().unarrow(a, b))
2049 }
2050 Operator::I16x8NarrowI32x4U => {
2051 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2052 state.push1(builder.ins().unarrow(a, b))
2053 }
2054 Operator::I16x8ExtendLowI8x16S => {
2055 let a = pop1_with_bitcast(state, I8X16, builder);
2056 state.push1(builder.ins().swiden_low(a))
2057 }
2058 Operator::I16x8ExtendHighI8x16S => {
2059 let a = pop1_with_bitcast(state, I8X16, builder);
2060 state.push1(builder.ins().swiden_high(a))
2061 }
2062 Operator::I16x8ExtendLowI8x16U => {
2063 let a = pop1_with_bitcast(state, I8X16, builder);
2064 state.push1(builder.ins().uwiden_low(a))
2065 }
2066 Operator::I16x8ExtendHighI8x16U => {
2067 let a = pop1_with_bitcast(state, I8X16, builder);
2068 state.push1(builder.ins().uwiden_high(a))
2069 }
2070 Operator::I32x4ExtendLowI16x8S => {
2071 let a = pop1_with_bitcast(state, I16X8, builder);
2072 state.push1(builder.ins().swiden_low(a))
2073 }
2074 Operator::I32x4ExtendHighI16x8S => {
2075 let a = pop1_with_bitcast(state, I16X8, builder);
2076 state.push1(builder.ins().swiden_high(a))
2077 }
2078 Operator::I32x4ExtendLowI16x8U => {
2079 let a = pop1_with_bitcast(state, I16X8, builder);
2080 state.push1(builder.ins().uwiden_low(a))
2081 }
2082 Operator::I32x4ExtendHighI16x8U => {
2083 let a = pop1_with_bitcast(state, I16X8, builder);
2084 state.push1(builder.ins().uwiden_high(a))
2085 }
2086 Operator::I64x2ExtendLowI32x4S => {
2087 let a = pop1_with_bitcast(state, I32X4, builder);
2088 state.push1(builder.ins().swiden_low(a))
2089 }
2090 Operator::I64x2ExtendHighI32x4S => {
2091 let a = pop1_with_bitcast(state, I32X4, builder);
2092 state.push1(builder.ins().swiden_high(a))
2093 }
2094 Operator::I64x2ExtendLowI32x4U => {
2095 let a = pop1_with_bitcast(state, I32X4, builder);
2096 state.push1(builder.ins().uwiden_low(a))
2097 }
2098 Operator::I64x2ExtendHighI32x4U => {
2099 let a = pop1_with_bitcast(state, I32X4, builder);
2100 state.push1(builder.ins().uwiden_high(a))
2101 }
2102 Operator::I16x8ExtAddPairwiseI8x16S => {
2103 let a = pop1_with_bitcast(state, I8X16, builder);
2104 let widen_low = builder.ins().swiden_low(a);
2105 let widen_high = builder.ins().swiden_high(a);
2106 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2107 }
2108 Operator::I32x4ExtAddPairwiseI16x8S => {
2109 let a = pop1_with_bitcast(state, I16X8, builder);
2110 let widen_low = builder.ins().swiden_low(a);
2111 let widen_high = builder.ins().swiden_high(a);
2112 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2113 }
2114 Operator::I16x8ExtAddPairwiseI8x16U => {
2115 let a = pop1_with_bitcast(state, I8X16, builder);
2116 let widen_low = builder.ins().uwiden_low(a);
2117 let widen_high = builder.ins().uwiden_high(a);
2118 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2119 }
2120 Operator::I32x4ExtAddPairwiseI16x8U => {
2121 let a = pop1_with_bitcast(state, I16X8, builder);
2122 let widen_low = builder.ins().uwiden_low(a);
2123 let widen_high = builder.ins().uwiden_high(a);
2124 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2125 }
2126 Operator::F32x4Ceil | Operator::F64x2Ceil => {
2127 let arg = pop1_with_bitcast(state, type_of(op), builder);
2131 state.push1(builder.ins().ceil(arg));
2132 }
2133 Operator::F32x4Floor | Operator::F64x2Floor => {
2134 let arg = pop1_with_bitcast(state, type_of(op), builder);
2135 state.push1(builder.ins().floor(arg));
2136 }
2137 Operator::F32x4Trunc | Operator::F64x2Trunc => {
2138 let arg = pop1_with_bitcast(state, type_of(op), builder);
2139 state.push1(builder.ins().trunc(arg));
2140 }
2141 Operator::F32x4Nearest | Operator::F64x2Nearest => {
2142 let arg = pop1_with_bitcast(state, type_of(op), builder);
2143 state.push1(builder.ins().nearest(arg));
2144 }
2145 Operator::I32x4DotI16x8S => {
2146 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2147 let alow = builder.ins().swiden_low(a);
2148 let blow = builder.ins().swiden_low(b);
2149 let low = builder.ins().imul(alow, blow);
2150 let ahigh = builder.ins().swiden_high(a);
2151 let bhigh = builder.ins().swiden_high(b);
2152 let high = builder.ins().imul(ahigh, bhigh);
2153 state.push1(builder.ins().iadd_pairwise(low, high));
2154 }
2155 Operator::I8x16Popcnt => {
2156 let arg = pop1_with_bitcast(state, type_of(op), builder);
2157 state.push1(builder.ins().popcnt(arg));
2158 }
2159 Operator::I16x8Q15MulrSatS => {
2160 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2161 state.push1(builder.ins().sqmul_round_sat(a, b))
2162 }
2163 Operator::I16x8ExtMulLowI8x16S => {
2164 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2165 let a_low = builder.ins().swiden_low(a);
2166 let b_low = builder.ins().swiden_low(b);
2167 state.push1(builder.ins().imul(a_low, b_low));
2168 }
2169 Operator::I16x8ExtMulHighI8x16S => {
2170 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2171 let a_high = builder.ins().swiden_high(a);
2172 let b_high = builder.ins().swiden_high(b);
2173 state.push1(builder.ins().imul(a_high, b_high));
2174 }
2175 Operator::I16x8ExtMulLowI8x16U => {
2176 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2177 let a_low = builder.ins().uwiden_low(a);
2178 let b_low = builder.ins().uwiden_low(b);
2179 state.push1(builder.ins().imul(a_low, b_low));
2180 }
2181 Operator::I16x8ExtMulHighI8x16U => {
2182 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2183 let a_high = builder.ins().uwiden_high(a);
2184 let b_high = builder.ins().uwiden_high(b);
2185 state.push1(builder.ins().imul(a_high, b_high));
2186 }
2187 Operator::I32x4ExtMulLowI16x8S => {
2188 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2189 let a_low = builder.ins().swiden_low(a);
2190 let b_low = builder.ins().swiden_low(b);
2191 state.push1(builder.ins().imul(a_low, b_low));
2192 }
2193 Operator::I32x4ExtMulHighI16x8S => {
2194 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2195 let a_high = builder.ins().swiden_high(a);
2196 let b_high = builder.ins().swiden_high(b);
2197 state.push1(builder.ins().imul(a_high, b_high));
2198 }
2199 Operator::I32x4ExtMulLowI16x8U => {
2200 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2201 let a_low = builder.ins().uwiden_low(a);
2202 let b_low = builder.ins().uwiden_low(b);
2203 state.push1(builder.ins().imul(a_low, b_low));
2204 }
2205 Operator::I32x4ExtMulHighI16x8U => {
2206 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2207 let a_high = builder.ins().uwiden_high(a);
2208 let b_high = builder.ins().uwiden_high(b);
2209 state.push1(builder.ins().imul(a_high, b_high));
2210 }
2211 Operator::I64x2ExtMulLowI32x4S => {
2212 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2213 let a_low = builder.ins().swiden_low(a);
2214 let b_low = builder.ins().swiden_low(b);
2215 state.push1(builder.ins().imul(a_low, b_low));
2216 }
2217 Operator::I64x2ExtMulHighI32x4S => {
2218 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2219 let a_high = builder.ins().swiden_high(a);
2220 let b_high = builder.ins().swiden_high(b);
2221 state.push1(builder.ins().imul(a_high, b_high));
2222 }
2223 Operator::I64x2ExtMulLowI32x4U => {
2224 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2225 let a_low = builder.ins().uwiden_low(a);
2226 let b_low = builder.ins().uwiden_low(b);
2227 state.push1(builder.ins().imul(a_low, b_low));
2228 }
2229 Operator::I64x2ExtMulHighI32x4U => {
2230 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2231 let a_high = builder.ins().uwiden_high(a);
2232 let b_high = builder.ins().uwiden_high(b);
2233 state.push1(builder.ins().imul(a_high, b_high));
2234 }
2235 Operator::MemoryDiscard { .. } => {
2236 return Err(wasm_unsupported!(
2237 "proposed memory-control operator {:?}",
2238 op
2239 ));
2240 }
2241
2242 Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => {
2243 let ty = type_of(op);
2244 let (a, b) = pop2_with_bitcast(state, ty, builder);
2245 state.push1(
2246 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2247 builder.ins().fmax(a, b)
2250 } else {
2251 let cmp = builder.ins().fcmp(FloatCC::LessThan, a, b);
2255 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2256 builder.ins().bitselect(cmp, b, a)
2257 },
2258 )
2259 }
2260
2261 Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => {
2262 let ty = type_of(op);
2263 let (a, b) = pop2_with_bitcast(state, ty, builder);
2264 state.push1(
2265 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2266 builder.ins().fmin(a, b)
2269 } else {
2270 let cmp = builder.ins().fcmp(FloatCC::LessThan, b, a);
2274 let cmp = optionally_bitcast_vector(cmp, ty, builder);
2275 builder.ins().bitselect(cmp, b, a)
2276 },
2277 );
2278 }
2279
2280 Operator::I8x16RelaxedSwizzle => {
2281 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2282 state.push1(
2283 if environ.relaxed_simd_deterministic()
2284 || !environ.use_x86_pshufb_for_relaxed_swizzle()
2285 {
2286 builder.ins().swizzle(a, b)
2289 } else {
2290 builder.ins().x86_pshufb(a, b)
2291 },
2292 );
2293 }
2294
2295 Operator::F32x4RelaxedMadd | Operator::F64x2RelaxedMadd => {
2296 let (a, b, c) = pop3_with_bitcast(state, type_of(op), builder);
2297 state.push1(
2298 if environ.relaxed_simd_deterministic() || environ.has_native_fma() {
2299 builder.ins().fma(a, b, c)
2302 } else {
2303 let mul = builder.ins().fmul(a, b);
2304 builder.ins().fadd(mul, c)
2305 },
2306 );
2307 }
2308 Operator::F32x4RelaxedNmadd | Operator::F64x2RelaxedNmadd => {
2309 let (a, b, c) = pop3_with_bitcast(state, type_of(op), builder);
2310 let a = builder.ins().fneg(a);
2311 state.push1(
2312 if environ.relaxed_simd_deterministic() || environ.has_native_fma() {
2313 builder.ins().fma(a, b, c)
2316 } else {
2317 let mul = builder.ins().fmul(a, b);
2318 builder.ins().fadd(mul, c)
2319 },
2320 );
2321 }
2322
2323 Operator::I8x16RelaxedLaneselect
2324 | Operator::I16x8RelaxedLaneselect
2325 | Operator::I32x4RelaxedLaneselect
2326 | Operator::I64x2RelaxedLaneselect => {
2327 let ty = type_of(op);
2328 let (a, b, c) = pop3_with_bitcast(state, ty, builder);
2329 state.push1(
2333 if environ.relaxed_simd_deterministic()
2334 || !environ.use_x86_blendv_for_relaxed_laneselect(ty)
2335 {
2336 builder.ins().bitselect(c, a, b)
2339 } else {
2340 builder.ins().x86_blendv(c, a, b)
2341 },
2342 );
2343 }
2344
2345 Operator::I32x4RelaxedTruncF32x4S => {
2346 let a = pop1_with_bitcast(state, F32X4, builder);
2347 state.push1(
2348 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2349 builder.ins().fcvt_to_sint_sat(I32X4, a)
2352 } else {
2353 builder.ins().x86_cvtt2dq(I32X4, a)
2354 },
2355 )
2356 }
2357 Operator::I32x4RelaxedTruncF64x2SZero => {
2358 let a = pop1_with_bitcast(state, F64X2, builder);
2359 let converted_a = if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2360 builder.ins().fcvt_to_sint_sat(I64X2, a)
2363 } else {
2364 builder.ins().x86_cvtt2dq(I64X2, a)
2365 };
2366 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2367 let zero = builder.ins().vconst(I64X2, handle);
2368
2369 state.push1(builder.ins().snarrow(converted_a, zero));
2370 }
2371 Operator::I16x8RelaxedQ15mulrS => {
2372 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2373 state.push1(
2374 if environ.relaxed_simd_deterministic()
2375 || !environ.use_x86_pmulhrsw_for_relaxed_q15mul()
2376 {
2377 builder.ins().sqmul_round_sat(a, b)
2380 } else {
2381 builder.ins().x86_pmulhrsw(a, b)
2382 },
2383 );
2384 }
2385 Operator::I16x8RelaxedDotI8x16I7x16S => {
2386 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2387 state.push1(
2388 if environ.relaxed_simd_deterministic() || !environ.use_x86_pmaddubsw_for_dot() {
2389 let alo = builder.ins().swiden_low(a);
2392 let blo = builder.ins().swiden_low(b);
2393 let lo = builder.ins().imul(alo, blo);
2394 let ahi = builder.ins().swiden_high(a);
2395 let bhi = builder.ins().swiden_high(b);
2396 let hi = builder.ins().imul(ahi, bhi);
2397 builder.ins().iadd_pairwise(lo, hi)
2398 } else {
2399 builder.ins().x86_pmaddubsw(a, b)
2400 },
2401 );
2402 }
2403
2404 Operator::I32x4RelaxedDotI8x16I7x16AddS => {
2405 let c = pop1_with_bitcast(state, I32X4, builder);
2406 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2407 let dot =
2408 if environ.relaxed_simd_deterministic() || !environ.use_x86_pmaddubsw_for_dot() {
2409 let alo = builder.ins().swiden_low(a);
2412 let blo = builder.ins().swiden_low(b);
2413 let lo = builder.ins().imul(alo, blo);
2414 let ahi = builder.ins().swiden_high(a);
2415 let bhi = builder.ins().swiden_high(b);
2416 let hi = builder.ins().imul(ahi, bhi);
2417 builder.ins().iadd_pairwise(lo, hi)
2418 } else {
2419 builder.ins().x86_pmaddubsw(a, b)
2420 };
2421 let dotlo = builder.ins().swiden_low(dot);
2422 let dothi = builder.ins().swiden_high(dot);
2423 let dot32 = builder.ins().iadd_pairwise(dotlo, dothi);
2424 state.push1(builder.ins().iadd(dot32, c));
2425 }
2426
2427 Operator::BrOnNull { relative_depth } => {
2428 let r = state.pop1();
2429 let (br_destination, inputs) = translate_br_if_args(*relative_depth, state);
2430 let is_null = environ.translate_ref_is_null(builder.cursor(), r)?;
2431 let else_block = builder.create_block();
2432 canonicalise_brif(builder, is_null, br_destination, inputs, else_block, &[]);
2433
2434 builder.seal_block(else_block); builder.switch_to_block(else_block);
2436 state.push1(r);
2437 }
2438 Operator::BrOnNonNull { relative_depth } => {
2439 let is_null = environ.translate_ref_is_null(builder.cursor(), state.peek1())?;
2446 let (br_destination, inputs) = translate_br_if_args(*relative_depth, state);
2447 let else_block = builder.create_block();
2448 canonicalise_brif(builder, is_null, else_block, &[], br_destination, inputs);
2449
2450 state.pop1();
2452
2453 builder.seal_block(else_block); builder.switch_to_block(else_block);
2458 }
2459 Operator::CallRef { type_index } => {
2460 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
2464 let callee = state.pop1();
2465
2466 let args = state.peekn_mut(num_args);
2468 bitcast_wasm_params(environ, sigref, args, builder);
2469
2470 let call =
2471 environ.translate_call_ref(builder, sigref, callee, state.peekn(num_args))?;
2472
2473 let inst_results = builder.inst_results(call);
2474 debug_assert_eq!(
2475 inst_results.len(),
2476 builder.func.dfg.signatures[sigref].returns.len(),
2477 "translate_call_ref results should match the call signature"
2478 );
2479 state.popn(num_args);
2480 state.pushn(inst_results);
2481 }
2482 Operator::RefAsNonNull => {
2483 let r = state.pop1();
2484 let is_null = environ.translate_ref_is_null(builder.cursor(), r)?;
2485 environ.trapnz(builder, is_null, crate::TRAP_NULL_REFERENCE);
2486 state.push1(r);
2487 }
2488
2489 Operator::RefI31 => {
2490 let val = state.pop1();
2491 let i31ref = environ.translate_ref_i31(builder.cursor(), val)?;
2492 state.push1(i31ref);
2493 }
2494 Operator::I31GetS => {
2495 let i31ref = state.pop1();
2496 let val = environ.translate_i31_get_s(builder, i31ref)?;
2497 state.push1(val);
2498 }
2499 Operator::I31GetU => {
2500 let i31ref = state.pop1();
2501 let val = environ.translate_i31_get_u(builder, i31ref)?;
2502 state.push1(val);
2503 }
2504
2505 Operator::StructNew { struct_type_index } => {
2506 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2507 let arity = environ.struct_fields_len(struct_type_index)?;
2508 let fields: StructFieldsVec = state.peekn(arity).iter().copied().collect();
2509 state.popn(arity);
2510 let struct_ref = environ.translate_struct_new(builder, struct_type_index, fields)?;
2511 state.push1(struct_ref);
2512 }
2513
2514 Operator::StructNewDefault { struct_type_index } => {
2515 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2516 let struct_ref = environ.translate_struct_new_default(builder, struct_type_index)?;
2517 state.push1(struct_ref);
2518 }
2519
2520 Operator::StructSet {
2521 struct_type_index,
2522 field_index,
2523 } => {
2524 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2525 let val = state.pop1();
2526 let struct_ref = state.pop1();
2527 environ.translate_struct_set(
2528 builder,
2529 struct_type_index,
2530 *field_index,
2531 struct_ref,
2532 val,
2533 )?;
2534 }
2535
2536 Operator::StructGetS {
2537 struct_type_index,
2538 field_index,
2539 } => {
2540 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2541 let struct_ref = state.pop1();
2542 let val = environ.translate_struct_get(
2543 builder,
2544 struct_type_index,
2545 *field_index,
2546 struct_ref,
2547 Some(Extension::Sign),
2548 )?;
2549 state.push1(val);
2550 }
2551
2552 Operator::StructGetU {
2553 struct_type_index,
2554 field_index,
2555 } => {
2556 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2557 let struct_ref = state.pop1();
2558 let val = environ.translate_struct_get(
2559 builder,
2560 struct_type_index,
2561 *field_index,
2562 struct_ref,
2563 Some(Extension::Zero),
2564 )?;
2565 state.push1(val);
2566 }
2567
2568 Operator::StructGet {
2569 struct_type_index,
2570 field_index,
2571 } => {
2572 let struct_type_index = TypeIndex::from_u32(*struct_type_index);
2573 let struct_ref = state.pop1();
2574 let val = environ.translate_struct_get(
2575 builder,
2576 struct_type_index,
2577 *field_index,
2578 struct_ref,
2579 None,
2580 )?;
2581 state.push1(val);
2582 }
2583
2584 Operator::TryTable { .. } | Operator::ThrowRef => {
2585 return Err(wasm_unsupported!(
2586 "exception operators are not yet implemented"
2587 ));
2588 }
2589
2590 Operator::ArrayNew { array_type_index } => {
2591 let array_type_index = TypeIndex::from_u32(*array_type_index);
2592 let (elem, len) = state.pop2();
2593 let array_ref = environ.translate_array_new(builder, array_type_index, elem, len)?;
2594 state.push1(array_ref);
2595 }
2596 Operator::ArrayNewDefault { array_type_index } => {
2597 let array_type_index = TypeIndex::from_u32(*array_type_index);
2598 let len = state.pop1();
2599 let array_ref = environ.translate_array_new_default(builder, array_type_index, len)?;
2600 state.push1(array_ref);
2601 }
2602 Operator::ArrayNewFixed {
2603 array_type_index,
2604 array_size,
2605 } => {
2606 let array_type_index = TypeIndex::from_u32(*array_type_index);
2607 let array_size = usize::try_from(*array_size).unwrap();
2608 let elems = state.peekn(array_size);
2609 let array_ref = environ.translate_array_new_fixed(builder, array_type_index, elems)?;
2610 state.popn(array_size);
2611 state.push1(array_ref);
2612 }
2613 Operator::ArrayNewData {
2614 array_type_index,
2615 array_data_index,
2616 } => {
2617 let array_type_index = TypeIndex::from_u32(*array_type_index);
2618 let array_data_index = DataIndex::from_u32(*array_data_index);
2619 let (data_offset, len) = state.pop2();
2620 let array_ref = environ.translate_array_new_data(
2621 builder,
2622 array_type_index,
2623 array_data_index,
2624 data_offset,
2625 len,
2626 )?;
2627 state.push1(array_ref);
2628 }
2629 Operator::ArrayNewElem {
2630 array_type_index,
2631 array_elem_index,
2632 } => {
2633 let array_type_index = TypeIndex::from_u32(*array_type_index);
2634 let array_elem_index = ElemIndex::from_u32(*array_elem_index);
2635 let (elem_offset, len) = state.pop2();
2636 let array_ref = environ.translate_array_new_elem(
2637 builder,
2638 array_type_index,
2639 array_elem_index,
2640 elem_offset,
2641 len,
2642 )?;
2643 state.push1(array_ref);
2644 }
2645 Operator::ArrayCopy {
2646 array_type_index_dst,
2647 array_type_index_src,
2648 } => {
2649 let array_type_index_dst = TypeIndex::from_u32(*array_type_index_dst);
2650 let array_type_index_src = TypeIndex::from_u32(*array_type_index_src);
2651 let (dst_array, dst_index, src_array, src_index, len) = state.pop5();
2652 environ.translate_array_copy(
2653 builder,
2654 array_type_index_dst,
2655 dst_array,
2656 dst_index,
2657 array_type_index_src,
2658 src_array,
2659 src_index,
2660 len,
2661 )?;
2662 }
2663 Operator::ArrayFill { array_type_index } => {
2664 let array_type_index = TypeIndex::from_u32(*array_type_index);
2665 let (array, index, val, len) = state.pop4();
2666 environ.translate_array_fill(builder, array_type_index, array, index, val, len)?;
2667 }
2668 Operator::ArrayInitData {
2669 array_type_index,
2670 array_data_index,
2671 } => {
2672 let array_type_index = TypeIndex::from_u32(*array_type_index);
2673 let array_data_index = DataIndex::from_u32(*array_data_index);
2674 let (array, dst_index, src_index, len) = state.pop4();
2675 environ.translate_array_init_data(
2676 builder,
2677 array_type_index,
2678 array,
2679 dst_index,
2680 array_data_index,
2681 src_index,
2682 len,
2683 )?;
2684 }
2685 Operator::ArrayInitElem {
2686 array_type_index,
2687 array_elem_index,
2688 } => {
2689 let array_type_index = TypeIndex::from_u32(*array_type_index);
2690 let array_elem_index = ElemIndex::from_u32(*array_elem_index);
2691 let (array, dst_index, src_index, len) = state.pop4();
2692 environ.translate_array_init_elem(
2693 builder,
2694 array_type_index,
2695 array,
2696 dst_index,
2697 array_elem_index,
2698 src_index,
2699 len,
2700 )?;
2701 }
2702 Operator::ArrayLen => {
2703 let array = state.pop1();
2704 let len = environ.translate_array_len(builder, array)?;
2705 state.push1(len);
2706 }
2707 Operator::ArrayGet { array_type_index } => {
2708 let array_type_index = TypeIndex::from_u32(*array_type_index);
2709 let (array, index) = state.pop2();
2710 let elem =
2711 environ.translate_array_get(builder, array_type_index, array, index, None)?;
2712 state.push1(elem);
2713 }
2714 Operator::ArrayGetS { array_type_index } => {
2715 let array_type_index = TypeIndex::from_u32(*array_type_index);
2716 let (array, index) = state.pop2();
2717 let elem = environ.translate_array_get(
2718 builder,
2719 array_type_index,
2720 array,
2721 index,
2722 Some(Extension::Sign),
2723 )?;
2724 state.push1(elem);
2725 }
2726 Operator::ArrayGetU { array_type_index } => {
2727 let array_type_index = TypeIndex::from_u32(*array_type_index);
2728 let (array, index) = state.pop2();
2729 let elem = environ.translate_array_get(
2730 builder,
2731 array_type_index,
2732 array,
2733 index,
2734 Some(Extension::Zero),
2735 )?;
2736 state.push1(elem);
2737 }
2738 Operator::ArraySet { array_type_index } => {
2739 let array_type_index = TypeIndex::from_u32(*array_type_index);
2740 let (array, index, elem) = state.pop3();
2741 environ.translate_array_set(builder, array_type_index, array, index, elem)?;
2742 }
2743 Operator::RefEq => {
2744 let (r1, r2) = state.pop2();
2745 let eq = builder.ins().icmp(ir::condcodes::IntCC::Equal, r1, r2);
2746 let eq = builder.ins().uextend(ir::types::I32, eq);
2747 state.push1(eq);
2748 }
2749 Operator::RefTestNonNull { hty } => {
2750 let r = state.pop1();
2751 let heap_type = environ.convert_heap_type(*hty);
2752 let result = environ.translate_ref_test(
2753 builder,
2754 WasmRefType {
2755 heap_type,
2756 nullable: false,
2757 },
2758 r,
2759 )?;
2760 state.push1(result);
2761 }
2762 Operator::RefTestNullable { hty } => {
2763 let r = state.pop1();
2764 let heap_type = environ.convert_heap_type(*hty);
2765 let result = environ.translate_ref_test(
2766 builder,
2767 WasmRefType {
2768 heap_type,
2769 nullable: true,
2770 },
2771 r,
2772 )?;
2773 state.push1(result);
2774 }
2775 Operator::RefCastNonNull { hty } => {
2776 let r = state.pop1();
2777 let heap_type = environ.convert_heap_type(*hty);
2778 let cast_okay = environ.translate_ref_test(
2779 builder,
2780 WasmRefType {
2781 heap_type,
2782 nullable: false,
2783 },
2784 r,
2785 )?;
2786 environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
2787 state.push1(r);
2788 }
2789 Operator::RefCastNullable { hty } => {
2790 let r = state.pop1();
2791 let heap_type = environ.convert_heap_type(*hty);
2792 let cast_okay = environ.translate_ref_test(
2793 builder,
2794 WasmRefType {
2795 heap_type,
2796 nullable: true,
2797 },
2798 r,
2799 )?;
2800 environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
2801 state.push1(r);
2802 }
2803 Operator::BrOnCast {
2804 relative_depth,
2805 to_ref_type,
2806 from_ref_type: _,
2809 } => {
2810 let r = state.peek1();
2811
2812 let to_ref_type = environ.convert_ref_type(*to_ref_type);
2813 let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r)?;
2814
2815 let (cast_succeeds_block, inputs) = translate_br_if_args(*relative_depth, state);
2816 let cast_fails_block = builder.create_block();
2817 canonicalise_brif(
2818 builder,
2819 cast_is_okay,
2820 cast_succeeds_block,
2821 inputs,
2822 cast_fails_block,
2823 &[
2824 ],
2827 );
2828
2829 builder.seal_block(cast_fails_block);
2831
2832 builder.switch_to_block(cast_fails_block);
2835 }
2836 Operator::BrOnCastFail {
2837 relative_depth,
2838 to_ref_type,
2839 from_ref_type: _,
2842 } => {
2843 let r = state.peek1();
2844
2845 let to_ref_type = environ.convert_ref_type(*to_ref_type);
2846 let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r)?;
2847
2848 let (cast_fails_block, inputs) = translate_br_if_args(*relative_depth, state);
2849 let cast_succeeds_block = builder.create_block();
2850 canonicalise_brif(
2851 builder,
2852 cast_is_okay,
2853 cast_succeeds_block,
2854 &[
2855 ],
2858 cast_fails_block,
2859 inputs,
2860 );
2861
2862 builder.seal_block(cast_succeeds_block);
2864
2865 builder.switch_to_block(cast_succeeds_block);
2868 }
2869
2870 Operator::AnyConvertExtern => {
2871 }
2874 Operator::ExternConvertAny => {
2875 }
2878
2879 Operator::GlobalAtomicGet { .. }
2880 | Operator::GlobalAtomicSet { .. }
2881 | Operator::GlobalAtomicRmwAdd { .. }
2882 | Operator::GlobalAtomicRmwSub { .. }
2883 | Operator::GlobalAtomicRmwOr { .. }
2884 | Operator::GlobalAtomicRmwXor { .. }
2885 | Operator::GlobalAtomicRmwAnd { .. }
2886 | Operator::GlobalAtomicRmwXchg { .. }
2887 | Operator::GlobalAtomicRmwCmpxchg { .. }
2888 | Operator::TableAtomicGet { .. }
2889 | Operator::TableAtomicSet { .. }
2890 | Operator::TableAtomicRmwXchg { .. }
2891 | Operator::TableAtomicRmwCmpxchg { .. }
2892 | Operator::StructAtomicGet { .. }
2893 | Operator::StructAtomicGetS { .. }
2894 | Operator::StructAtomicGetU { .. }
2895 | Operator::StructAtomicSet { .. }
2896 | Operator::StructAtomicRmwAdd { .. }
2897 | Operator::StructAtomicRmwSub { .. }
2898 | Operator::StructAtomicRmwOr { .. }
2899 | Operator::StructAtomicRmwXor { .. }
2900 | Operator::StructAtomicRmwAnd { .. }
2901 | Operator::StructAtomicRmwXchg { .. }
2902 | Operator::StructAtomicRmwCmpxchg { .. }
2903 | Operator::ArrayAtomicGet { .. }
2904 | Operator::ArrayAtomicGetS { .. }
2905 | Operator::ArrayAtomicGetU { .. }
2906 | Operator::ArrayAtomicSet { .. }
2907 | Operator::ArrayAtomicRmwAdd { .. }
2908 | Operator::ArrayAtomicRmwSub { .. }
2909 | Operator::ArrayAtomicRmwOr { .. }
2910 | Operator::ArrayAtomicRmwXor { .. }
2911 | Operator::ArrayAtomicRmwAnd { .. }
2912 | Operator::ArrayAtomicRmwXchg { .. }
2913 | Operator::ArrayAtomicRmwCmpxchg { .. }
2914 | Operator::RefI31Shared { .. } => {
2915 return Err(wasm_unsupported!(
2916 "shared-everything-threads operators are not yet implemented"
2917 ));
2918 }
2919
2920 Operator::ContNew { .. }
2921 | Operator::ContBind { .. }
2922 | Operator::Suspend { .. }
2923 | Operator::Resume { .. }
2924 | Operator::ResumeThrow { .. }
2925 | Operator::Switch { .. } => {
2926 return Err(wasm_unsupported!(
2927 "stack-switching operators are not yet implemented"
2928 ));
2929 }
2930
2931 Operator::I64MulWideS => {
2932 let (arg1, arg2) = state.pop2();
2933 let arg1 = builder.ins().sextend(I128, arg1);
2934 let arg2 = builder.ins().sextend(I128, arg2);
2935 let result = builder.ins().imul(arg1, arg2);
2936 let (lo, hi) = builder.ins().isplit(result);
2937 state.push2(lo, hi);
2938 }
2939 Operator::I64MulWideU => {
2940 let (arg1, arg2) = state.pop2();
2941 let arg1 = builder.ins().uextend(I128, arg1);
2942 let arg2 = builder.ins().uextend(I128, arg2);
2943 let result = builder.ins().imul(arg1, arg2);
2944 let (lo, hi) = builder.ins().isplit(result);
2945 state.push2(lo, hi);
2946 }
2947 Operator::I64Add128 => {
2948 let (arg1, arg2, arg3, arg4) = state.pop4();
2949 let arg1 = builder.ins().iconcat(arg1, arg2);
2950 let arg2 = builder.ins().iconcat(arg3, arg4);
2951 let result = builder.ins().iadd(arg1, arg2);
2952 let (res1, res2) = builder.ins().isplit(result);
2953 state.push2(res1, res2);
2954 }
2955 Operator::I64Sub128 => {
2956 let (arg1, arg2, arg3, arg4) = state.pop4();
2957 let arg1 = builder.ins().iconcat(arg1, arg2);
2958 let arg2 = builder.ins().iconcat(arg3, arg4);
2959 let result = builder.ins().isub(arg1, arg2);
2960 let (res1, res2) = builder.ins().isplit(result);
2961 state.push2(res1, res2);
2962 }
2963
2964 op => return Err(wasm_unsupported!("operator {op:?}")),
2966 };
2967 Ok(())
2968}
2969
2970fn translate_unreachable_operator(
2974 validator: &FuncValidator<impl WasmModuleResources>,
2975 op: &Operator,
2976 builder: &mut FunctionBuilder,
2977 state: &mut FuncTranslationState,
2978 environ: &mut FuncEnvironment<'_>,
2979) -> WasmResult<()> {
2980 debug_assert!(!state.reachable);
2981 match *op {
2982 Operator::If { blockty } => {
2983 state.push_if(
2986 ir::Block::reserved_value(),
2987 ElseData::NoElse {
2988 branch_inst: ir::Inst::reserved_value(),
2989 placeholder: ir::Block::reserved_value(),
2990 },
2991 0,
2992 0,
2993 blockty,
2994 );
2995 }
2996 Operator::Loop { blockty: _ } | Operator::Block { blockty: _ } => {
2997 state.push_block(ir::Block::reserved_value(), 0, 0);
2998 }
2999 Operator::Else => {
3000 let i = state.control_stack.len() - 1;
3001 match state.control_stack[i] {
3002 ControlStackFrame::If {
3003 ref else_data,
3004 head_is_reachable,
3005 ref mut consequent_ends_reachable,
3006 blocktype,
3007 ..
3008 } => {
3009 debug_assert!(consequent_ends_reachable.is_none());
3010 *consequent_ends_reachable = Some(state.reachable);
3011
3012 if head_is_reachable {
3013 state.reachable = true;
3015
3016 let else_block = match *else_data {
3017 ElseData::NoElse {
3018 branch_inst,
3019 placeholder,
3020 } => {
3021 let (params, _results) =
3022 blocktype_params_results(validator, blocktype)?;
3023 let else_block = block_with_params(builder, params, environ)?;
3024 let frame = state.control_stack.last().unwrap();
3025 frame.truncate_value_stack_to_else_params(&mut state.stack);
3026
3027 builder.change_jump_destination(
3029 branch_inst,
3030 placeholder,
3031 else_block,
3032 );
3033 builder.seal_block(else_block);
3034 else_block
3035 }
3036 ElseData::WithElse { else_block } => {
3037 let frame = state.control_stack.last().unwrap();
3038 frame.truncate_value_stack_to_else_params(&mut state.stack);
3039 else_block
3040 }
3041 };
3042
3043 builder.switch_to_block(else_block);
3044
3045 }
3050 }
3051 _ => unreachable!(),
3052 }
3053 }
3054 Operator::End => {
3055 let stack = &mut state.stack;
3056 let control_stack = &mut state.control_stack;
3057 let frame = control_stack.pop().unwrap();
3058
3059 frame.truncate_value_stack_to_original_size(stack);
3061
3062 let reachable_anyway = match frame {
3063 ControlStackFrame::Loop { header, .. } => {
3065 builder.seal_block(header);
3066 false
3068 }
3069 ControlStackFrame::If {
3074 head_is_reachable,
3075 consequent_ends_reachable: None,
3076 ..
3077 } => head_is_reachable,
3078 ControlStackFrame::If {
3083 head_is_reachable,
3084 consequent_ends_reachable: Some(consequent_ends_reachable),
3085 ..
3086 } => head_is_reachable && consequent_ends_reachable,
3087 _ => false,
3089 };
3090
3091 if frame.exit_is_branched_to() || reachable_anyway {
3092 builder.switch_to_block(frame.following_code());
3093 builder.seal_block(frame.following_code());
3094
3095 stack.extend_from_slice(builder.block_params(frame.following_code()));
3098 state.reachable = true;
3099 }
3100 }
3101 _ => {
3102 }
3104 }
3105
3106 Ok(())
3107}
3108
3109fn prepare_addr(
3122 memarg: &MemArg,
3123 access_size: u8,
3124 builder: &mut FunctionBuilder,
3125 state: &mut FuncTranslationState,
3126 environ: &mut FuncEnvironment<'_>,
3127) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
3128 let index = state.pop1();
3129 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
3130
3131 let heap = environ.heaps()[heap].clone();
3202 let addr = match u32::try_from(memarg.offset) {
3203 Ok(offset) => bounds_checks::bounds_check_and_compute_addr(
3206 builder,
3207 environ,
3208 &heap,
3209 index,
3210 offset,
3211 access_size,
3212 )?,
3213
3214 Err(_) => {
3241 let offset = builder
3242 .ins()
3243 .iconst(heap.index_type(), memarg.offset.signed());
3244 let adjusted_index = environ.uadd_overflow_trap(
3245 builder,
3246 index,
3247 offset,
3248 ir::TrapCode::HEAP_OUT_OF_BOUNDS,
3249 );
3250 bounds_checks::bounds_check_and_compute_addr(
3251 builder,
3252 environ,
3253 &heap,
3254 adjusted_index,
3255 0,
3256 access_size,
3257 )?
3258 }
3259 };
3260 let addr = match addr {
3261 Reachability::Unreachable => return Ok(Reachability::Unreachable),
3262 Reachability::Reachable(a) => a,
3263 };
3264
3265 let mut flags = MemFlags::new();
3270 flags.set_endianness(ir::Endianness::Little);
3271
3272 if heap.pcc_memory_type.is_some() {
3273 flags.set_checked();
3275 }
3276
3277 flags.set_alias_region(Some(ir::AliasRegion::Heap));
3282
3283 Ok(Reachability::Reachable((flags, index, addr)))
3284}
3285
3286fn align_atomic_addr(
3287 memarg: &MemArg,
3288 loaded_bytes: u8,
3289 builder: &mut FunctionBuilder,
3290 state: &mut FuncTranslationState,
3291 environ: &mut FuncEnvironment<'_>,
3292) {
3293 if loaded_bytes > 1 {
3304 let addr = state.pop1(); state.push1(addr);
3306 let effective_addr = if memarg.offset == 0 {
3307 addr
3308 } else {
3309 builder.ins().iadd_imm(addr, memarg.offset.signed())
3310 };
3311 debug_assert!(loaded_bytes.is_power_of_two());
3312 let misalignment = builder
3313 .ins()
3314 .band_imm(effective_addr, i64::from(loaded_bytes - 1));
3315 let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0);
3316 environ.trapnz(builder, f, crate::TRAP_HEAP_MISALIGNED);
3317 }
3318}
3319
3320fn prepare_atomic_addr(
3324 memarg: &MemArg,
3325 loaded_bytes: u8,
3326 builder: &mut FunctionBuilder,
3327 state: &mut FuncTranslationState,
3328 environ: &mut FuncEnvironment<'_>,
3329) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
3330 align_atomic_addr(memarg, loaded_bytes, builder, state, environ);
3331 prepare_addr(memarg, loaded_bytes, builder, state, environ)
3332}
3333
3334#[derive(PartialEq, Eq)]
3340#[must_use]
3341pub enum Reachability<T> {
3342 Reachable(T),
3344 Unreachable,
3348}
3349
3350fn translate_load(
3354 memarg: &MemArg,
3355 opcode: ir::Opcode,
3356 result_ty: Type,
3357 builder: &mut FunctionBuilder,
3358 state: &mut FuncTranslationState,
3359 environ: &mut FuncEnvironment<'_>,
3360) -> WasmResult<Reachability<()>> {
3361 let mem_op_size = mem_op_size(opcode, result_ty);
3362 let (flags, wasm_index, base) =
3363 match prepare_addr(memarg, mem_op_size, builder, state, environ)? {
3364 Reachability::Unreachable => return Ok(Reachability::Unreachable),
3365 Reachability::Reachable((f, i, b)) => (f, i, b),
3366 };
3367
3368 environ.before_load(builder, mem_op_size, wasm_index, memarg.offset);
3369
3370 let (load, dfg) = builder
3371 .ins()
3372 .Load(opcode, result_ty, flags, Offset32::new(0), base);
3373 state.push1(dfg.first_result(load));
3374 Ok(Reachability::Reachable(()))
3375}
3376
3377fn translate_store(
3379 memarg: &MemArg,
3380 opcode: ir::Opcode,
3381 builder: &mut FunctionBuilder,
3382 state: &mut FuncTranslationState,
3383 environ: &mut FuncEnvironment<'_>,
3384) -> WasmResult<()> {
3385 let val = state.pop1();
3386 let val_ty = builder.func.dfg.value_type(val);
3387 let mem_op_size = mem_op_size(opcode, val_ty);
3388
3389 let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!(
3390 state,
3391 prepare_addr(memarg, mem_op_size, builder, state, environ)?
3392 );
3393
3394 environ.before_store(builder, mem_op_size, wasm_index, memarg.offset);
3395
3396 builder
3397 .ins()
3398 .Store(opcode, val_ty, flags, Offset32::new(0), val, base);
3399 Ok(())
3400}
3401
3402fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
3403 match opcode {
3404 ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
3405 ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
3406 ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
3407 ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
3408 _ => panic!("unknown size of mem op for {opcode:?}"),
3409 }
3410}
3411
3412fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3413 let (arg0, arg1) = state.pop2();
3414 let val = builder.ins().icmp(cc, arg0, arg1);
3415 state.push1(builder.ins().uextend(I32, val));
3416}
3417
3418fn translate_atomic_rmw(
3419 widened_ty: Type,
3420 access_ty: Type,
3421 op: AtomicRmwOp,
3422 memarg: &MemArg,
3423 builder: &mut FunctionBuilder,
3424 state: &mut FuncTranslationState,
3425 environ: &mut FuncEnvironment<'_>,
3426) -> WasmResult<()> {
3427 let mut arg2 = state.pop1();
3428 let arg2_ty = builder.func.dfg.value_type(arg2);
3429
3430 match access_ty {
3433 I8 | I16 | I32 | I64 => {}
3434 _ => {
3435 return Err(wasm_unsupported!(
3436 "atomic_rmw: unsupported access type {:?}",
3437 access_ty
3438 ))
3439 }
3440 };
3441 let w_ty_ok = match widened_ty {
3442 I32 | I64 => true,
3443 _ => false,
3444 };
3445 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3446
3447 assert!(arg2_ty.bytes() >= access_ty.bytes());
3448 if arg2_ty.bytes() > access_ty.bytes() {
3449 arg2 = builder.ins().ireduce(access_ty, arg2);
3450 }
3451
3452 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3453 state,
3454 prepare_atomic_addr(
3455 memarg,
3456 u8::try_from(access_ty.bytes()).unwrap(),
3457 builder,
3458 state,
3459 environ,
3460 )?
3461 );
3462
3463 let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
3464 if access_ty != widened_ty {
3465 res = builder.ins().uextend(widened_ty, res);
3466 }
3467 state.push1(res);
3468 Ok(())
3469}
3470
3471fn translate_atomic_cas(
3472 widened_ty: Type,
3473 access_ty: Type,
3474 memarg: &MemArg,
3475 builder: &mut FunctionBuilder,
3476 state: &mut FuncTranslationState,
3477 environ: &mut FuncEnvironment<'_>,
3478) -> WasmResult<()> {
3479 let (mut expected, mut replacement) = state.pop2();
3480 let expected_ty = builder.func.dfg.value_type(expected);
3481 let replacement_ty = builder.func.dfg.value_type(replacement);
3482
3483 match access_ty {
3486 I8 | I16 | I32 | I64 => {}
3487 _ => {
3488 return Err(wasm_unsupported!(
3489 "atomic_cas: unsupported access type {:?}",
3490 access_ty
3491 ))
3492 }
3493 };
3494 let w_ty_ok = match widened_ty {
3495 I32 | I64 => true,
3496 _ => false,
3497 };
3498 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3499
3500 assert!(expected_ty.bytes() >= access_ty.bytes());
3501 if expected_ty.bytes() > access_ty.bytes() {
3502 expected = builder.ins().ireduce(access_ty, expected);
3503 }
3504 assert!(replacement_ty.bytes() >= access_ty.bytes());
3505 if replacement_ty.bytes() > access_ty.bytes() {
3506 replacement = builder.ins().ireduce(access_ty, replacement);
3507 }
3508
3509 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3510 state,
3511 prepare_atomic_addr(
3512 memarg,
3513 u8::try_from(access_ty.bytes()).unwrap(),
3514 builder,
3515 state,
3516 environ,
3517 )?
3518 );
3519 let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
3520 if access_ty != widened_ty {
3521 res = builder.ins().uextend(widened_ty, res);
3522 }
3523 state.push1(res);
3524 Ok(())
3525}
3526
3527fn translate_atomic_load(
3528 widened_ty: Type,
3529 access_ty: Type,
3530 memarg: &MemArg,
3531 builder: &mut FunctionBuilder,
3532 state: &mut FuncTranslationState,
3533 environ: &mut FuncEnvironment<'_>,
3534) -> WasmResult<()> {
3535 match access_ty {
3538 I8 | I16 | I32 | I64 => {}
3539 _ => {
3540 return Err(wasm_unsupported!(
3541 "atomic_load: unsupported access type {:?}",
3542 access_ty
3543 ))
3544 }
3545 };
3546 let w_ty_ok = match widened_ty {
3547 I32 | I64 => true,
3548 _ => false,
3549 };
3550 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
3551
3552 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3553 state,
3554 prepare_atomic_addr(
3555 memarg,
3556 u8::try_from(access_ty.bytes()).unwrap(),
3557 builder,
3558 state,
3559 environ,
3560 )?
3561 );
3562 let mut res = builder.ins().atomic_load(access_ty, flags, addr);
3563 if access_ty != widened_ty {
3564 res = builder.ins().uextend(widened_ty, res);
3565 }
3566 state.push1(res);
3567 Ok(())
3568}
3569
3570fn translate_atomic_store(
3571 access_ty: Type,
3572 memarg: &MemArg,
3573 builder: &mut FunctionBuilder,
3574 state: &mut FuncTranslationState,
3575 environ: &mut FuncEnvironment<'_>,
3576) -> WasmResult<()> {
3577 let mut data = state.pop1();
3578 let data_ty = builder.func.dfg.value_type(data);
3579
3580 match access_ty {
3583 I8 | I16 | I32 | I64 => {}
3584 _ => {
3585 return Err(wasm_unsupported!(
3586 "atomic_store: unsupported access type {:?}",
3587 access_ty
3588 ))
3589 }
3590 };
3591 let d_ty_ok = match data_ty {
3592 I32 | I64 => true,
3593 _ => false,
3594 };
3595 assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
3596
3597 if data_ty.bytes() > access_ty.bytes() {
3598 data = builder.ins().ireduce(access_ty, data);
3599 }
3600
3601 let (flags, _, addr) = unwrap_or_return_unreachable_state!(
3602 state,
3603 prepare_atomic_addr(
3604 memarg,
3605 u8::try_from(access_ty.bytes()).unwrap(),
3606 builder,
3607 state,
3608 environ,
3609 )?
3610 );
3611 builder.ins().atomic_store(flags, data, addr);
3612 Ok(())
3613}
3614
3615fn translate_vector_icmp(
3616 cc: IntCC,
3617 needed_type: Type,
3618 builder: &mut FunctionBuilder,
3619 state: &mut FuncTranslationState,
3620) {
3621 let (a, b) = state.pop2();
3622 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3623 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3624 state.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3625}
3626
3627fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3628 let (arg0, arg1) = state.pop2();
3629 let val = builder.ins().fcmp(cc, arg0, arg1);
3630 state.push1(builder.ins().uextend(I32, val));
3631}
3632
3633fn translate_vector_fcmp(
3634 cc: FloatCC,
3635 needed_type: Type,
3636 builder: &mut FunctionBuilder,
3637 state: &mut FuncTranslationState,
3638) {
3639 let (a, b) = state.pop2();
3640 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3641 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3642 state.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3643}
3644
3645fn translate_br_if(
3646 relative_depth: u32,
3647 builder: &mut FunctionBuilder,
3648 state: &mut FuncTranslationState,
3649) {
3650 let val = state.pop1();
3651 let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
3652 let next_block = builder.create_block();
3653 canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3654
3655 builder.seal_block(next_block); builder.switch_to_block(next_block);
3657}
3658
3659fn translate_br_if_args(
3660 relative_depth: u32,
3661 state: &mut FuncTranslationState,
3662) -> (ir::Block, &mut [ir::Value]) {
3663 let i = state.control_stack.len() - 1 - (relative_depth as usize);
3664 let (return_count, br_destination) = {
3665 let frame = &mut state.control_stack[i];
3666 frame.set_branched_to_exit();
3669 let return_count = if frame.is_loop() {
3670 frame.num_param_values()
3671 } else {
3672 frame.num_return_values()
3673 };
3674 (return_count, frame.br_destination())
3675 };
3676 let inputs = state.peekn_mut(return_count);
3677 (br_destination, inputs)
3678}
3679
3680fn type_of(operator: &Operator) -> Type {
3682 match operator {
3683 Operator::V128Load { .. }
3684 | Operator::V128Store { .. }
3685 | Operator::V128Const { .. }
3686 | Operator::V128Not
3687 | Operator::V128And
3688 | Operator::V128AndNot
3689 | Operator::V128Or
3690 | Operator::V128Xor
3691 | Operator::V128AnyTrue
3692 | Operator::V128Bitselect => I8X16, Operator::I8x16Shuffle { .. }
3695 | Operator::I8x16Splat
3696 | Operator::V128Load8Splat { .. }
3697 | Operator::V128Load8Lane { .. }
3698 | Operator::V128Store8Lane { .. }
3699 | Operator::I8x16ExtractLaneS { .. }
3700 | Operator::I8x16ExtractLaneU { .. }
3701 | Operator::I8x16ReplaceLane { .. }
3702 | Operator::I8x16Eq
3703 | Operator::I8x16Ne
3704 | Operator::I8x16LtS
3705 | Operator::I8x16LtU
3706 | Operator::I8x16GtS
3707 | Operator::I8x16GtU
3708 | Operator::I8x16LeS
3709 | Operator::I8x16LeU
3710 | Operator::I8x16GeS
3711 | Operator::I8x16GeU
3712 | Operator::I8x16Neg
3713 | Operator::I8x16Abs
3714 | Operator::I8x16AllTrue
3715 | Operator::I8x16Shl
3716 | Operator::I8x16ShrS
3717 | Operator::I8x16ShrU
3718 | Operator::I8x16Add
3719 | Operator::I8x16AddSatS
3720 | Operator::I8x16AddSatU
3721 | Operator::I8x16Sub
3722 | Operator::I8x16SubSatS
3723 | Operator::I8x16SubSatU
3724 | Operator::I8x16MinS
3725 | Operator::I8x16MinU
3726 | Operator::I8x16MaxS
3727 | Operator::I8x16MaxU
3728 | Operator::I8x16AvgrU
3729 | Operator::I8x16Bitmask
3730 | Operator::I8x16Popcnt
3731 | Operator::I8x16RelaxedLaneselect => I8X16,
3732
3733 Operator::I16x8Splat
3734 | Operator::V128Load16Splat { .. }
3735 | Operator::V128Load16Lane { .. }
3736 | Operator::V128Store16Lane { .. }
3737 | Operator::I16x8ExtractLaneS { .. }
3738 | Operator::I16x8ExtractLaneU { .. }
3739 | Operator::I16x8ReplaceLane { .. }
3740 | Operator::I16x8Eq
3741 | Operator::I16x8Ne
3742 | Operator::I16x8LtS
3743 | Operator::I16x8LtU
3744 | Operator::I16x8GtS
3745 | Operator::I16x8GtU
3746 | Operator::I16x8LeS
3747 | Operator::I16x8LeU
3748 | Operator::I16x8GeS
3749 | Operator::I16x8GeU
3750 | Operator::I16x8Neg
3751 | Operator::I16x8Abs
3752 | Operator::I16x8AllTrue
3753 | Operator::I16x8Shl
3754 | Operator::I16x8ShrS
3755 | Operator::I16x8ShrU
3756 | Operator::I16x8Add
3757 | Operator::I16x8AddSatS
3758 | Operator::I16x8AddSatU
3759 | Operator::I16x8Sub
3760 | Operator::I16x8SubSatS
3761 | Operator::I16x8SubSatU
3762 | Operator::I16x8MinS
3763 | Operator::I16x8MinU
3764 | Operator::I16x8MaxS
3765 | Operator::I16x8MaxU
3766 | Operator::I16x8AvgrU
3767 | Operator::I16x8Mul
3768 | Operator::I16x8Bitmask
3769 | Operator::I16x8RelaxedLaneselect => I16X8,
3770
3771 Operator::I32x4Splat
3772 | Operator::V128Load32Splat { .. }
3773 | Operator::V128Load32Lane { .. }
3774 | Operator::V128Store32Lane { .. }
3775 | Operator::I32x4ExtractLane { .. }
3776 | Operator::I32x4ReplaceLane { .. }
3777 | Operator::I32x4Eq
3778 | Operator::I32x4Ne
3779 | Operator::I32x4LtS
3780 | Operator::I32x4LtU
3781 | Operator::I32x4GtS
3782 | Operator::I32x4GtU
3783 | Operator::I32x4LeS
3784 | Operator::I32x4LeU
3785 | Operator::I32x4GeS
3786 | Operator::I32x4GeU
3787 | Operator::I32x4Neg
3788 | Operator::I32x4Abs
3789 | Operator::I32x4AllTrue
3790 | Operator::I32x4Shl
3791 | Operator::I32x4ShrS
3792 | Operator::I32x4ShrU
3793 | Operator::I32x4Add
3794 | Operator::I32x4Sub
3795 | Operator::I32x4Mul
3796 | Operator::I32x4MinS
3797 | Operator::I32x4MinU
3798 | Operator::I32x4MaxS
3799 | Operator::I32x4MaxU
3800 | Operator::I32x4Bitmask
3801 | Operator::I32x4TruncSatF32x4S
3802 | Operator::I32x4TruncSatF32x4U
3803 | Operator::I32x4RelaxedLaneselect
3804 | Operator::V128Load32Zero { .. } => I32X4,
3805
3806 Operator::I64x2Splat
3807 | Operator::V128Load64Splat { .. }
3808 | Operator::V128Load64Lane { .. }
3809 | Operator::V128Store64Lane { .. }
3810 | Operator::I64x2ExtractLane { .. }
3811 | Operator::I64x2ReplaceLane { .. }
3812 | Operator::I64x2Eq
3813 | Operator::I64x2Ne
3814 | Operator::I64x2LtS
3815 | Operator::I64x2GtS
3816 | Operator::I64x2LeS
3817 | Operator::I64x2GeS
3818 | Operator::I64x2Neg
3819 | Operator::I64x2Abs
3820 | Operator::I64x2AllTrue
3821 | Operator::I64x2Shl
3822 | Operator::I64x2ShrS
3823 | Operator::I64x2ShrU
3824 | Operator::I64x2Add
3825 | Operator::I64x2Sub
3826 | Operator::I64x2Mul
3827 | Operator::I64x2Bitmask
3828 | Operator::I64x2RelaxedLaneselect
3829 | Operator::V128Load64Zero { .. } => I64X2,
3830
3831 Operator::F32x4Splat
3832 | Operator::F32x4ExtractLane { .. }
3833 | Operator::F32x4ReplaceLane { .. }
3834 | Operator::F32x4Eq
3835 | Operator::F32x4Ne
3836 | Operator::F32x4Lt
3837 | Operator::F32x4Gt
3838 | Operator::F32x4Le
3839 | Operator::F32x4Ge
3840 | Operator::F32x4Abs
3841 | Operator::F32x4Neg
3842 | Operator::F32x4Sqrt
3843 | Operator::F32x4Add
3844 | Operator::F32x4Sub
3845 | Operator::F32x4Mul
3846 | Operator::F32x4Div
3847 | Operator::F32x4Min
3848 | Operator::F32x4Max
3849 | Operator::F32x4PMin
3850 | Operator::F32x4PMax
3851 | Operator::F32x4ConvertI32x4S
3852 | Operator::F32x4ConvertI32x4U
3853 | Operator::F32x4Ceil
3854 | Operator::F32x4Floor
3855 | Operator::F32x4Trunc
3856 | Operator::F32x4Nearest
3857 | Operator::F32x4RelaxedMax
3858 | Operator::F32x4RelaxedMin
3859 | Operator::F32x4RelaxedMadd
3860 | Operator::F32x4RelaxedNmadd => F32X4,
3861
3862 Operator::F64x2Splat
3863 | Operator::F64x2ExtractLane { .. }
3864 | Operator::F64x2ReplaceLane { .. }
3865 | Operator::F64x2Eq
3866 | Operator::F64x2Ne
3867 | Operator::F64x2Lt
3868 | Operator::F64x2Gt
3869 | Operator::F64x2Le
3870 | Operator::F64x2Ge
3871 | Operator::F64x2Abs
3872 | Operator::F64x2Neg
3873 | Operator::F64x2Sqrt
3874 | Operator::F64x2Add
3875 | Operator::F64x2Sub
3876 | Operator::F64x2Mul
3877 | Operator::F64x2Div
3878 | Operator::F64x2Min
3879 | Operator::F64x2Max
3880 | Operator::F64x2PMin
3881 | Operator::F64x2PMax
3882 | Operator::F64x2Ceil
3883 | Operator::F64x2Floor
3884 | Operator::F64x2Trunc
3885 | Operator::F64x2Nearest
3886 | Operator::F64x2RelaxedMax
3887 | Operator::F64x2RelaxedMin
3888 | Operator::F64x2RelaxedMadd
3889 | Operator::F64x2RelaxedNmadd => F64X2,
3890
3891 _ => unimplemented!(
3892 "Currently only SIMD instructions are mapped to their return type; the \
3893 following instruction is not mapped: {:?}",
3894 operator
3895 ),
3896 }
3897}
3898
3899fn optionally_bitcast_vector(
3902 value: Value,
3903 needed_type: Type,
3904 builder: &mut FunctionBuilder,
3905) -> Value {
3906 if builder.func.dfg.value_type(value) != needed_type {
3907 let mut flags = MemFlags::new();
3908 flags.set_endianness(ir::Endianness::Little);
3909 builder.ins().bitcast(needed_type, flags, value)
3910 } else {
3911 value
3912 }
3913}
3914
3915#[inline(always)]
3916fn is_non_canonical_v128(ty: ir::Type) -> bool {
3917 match ty {
3918 I64X2 | I32X4 | I16X8 | F32X4 | F64X2 => true,
3919 _ => false,
3920 }
3921}
3922
3923fn canonicalise_v128_values<'a>(
3928 tmp_canonicalised: &'a mut SmallVec<[ir::Value; 16]>,
3929 builder: &mut FunctionBuilder,
3930 values: &'a [ir::Value],
3931) -> &'a [ir::Value] {
3932 debug_assert!(tmp_canonicalised.is_empty());
3933 let any_non_canonical = values
3935 .iter()
3936 .any(|v| is_non_canonical_v128(builder.func.dfg.value_type(*v)));
3937 if !any_non_canonical {
3939 return values;
3940 }
3941 for v in values {
3943 tmp_canonicalised.push(if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
3944 let mut flags = MemFlags::new();
3945 flags.set_endianness(ir::Endianness::Little);
3946 builder.ins().bitcast(I8X16, flags, *v)
3947 } else {
3948 *v
3949 });
3950 }
3951 tmp_canonicalised.as_slice()
3952}
3953
3954fn canonicalise_then_jump(
3958 builder: &mut FunctionBuilder,
3959 destination: ir::Block,
3960 params: &[ir::Value],
3961) -> ir::Inst {
3962 let mut tmp_canonicalised = SmallVec::<[ir::Value; 16]>::new();
3963 let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
3964 builder.ins().jump(destination, canonicalised)
3965}
3966
3967fn canonicalise_brif(
3969 builder: &mut FunctionBuilder,
3970 cond: ir::Value,
3971 block_then: ir::Block,
3972 params_then: &[ir::Value],
3973 block_else: ir::Block,
3974 params_else: &[ir::Value],
3975) -> ir::Inst {
3976 let mut tmp_canonicalised_then = SmallVec::<[ir::Value; 16]>::new();
3977 let canonicalised_then =
3978 canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
3979 let mut tmp_canonicalised_else = SmallVec::<[ir::Value; 16]>::new();
3980 let canonicalised_else =
3981 canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
3982 builder.ins().brif(
3983 cond,
3984 block_then,
3985 canonicalised_then,
3986 block_else,
3987 canonicalised_else,
3988 )
3989}
3990
3991fn pop1_with_bitcast(
3995 state: &mut FuncTranslationState,
3996 needed_type: Type,
3997 builder: &mut FunctionBuilder,
3998) -> Value {
3999 optionally_bitcast_vector(state.pop1(), needed_type, builder)
4000}
4001
4002fn pop2_with_bitcast(
4006 state: &mut FuncTranslationState,
4007 needed_type: Type,
4008 builder: &mut FunctionBuilder,
4009) -> (Value, Value) {
4010 let (a, b) = state.pop2();
4011 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
4012 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
4013 (bitcast_a, bitcast_b)
4014}
4015
4016fn pop3_with_bitcast(
4017 state: &mut FuncTranslationState,
4018 needed_type: Type,
4019 builder: &mut FunctionBuilder,
4020) -> (Value, Value, Value) {
4021 let (a, b, c) = state.pop3();
4022 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
4023 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
4024 let bitcast_c = optionally_bitcast_vector(c, needed_type, builder);
4025 (bitcast_a, bitcast_b, bitcast_c)
4026}
4027
4028fn bitcast_arguments<'a>(
4029 builder: &FunctionBuilder,
4030 arguments: &'a mut [Value],
4031 params: &[ir::AbiParam],
4032 param_predicate: impl Fn(usize) -> bool,
4033) -> Vec<(Type, &'a mut Value)> {
4034 let filtered_param_types = params
4035 .iter()
4036 .enumerate()
4037 .filter(|(i, _)| param_predicate(*i))
4038 .map(|(_, param)| param.value_type);
4039
4040 let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
4044
4045 pairs
4048 .filter(|(param_type, _)| param_type.is_vector())
4049 .filter(|(param_type, arg)| {
4050 let arg_type = builder.func.dfg.value_type(**arg);
4051 assert!(
4052 arg_type.is_vector(),
4053 "unexpected type mismatch: expected {}, argument {} was actually of type {}",
4054 param_type,
4055 *arg,
4056 arg_type
4057 );
4058
4059 arg_type != *param_type
4063 })
4064 .collect()
4065}
4066
4067pub fn bitcast_wasm_returns(arguments: &mut [Value], builder: &mut FunctionBuilder) {
4073 let changes = bitcast_arguments(builder, arguments, &builder.func.signature.returns, |i| {
4074 builder.func.signature.returns[i].purpose == ir::ArgumentPurpose::Normal
4075 });
4076 for (t, arg) in changes {
4077 let mut flags = MemFlags::new();
4078 flags.set_endianness(ir::Endianness::Little);
4079 *arg = builder.ins().bitcast(t, flags, *arg);
4080 }
4081}
4082
4083fn bitcast_wasm_params(
4085 environ: &mut FuncEnvironment<'_>,
4086 callee_signature: ir::SigRef,
4087 arguments: &mut [Value],
4088 builder: &mut FunctionBuilder,
4089) {
4090 let callee_signature = &builder.func.dfg.signatures[callee_signature];
4091 let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
4092 environ.is_wasm_parameter(&callee_signature, i)
4093 });
4094 for (t, arg) in changes {
4095 let mut flags = MemFlags::new();
4096 flags.set_endianness(ir::Endianness::Little);
4097 *arg = builder.ins().bitcast(t, flags, *arg);
4098 }
4099}