1mod bounds_checks;
75
76use super::{hash_map, HashMap};
77use crate::environ::{FuncEnvironment, GlobalVariable};
78use crate::state::{ControlStackFrame, ElseData, FuncTranslationState};
79use crate::translation_utils::{
80 block_with_params, blocktype_params_results, f32_translation, f64_translation,
81};
82use crate::wasm_unsupported;
83use crate::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex, WasmResult};
84use core::convert::TryInto;
85use core::{i32, u32};
86use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
87use cranelift_codegen::ir::immediates::Offset32;
88use cranelift_codegen::ir::types::*;
89use cranelift_codegen::ir::{
90 self, AtomicRmwOp, ConstantData, InstBuilder, JumpTableData, MemFlags, Value, ValueLabel,
91};
92use cranelift_codegen::packed_option::ReservedValue;
93use cranelift_frontend::{FunctionBuilder, Variable};
94use itertools::Itertools;
95use smallvec::SmallVec;
96use std::convert::TryFrom;
97use std::vec::Vec;
98use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
99
100macro_rules! unwrap_or_return_unreachable_state {
107 ($state:ident, $value:expr) => {
108 match $value {
109 Reachability::Reachable(x) => x,
110 Reachability::Unreachable => {
111 $state.reachable = false;
112 return Ok(());
113 }
114 }
115 };
116}
117
118#[cfg_attr(
120 feature = "cargo-clippy",
121 allow(clippy::unneeded_field_pattern, clippy::cognitive_complexity)
122)]
123pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
125 validator: &mut FuncValidator<impl WasmModuleResources>,
126 op: &Operator,
127 builder: &mut FunctionBuilder,
128 state: &mut FuncTranslationState,
129 environ: &mut FE,
130) -> WasmResult<()> {
131 if !state.reachable {
132 translate_unreachable_operator(validator, &op, builder, state, environ)?;
133 return Ok(());
134 }
135
136 debug_assert!(!builder.is_unreachable());
138
139 match op {
141 Operator::LocalGet { local_index } => {
146 let val = builder.use_var(Variable::from_u32(*local_index));
147 state.push1(val);
148 let label = ValueLabel::from_u32(*local_index);
149 builder.set_val_label(val, label);
150 }
151 Operator::LocalSet { local_index } => {
152 let mut val = state.pop1();
153
154 let ty = builder.func.dfg.value_type(val);
156 if ty.is_vector() {
157 val = optionally_bitcast_vector(val, I8X16, builder);
158 }
159
160 builder.def_var(Variable::from_u32(*local_index), val);
161 let label = ValueLabel::from_u32(*local_index);
162 builder.set_val_label(val, label);
163 }
164 Operator::LocalTee { local_index } => {
165 let mut val = state.peek1();
166
167 let ty = builder.func.dfg.value_type(val);
169 if ty.is_vector() {
170 val = optionally_bitcast_vector(val, I8X16, builder);
171 }
172
173 builder.def_var(Variable::from_u32(*local_index), val);
174 let label = ValueLabel::from_u32(*local_index);
175 builder.set_val_label(val, label);
176 }
177 Operator::GlobalGet { global_index } => {
181 let val = match state.get_global(builder.func, *global_index, environ)? {
182 GlobalVariable::Const(val) => val,
183 GlobalVariable::Memory { gv, offset, ty } => {
184 let addr = builder.ins().global_value(environ.pointer_type(), gv);
185 let mut flags = ir::MemFlags::trusted();
186 flags.set_table();
188 builder.ins().load(ty, flags, addr, offset)
189 }
190 GlobalVariable::Custom => environ.translate_custom_global_get(
191 builder.cursor(),
192 GlobalIndex::from_u32(*global_index),
193 )?,
194 };
195 state.push1(val);
196 }
197 Operator::GlobalSet { global_index } => {
198 match state.get_global(builder.func, *global_index, environ)? {
199 GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
200 GlobalVariable::Memory { gv, offset, ty } => {
201 let addr = builder.ins().global_value(environ.pointer_type(), gv);
202 let mut flags = ir::MemFlags::trusted();
203 flags.set_table();
205 let mut val = state.pop1();
206 if ty.is_vector() {
208 val = optionally_bitcast_vector(val, I8X16, builder);
209 }
210 debug_assert_eq!(ty, builder.func.dfg.value_type(val));
211 builder.ins().store(flags, val, addr, offset);
212 }
213 GlobalVariable::Custom => {
214 let val = state.pop1();
215 environ.translate_custom_global_set(
216 builder.cursor(),
217 GlobalIndex::from_u32(*global_index),
218 val,
219 )?;
220 }
221 }
222 }
223 Operator::Drop => {
227 state.pop1();
228 }
229 Operator::Select => {
230 let (mut arg1, mut arg2, cond) = state.pop3();
231 if builder.func.dfg.value_type(arg1).is_vector() {
232 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
233 }
234 if builder.func.dfg.value_type(arg2).is_vector() {
235 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
236 }
237 state.push1(builder.ins().select(cond, arg1, arg2));
238 }
239 Operator::TypedSelect { ty: _ } => {
240 let (mut arg1, mut arg2, cond) = state.pop3();
244 if builder.func.dfg.value_type(arg1).is_vector() {
245 arg1 = optionally_bitcast_vector(arg1, I8X16, builder);
246 }
247 if builder.func.dfg.value_type(arg2).is_vector() {
248 arg2 = optionally_bitcast_vector(arg2, I8X16, builder);
249 }
250 state.push1(builder.ins().select(cond, arg1, arg2));
251 }
252 Operator::Nop => {
253 }
255 Operator::Unreachable => {
256 builder.ins().trap(ir::TrapCode::UnreachableCodeReached);
257 state.reachable = false;
258 }
259 Operator::Block { blockty } => {
271 let (params, results) = blocktype_params_results(validator, *blockty)?;
272 let next = block_with_params(builder, results.clone(), environ)?;
273 state.push_block(next, params.len(), results.len());
274 }
275 Operator::Loop { blockty } => {
276 let (params, results) = blocktype_params_results(validator, *blockty)?;
277 let loop_body = block_with_params(builder, params.clone(), environ)?;
278 let next = block_with_params(builder, results.clone(), environ)?;
279 canonicalise_then_jump(builder, loop_body, state.peekn(params.len()));
280 state.push_loop(loop_body, next, params.len(), results.len());
281
282 state.popn(params.len());
285 state
286 .stack
287 .extend_from_slice(builder.block_params(loop_body));
288
289 builder.switch_to_block(loop_body);
290 environ.translate_loop_header(builder)?;
291 }
292 Operator::If { blockty } => {
293 let val = state.pop1();
294
295 let next_block = builder.create_block();
296 let (params, results) = blocktype_params_results(validator, *blockty)?;
297 let (destination, else_data) = if params.clone().eq(results.clone()) {
298 let destination = block_with_params(builder, results.clone(), environ)?;
305 let branch_inst = canonicalise_brif(
306 builder,
307 val,
308 next_block,
309 &[],
310 destination,
311 state.peekn(params.len()),
312 );
313 (
314 destination,
315 ElseData::NoElse {
316 branch_inst,
317 placeholder: destination,
318 },
319 )
320 } else {
321 let destination = block_with_params(builder, results.clone(), environ)?;
324 let else_block = block_with_params(builder, params.clone(), environ)?;
325 canonicalise_brif(
326 builder,
327 val,
328 next_block,
329 &[],
330 else_block,
331 state.peekn(params.len()),
332 );
333 builder.seal_block(else_block);
334 (destination, ElseData::WithElse { else_block })
335 };
336
337 builder.seal_block(next_block); builder.switch_to_block(next_block);
339
340 state.push_if(
347 destination,
348 else_data,
349 params.len(),
350 results.len(),
351 *blockty,
352 );
353 }
354 Operator::Else => {
355 let i = state.control_stack.len() - 1;
356 match state.control_stack[i] {
357 ControlStackFrame::If {
358 ref else_data,
359 head_is_reachable,
360 ref mut consequent_ends_reachable,
361 num_return_values,
362 blocktype,
363 destination,
364 ..
365 } => {
366 debug_assert!(consequent_ends_reachable.is_none());
369 *consequent_ends_reachable = Some(state.reachable);
370
371 if head_is_reachable {
372 state.reachable = true;
374
375 let else_block = match *else_data {
378 ElseData::NoElse {
379 branch_inst,
380 placeholder,
381 } => {
382 let (params, _results) =
383 blocktype_params_results(validator, blocktype)?;
384 debug_assert_eq!(params.len(), num_return_values);
385 let else_block =
386 block_with_params(builder, params.clone(), environ)?;
387 canonicalise_then_jump(
388 builder,
389 destination,
390 state.peekn(params.len()),
391 );
392 state.popn(params.len());
393
394 builder.change_jump_destination(
395 branch_inst,
396 placeholder,
397 else_block,
398 );
399 builder.seal_block(else_block);
400 else_block
401 }
402 ElseData::WithElse { else_block } => {
403 canonicalise_then_jump(
404 builder,
405 destination,
406 state.peekn(num_return_values),
407 );
408 state.popn(num_return_values);
409 else_block
410 }
411 };
412
413 builder.switch_to_block(else_block);
424
425 }
428 }
429 _ => unreachable!(),
430 }
431 }
432 Operator::End => {
433 let frame = state.control_stack.pop().unwrap();
434 let next_block = frame.following_code();
435 let return_count = frame.num_return_values();
436 let return_args = state.peekn_mut(return_count);
437
438 canonicalise_then_jump(builder, next_block, return_args);
439 builder.switch_to_block(next_block);
447 builder.seal_block(next_block);
448
449 if let ControlStackFrame::Loop { header, .. } = frame {
451 builder.seal_block(header)
452 }
453
454 frame.truncate_value_stack_to_original_size(&mut state.stack);
455 state
456 .stack
457 .extend_from_slice(builder.block_params(next_block));
458 }
459 Operator::Br { relative_depth } => {
481 let i = state.control_stack.len() - 1 - (*relative_depth as usize);
482 let (return_count, br_destination) = {
483 let frame = &mut state.control_stack[i];
484 frame.set_branched_to_exit();
486 let return_count = if frame.is_loop() {
487 frame.num_param_values()
488 } else {
489 frame.num_return_values()
490 };
491 (return_count, frame.br_destination())
492 };
493 let destination_args = state.peekn_mut(return_count);
494 canonicalise_then_jump(builder, br_destination, destination_args);
495 state.popn(return_count);
496 state.reachable = false;
497 }
498 Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, state),
499 Operator::BrTable { targets } => {
500 let default = targets.default();
501 let mut min_depth = default;
502 for depth in targets.targets() {
503 let depth = depth?;
504 if depth < min_depth {
505 min_depth = depth;
506 }
507 }
508 let jump_args_count = {
509 let i = state.control_stack.len() - 1 - (min_depth as usize);
510 let min_depth_frame = &state.control_stack[i];
511 if min_depth_frame.is_loop() {
512 min_depth_frame.num_param_values()
513 } else {
514 min_depth_frame.num_return_values()
515 }
516 };
517 let val = state.pop1();
518 let mut data = Vec::with_capacity(targets.len() as usize);
519 if jump_args_count == 0 {
520 for depth in targets.targets() {
522 let depth = depth?;
523 let block = {
524 let i = state.control_stack.len() - 1 - (depth as usize);
525 let frame = &mut state.control_stack[i];
526 frame.set_branched_to_exit();
527 frame.br_destination()
528 };
529 data.push(builder.func.dfg.block_call(block, &[]));
530 }
531 let block = {
532 let i = state.control_stack.len() - 1 - (default as usize);
533 let frame = &mut state.control_stack[i];
534 frame.set_branched_to_exit();
535 frame.br_destination()
536 };
537 let block = builder.func.dfg.block_call(block, &[]);
538 let jt = builder.create_jump_table(JumpTableData::new(block, &data));
539 builder.ins().br_table(val, jt);
540 } else {
541 let return_count = jump_args_count;
544 let mut dest_block_sequence = vec![];
545 let mut dest_block_map = HashMap::new();
546 for depth in targets.targets() {
547 let depth = depth?;
548 let branch_block = match dest_block_map.entry(depth as usize) {
549 hash_map::Entry::Occupied(entry) => *entry.get(),
550 hash_map::Entry::Vacant(entry) => {
551 let block = builder.create_block();
552 dest_block_sequence.push((depth as usize, block));
553 *entry.insert(block)
554 }
555 };
556 data.push(builder.func.dfg.block_call(branch_block, &[]));
557 }
558 let default_branch_block = match dest_block_map.entry(default as usize) {
559 hash_map::Entry::Occupied(entry) => *entry.get(),
560 hash_map::Entry::Vacant(entry) => {
561 let block = builder.create_block();
562 dest_block_sequence.push((default as usize, block));
563 *entry.insert(block)
564 }
565 };
566 let default_branch_block = builder.func.dfg.block_call(default_branch_block, &[]);
567 let jt = builder.create_jump_table(JumpTableData::new(default_branch_block, &data));
568 builder.ins().br_table(val, jt);
569 for (depth, dest_block) in dest_block_sequence {
570 builder.switch_to_block(dest_block);
571 builder.seal_block(dest_block);
572 let real_dest_block = {
573 let i = state.control_stack.len() - 1 - depth;
574 let frame = &mut state.control_stack[i];
575 frame.set_branched_to_exit();
576 frame.br_destination()
577 };
578 let destination_args = state.peekn_mut(return_count);
579 canonicalise_then_jump(builder, real_dest_block, destination_args);
580 }
581 state.popn(return_count);
582 }
583 state.reachable = false;
584 }
585 Operator::Return => {
586 let return_count = {
587 let frame = &mut state.control_stack[0];
588 frame.num_return_values()
589 };
590 {
591 let return_args = state.peekn_mut(return_count);
592 bitcast_wasm_returns(environ, return_args, builder);
593 builder.ins().return_(return_args);
594 }
595 state.popn(return_count);
596 state.reachable = false;
597 }
598 Operator::Try { .. }
600 | Operator::Catch { .. }
601 | Operator::Throw { .. }
602 | Operator::Rethrow { .. }
603 | Operator::Delegate { .. }
604 | Operator::CatchAll => {
605 return Err(wasm_unsupported!(
606 "proposed exception handling operator {:?}",
607 op
608 ));
609 }
610 Operator::Call { function_index } => {
616 let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
617
618 let args = state.peekn_mut(num_args);
620 bitcast_wasm_params(
621 environ,
622 builder.func.dfg.ext_funcs[fref].signature,
623 args,
624 builder,
625 );
626
627 let call = environ.translate_call(
628 builder.cursor(),
629 FuncIndex::from_u32(*function_index),
630 fref,
631 args,
632 )?;
633 let inst_results = builder.inst_results(call);
634 debug_assert_eq!(
635 inst_results.len(),
636 builder.func.dfg.signatures[builder.func.dfg.ext_funcs[fref].signature]
637 .returns
638 .len(),
639 "translate_call results should match the call signature"
640 );
641 state.popn(num_args);
642 state.pushn(inst_results);
643 }
644 Operator::CallIndirect {
645 type_index,
646 table_index,
647 table_byte: _,
648 } => {
649 let (sigref, num_args) = state.get_indirect_sig(builder.func, *type_index, environ)?;
653 let table = state.get_or_create_table(builder.func, *table_index, environ)?;
654 let callee = state.pop1();
655
656 let args = state.peekn_mut(num_args);
658 bitcast_wasm_params(environ, sigref, args, builder);
659
660 let call = environ.translate_call_indirect(
661 builder,
662 TableIndex::from_u32(*table_index),
663 table,
664 TypeIndex::from_u32(*type_index),
665 sigref,
666 callee,
667 state.peekn(num_args),
668 )?;
669 let inst_results = builder.inst_results(call);
670 debug_assert_eq!(
671 inst_results.len(),
672 builder.func.dfg.signatures[sigref].returns.len(),
673 "translate_call_indirect results should match the call signature"
674 );
675 state.popn(num_args);
676 state.pushn(inst_results);
677 }
678 Operator::MemoryGrow { mem, mem_byte: _ } => {
683 let heap_index = MemoryIndex::from_u32(*mem);
686 let heap = state.get_heap(builder.func, *mem, environ)?;
687 let val = state.pop1();
688 state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
689 }
690 Operator::MemorySize { mem, mem_byte: _ } => {
691 let heap_index = MemoryIndex::from_u32(*mem);
692 let heap = state.get_heap(builder.func, *mem, environ)?;
693 state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
694 }
695 Operator::I32Load8U { memarg } => {
700 unwrap_or_return_unreachable_state!(
701 state,
702 translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?
703 );
704 }
705 Operator::I32Load16U { memarg } => {
706 unwrap_or_return_unreachable_state!(
707 state,
708 translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?
709 );
710 }
711 Operator::I32Load8S { memarg } => {
712 unwrap_or_return_unreachable_state!(
713 state,
714 translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?
715 );
716 }
717 Operator::I32Load16S { memarg } => {
718 unwrap_or_return_unreachable_state!(
719 state,
720 translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?
721 );
722 }
723 Operator::I64Load8U { memarg } => {
724 unwrap_or_return_unreachable_state!(
725 state,
726 translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?
727 );
728 }
729 Operator::I64Load16U { memarg } => {
730 unwrap_or_return_unreachable_state!(
731 state,
732 translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?
733 );
734 }
735 Operator::I64Load8S { memarg } => {
736 unwrap_or_return_unreachable_state!(
737 state,
738 translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?
739 );
740 }
741 Operator::I64Load16S { memarg } => {
742 unwrap_or_return_unreachable_state!(
743 state,
744 translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?
745 );
746 }
747 Operator::I64Load32S { memarg } => {
748 unwrap_or_return_unreachable_state!(
749 state,
750 translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?
751 );
752 }
753 Operator::I64Load32U { memarg } => {
754 unwrap_or_return_unreachable_state!(
755 state,
756 translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?
757 );
758 }
759 Operator::I32Load { memarg } => {
760 unwrap_or_return_unreachable_state!(
761 state,
762 translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?
763 );
764 }
765 Operator::F32Load { memarg } => {
766 unwrap_or_return_unreachable_state!(
767 state,
768 translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?
769 );
770 }
771 Operator::I64Load { memarg } => {
772 unwrap_or_return_unreachable_state!(
773 state,
774 translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?
775 );
776 }
777 Operator::F64Load { memarg } => {
778 unwrap_or_return_unreachable_state!(
779 state,
780 translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?
781 );
782 }
783 Operator::V128Load { memarg } => {
784 unwrap_or_return_unreachable_state!(
785 state,
786 translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?
787 );
788 }
789 Operator::V128Load8x8S { memarg } => {
790 let (flags, base) = unwrap_or_return_unreachable_state!(
791 state,
792 prepare_addr(memarg, 8, builder, state, environ)?
793 );
794 let loaded = builder.ins().sload8x8(flags, base, 0);
795 state.push1(loaded);
796 }
797 Operator::V128Load8x8U { memarg } => {
798 let (flags, base) = unwrap_or_return_unreachable_state!(
799 state,
800 prepare_addr(memarg, 8, builder, state, environ)?
801 );
802 let loaded = builder.ins().uload8x8(flags, base, 0);
803 state.push1(loaded);
804 }
805 Operator::V128Load16x4S { memarg } => {
806 let (flags, base) = unwrap_or_return_unreachable_state!(
807 state,
808 prepare_addr(memarg, 8, builder, state, environ)?
809 );
810 let loaded = builder.ins().sload16x4(flags, base, 0);
811 state.push1(loaded);
812 }
813 Operator::V128Load16x4U { memarg } => {
814 let (flags, base) = unwrap_or_return_unreachable_state!(
815 state,
816 prepare_addr(memarg, 8, builder, state, environ)?
817 );
818 let loaded = builder.ins().uload16x4(flags, base, 0);
819 state.push1(loaded);
820 }
821 Operator::V128Load32x2S { memarg } => {
822 let (flags, base) = unwrap_or_return_unreachable_state!(
823 state,
824 prepare_addr(memarg, 8, builder, state, environ)?
825 );
826 let loaded = builder.ins().sload32x2(flags, base, 0);
827 state.push1(loaded);
828 }
829 Operator::V128Load32x2U { memarg } => {
830 let (flags, base) = unwrap_or_return_unreachable_state!(
831 state,
832 prepare_addr(memarg, 8, builder, state, environ)?
833 );
834 let loaded = builder.ins().uload32x2(flags, base, 0);
835 state.push1(loaded);
836 }
837 Operator::I32Store { memarg }
842 | Operator::I64Store { memarg }
843 | Operator::F32Store { memarg }
844 | Operator::F64Store { memarg } => {
845 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
846 }
847 Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
848 translate_store(memarg, ir::Opcode::Istore8, builder, state, environ)?;
849 }
850 Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
851 translate_store(memarg, ir::Opcode::Istore16, builder, state, environ)?;
852 }
853 Operator::I64Store32 { memarg } => {
854 translate_store(memarg, ir::Opcode::Istore32, builder, state, environ)?;
855 }
856 Operator::V128Store { memarg } => {
857 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
858 }
859 Operator::I32Const { value } => state.push1(builder.ins().iconst(I32, i64::from(*value))),
861 Operator::I64Const { value } => state.push1(builder.ins().iconst(I64, *value)),
862 Operator::F32Const { value } => {
863 state.push1(builder.ins().f32const(f32_translation(*value)));
864 }
865 Operator::F64Const { value } => {
866 state.push1(builder.ins().f64const(f64_translation(*value)));
867 }
868 Operator::I32Clz | Operator::I64Clz => {
870 let arg = state.pop1();
871 state.push1(builder.ins().clz(arg));
872 }
873 Operator::I32Ctz | Operator::I64Ctz => {
874 let arg = state.pop1();
875 state.push1(builder.ins().ctz(arg));
876 }
877 Operator::I32Popcnt | Operator::I64Popcnt => {
878 let arg = state.pop1();
879 state.push1(builder.ins().popcnt(arg));
880 }
881 Operator::I64ExtendI32S => {
882 let val = state.pop1();
883 state.push1(builder.ins().sextend(I64, val));
884 }
885 Operator::I64ExtendI32U => {
886 let val = state.pop1();
887 state.push1(builder.ins().uextend(I64, val));
888 }
889 Operator::I32WrapI64 => {
890 let val = state.pop1();
891 state.push1(builder.ins().ireduce(I32, val));
892 }
893 Operator::F32Sqrt | Operator::F64Sqrt => {
894 let arg = state.pop1();
895 state.push1(builder.ins().sqrt(arg));
896 }
897 Operator::F32Ceil | Operator::F64Ceil => {
898 let arg = state.pop1();
899 state.push1(builder.ins().ceil(arg));
900 }
901 Operator::F32Floor | Operator::F64Floor => {
902 let arg = state.pop1();
903 state.push1(builder.ins().floor(arg));
904 }
905 Operator::F32Trunc | Operator::F64Trunc => {
906 let arg = state.pop1();
907 state.push1(builder.ins().trunc(arg));
908 }
909 Operator::F32Nearest | Operator::F64Nearest => {
910 let arg = state.pop1();
911 state.push1(builder.ins().nearest(arg));
912 }
913 Operator::F32Abs | Operator::F64Abs => {
914 let val = state.pop1();
915 state.push1(builder.ins().fabs(val));
916 }
917 Operator::F32Neg | Operator::F64Neg => {
918 let arg = state.pop1();
919 state.push1(builder.ins().fneg(arg));
920 }
921 Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
922 let val = state.pop1();
923 state.push1(builder.ins().fcvt_from_uint(F64, val));
924 }
925 Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
926 let val = state.pop1();
927 state.push1(builder.ins().fcvt_from_sint(F64, val));
928 }
929 Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
930 let val = state.pop1();
931 state.push1(builder.ins().fcvt_from_sint(F32, val));
932 }
933 Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
934 let val = state.pop1();
935 state.push1(builder.ins().fcvt_from_uint(F32, val));
936 }
937 Operator::F64PromoteF32 => {
938 let val = state.pop1();
939 state.push1(builder.ins().fpromote(F64, val));
940 }
941 Operator::F32DemoteF64 => {
942 let val = state.pop1();
943 state.push1(builder.ins().fdemote(F32, val));
944 }
945 Operator::I64TruncF64S | Operator::I64TruncF32S => {
946 let val = state.pop1();
947 state.push1(builder.ins().fcvt_to_sint(I64, val));
948 }
949 Operator::I32TruncF64S | Operator::I32TruncF32S => {
950 let val = state.pop1();
951 state.push1(builder.ins().fcvt_to_sint(I32, val));
952 }
953 Operator::I64TruncF64U | Operator::I64TruncF32U => {
954 let val = state.pop1();
955 state.push1(builder.ins().fcvt_to_uint(I64, val));
956 }
957 Operator::I32TruncF64U | Operator::I32TruncF32U => {
958 let val = state.pop1();
959 state.push1(builder.ins().fcvt_to_uint(I32, val));
960 }
961 Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
962 let val = state.pop1();
963 state.push1(builder.ins().fcvt_to_sint_sat(I64, val));
964 }
965 Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
966 let val = state.pop1();
967 state.push1(builder.ins().fcvt_to_sint_sat(I32, val));
968 }
969 Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
970 let val = state.pop1();
971 state.push1(builder.ins().fcvt_to_uint_sat(I64, val));
972 }
973 Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
974 let val = state.pop1();
975 state.push1(builder.ins().fcvt_to_uint_sat(I32, val));
976 }
977 Operator::F32ReinterpretI32 => {
978 let val = state.pop1();
979 state.push1(builder.ins().bitcast(F32, MemFlags::new(), val));
980 }
981 Operator::F64ReinterpretI64 => {
982 let val = state.pop1();
983 state.push1(builder.ins().bitcast(F64, MemFlags::new(), val));
984 }
985 Operator::I32ReinterpretF32 => {
986 let val = state.pop1();
987 state.push1(builder.ins().bitcast(I32, MemFlags::new(), val));
988 }
989 Operator::I64ReinterpretF64 => {
990 let val = state.pop1();
991 state.push1(builder.ins().bitcast(I64, MemFlags::new(), val));
992 }
993 Operator::I32Extend8S => {
994 let val = state.pop1();
995 state.push1(builder.ins().ireduce(I8, val));
996 let val = state.pop1();
997 state.push1(builder.ins().sextend(I32, val));
998 }
999 Operator::I32Extend16S => {
1000 let val = state.pop1();
1001 state.push1(builder.ins().ireduce(I16, val));
1002 let val = state.pop1();
1003 state.push1(builder.ins().sextend(I32, val));
1004 }
1005 Operator::I64Extend8S => {
1006 let val = state.pop1();
1007 state.push1(builder.ins().ireduce(I8, val));
1008 let val = state.pop1();
1009 state.push1(builder.ins().sextend(I64, val));
1010 }
1011 Operator::I64Extend16S => {
1012 let val = state.pop1();
1013 state.push1(builder.ins().ireduce(I16, val));
1014 let val = state.pop1();
1015 state.push1(builder.ins().sextend(I64, val));
1016 }
1017 Operator::I64Extend32S => {
1018 let val = state.pop1();
1019 state.push1(builder.ins().ireduce(I32, val));
1020 let val = state.pop1();
1021 state.push1(builder.ins().sextend(I64, val));
1022 }
1023 Operator::I32Add | Operator::I64Add => {
1025 let (arg1, arg2) = state.pop2();
1026 state.push1(builder.ins().iadd(arg1, arg2));
1027 }
1028 Operator::I32And | Operator::I64And => {
1029 let (arg1, arg2) = state.pop2();
1030 state.push1(builder.ins().band(arg1, arg2));
1031 }
1032 Operator::I32Or | Operator::I64Or => {
1033 let (arg1, arg2) = state.pop2();
1034 state.push1(builder.ins().bor(arg1, arg2));
1035 }
1036 Operator::I32Xor | Operator::I64Xor => {
1037 let (arg1, arg2) = state.pop2();
1038 state.push1(builder.ins().bxor(arg1, arg2));
1039 }
1040 Operator::I32Shl | Operator::I64Shl => {
1041 let (arg1, arg2) = state.pop2();
1042 state.push1(builder.ins().ishl(arg1, arg2));
1043 }
1044 Operator::I32ShrS | Operator::I64ShrS => {
1045 let (arg1, arg2) = state.pop2();
1046 state.push1(builder.ins().sshr(arg1, arg2));
1047 }
1048 Operator::I32ShrU | Operator::I64ShrU => {
1049 let (arg1, arg2) = state.pop2();
1050 state.push1(builder.ins().ushr(arg1, arg2));
1051 }
1052 Operator::I32Rotl | Operator::I64Rotl => {
1053 let (arg1, arg2) = state.pop2();
1054 state.push1(builder.ins().rotl(arg1, arg2));
1055 }
1056 Operator::I32Rotr | Operator::I64Rotr => {
1057 let (arg1, arg2) = state.pop2();
1058 state.push1(builder.ins().rotr(arg1, arg2));
1059 }
1060 Operator::F32Add | Operator::F64Add => {
1061 let (arg1, arg2) = state.pop2();
1062 state.push1(builder.ins().fadd(arg1, arg2));
1063 }
1064 Operator::I32Sub | Operator::I64Sub => {
1065 let (arg1, arg2) = state.pop2();
1066 state.push1(builder.ins().isub(arg1, arg2));
1067 }
1068 Operator::F32Sub | Operator::F64Sub => {
1069 let (arg1, arg2) = state.pop2();
1070 state.push1(builder.ins().fsub(arg1, arg2));
1071 }
1072 Operator::I32Mul | Operator::I64Mul => {
1073 let (arg1, arg2) = state.pop2();
1074 state.push1(builder.ins().imul(arg1, arg2));
1075 }
1076 Operator::F32Mul | Operator::F64Mul => {
1077 let (arg1, arg2) = state.pop2();
1078 state.push1(builder.ins().fmul(arg1, arg2));
1079 }
1080 Operator::F32Div | Operator::F64Div => {
1081 let (arg1, arg2) = state.pop2();
1082 state.push1(builder.ins().fdiv(arg1, arg2));
1083 }
1084 Operator::I32DivS | Operator::I64DivS => {
1085 let (arg1, arg2) = state.pop2();
1086 state.push1(builder.ins().sdiv(arg1, arg2));
1087 }
1088 Operator::I32DivU | Operator::I64DivU => {
1089 let (arg1, arg2) = state.pop2();
1090 state.push1(builder.ins().udiv(arg1, arg2));
1091 }
1092 Operator::I32RemS | Operator::I64RemS => {
1093 let (arg1, arg2) = state.pop2();
1094 state.push1(builder.ins().srem(arg1, arg2));
1095 }
1096 Operator::I32RemU | Operator::I64RemU => {
1097 let (arg1, arg2) = state.pop2();
1098 state.push1(builder.ins().urem(arg1, arg2));
1099 }
1100 Operator::F32Min | Operator::F64Min => {
1101 let (arg1, arg2) = state.pop2();
1102 state.push1(builder.ins().fmin(arg1, arg2));
1103 }
1104 Operator::F32Max | Operator::F64Max => {
1105 let (arg1, arg2) = state.pop2();
1106 state.push1(builder.ins().fmax(arg1, arg2));
1107 }
1108 Operator::F32Copysign | Operator::F64Copysign => {
1109 let (arg1, arg2) = state.pop2();
1110 state.push1(builder.ins().fcopysign(arg1, arg2));
1111 }
1112 Operator::I32LtS | Operator::I64LtS => {
1114 translate_icmp(IntCC::SignedLessThan, builder, state)
1115 }
1116 Operator::I32LtU | Operator::I64LtU => {
1117 translate_icmp(IntCC::UnsignedLessThan, builder, state)
1118 }
1119 Operator::I32LeS | Operator::I64LeS => {
1120 translate_icmp(IntCC::SignedLessThanOrEqual, builder, state)
1121 }
1122 Operator::I32LeU | Operator::I64LeU => {
1123 translate_icmp(IntCC::UnsignedLessThanOrEqual, builder, state)
1124 }
1125 Operator::I32GtS | Operator::I64GtS => {
1126 translate_icmp(IntCC::SignedGreaterThan, builder, state)
1127 }
1128 Operator::I32GtU | Operator::I64GtU => {
1129 translate_icmp(IntCC::UnsignedGreaterThan, builder, state)
1130 }
1131 Operator::I32GeS | Operator::I64GeS => {
1132 translate_icmp(IntCC::SignedGreaterThanOrEqual, builder, state)
1133 }
1134 Operator::I32GeU | Operator::I64GeU => {
1135 translate_icmp(IntCC::UnsignedGreaterThanOrEqual, builder, state)
1136 }
1137 Operator::I32Eqz | Operator::I64Eqz => {
1138 let arg = state.pop1();
1139 let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0);
1140 state.push1(builder.ins().uextend(I32, val));
1141 }
1142 Operator::I32Eq | Operator::I64Eq => translate_icmp(IntCC::Equal, builder, state),
1143 Operator::F32Eq | Operator::F64Eq => translate_fcmp(FloatCC::Equal, builder, state),
1144 Operator::I32Ne | Operator::I64Ne => translate_icmp(IntCC::NotEqual, builder, state),
1145 Operator::F32Ne | Operator::F64Ne => translate_fcmp(FloatCC::NotEqual, builder, state),
1146 Operator::F32Gt | Operator::F64Gt => translate_fcmp(FloatCC::GreaterThan, builder, state),
1147 Operator::F32Ge | Operator::F64Ge => {
1148 translate_fcmp(FloatCC::GreaterThanOrEqual, builder, state)
1149 }
1150 Operator::F32Lt | Operator::F64Lt => translate_fcmp(FloatCC::LessThan, builder, state),
1151 Operator::F32Le | Operator::F64Le => {
1152 translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
1153 }
1154 Operator::RefNull { hty } => {
1155 state.push1(environ.translate_ref_null(builder.cursor(), (*hty).try_into()?)?)
1156 }
1157 Operator::RefIsNull => {
1158 let value = state.pop1();
1159 state.push1(environ.translate_ref_is_null(builder.cursor(), value)?);
1160 }
1161 Operator::RefFunc { function_index } => {
1162 let index = FuncIndex::from_u32(*function_index);
1163 state.push1(environ.translate_ref_func(builder.cursor(), index)?);
1164 }
1165 Operator::MemoryAtomicWait32 { memarg } | Operator::MemoryAtomicWait64 { memarg } => {
1166 let implied_ty = match op {
1170 Operator::MemoryAtomicWait64 { .. } => I64,
1171 Operator::MemoryAtomicWait32 { .. } => I32,
1172 _ => unreachable!(),
1173 };
1174 let heap_index = MemoryIndex::from_u32(memarg.memory);
1175 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1176 let timeout = state.pop1(); let expected = state.pop1(); assert!(builder.func.dfg.value_type(expected) == implied_ty);
1179 let addr = state.pop1();
1180 let effective_addr = if memarg.offset == 0 {
1181 addr
1182 } else {
1183 let index_type = environ.heaps()[heap].index_type;
1184 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1185 builder
1186 .ins()
1187 .uadd_overflow_trap(addr, offset, ir::TrapCode::HeapOutOfBounds)
1188 };
1189 let res = environ.translate_atomic_wait(
1192 builder.cursor(),
1193 heap_index,
1194 heap,
1195 effective_addr,
1196 expected,
1197 timeout,
1198 )?;
1199 state.push1(res);
1200 }
1201 Operator::MemoryAtomicNotify { memarg } => {
1202 let heap_index = MemoryIndex::from_u32(memarg.memory);
1203 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
1204 let count = state.pop1(); let addr = state.pop1();
1206 let effective_addr = if memarg.offset == 0 {
1207 addr
1208 } else {
1209 let index_type = environ.heaps()[heap].index_type;
1210 let offset = builder.ins().iconst(index_type, memarg.offset as i64);
1211 builder
1212 .ins()
1213 .uadd_overflow_trap(addr, offset, ir::TrapCode::HeapOutOfBounds)
1214 };
1215 let res = environ.translate_atomic_notify(
1216 builder.cursor(),
1217 heap_index,
1218 heap,
1219 effective_addr,
1220 count,
1221 )?;
1222 state.push1(res);
1223 }
1224 Operator::I32AtomicLoad { memarg } => {
1225 translate_atomic_load(I32, I32, memarg, builder, state, environ)?
1226 }
1227 Operator::I64AtomicLoad { memarg } => {
1228 translate_atomic_load(I64, I64, memarg, builder, state, environ)?
1229 }
1230 Operator::I32AtomicLoad8U { memarg } => {
1231 translate_atomic_load(I32, I8, memarg, builder, state, environ)?
1232 }
1233 Operator::I32AtomicLoad16U { memarg } => {
1234 translate_atomic_load(I32, I16, memarg, builder, state, environ)?
1235 }
1236 Operator::I64AtomicLoad8U { memarg } => {
1237 translate_atomic_load(I64, I8, memarg, builder, state, environ)?
1238 }
1239 Operator::I64AtomicLoad16U { memarg } => {
1240 translate_atomic_load(I64, I16, memarg, builder, state, environ)?
1241 }
1242 Operator::I64AtomicLoad32U { memarg } => {
1243 translate_atomic_load(I64, I32, memarg, builder, state, environ)?
1244 }
1245
1246 Operator::I32AtomicStore { memarg } => {
1247 translate_atomic_store(I32, memarg, builder, state, environ)?
1248 }
1249 Operator::I64AtomicStore { memarg } => {
1250 translate_atomic_store(I64, memarg, builder, state, environ)?
1251 }
1252 Operator::I32AtomicStore8 { memarg } => {
1253 translate_atomic_store(I8, memarg, builder, state, environ)?
1254 }
1255 Operator::I32AtomicStore16 { memarg } => {
1256 translate_atomic_store(I16, memarg, builder, state, environ)?
1257 }
1258 Operator::I64AtomicStore8 { memarg } => {
1259 translate_atomic_store(I8, memarg, builder, state, environ)?
1260 }
1261 Operator::I64AtomicStore16 { memarg } => {
1262 translate_atomic_store(I16, memarg, builder, state, environ)?
1263 }
1264 Operator::I64AtomicStore32 { memarg } => {
1265 translate_atomic_store(I32, memarg, builder, state, environ)?
1266 }
1267
1268 Operator::I32AtomicRmwAdd { memarg } => {
1269 translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1270 }
1271 Operator::I64AtomicRmwAdd { memarg } => {
1272 translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, state, environ)?
1273 }
1274 Operator::I32AtomicRmw8AddU { memarg } => {
1275 translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1276 }
1277 Operator::I32AtomicRmw16AddU { memarg } => {
1278 translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1279 }
1280 Operator::I64AtomicRmw8AddU { memarg } => {
1281 translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, state, environ)?
1282 }
1283 Operator::I64AtomicRmw16AddU { memarg } => {
1284 translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, state, environ)?
1285 }
1286 Operator::I64AtomicRmw32AddU { memarg } => {
1287 translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, state, environ)?
1288 }
1289
1290 Operator::I32AtomicRmwSub { memarg } => {
1291 translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1292 }
1293 Operator::I64AtomicRmwSub { memarg } => {
1294 translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1295 }
1296 Operator::I32AtomicRmw8SubU { memarg } => {
1297 translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1298 }
1299 Operator::I32AtomicRmw16SubU { memarg } => {
1300 translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1301 }
1302 Operator::I64AtomicRmw8SubU { memarg } => {
1303 translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1304 }
1305 Operator::I64AtomicRmw16SubU { memarg } => {
1306 translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1307 }
1308 Operator::I64AtomicRmw32SubU { memarg } => {
1309 translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)?
1310 }
1311
1312 Operator::I32AtomicRmwAnd { memarg } => {
1313 translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1314 }
1315 Operator::I64AtomicRmwAnd { memarg } => {
1316 translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, state, environ)?
1317 }
1318 Operator::I32AtomicRmw8AndU { memarg } => {
1319 translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1320 }
1321 Operator::I32AtomicRmw16AndU { memarg } => {
1322 translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1323 }
1324 Operator::I64AtomicRmw8AndU { memarg } => {
1325 translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, state, environ)?
1326 }
1327 Operator::I64AtomicRmw16AndU { memarg } => {
1328 translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, state, environ)?
1329 }
1330 Operator::I64AtomicRmw32AndU { memarg } => {
1331 translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, state, environ)?
1332 }
1333
1334 Operator::I32AtomicRmwOr { memarg } => {
1335 translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1336 }
1337 Operator::I64AtomicRmwOr { memarg } => {
1338 translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, state, environ)?
1339 }
1340 Operator::I32AtomicRmw8OrU { memarg } => {
1341 translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1342 }
1343 Operator::I32AtomicRmw16OrU { memarg } => {
1344 translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1345 }
1346 Operator::I64AtomicRmw8OrU { memarg } => {
1347 translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, state, environ)?
1348 }
1349 Operator::I64AtomicRmw16OrU { memarg } => {
1350 translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, state, environ)?
1351 }
1352 Operator::I64AtomicRmw32OrU { memarg } => {
1353 translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, state, environ)?
1354 }
1355
1356 Operator::I32AtomicRmwXor { memarg } => {
1357 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1358 }
1359 Operator::I64AtomicRmwXor { memarg } => {
1360 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1361 }
1362 Operator::I32AtomicRmw8XorU { memarg } => {
1363 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1364 }
1365 Operator::I32AtomicRmw16XorU { memarg } => {
1366 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1367 }
1368 Operator::I64AtomicRmw8XorU { memarg } => {
1369 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1370 }
1371 Operator::I64AtomicRmw16XorU { memarg } => {
1372 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1373 }
1374 Operator::I64AtomicRmw32XorU { memarg } => {
1375 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)?
1376 }
1377
1378 Operator::I32AtomicRmwXchg { memarg } => {
1379 translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1380 }
1381 Operator::I64AtomicRmwXchg { memarg } => {
1382 translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1383 }
1384 Operator::I32AtomicRmw8XchgU { memarg } => {
1385 translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1386 }
1387 Operator::I32AtomicRmw16XchgU { memarg } => {
1388 translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1389 }
1390 Operator::I64AtomicRmw8XchgU { memarg } => {
1391 translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1392 }
1393 Operator::I64AtomicRmw16XchgU { memarg } => {
1394 translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1395 }
1396 Operator::I64AtomicRmw32XchgU { memarg } => {
1397 translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)?
1398 }
1399
1400 Operator::I32AtomicRmwCmpxchg { memarg } => {
1401 translate_atomic_cas(I32, I32, memarg, builder, state, environ)?
1402 }
1403 Operator::I64AtomicRmwCmpxchg { memarg } => {
1404 translate_atomic_cas(I64, I64, memarg, builder, state, environ)?
1405 }
1406 Operator::I32AtomicRmw8CmpxchgU { memarg } => {
1407 translate_atomic_cas(I32, I8, memarg, builder, state, environ)?
1408 }
1409 Operator::I32AtomicRmw16CmpxchgU { memarg } => {
1410 translate_atomic_cas(I32, I16, memarg, builder, state, environ)?
1411 }
1412 Operator::I64AtomicRmw8CmpxchgU { memarg } => {
1413 translate_atomic_cas(I64, I8, memarg, builder, state, environ)?
1414 }
1415 Operator::I64AtomicRmw16CmpxchgU { memarg } => {
1416 translate_atomic_cas(I64, I16, memarg, builder, state, environ)?
1417 }
1418 Operator::I64AtomicRmw32CmpxchgU { memarg } => {
1419 translate_atomic_cas(I64, I32, memarg, builder, state, environ)?
1420 }
1421
1422 Operator::AtomicFence { .. } => {
1423 builder.ins().fence();
1424 }
1425 Operator::MemoryCopy { src_mem, dst_mem } => {
1426 let src_index = MemoryIndex::from_u32(*src_mem);
1427 let dst_index = MemoryIndex::from_u32(*dst_mem);
1428 let src_heap = state.get_heap(builder.func, *src_mem, environ)?;
1429 let dst_heap = state.get_heap(builder.func, *dst_mem, environ)?;
1430 let len = state.pop1();
1431 let src_pos = state.pop1();
1432 let dst_pos = state.pop1();
1433 environ.translate_memory_copy(
1434 builder.cursor(),
1435 src_index,
1436 src_heap,
1437 dst_index,
1438 dst_heap,
1439 dst_pos,
1440 src_pos,
1441 len,
1442 )?;
1443 }
1444 Operator::MemoryFill { mem } => {
1445 let heap_index = MemoryIndex::from_u32(*mem);
1446 let heap = state.get_heap(builder.func, *mem, environ)?;
1447 let len = state.pop1();
1448 let val = state.pop1();
1449 let dest = state.pop1();
1450 environ.translate_memory_fill(builder.cursor(), heap_index, heap, dest, val, len)?;
1451 }
1452 Operator::MemoryInit { data_index, mem } => {
1453 let heap_index = MemoryIndex::from_u32(*mem);
1454 let heap = state.get_heap(builder.func, *mem, environ)?;
1455 let len = state.pop1();
1456 let src = state.pop1();
1457 let dest = state.pop1();
1458 environ.translate_memory_init(
1459 builder.cursor(),
1460 heap_index,
1461 heap,
1462 *data_index,
1463 dest,
1464 src,
1465 len,
1466 )?;
1467 }
1468 Operator::DataDrop { data_index } => {
1469 environ.translate_data_drop(builder.cursor(), *data_index)?;
1470 }
1471 Operator::TableSize { table: index } => {
1472 let table = state.get_or_create_table(builder.func, *index, environ)?;
1473 state.push1(environ.translate_table_size(
1474 builder.cursor(),
1475 TableIndex::from_u32(*index),
1476 table,
1477 )?);
1478 }
1479 Operator::TableGrow { table: index } => {
1480 let table_index = TableIndex::from_u32(*index);
1481 let table = state.get_or_create_table(builder.func, *index, environ)?;
1482 let delta = state.pop1();
1483 let init_value = state.pop1();
1484 state.push1(environ.translate_table_grow(
1485 builder.cursor(),
1486 table_index,
1487 table,
1488 delta,
1489 init_value,
1490 )?);
1491 }
1492 Operator::TableGet { table: index } => {
1493 let table_index = TableIndex::from_u32(*index);
1494 let table = state.get_or_create_table(builder.func, *index, environ)?;
1495 let index = state.pop1();
1496 state.push1(environ.translate_table_get(builder, table_index, table, index)?);
1497 }
1498 Operator::TableSet { table: index } => {
1499 let table_index = TableIndex::from_u32(*index);
1500 let table = state.get_or_create_table(builder.func, *index, environ)?;
1501 let value = state.pop1();
1502 let index = state.pop1();
1503 environ.translate_table_set(builder, table_index, table, value, index)?;
1504 }
1505 Operator::TableCopy {
1506 dst_table: dst_table_index,
1507 src_table: src_table_index,
1508 } => {
1509 let dst_table = state.get_or_create_table(builder.func, *dst_table_index, environ)?;
1510 let src_table = state.get_or_create_table(builder.func, *src_table_index, environ)?;
1511 let len = state.pop1();
1512 let src = state.pop1();
1513 let dest = state.pop1();
1514 environ.translate_table_copy(
1515 builder.cursor(),
1516 TableIndex::from_u32(*dst_table_index),
1517 dst_table,
1518 TableIndex::from_u32(*src_table_index),
1519 src_table,
1520 dest,
1521 src,
1522 len,
1523 )?;
1524 }
1525 Operator::TableFill { table } => {
1526 let table_index = TableIndex::from_u32(*table);
1527 let len = state.pop1();
1528 let val = state.pop1();
1529 let dest = state.pop1();
1530 environ.translate_table_fill(builder.cursor(), table_index, dest, val, len)?;
1531 }
1532 Operator::TableInit {
1533 elem_index,
1534 table: table_index,
1535 } => {
1536 let table = state.get_or_create_table(builder.func, *table_index, environ)?;
1537 let len = state.pop1();
1538 let src = state.pop1();
1539 let dest = state.pop1();
1540 environ.translate_table_init(
1541 builder.cursor(),
1542 *elem_index,
1543 TableIndex::from_u32(*table_index),
1544 table,
1545 dest,
1546 src,
1547 len,
1548 )?;
1549 }
1550 Operator::ElemDrop { elem_index } => {
1551 environ.translate_elem_drop(builder.cursor(), *elem_index)?;
1552 }
1553 Operator::V128Const { value } => {
1554 let data = value.bytes().to_vec().into();
1555 let handle = builder.func.dfg.constants.insert(data);
1556 let value = builder.ins().vconst(I8X16, handle);
1557 state.push1(value)
1560 }
1561 Operator::I8x16Splat | Operator::I16x8Splat => {
1562 let reduced = builder.ins().ireduce(type_of(op).lane_type(), state.pop1());
1563 let splatted = builder.ins().splat(type_of(op), reduced);
1564 state.push1(splatted)
1565 }
1566 Operator::I32x4Splat
1567 | Operator::I64x2Splat
1568 | Operator::F32x4Splat
1569 | Operator::F64x2Splat => {
1570 let splatted = builder.ins().splat(type_of(op), state.pop1());
1571 state.push1(splatted)
1572 }
1573 Operator::V128Load8Splat { memarg }
1574 | Operator::V128Load16Splat { memarg }
1575 | Operator::V128Load32Splat { memarg }
1576 | Operator::V128Load64Splat { memarg } => {
1577 unwrap_or_return_unreachable_state!(
1578 state,
1579 translate_load(
1580 memarg,
1581 ir::Opcode::Load,
1582 type_of(op).lane_type(),
1583 builder,
1584 state,
1585 environ,
1586 )?
1587 );
1588 let splatted = builder.ins().splat(type_of(op), state.pop1());
1589 state.push1(splatted)
1590 }
1591 Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
1592 unwrap_or_return_unreachable_state!(
1593 state,
1594 translate_load(
1595 memarg,
1596 ir::Opcode::Load,
1597 type_of(op).lane_type(),
1598 builder,
1599 state,
1600 environ,
1601 )?
1602 );
1603 let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
1604 state.push1(as_vector)
1605 }
1606 Operator::V128Load8Lane { memarg, lane }
1607 | Operator::V128Load16Lane { memarg, lane }
1608 | Operator::V128Load32Lane { memarg, lane }
1609 | Operator::V128Load64Lane { memarg, lane } => {
1610 let vector = pop1_with_bitcast(state, type_of(op), builder);
1611 unwrap_or_return_unreachable_state!(
1612 state,
1613 translate_load(
1614 memarg,
1615 ir::Opcode::Load,
1616 type_of(op).lane_type(),
1617 builder,
1618 state,
1619 environ,
1620 )?
1621 );
1622 let replacement = state.pop1();
1623 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1624 }
1625 Operator::V128Store8Lane { memarg, lane }
1626 | Operator::V128Store16Lane { memarg, lane }
1627 | Operator::V128Store32Lane { memarg, lane }
1628 | Operator::V128Store64Lane { memarg, lane } => {
1629 let vector = pop1_with_bitcast(state, type_of(op), builder);
1630 state.push1(builder.ins().extractlane(vector, lane.clone()));
1631 translate_store(memarg, ir::Opcode::Store, builder, state, environ)?;
1632 }
1633 Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => {
1634 let vector = pop1_with_bitcast(state, type_of(op), builder);
1635 let extracted = builder.ins().extractlane(vector, lane.clone());
1636 state.push1(builder.ins().sextend(I32, extracted))
1637 }
1638 Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => {
1639 let vector = pop1_with_bitcast(state, type_of(op), builder);
1640 let extracted = builder.ins().extractlane(vector, lane.clone());
1641 state.push1(builder.ins().uextend(I32, extracted));
1642 }
1646 Operator::I32x4ExtractLane { lane }
1647 | Operator::I64x2ExtractLane { lane }
1648 | Operator::F32x4ExtractLane { lane }
1649 | Operator::F64x2ExtractLane { lane } => {
1650 let vector = pop1_with_bitcast(state, type_of(op), builder);
1651 state.push1(builder.ins().extractlane(vector, lane.clone()))
1652 }
1653 Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => {
1654 let (vector, replacement) = state.pop2();
1655 let ty = type_of(op);
1656 let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
1657 let vector = optionally_bitcast_vector(vector, ty, builder);
1658 state.push1(builder.ins().insertlane(vector, reduced, *lane))
1659 }
1660 Operator::I32x4ReplaceLane { lane }
1661 | Operator::I64x2ReplaceLane { lane }
1662 | Operator::F32x4ReplaceLane { lane }
1663 | Operator::F64x2ReplaceLane { lane } => {
1664 let (vector, replacement) = state.pop2();
1665 let vector = optionally_bitcast_vector(vector, type_of(op), builder);
1666 state.push1(builder.ins().insertlane(vector, replacement, *lane))
1667 }
1668 Operator::I8x16Shuffle { lanes, .. } => {
1669 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1670 let lanes = ConstantData::from(lanes.as_ref());
1671 let mask = builder.func.dfg.immediates.push(lanes);
1672 let shuffled = builder.ins().shuffle(a, b, mask);
1673 state.push1(shuffled)
1674 }
1679 Operator::I8x16Swizzle => {
1680 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
1681 state.push1(builder.ins().swizzle(a, b))
1682 }
1683 Operator::I8x16Add | Operator::I16x8Add | Operator::I32x4Add | Operator::I64x2Add => {
1684 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1685 state.push1(builder.ins().iadd(a, b))
1686 }
1687 Operator::I8x16AddSatS | Operator::I16x8AddSatS => {
1688 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1689 state.push1(builder.ins().sadd_sat(a, b))
1690 }
1691 Operator::I8x16AddSatU | Operator::I16x8AddSatU => {
1692 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1693 state.push1(builder.ins().uadd_sat(a, b))
1694 }
1695 Operator::I8x16Sub | Operator::I16x8Sub | Operator::I32x4Sub | Operator::I64x2Sub => {
1696 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1697 state.push1(builder.ins().isub(a, b))
1698 }
1699 Operator::I8x16SubSatS | Operator::I16x8SubSatS => {
1700 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1701 state.push1(builder.ins().ssub_sat(a, b))
1702 }
1703 Operator::I8x16SubSatU | Operator::I16x8SubSatU => {
1704 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1705 state.push1(builder.ins().usub_sat(a, b))
1706 }
1707 Operator::I8x16MinS | Operator::I16x8MinS | Operator::I32x4MinS => {
1708 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1709 state.push1(builder.ins().smin(a, b))
1710 }
1711 Operator::I8x16MinU | Operator::I16x8MinU | Operator::I32x4MinU => {
1712 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1713 state.push1(builder.ins().umin(a, b))
1714 }
1715 Operator::I8x16MaxS | Operator::I16x8MaxS | Operator::I32x4MaxS => {
1716 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1717 state.push1(builder.ins().smax(a, b))
1718 }
1719 Operator::I8x16MaxU | Operator::I16x8MaxU | Operator::I32x4MaxU => {
1720 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1721 state.push1(builder.ins().umax(a, b))
1722 }
1723 Operator::I8x16AvgrU | Operator::I16x8AvgrU => {
1724 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1725 state.push1(builder.ins().avg_round(a, b))
1726 }
1727 Operator::I8x16Neg | Operator::I16x8Neg | Operator::I32x4Neg | Operator::I64x2Neg => {
1728 let a = pop1_with_bitcast(state, type_of(op), builder);
1729 state.push1(builder.ins().ineg(a))
1730 }
1731 Operator::I8x16Abs | Operator::I16x8Abs | Operator::I32x4Abs | Operator::I64x2Abs => {
1732 let a = pop1_with_bitcast(state, type_of(op), builder);
1733 state.push1(builder.ins().iabs(a))
1734 }
1735 Operator::I16x8Mul | Operator::I32x4Mul | Operator::I64x2Mul => {
1736 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1737 state.push1(builder.ins().imul(a, b))
1738 }
1739 Operator::V128Or => {
1740 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1741 state.push1(builder.ins().bor(a, b))
1742 }
1743 Operator::V128Xor => {
1744 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1745 state.push1(builder.ins().bxor(a, b))
1746 }
1747 Operator::V128And => {
1748 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1749 state.push1(builder.ins().band(a, b))
1750 }
1751 Operator::V128AndNot => {
1752 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1753 state.push1(builder.ins().band_not(a, b))
1754 }
1755 Operator::V128Not => {
1756 let a = state.pop1();
1757 state.push1(builder.ins().bnot(a));
1758 }
1759 Operator::I8x16Shl | Operator::I16x8Shl | Operator::I32x4Shl | Operator::I64x2Shl => {
1760 let (a, b) = state.pop2();
1761 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1762 state.push1(builder.ins().ishl(bitcast_a, b))
1765 }
1766 Operator::I8x16ShrU | Operator::I16x8ShrU | Operator::I32x4ShrU | Operator::I64x2ShrU => {
1767 let (a, b) = state.pop2();
1768 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1769 state.push1(builder.ins().ushr(bitcast_a, b))
1772 }
1773 Operator::I8x16ShrS | Operator::I16x8ShrS | Operator::I32x4ShrS | Operator::I64x2ShrS => {
1774 let (a, b) = state.pop2();
1775 let bitcast_a = optionally_bitcast_vector(a, type_of(op), builder);
1776 state.push1(builder.ins().sshr(bitcast_a, b))
1779 }
1780 Operator::V128Bitselect => {
1781 let (a, b, c) = pop3_with_bitcast(state, I8X16, builder);
1782 state.push1(builder.ins().bitselect(c, a, b))
1785 }
1786 Operator::V128AnyTrue => {
1787 let a = pop1_with_bitcast(state, type_of(op), builder);
1788 let bool_result = builder.ins().vany_true(a);
1789 state.push1(builder.ins().uextend(I32, bool_result))
1790 }
1791 Operator::I8x16AllTrue
1792 | Operator::I16x8AllTrue
1793 | Operator::I32x4AllTrue
1794 | Operator::I64x2AllTrue => {
1795 let a = pop1_with_bitcast(state, type_of(op), builder);
1796 let bool_result = builder.ins().vall_true(a);
1797 state.push1(builder.ins().uextend(I32, bool_result))
1798 }
1799 Operator::I8x16Bitmask
1800 | Operator::I16x8Bitmask
1801 | Operator::I32x4Bitmask
1802 | Operator::I64x2Bitmask => {
1803 let a = pop1_with_bitcast(state, type_of(op), builder);
1804 state.push1(builder.ins().vhigh_bits(I32, a));
1805 }
1806 Operator::I8x16Eq | Operator::I16x8Eq | Operator::I32x4Eq | Operator::I64x2Eq => {
1807 translate_vector_icmp(IntCC::Equal, type_of(op), builder, state)
1808 }
1809 Operator::I8x16Ne | Operator::I16x8Ne | Operator::I32x4Ne | Operator::I64x2Ne => {
1810 translate_vector_icmp(IntCC::NotEqual, type_of(op), builder, state)
1811 }
1812 Operator::I8x16GtS | Operator::I16x8GtS | Operator::I32x4GtS | Operator::I64x2GtS => {
1813 translate_vector_icmp(IntCC::SignedGreaterThan, type_of(op), builder, state)
1814 }
1815 Operator::I8x16LtS | Operator::I16x8LtS | Operator::I32x4LtS | Operator::I64x2LtS => {
1816 translate_vector_icmp(IntCC::SignedLessThan, type_of(op), builder, state)
1817 }
1818 Operator::I8x16GtU | Operator::I16x8GtU | Operator::I32x4GtU => {
1819 translate_vector_icmp(IntCC::UnsignedGreaterThan, type_of(op), builder, state)
1820 }
1821 Operator::I8x16LtU | Operator::I16x8LtU | Operator::I32x4LtU => {
1822 translate_vector_icmp(IntCC::UnsignedLessThan, type_of(op), builder, state)
1823 }
1824 Operator::I8x16GeS | Operator::I16x8GeS | Operator::I32x4GeS | Operator::I64x2GeS => {
1825 translate_vector_icmp(IntCC::SignedGreaterThanOrEqual, type_of(op), builder, state)
1826 }
1827 Operator::I8x16LeS | Operator::I16x8LeS | Operator::I32x4LeS | Operator::I64x2LeS => {
1828 translate_vector_icmp(IntCC::SignedLessThanOrEqual, type_of(op), builder, state)
1829 }
1830 Operator::I8x16GeU | Operator::I16x8GeU | Operator::I32x4GeU => translate_vector_icmp(
1831 IntCC::UnsignedGreaterThanOrEqual,
1832 type_of(op),
1833 builder,
1834 state,
1835 ),
1836 Operator::I8x16LeU | Operator::I16x8LeU | Operator::I32x4LeU => {
1837 translate_vector_icmp(IntCC::UnsignedLessThanOrEqual, type_of(op), builder, state)
1838 }
1839 Operator::F32x4Eq | Operator::F64x2Eq => {
1840 translate_vector_fcmp(FloatCC::Equal, type_of(op), builder, state)
1841 }
1842 Operator::F32x4Ne | Operator::F64x2Ne => {
1843 translate_vector_fcmp(FloatCC::NotEqual, type_of(op), builder, state)
1844 }
1845 Operator::F32x4Lt | Operator::F64x2Lt => {
1846 translate_vector_fcmp(FloatCC::LessThan, type_of(op), builder, state)
1847 }
1848 Operator::F32x4Gt | Operator::F64x2Gt => {
1849 translate_vector_fcmp(FloatCC::GreaterThan, type_of(op), builder, state)
1850 }
1851 Operator::F32x4Le | Operator::F64x2Le => {
1852 translate_vector_fcmp(FloatCC::LessThanOrEqual, type_of(op), builder, state)
1853 }
1854 Operator::F32x4Ge | Operator::F64x2Ge => {
1855 translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, state)
1856 }
1857 Operator::F32x4Add | Operator::F64x2Add => {
1858 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1859 state.push1(builder.ins().fadd(a, b))
1860 }
1861 Operator::F32x4Sub | Operator::F64x2Sub => {
1862 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1863 state.push1(builder.ins().fsub(a, b))
1864 }
1865 Operator::F32x4Mul | Operator::F64x2Mul => {
1866 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1867 state.push1(builder.ins().fmul(a, b))
1868 }
1869 Operator::F32x4Div | Operator::F64x2Div => {
1870 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1871 state.push1(builder.ins().fdiv(a, b))
1872 }
1873 Operator::F32x4Max | Operator::F64x2Max => {
1874 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1875 state.push1(builder.ins().fmax(a, b))
1876 }
1877 Operator::F32x4Min | Operator::F64x2Min => {
1878 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1879 state.push1(builder.ins().fmin(a, b))
1880 }
1881 Operator::F32x4PMax | Operator::F64x2PMax => {
1882 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1883 state.push1(builder.ins().fmax_pseudo(a, b))
1884 }
1885 Operator::F32x4PMin | Operator::F64x2PMin => {
1886 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
1887 state.push1(builder.ins().fmin_pseudo(a, b))
1888 }
1889 Operator::F32x4Sqrt | Operator::F64x2Sqrt => {
1890 let a = pop1_with_bitcast(state, type_of(op), builder);
1891 state.push1(builder.ins().sqrt(a))
1892 }
1893 Operator::F32x4Neg | Operator::F64x2Neg => {
1894 let a = pop1_with_bitcast(state, type_of(op), builder);
1895 state.push1(builder.ins().fneg(a))
1896 }
1897 Operator::F32x4Abs | Operator::F64x2Abs => {
1898 let a = pop1_with_bitcast(state, type_of(op), builder);
1899 state.push1(builder.ins().fabs(a))
1900 }
1901 Operator::F32x4ConvertI32x4S => {
1902 let a = pop1_with_bitcast(state, I32X4, builder);
1903 state.push1(builder.ins().fcvt_from_sint(F32X4, a))
1904 }
1905 Operator::F32x4ConvertI32x4U => {
1906 let a = pop1_with_bitcast(state, I32X4, builder);
1907 state.push1(builder.ins().fcvt_from_uint(F32X4, a))
1908 }
1909 Operator::F64x2ConvertLowI32x4S => {
1910 let a = pop1_with_bitcast(state, I32X4, builder);
1911 state.push1(builder.ins().fcvt_low_from_sint(F64X2, a));
1912 }
1913 Operator::F64x2ConvertLowI32x4U => {
1914 let a = pop1_with_bitcast(state, I32X4, builder);
1915 let widened_a = builder.ins().uwiden_low(a);
1916 state.push1(builder.ins().fcvt_from_uint(F64X2, widened_a));
1917 }
1918 Operator::F64x2PromoteLowF32x4 => {
1919 let a = pop1_with_bitcast(state, F32X4, builder);
1920 state.push1(builder.ins().fvpromote_low(a));
1921 }
1922 Operator::F32x4DemoteF64x2Zero => {
1923 let a = pop1_with_bitcast(state, F64X2, builder);
1924 state.push1(builder.ins().fvdemote(a));
1925 }
1926 Operator::I32x4TruncSatF32x4S => {
1927 let a = pop1_with_bitcast(state, F32X4, builder);
1928 state.push1(builder.ins().fcvt_to_sint_sat(I32X4, a))
1929 }
1930 Operator::I32x4TruncSatF64x2SZero => {
1931 let a = pop1_with_bitcast(state, F64X2, builder);
1932 let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a);
1933 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
1934 let zero = builder.ins().vconst(I64X2, handle);
1935
1936 state.push1(builder.ins().snarrow(converted_a, zero));
1937 }
1938
1939 Operator::I32x4RelaxedTruncF32x4U | Operator::I32x4TruncSatF32x4U => {
1951 let a = pop1_with_bitcast(state, F32X4, builder);
1952 state.push1(builder.ins().fcvt_to_uint_sat(I32X4, a))
1953 }
1954 Operator::I32x4RelaxedTruncF64x2UZero | Operator::I32x4TruncSatF64x2UZero => {
1955 let a = pop1_with_bitcast(state, F64X2, builder);
1956 let converted_a = builder.ins().fcvt_to_uint_sat(I64X2, a);
1957 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
1958 let zero = builder.ins().vconst(I64X2, handle);
1959
1960 state.push1(builder.ins().uunarrow(converted_a, zero));
1961 }
1962
1963 Operator::I8x16NarrowI16x8S => {
1964 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
1965 state.push1(builder.ins().snarrow(a, b))
1966 }
1967 Operator::I16x8NarrowI32x4S => {
1968 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
1969 state.push1(builder.ins().snarrow(a, b))
1970 }
1971 Operator::I8x16NarrowI16x8U => {
1972 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
1973 state.push1(builder.ins().unarrow(a, b))
1974 }
1975 Operator::I16x8NarrowI32x4U => {
1976 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
1977 state.push1(builder.ins().unarrow(a, b))
1978 }
1979 Operator::I16x8ExtendLowI8x16S => {
1980 let a = pop1_with_bitcast(state, I8X16, builder);
1981 state.push1(builder.ins().swiden_low(a))
1982 }
1983 Operator::I16x8ExtendHighI8x16S => {
1984 let a = pop1_with_bitcast(state, I8X16, builder);
1985 state.push1(builder.ins().swiden_high(a))
1986 }
1987 Operator::I16x8ExtendLowI8x16U => {
1988 let a = pop1_with_bitcast(state, I8X16, builder);
1989 state.push1(builder.ins().uwiden_low(a))
1990 }
1991 Operator::I16x8ExtendHighI8x16U => {
1992 let a = pop1_with_bitcast(state, I8X16, builder);
1993 state.push1(builder.ins().uwiden_high(a))
1994 }
1995 Operator::I32x4ExtendLowI16x8S => {
1996 let a = pop1_with_bitcast(state, I16X8, builder);
1997 state.push1(builder.ins().swiden_low(a))
1998 }
1999 Operator::I32x4ExtendHighI16x8S => {
2000 let a = pop1_with_bitcast(state, I16X8, builder);
2001 state.push1(builder.ins().swiden_high(a))
2002 }
2003 Operator::I32x4ExtendLowI16x8U => {
2004 let a = pop1_with_bitcast(state, I16X8, builder);
2005 state.push1(builder.ins().uwiden_low(a))
2006 }
2007 Operator::I32x4ExtendHighI16x8U => {
2008 let a = pop1_with_bitcast(state, I16X8, builder);
2009 state.push1(builder.ins().uwiden_high(a))
2010 }
2011 Operator::I64x2ExtendLowI32x4S => {
2012 let a = pop1_with_bitcast(state, I32X4, builder);
2013 state.push1(builder.ins().swiden_low(a))
2014 }
2015 Operator::I64x2ExtendHighI32x4S => {
2016 let a = pop1_with_bitcast(state, I32X4, builder);
2017 state.push1(builder.ins().swiden_high(a))
2018 }
2019 Operator::I64x2ExtendLowI32x4U => {
2020 let a = pop1_with_bitcast(state, I32X4, builder);
2021 state.push1(builder.ins().uwiden_low(a))
2022 }
2023 Operator::I64x2ExtendHighI32x4U => {
2024 let a = pop1_with_bitcast(state, I32X4, builder);
2025 state.push1(builder.ins().uwiden_high(a))
2026 }
2027 Operator::I16x8ExtAddPairwiseI8x16S => {
2028 let a = pop1_with_bitcast(state, I8X16, builder);
2029 let widen_low = builder.ins().swiden_low(a);
2030 let widen_high = builder.ins().swiden_high(a);
2031 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2032 }
2033 Operator::I32x4ExtAddPairwiseI16x8S => {
2034 let a = pop1_with_bitcast(state, I16X8, builder);
2035 let widen_low = builder.ins().swiden_low(a);
2036 let widen_high = builder.ins().swiden_high(a);
2037 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2038 }
2039 Operator::I16x8ExtAddPairwiseI8x16U => {
2040 let a = pop1_with_bitcast(state, I8X16, builder);
2041 let widen_low = builder.ins().uwiden_low(a);
2042 let widen_high = builder.ins().uwiden_high(a);
2043 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2044 }
2045 Operator::I32x4ExtAddPairwiseI16x8U => {
2046 let a = pop1_with_bitcast(state, I16X8, builder);
2047 let widen_low = builder.ins().uwiden_low(a);
2048 let widen_high = builder.ins().uwiden_high(a);
2049 state.push1(builder.ins().iadd_pairwise(widen_low, widen_high));
2050 }
2051 Operator::F32x4Ceil | Operator::F64x2Ceil => {
2052 let arg = pop1_with_bitcast(state, type_of(op), builder);
2056 state.push1(builder.ins().ceil(arg));
2057 }
2058 Operator::F32x4Floor | Operator::F64x2Floor => {
2059 let arg = pop1_with_bitcast(state, type_of(op), builder);
2060 state.push1(builder.ins().floor(arg));
2061 }
2062 Operator::F32x4Trunc | Operator::F64x2Trunc => {
2063 let arg = pop1_with_bitcast(state, type_of(op), builder);
2064 state.push1(builder.ins().trunc(arg));
2065 }
2066 Operator::F32x4Nearest | Operator::F64x2Nearest => {
2067 let arg = pop1_with_bitcast(state, type_of(op), builder);
2068 state.push1(builder.ins().nearest(arg));
2069 }
2070 Operator::I32x4DotI16x8S => {
2071 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2072 let alow = builder.ins().swiden_low(a);
2073 let blow = builder.ins().swiden_low(b);
2074 let low = builder.ins().imul(alow, blow);
2075 let ahigh = builder.ins().swiden_high(a);
2076 let bhigh = builder.ins().swiden_high(b);
2077 let high = builder.ins().imul(ahigh, bhigh);
2078 state.push1(builder.ins().iadd_pairwise(low, high));
2079 }
2080 Operator::I8x16Popcnt => {
2081 let arg = pop1_with_bitcast(state, type_of(op), builder);
2082 state.push1(builder.ins().popcnt(arg));
2083 }
2084 Operator::I16x8Q15MulrSatS => {
2085 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2086 state.push1(builder.ins().sqmul_round_sat(a, b))
2087 }
2088 Operator::I16x8ExtMulLowI8x16S => {
2089 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2090 let a_low = builder.ins().swiden_low(a);
2091 let b_low = builder.ins().swiden_low(b);
2092 state.push1(builder.ins().imul(a_low, b_low));
2093 }
2094 Operator::I16x8ExtMulHighI8x16S => {
2095 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2096 let a_high = builder.ins().swiden_high(a);
2097 let b_high = builder.ins().swiden_high(b);
2098 state.push1(builder.ins().imul(a_high, b_high));
2099 }
2100 Operator::I16x8ExtMulLowI8x16U => {
2101 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2102 let a_low = builder.ins().uwiden_low(a);
2103 let b_low = builder.ins().uwiden_low(b);
2104 state.push1(builder.ins().imul(a_low, b_low));
2105 }
2106 Operator::I16x8ExtMulHighI8x16U => {
2107 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2108 let a_high = builder.ins().uwiden_high(a);
2109 let b_high = builder.ins().uwiden_high(b);
2110 state.push1(builder.ins().imul(a_high, b_high));
2111 }
2112 Operator::I32x4ExtMulLowI16x8S => {
2113 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2114 let a_low = builder.ins().swiden_low(a);
2115 let b_low = builder.ins().swiden_low(b);
2116 state.push1(builder.ins().imul(a_low, b_low));
2117 }
2118 Operator::I32x4ExtMulHighI16x8S => {
2119 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2120 let a_high = builder.ins().swiden_high(a);
2121 let b_high = builder.ins().swiden_high(b);
2122 state.push1(builder.ins().imul(a_high, b_high));
2123 }
2124 Operator::I32x4ExtMulLowI16x8U => {
2125 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2126 let a_low = builder.ins().uwiden_low(a);
2127 let b_low = builder.ins().uwiden_low(b);
2128 state.push1(builder.ins().imul(a_low, b_low));
2129 }
2130 Operator::I32x4ExtMulHighI16x8U => {
2131 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2132 let a_high = builder.ins().uwiden_high(a);
2133 let b_high = builder.ins().uwiden_high(b);
2134 state.push1(builder.ins().imul(a_high, b_high));
2135 }
2136 Operator::I64x2ExtMulLowI32x4S => {
2137 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2138 let a_low = builder.ins().swiden_low(a);
2139 let b_low = builder.ins().swiden_low(b);
2140 state.push1(builder.ins().imul(a_low, b_low));
2141 }
2142 Operator::I64x2ExtMulHighI32x4S => {
2143 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2144 let a_high = builder.ins().swiden_high(a);
2145 let b_high = builder.ins().swiden_high(b);
2146 state.push1(builder.ins().imul(a_high, b_high));
2147 }
2148 Operator::I64x2ExtMulLowI32x4U => {
2149 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2150 let a_low = builder.ins().uwiden_low(a);
2151 let b_low = builder.ins().uwiden_low(b);
2152 state.push1(builder.ins().imul(a_low, b_low));
2153 }
2154 Operator::I64x2ExtMulHighI32x4U => {
2155 let (a, b) = pop2_with_bitcast(state, I32X4, builder);
2156 let a_high = builder.ins().uwiden_high(a);
2157 let b_high = builder.ins().uwiden_high(b);
2158 state.push1(builder.ins().imul(a_high, b_high));
2159 }
2160 Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
2161 return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
2162 }
2163 Operator::MemoryDiscard { .. } => {
2164 return Err(wasm_unsupported!(
2165 "proposed memory-control operator {:?}",
2166 op
2167 ));
2168 }
2169
2170 Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => {
2171 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2172 state.push1(
2173 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2174 builder.ins().fmax(a, b)
2177 } else {
2178 builder.ins().fmax_pseudo(a, b)
2179 },
2180 )
2181 }
2182
2183 Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => {
2184 let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
2185 state.push1(
2186 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2187 builder.ins().fmin(a, b)
2190 } else {
2191 builder.ins().fmin_pseudo(a, b)
2192 },
2193 );
2194 }
2195
2196 Operator::I8x16RelaxedSwizzle => {
2197 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2198 state.push1(
2199 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2200 builder.ins().swizzle(a, b)
2203 } else {
2204 builder.ins().x86_pshufb(a, b)
2205 },
2206 );
2207 }
2208
2209 Operator::F32x4RelaxedMadd | Operator::F64x2RelaxedMadd => {
2210 let (a, b, c) = pop3_with_bitcast(state, type_of(op), builder);
2211 state.push1(
2212 if environ.relaxed_simd_deterministic() || environ.has_native_fma() {
2213 builder.ins().fma(a, b, c)
2216 } else {
2217 let mul = builder.ins().fmul(a, b);
2218 builder.ins().fadd(mul, c)
2219 },
2220 );
2221 }
2222 Operator::F32x4RelaxedNmadd | Operator::F64x2RelaxedNmadd => {
2223 let (a, b, c) = pop3_with_bitcast(state, type_of(op), builder);
2224 let a = builder.ins().fneg(a);
2225 state.push1(
2226 if environ.relaxed_simd_deterministic() || environ.has_native_fma() {
2227 builder.ins().fma(a, b, c)
2230 } else {
2231 let mul = builder.ins().fmul(a, b);
2232 builder.ins().fadd(mul, c)
2233 },
2234 );
2235 }
2236
2237 Operator::I8x16RelaxedLaneselect
2238 | Operator::I16x8RelaxedLaneselect
2239 | Operator::I32x4RelaxedLaneselect
2240 | Operator::I64x2RelaxedLaneselect => {
2241 let ty = type_of(op);
2242 let (a, b, c) = pop3_with_bitcast(state, ty, builder);
2243 state.push1(
2251 if environ.relaxed_simd_deterministic() || !environ.is_x86() || ty == I16X8 {
2252 builder.ins().bitselect(c, a, b)
2255 } else {
2256 builder.ins().x86_blendv(c, a, b)
2257 },
2258 );
2259 }
2260
2261 Operator::I32x4RelaxedTruncF32x4S => {
2262 let a = pop1_with_bitcast(state, F32X4, builder);
2263 state.push1(
2264 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2265 builder.ins().fcvt_to_sint_sat(I32X4, a)
2268 } else {
2269 builder.ins().x86_cvtt2dq(I32X4, a)
2270 },
2271 )
2272 }
2273 Operator::I32x4RelaxedTruncF64x2SZero => {
2274 let a = pop1_with_bitcast(state, F64X2, builder);
2275 let converted_a = if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2276 builder.ins().fcvt_to_sint_sat(I64X2, a)
2279 } else {
2280 builder.ins().x86_cvtt2dq(I64X2, a)
2281 };
2282 let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into());
2283 let zero = builder.ins().vconst(I64X2, handle);
2284
2285 state.push1(builder.ins().snarrow(converted_a, zero));
2286 }
2287 Operator::I16x8RelaxedQ15mulrS => {
2288 let (a, b) = pop2_with_bitcast(state, I16X8, builder);
2289 state.push1(
2290 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2291 builder.ins().sqmul_round_sat(a, b)
2294 } else {
2295 builder.ins().x86_pmulhrsw(a, b)
2296 },
2297 );
2298 }
2299 Operator::I16x8RelaxedDotI8x16I7x16S => {
2300 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2301 state.push1(
2302 if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2303 let alo = builder.ins().swiden_low(a);
2306 let blo = builder.ins().swiden_low(b);
2307 let lo = builder.ins().imul(alo, blo);
2308 let ahi = builder.ins().swiden_high(a);
2309 let bhi = builder.ins().swiden_high(b);
2310 let hi = builder.ins().imul(ahi, bhi);
2311 builder.ins().iadd_pairwise(lo, hi)
2312 } else {
2313 builder.ins().x86_pmaddubsw(a, b)
2314 },
2315 );
2316 }
2317
2318 Operator::I32x4RelaxedDotI8x16I7x16AddS => {
2319 let c = pop1_with_bitcast(state, I32X4, builder);
2320 let (a, b) = pop2_with_bitcast(state, I8X16, builder);
2321 let dot = if environ.relaxed_simd_deterministic() || !environ.is_x86() {
2322 let alo = builder.ins().swiden_low(a);
2325 let blo = builder.ins().swiden_low(b);
2326 let lo = builder.ins().imul(alo, blo);
2327 let ahi = builder.ins().swiden_high(a);
2328 let bhi = builder.ins().swiden_high(b);
2329 let hi = builder.ins().imul(ahi, bhi);
2330 builder.ins().iadd_pairwise(lo, hi)
2331 } else {
2332 builder.ins().x86_pmaddubsw(a, b)
2333 };
2334 let dotlo = builder.ins().swiden_low(dot);
2335 let dothi = builder.ins().swiden_high(dot);
2336 let dot32 = builder.ins().iadd_pairwise(dotlo, dothi);
2337 state.push1(builder.ins().iadd(dot32, c));
2338 }
2339
2340 Operator::CallRef { .. }
2341 | Operator::ReturnCallRef { .. }
2342 | Operator::BrOnNull { .. }
2343 | Operator::BrOnNonNull { .. }
2344 | Operator::RefAsNonNull => {
2345 return Err(wasm_unsupported!(
2346 "proposed function-references operator {:?}",
2347 op
2348 ));
2349 }
2350 };
2351 Ok(())
2352}
2353
2354#[cfg_attr(feature = "cargo-clippy", allow(clippy::unneeded_field_pattern))]
2356fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
2360 validator: &FuncValidator<impl WasmModuleResources>,
2361 op: &Operator,
2362 builder: &mut FunctionBuilder,
2363 state: &mut FuncTranslationState,
2364 environ: &mut FE,
2365) -> WasmResult<()> {
2366 debug_assert!(!state.reachable);
2367 match *op {
2368 Operator::If { blockty } => {
2369 state.push_if(
2372 ir::Block::reserved_value(),
2373 ElseData::NoElse {
2374 branch_inst: ir::Inst::reserved_value(),
2375 placeholder: ir::Block::reserved_value(),
2376 },
2377 0,
2378 0,
2379 blockty,
2380 );
2381 }
2382 Operator::Loop { blockty: _ } | Operator::Block { blockty: _ } => {
2383 state.push_block(ir::Block::reserved_value(), 0, 0);
2384 }
2385 Operator::Else => {
2386 let i = state.control_stack.len() - 1;
2387 match state.control_stack[i] {
2388 ControlStackFrame::If {
2389 ref else_data,
2390 head_is_reachable,
2391 ref mut consequent_ends_reachable,
2392 blocktype,
2393 ..
2394 } => {
2395 debug_assert!(consequent_ends_reachable.is_none());
2396 *consequent_ends_reachable = Some(state.reachable);
2397
2398 if head_is_reachable {
2399 state.reachable = true;
2401
2402 let else_block = match *else_data {
2403 ElseData::NoElse {
2404 branch_inst,
2405 placeholder,
2406 } => {
2407 let (params, _results) =
2408 blocktype_params_results(validator, blocktype)?;
2409 let else_block = block_with_params(builder, params, environ)?;
2410 let frame = state.control_stack.last().unwrap();
2411 frame.truncate_value_stack_to_else_params(&mut state.stack);
2412
2413 builder.change_jump_destination(
2415 branch_inst,
2416 placeholder,
2417 else_block,
2418 );
2419 builder.seal_block(else_block);
2420 else_block
2421 }
2422 ElseData::WithElse { else_block } => {
2423 let frame = state.control_stack.last().unwrap();
2424 frame.truncate_value_stack_to_else_params(&mut state.stack);
2425 else_block
2426 }
2427 };
2428
2429 builder.switch_to_block(else_block);
2430
2431 }
2436 }
2437 _ => unreachable!(),
2438 }
2439 }
2440 Operator::End => {
2441 let stack = &mut state.stack;
2442 let control_stack = &mut state.control_stack;
2443 let frame = control_stack.pop().unwrap();
2444
2445 frame.truncate_value_stack_to_original_size(stack);
2447
2448 let reachable_anyway = match frame {
2449 ControlStackFrame::Loop { header, .. } => {
2451 builder.seal_block(header);
2452 false
2454 }
2455 ControlStackFrame::If {
2460 head_is_reachable,
2461 consequent_ends_reachable: None,
2462 ..
2463 } => head_is_reachable,
2464 ControlStackFrame::If {
2469 head_is_reachable,
2470 consequent_ends_reachable: Some(consequent_ends_reachable),
2471 ..
2472 } => head_is_reachable && consequent_ends_reachable,
2473 _ => false,
2475 };
2476
2477 if frame.exit_is_branched_to() || reachable_anyway {
2478 builder.switch_to_block(frame.following_code());
2479 builder.seal_block(frame.following_code());
2480
2481 stack.extend_from_slice(builder.block_params(frame.following_code()));
2484 state.reachable = true;
2485 }
2486 }
2487 _ => {
2488 }
2490 }
2491
2492 Ok(())
2493}
2494
2495fn prepare_addr<FE>(
2506 memarg: &MemArg,
2507 access_size: u8,
2508 builder: &mut FunctionBuilder,
2509 state: &mut FuncTranslationState,
2510 environ: &mut FE,
2511) -> WasmResult<Reachability<(MemFlags, Value)>>
2512where
2513 FE: FuncEnvironment + ?Sized,
2514{
2515 let index = state.pop1();
2516 let heap = state.get_heap(builder.func, memarg.memory, environ)?;
2517
2518 let heap = environ.heaps()[heap].clone();
2589 let addr = match u32::try_from(memarg.offset) {
2590 Ok(offset) => bounds_checks::bounds_check_and_compute_addr(
2593 builder,
2594 environ,
2595 &heap,
2596 index,
2597 offset,
2598 access_size,
2599 )?,
2600
2601 Err(_) => {
2628 let offset = builder.ins().iconst(heap.index_type, memarg.offset as i64);
2629 let adjusted_index =
2630 builder
2631 .ins()
2632 .uadd_overflow_trap(index, offset, ir::TrapCode::HeapOutOfBounds);
2633 bounds_checks::bounds_check_and_compute_addr(
2634 builder,
2635 environ,
2636 &heap,
2637 adjusted_index,
2638 0,
2639 access_size,
2640 )?
2641 }
2642 };
2643 let addr = match addr {
2644 Reachability::Unreachable => return Ok(Reachability::Unreachable),
2645 Reachability::Reachable(a) => a,
2646 };
2647
2648 let mut flags = MemFlags::new();
2653 flags.set_endianness(ir::Endianness::Little);
2654
2655 flags.set_heap();
2660
2661 Ok(Reachability::Reachable((flags, addr)))
2662}
2663
2664fn align_atomic_addr(
2665 memarg: &MemArg,
2666 loaded_bytes: u8,
2667 builder: &mut FunctionBuilder,
2668 state: &mut FuncTranslationState,
2669) {
2670 if loaded_bytes > 1 {
2681 let addr = state.pop1(); state.push1(addr);
2683 let effective_addr = if memarg.offset == 0 {
2684 addr
2685 } else {
2686 builder
2687 .ins()
2688 .iadd_imm(addr, i64::from(memarg.offset as i32))
2689 };
2690 debug_assert!(loaded_bytes.is_power_of_two());
2691 let misalignment = builder
2692 .ins()
2693 .band_imm(effective_addr, i64::from(loaded_bytes - 1));
2694 let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0);
2695 builder.ins().trapnz(f, ir::TrapCode::HeapMisaligned);
2696 }
2697}
2698
2699fn prepare_atomic_addr<FE: FuncEnvironment + ?Sized>(
2703 memarg: &MemArg,
2704 loaded_bytes: u8,
2705 builder: &mut FunctionBuilder,
2706 state: &mut FuncTranslationState,
2707 environ: &mut FE,
2708) -> WasmResult<Reachability<(MemFlags, Value)>> {
2709 align_atomic_addr(memarg, loaded_bytes, builder, state);
2710 prepare_addr(memarg, loaded_bytes, builder, state, environ)
2711}
2712
2713#[derive(PartialEq, Eq)]
2719#[must_use]
2720pub enum Reachability<T> {
2721 Reachable(T),
2723 Unreachable,
2727}
2728
2729fn translate_load<FE: FuncEnvironment + ?Sized>(
2733 memarg: &MemArg,
2734 opcode: ir::Opcode,
2735 result_ty: Type,
2736 builder: &mut FunctionBuilder,
2737 state: &mut FuncTranslationState,
2738 environ: &mut FE,
2739) -> WasmResult<Reachability<()>> {
2740 let (flags, base) = match prepare_addr(
2741 memarg,
2742 mem_op_size(opcode, result_ty),
2743 builder,
2744 state,
2745 environ,
2746 )? {
2747 Reachability::Unreachable => return Ok(Reachability::Unreachable),
2748 Reachability::Reachable((f, b)) => (f, b),
2749 };
2750 let (load, dfg) = builder
2751 .ins()
2752 .Load(opcode, result_ty, flags, Offset32::new(0), base);
2753 state.push1(dfg.first_result(load));
2754 Ok(Reachability::Reachable(()))
2755}
2756
2757fn translate_store<FE: FuncEnvironment + ?Sized>(
2759 memarg: &MemArg,
2760 opcode: ir::Opcode,
2761 builder: &mut FunctionBuilder,
2762 state: &mut FuncTranslationState,
2763 environ: &mut FE,
2764) -> WasmResult<()> {
2765 let val = state.pop1();
2766 let val_ty = builder.func.dfg.value_type(val);
2767
2768 let (flags, base) = unwrap_or_return_unreachable_state!(
2769 state,
2770 prepare_addr(memarg, mem_op_size(opcode, val_ty), builder, state, environ)?
2771 );
2772 builder
2773 .ins()
2774 .Store(opcode, val_ty, flags, Offset32::new(0), val, base);
2775 Ok(())
2776}
2777
2778fn mem_op_size(opcode: ir::Opcode, ty: Type) -> u8 {
2779 match opcode {
2780 ir::Opcode::Istore8 | ir::Opcode::Sload8 | ir::Opcode::Uload8 => 1,
2781 ir::Opcode::Istore16 | ir::Opcode::Sload16 | ir::Opcode::Uload16 => 2,
2782 ir::Opcode::Istore32 | ir::Opcode::Sload32 | ir::Opcode::Uload32 => 4,
2783 ir::Opcode::Store | ir::Opcode::Load => u8::try_from(ty.bytes()).unwrap(),
2784 _ => panic!("unknown size of mem op for {:?}", opcode),
2785 }
2786}
2787
2788fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
2789 let (arg0, arg1) = state.pop2();
2790 let val = builder.ins().icmp(cc, arg0, arg1);
2791 state.push1(builder.ins().uextend(I32, val));
2792}
2793
2794fn translate_atomic_rmw<FE: FuncEnvironment + ?Sized>(
2795 widened_ty: Type,
2796 access_ty: Type,
2797 op: AtomicRmwOp,
2798 memarg: &MemArg,
2799 builder: &mut FunctionBuilder,
2800 state: &mut FuncTranslationState,
2801 environ: &mut FE,
2802) -> WasmResult<()> {
2803 let mut arg2 = state.pop1();
2804 let arg2_ty = builder.func.dfg.value_type(arg2);
2805
2806 match access_ty {
2809 I8 | I16 | I32 | I64 => {}
2810 _ => {
2811 return Err(wasm_unsupported!(
2812 "atomic_rmw: unsupported access type {:?}",
2813 access_ty
2814 ))
2815 }
2816 };
2817 let w_ty_ok = match widened_ty {
2818 I32 | I64 => true,
2819 _ => false,
2820 };
2821 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2822
2823 assert!(arg2_ty.bytes() >= access_ty.bytes());
2824 if arg2_ty.bytes() > access_ty.bytes() {
2825 arg2 = builder.ins().ireduce(access_ty, arg2);
2826 }
2827
2828 let (flags, addr) = unwrap_or_return_unreachable_state!(
2829 state,
2830 prepare_atomic_addr(
2831 memarg,
2832 u8::try_from(access_ty.bytes()).unwrap(),
2833 builder,
2834 state,
2835 environ,
2836 )?
2837 );
2838
2839 let mut res = builder.ins().atomic_rmw(access_ty, flags, op, addr, arg2);
2840 if access_ty != widened_ty {
2841 res = builder.ins().uextend(widened_ty, res);
2842 }
2843 state.push1(res);
2844 Ok(())
2845}
2846
2847fn translate_atomic_cas<FE: FuncEnvironment + ?Sized>(
2848 widened_ty: Type,
2849 access_ty: Type,
2850 memarg: &MemArg,
2851 builder: &mut FunctionBuilder,
2852 state: &mut FuncTranslationState,
2853 environ: &mut FE,
2854) -> WasmResult<()> {
2855 let (mut expected, mut replacement) = state.pop2();
2856 let expected_ty = builder.func.dfg.value_type(expected);
2857 let replacement_ty = builder.func.dfg.value_type(replacement);
2858
2859 match access_ty {
2862 I8 | I16 | I32 | I64 => {}
2863 _ => {
2864 return Err(wasm_unsupported!(
2865 "atomic_cas: unsupported access type {:?}",
2866 access_ty
2867 ))
2868 }
2869 };
2870 let w_ty_ok = match widened_ty {
2871 I32 | I64 => true,
2872 _ => false,
2873 };
2874 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2875
2876 assert!(expected_ty.bytes() >= access_ty.bytes());
2877 if expected_ty.bytes() > access_ty.bytes() {
2878 expected = builder.ins().ireduce(access_ty, expected);
2879 }
2880 assert!(replacement_ty.bytes() >= access_ty.bytes());
2881 if replacement_ty.bytes() > access_ty.bytes() {
2882 replacement = builder.ins().ireduce(access_ty, replacement);
2883 }
2884
2885 let (flags, addr) = unwrap_or_return_unreachable_state!(
2886 state,
2887 prepare_atomic_addr(
2888 memarg,
2889 u8::try_from(access_ty.bytes()).unwrap(),
2890 builder,
2891 state,
2892 environ,
2893 )?
2894 );
2895 let mut res = builder.ins().atomic_cas(flags, addr, expected, replacement);
2896 if access_ty != widened_ty {
2897 res = builder.ins().uextend(widened_ty, res);
2898 }
2899 state.push1(res);
2900 Ok(())
2901}
2902
2903fn translate_atomic_load<FE: FuncEnvironment + ?Sized>(
2904 widened_ty: Type,
2905 access_ty: Type,
2906 memarg: &MemArg,
2907 builder: &mut FunctionBuilder,
2908 state: &mut FuncTranslationState,
2909 environ: &mut FE,
2910) -> WasmResult<()> {
2911 match access_ty {
2914 I8 | I16 | I32 | I64 => {}
2915 _ => {
2916 return Err(wasm_unsupported!(
2917 "atomic_load: unsupported access type {:?}",
2918 access_ty
2919 ))
2920 }
2921 };
2922 let w_ty_ok = match widened_ty {
2923 I32 | I64 => true,
2924 _ => false,
2925 };
2926 assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());
2927
2928 let (flags, addr) = unwrap_or_return_unreachable_state!(
2929 state,
2930 prepare_atomic_addr(
2931 memarg,
2932 u8::try_from(access_ty.bytes()).unwrap(),
2933 builder,
2934 state,
2935 environ,
2936 )?
2937 );
2938 let mut res = builder.ins().atomic_load(access_ty, flags, addr);
2939 if access_ty != widened_ty {
2940 res = builder.ins().uextend(widened_ty, res);
2941 }
2942 state.push1(res);
2943 Ok(())
2944}
2945
2946fn translate_atomic_store<FE: FuncEnvironment + ?Sized>(
2947 access_ty: Type,
2948 memarg: &MemArg,
2949 builder: &mut FunctionBuilder,
2950 state: &mut FuncTranslationState,
2951 environ: &mut FE,
2952) -> WasmResult<()> {
2953 let mut data = state.pop1();
2954 let data_ty = builder.func.dfg.value_type(data);
2955
2956 match access_ty {
2959 I8 | I16 | I32 | I64 => {}
2960 _ => {
2961 return Err(wasm_unsupported!(
2962 "atomic_store: unsupported access type {:?}",
2963 access_ty
2964 ))
2965 }
2966 };
2967 let d_ty_ok = match data_ty {
2968 I32 | I64 => true,
2969 _ => false,
2970 };
2971 assert!(d_ty_ok && data_ty.bytes() >= access_ty.bytes());
2972
2973 if data_ty.bytes() > access_ty.bytes() {
2974 data = builder.ins().ireduce(access_ty, data);
2975 }
2976
2977 let (flags, addr) = unwrap_or_return_unreachable_state!(
2978 state,
2979 prepare_atomic_addr(
2980 memarg,
2981 u8::try_from(access_ty.bytes()).unwrap(),
2982 builder,
2983 state,
2984 environ,
2985 )?
2986 );
2987 builder.ins().atomic_store(flags, data, addr);
2988 Ok(())
2989}
2990
2991fn translate_vector_icmp(
2992 cc: IntCC,
2993 needed_type: Type,
2994 builder: &mut FunctionBuilder,
2995 state: &mut FuncTranslationState,
2996) {
2997 let (a, b) = state.pop2();
2998 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
2999 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3000 state.push1(builder.ins().icmp(cc, bitcast_a, bitcast_b))
3001}
3002
3003fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
3004 let (arg0, arg1) = state.pop2();
3005 let val = builder.ins().fcmp(cc, arg0, arg1);
3006 state.push1(builder.ins().uextend(I32, val));
3007}
3008
3009fn translate_vector_fcmp(
3010 cc: FloatCC,
3011 needed_type: Type,
3012 builder: &mut FunctionBuilder,
3013 state: &mut FuncTranslationState,
3014) {
3015 let (a, b) = state.pop2();
3016 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3017 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3018 state.push1(builder.ins().fcmp(cc, bitcast_a, bitcast_b))
3019}
3020
3021fn translate_br_if(
3022 relative_depth: u32,
3023 builder: &mut FunctionBuilder,
3024 state: &mut FuncTranslationState,
3025) {
3026 let val = state.pop1();
3027 let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
3028 let next_block = builder.create_block();
3029 canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]);
3030
3031 builder.seal_block(next_block); builder.switch_to_block(next_block);
3033}
3034
3035fn translate_br_if_args(
3036 relative_depth: u32,
3037 state: &mut FuncTranslationState,
3038) -> (ir::Block, &mut [ir::Value]) {
3039 let i = state.control_stack.len() - 1 - (relative_depth as usize);
3040 let (return_count, br_destination) = {
3041 let frame = &mut state.control_stack[i];
3042 frame.set_branched_to_exit();
3045 let return_count = if frame.is_loop() {
3046 frame.num_param_values()
3047 } else {
3048 frame.num_return_values()
3049 };
3050 (return_count, frame.br_destination())
3051 };
3052 let inputs = state.peekn_mut(return_count);
3053 (br_destination, inputs)
3054}
3055
3056fn type_of(operator: &Operator) -> Type {
3058 match operator {
3059 Operator::V128Load { .. }
3060 | Operator::V128Store { .. }
3061 | Operator::V128Const { .. }
3062 | Operator::V128Not
3063 | Operator::V128And
3064 | Operator::V128AndNot
3065 | Operator::V128Or
3066 | Operator::V128Xor
3067 | Operator::V128AnyTrue
3068 | Operator::V128Bitselect => I8X16, Operator::I8x16Shuffle { .. }
3071 | Operator::I8x16Splat
3072 | Operator::V128Load8Splat { .. }
3073 | Operator::V128Load8Lane { .. }
3074 | Operator::V128Store8Lane { .. }
3075 | Operator::I8x16ExtractLaneS { .. }
3076 | Operator::I8x16ExtractLaneU { .. }
3077 | Operator::I8x16ReplaceLane { .. }
3078 | Operator::I8x16Eq
3079 | Operator::I8x16Ne
3080 | Operator::I8x16LtS
3081 | Operator::I8x16LtU
3082 | Operator::I8x16GtS
3083 | Operator::I8x16GtU
3084 | Operator::I8x16LeS
3085 | Operator::I8x16LeU
3086 | Operator::I8x16GeS
3087 | Operator::I8x16GeU
3088 | Operator::I8x16Neg
3089 | Operator::I8x16Abs
3090 | Operator::I8x16AllTrue
3091 | Operator::I8x16Shl
3092 | Operator::I8x16ShrS
3093 | Operator::I8x16ShrU
3094 | Operator::I8x16Add
3095 | Operator::I8x16AddSatS
3096 | Operator::I8x16AddSatU
3097 | Operator::I8x16Sub
3098 | Operator::I8x16SubSatS
3099 | Operator::I8x16SubSatU
3100 | Operator::I8x16MinS
3101 | Operator::I8x16MinU
3102 | Operator::I8x16MaxS
3103 | Operator::I8x16MaxU
3104 | Operator::I8x16AvgrU
3105 | Operator::I8x16Bitmask
3106 | Operator::I8x16Popcnt
3107 | Operator::I8x16RelaxedLaneselect => I8X16,
3108
3109 Operator::I16x8Splat
3110 | Operator::V128Load16Splat { .. }
3111 | Operator::V128Load16Lane { .. }
3112 | Operator::V128Store16Lane { .. }
3113 | Operator::I16x8ExtractLaneS { .. }
3114 | Operator::I16x8ExtractLaneU { .. }
3115 | Operator::I16x8ReplaceLane { .. }
3116 | Operator::I16x8Eq
3117 | Operator::I16x8Ne
3118 | Operator::I16x8LtS
3119 | Operator::I16x8LtU
3120 | Operator::I16x8GtS
3121 | Operator::I16x8GtU
3122 | Operator::I16x8LeS
3123 | Operator::I16x8LeU
3124 | Operator::I16x8GeS
3125 | Operator::I16x8GeU
3126 | Operator::I16x8Neg
3127 | Operator::I16x8Abs
3128 | Operator::I16x8AllTrue
3129 | Operator::I16x8Shl
3130 | Operator::I16x8ShrS
3131 | Operator::I16x8ShrU
3132 | Operator::I16x8Add
3133 | Operator::I16x8AddSatS
3134 | Operator::I16x8AddSatU
3135 | Operator::I16x8Sub
3136 | Operator::I16x8SubSatS
3137 | Operator::I16x8SubSatU
3138 | Operator::I16x8MinS
3139 | Operator::I16x8MinU
3140 | Operator::I16x8MaxS
3141 | Operator::I16x8MaxU
3142 | Operator::I16x8AvgrU
3143 | Operator::I16x8Mul
3144 | Operator::I16x8Bitmask
3145 | Operator::I16x8RelaxedLaneselect => I16X8,
3146
3147 Operator::I32x4Splat
3148 | Operator::V128Load32Splat { .. }
3149 | Operator::V128Load32Lane { .. }
3150 | Operator::V128Store32Lane { .. }
3151 | Operator::I32x4ExtractLane { .. }
3152 | Operator::I32x4ReplaceLane { .. }
3153 | Operator::I32x4Eq
3154 | Operator::I32x4Ne
3155 | Operator::I32x4LtS
3156 | Operator::I32x4LtU
3157 | Operator::I32x4GtS
3158 | Operator::I32x4GtU
3159 | Operator::I32x4LeS
3160 | Operator::I32x4LeU
3161 | Operator::I32x4GeS
3162 | Operator::I32x4GeU
3163 | Operator::I32x4Neg
3164 | Operator::I32x4Abs
3165 | Operator::I32x4AllTrue
3166 | Operator::I32x4Shl
3167 | Operator::I32x4ShrS
3168 | Operator::I32x4ShrU
3169 | Operator::I32x4Add
3170 | Operator::I32x4Sub
3171 | Operator::I32x4Mul
3172 | Operator::I32x4MinS
3173 | Operator::I32x4MinU
3174 | Operator::I32x4MaxS
3175 | Operator::I32x4MaxU
3176 | Operator::I32x4Bitmask
3177 | Operator::I32x4TruncSatF32x4S
3178 | Operator::I32x4TruncSatF32x4U
3179 | Operator::I32x4RelaxedLaneselect
3180 | Operator::V128Load32Zero { .. } => I32X4,
3181
3182 Operator::I64x2Splat
3183 | Operator::V128Load64Splat { .. }
3184 | Operator::V128Load64Lane { .. }
3185 | Operator::V128Store64Lane { .. }
3186 | Operator::I64x2ExtractLane { .. }
3187 | Operator::I64x2ReplaceLane { .. }
3188 | Operator::I64x2Eq
3189 | Operator::I64x2Ne
3190 | Operator::I64x2LtS
3191 | Operator::I64x2GtS
3192 | Operator::I64x2LeS
3193 | Operator::I64x2GeS
3194 | Operator::I64x2Neg
3195 | Operator::I64x2Abs
3196 | Operator::I64x2AllTrue
3197 | Operator::I64x2Shl
3198 | Operator::I64x2ShrS
3199 | Operator::I64x2ShrU
3200 | Operator::I64x2Add
3201 | Operator::I64x2Sub
3202 | Operator::I64x2Mul
3203 | Operator::I64x2Bitmask
3204 | Operator::I64x2RelaxedLaneselect
3205 | Operator::V128Load64Zero { .. } => I64X2,
3206
3207 Operator::F32x4Splat
3208 | Operator::F32x4ExtractLane { .. }
3209 | Operator::F32x4ReplaceLane { .. }
3210 | Operator::F32x4Eq
3211 | Operator::F32x4Ne
3212 | Operator::F32x4Lt
3213 | Operator::F32x4Gt
3214 | Operator::F32x4Le
3215 | Operator::F32x4Ge
3216 | Operator::F32x4Abs
3217 | Operator::F32x4Neg
3218 | Operator::F32x4Sqrt
3219 | Operator::F32x4Add
3220 | Operator::F32x4Sub
3221 | Operator::F32x4Mul
3222 | Operator::F32x4Div
3223 | Operator::F32x4Min
3224 | Operator::F32x4Max
3225 | Operator::F32x4PMin
3226 | Operator::F32x4PMax
3227 | Operator::F32x4ConvertI32x4S
3228 | Operator::F32x4ConvertI32x4U
3229 | Operator::F32x4Ceil
3230 | Operator::F32x4Floor
3231 | Operator::F32x4Trunc
3232 | Operator::F32x4Nearest
3233 | Operator::F32x4RelaxedMax
3234 | Operator::F32x4RelaxedMin
3235 | Operator::F32x4RelaxedMadd
3236 | Operator::F32x4RelaxedNmadd => F32X4,
3237
3238 Operator::F64x2Splat
3239 | Operator::F64x2ExtractLane { .. }
3240 | Operator::F64x2ReplaceLane { .. }
3241 | Operator::F64x2Eq
3242 | Operator::F64x2Ne
3243 | Operator::F64x2Lt
3244 | Operator::F64x2Gt
3245 | Operator::F64x2Le
3246 | Operator::F64x2Ge
3247 | Operator::F64x2Abs
3248 | Operator::F64x2Neg
3249 | Operator::F64x2Sqrt
3250 | Operator::F64x2Add
3251 | Operator::F64x2Sub
3252 | Operator::F64x2Mul
3253 | Operator::F64x2Div
3254 | Operator::F64x2Min
3255 | Operator::F64x2Max
3256 | Operator::F64x2PMin
3257 | Operator::F64x2PMax
3258 | Operator::F64x2Ceil
3259 | Operator::F64x2Floor
3260 | Operator::F64x2Trunc
3261 | Operator::F64x2Nearest
3262 | Operator::F64x2RelaxedMax
3263 | Operator::F64x2RelaxedMin
3264 | Operator::F64x2RelaxedMadd
3265 | Operator::F64x2RelaxedNmadd => F64X2,
3266
3267 _ => unimplemented!(
3268 "Currently only SIMD instructions are mapped to their return type; the \
3269 following instruction is not mapped: {:?}",
3270 operator
3271 ),
3272 }
3273}
3274
3275fn optionally_bitcast_vector(
3278 value: Value,
3279 needed_type: Type,
3280 builder: &mut FunctionBuilder,
3281) -> Value {
3282 if builder.func.dfg.value_type(value) != needed_type {
3283 let mut flags = MemFlags::new();
3284 flags.set_endianness(ir::Endianness::Little);
3285 builder.ins().bitcast(needed_type, flags, value)
3286 } else {
3287 value
3288 }
3289}
3290
3291#[inline(always)]
3292fn is_non_canonical_v128(ty: ir::Type) -> bool {
3293 match ty {
3294 I64X2 | I32X4 | I16X8 | F32X4 | F64X2 => true,
3295 _ => false,
3296 }
3297}
3298
3299fn canonicalise_v128_values<'a>(
3304 tmp_canonicalised: &'a mut SmallVec<[ir::Value; 16]>,
3305 builder: &mut FunctionBuilder,
3306 values: &'a [ir::Value],
3307) -> &'a [ir::Value] {
3308 debug_assert!(tmp_canonicalised.is_empty());
3309 let any_non_canonical = values
3311 .iter()
3312 .any(|v| is_non_canonical_v128(builder.func.dfg.value_type(*v)));
3313 if !any_non_canonical {
3315 return values;
3316 }
3317 for v in values {
3319 tmp_canonicalised.push(if is_non_canonical_v128(builder.func.dfg.value_type(*v)) {
3320 let mut flags = MemFlags::new();
3321 flags.set_endianness(ir::Endianness::Little);
3322 builder.ins().bitcast(I8X16, flags, *v)
3323 } else {
3324 *v
3325 });
3326 }
3327 tmp_canonicalised.as_slice()
3328}
3329
3330fn canonicalise_then_jump(
3334 builder: &mut FunctionBuilder,
3335 destination: ir::Block,
3336 params: &[ir::Value],
3337) -> ir::Inst {
3338 let mut tmp_canonicalised = SmallVec::<[ir::Value; 16]>::new();
3339 let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params);
3340 builder.ins().jump(destination, canonicalised)
3341}
3342
3343fn canonicalise_brif(
3345 builder: &mut FunctionBuilder,
3346 cond: ir::Value,
3347 block_then: ir::Block,
3348 params_then: &[ir::Value],
3349 block_else: ir::Block,
3350 params_else: &[ir::Value],
3351) -> ir::Inst {
3352 let mut tmp_canonicalised_then = SmallVec::<[ir::Value; 16]>::new();
3353 let canonicalised_then =
3354 canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then);
3355 let mut tmp_canonicalised_else = SmallVec::<[ir::Value; 16]>::new();
3356 let canonicalised_else =
3357 canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else);
3358 builder.ins().brif(
3359 cond,
3360 block_then,
3361 canonicalised_then,
3362 block_else,
3363 canonicalised_else,
3364 )
3365}
3366
3367fn pop1_with_bitcast(
3371 state: &mut FuncTranslationState,
3372 needed_type: Type,
3373 builder: &mut FunctionBuilder,
3374) -> Value {
3375 optionally_bitcast_vector(state.pop1(), needed_type, builder)
3376}
3377
3378fn pop2_with_bitcast(
3382 state: &mut FuncTranslationState,
3383 needed_type: Type,
3384 builder: &mut FunctionBuilder,
3385) -> (Value, Value) {
3386 let (a, b) = state.pop2();
3387 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3388 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3389 (bitcast_a, bitcast_b)
3390}
3391
3392fn pop3_with_bitcast(
3393 state: &mut FuncTranslationState,
3394 needed_type: Type,
3395 builder: &mut FunctionBuilder,
3396) -> (Value, Value, Value) {
3397 let (a, b, c) = state.pop3();
3398 let bitcast_a = optionally_bitcast_vector(a, needed_type, builder);
3399 let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
3400 let bitcast_c = optionally_bitcast_vector(c, needed_type, builder);
3401 (bitcast_a, bitcast_b, bitcast_c)
3402}
3403
3404fn bitcast_arguments<'a>(
3405 builder: &FunctionBuilder,
3406 arguments: &'a mut [Value],
3407 params: &[ir::AbiParam],
3408 param_predicate: impl Fn(usize) -> bool,
3409) -> Vec<(Type, &'a mut Value)> {
3410 let filtered_param_types = params
3411 .iter()
3412 .enumerate()
3413 .filter(|(i, _)| param_predicate(*i))
3414 .map(|(_, param)| param.value_type);
3415
3416 let pairs = filtered_param_types.zip_eq(arguments.iter_mut());
3420
3421 pairs
3424 .filter(|(param_type, _)| param_type.is_vector())
3425 .filter(|(param_type, arg)| {
3426 let arg_type = builder.func.dfg.value_type(**arg);
3427 assert!(
3428 arg_type.is_vector(),
3429 "unexpected type mismatch: expected {}, argument {} was actually of type {}",
3430 param_type,
3431 *arg,
3432 arg_type
3433 );
3434
3435 arg_type != *param_type
3439 })
3440 .collect()
3441}
3442
3443pub fn bitcast_wasm_returns<FE: FuncEnvironment + ?Sized>(
3449 environ: &mut FE,
3450 arguments: &mut [Value],
3451 builder: &mut FunctionBuilder,
3452) {
3453 let changes = bitcast_arguments(builder, arguments, &builder.func.signature.returns, |i| {
3454 environ.is_wasm_return(&builder.func.signature, i)
3455 });
3456 for (t, arg) in changes {
3457 let mut flags = MemFlags::new();
3458 flags.set_endianness(ir::Endianness::Little);
3459 *arg = builder.ins().bitcast(t, flags, *arg);
3460 }
3461}
3462
3463fn bitcast_wasm_params<FE: FuncEnvironment + ?Sized>(
3465 environ: &mut FE,
3466 callee_signature: ir::SigRef,
3467 arguments: &mut [Value],
3468 builder: &mut FunctionBuilder,
3469) {
3470 let callee_signature = &builder.func.dfg.signatures[callee_signature];
3471 let changes = bitcast_arguments(builder, arguments, &callee_signature.params, |i| {
3472 environ.is_wasm_parameter(&callee_signature, i)
3473 });
3474 for (t, arg) in changes {
3475 let mut flags = MemFlags::new();
3476 flags.set_endianness(ir::Endianness::Little);
3477 *arg = builder.ins().bitcast(t, flags, *arg);
3478 }
3479}