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