@@ -8,7 +8,7 @@ use crate::{
88 V128 ,
99 } ,
1010 engine:: { executor:: InstructionPtr , utils:: unreachable_unchecked} ,
11- ir:: { Instruction , Reg , ShiftAmount } ,
11+ ir:: { AnyConst32 , Instruction , Reg , ShiftAmount } ,
1212} ;
1313
1414impl Executor < ' _ > {
@@ -29,6 +29,60 @@ impl Executor<'_> {
2929 }
3030 }
3131
32+ /// Fetches a [`Reg`] from an [`Instruction::Const32`] instruction parameter.
33+ fn fetch_const32_as < T > ( & self ) -> T
34+ where
35+ T : From < AnyConst32 > ,
36+ {
37+ let mut addr: InstructionPtr = self . ip ;
38+ addr. add ( 1 ) ;
39+ match * addr. get ( ) {
40+ Instruction :: Const32 { value } => value. into ( ) ,
41+ unexpected => {
42+ // Safety: Wasmi translation guarantees that [`Instruction::Const32`] exists.
43+ unsafe {
44+ unreachable_unchecked ! (
45+ "expected `Instruction::Const32` but found {unexpected:?}"
46+ )
47+ }
48+ }
49+ }
50+ }
51+
52+ /// Fetches a [`Reg`] from an [`Instruction::I64Const32`] instruction parameter.
53+ fn fetch_i64const32 ( & self ) -> i64 {
54+ let mut addr: InstructionPtr = self . ip ;
55+ addr. add ( 1 ) ;
56+ match * addr. get ( ) {
57+ Instruction :: I64Const32 { value } => value. into ( ) ,
58+ unexpected => {
59+ // Safety: Wasmi translation guarantees that [`Instruction::I64Const32`] exists.
60+ unsafe {
61+ unreachable_unchecked ! (
62+ "expected `Instruction::I64Const32` but found {unexpected:?}"
63+ )
64+ }
65+ }
66+ }
67+ }
68+
69+ /// Fetches a [`Reg`] from an [`Instruction::F64Const32`] instruction parameter.
70+ fn fetch_f64const32 ( & self ) -> f64 {
71+ let mut addr: InstructionPtr = self . ip ;
72+ addr. add ( 1 ) ;
73+ match * addr. get ( ) {
74+ Instruction :: F64Const32 { value } => value. into ( ) ,
75+ unexpected => {
76+ // Safety: Wasmi translation guarantees that [`Instruction::F64Const32`] exists.
77+ unsafe {
78+ unreachable_unchecked ! (
79+ "expected `Instruction::F64Const32` but found {unexpected:?}"
80+ )
81+ }
82+ }
83+ }
84+ }
85+
3286 /// Executes an [`Instruction::I8x16Shuffle`] instruction.
3387 pub fn execute_i8x16_shuffle ( & mut self , result : Reg , lhs : Reg , rhs : Reg ) {
3488 let selector = self . fetch_register ( ) ;
@@ -60,6 +114,91 @@ impl Executor<'_> {
60114 self . set_register_as :: < V128 > ( result, simd:: v128_bitselect ( lhs, rhs, selector) ) ;
61115 self . next_instr_at ( 2 ) ;
62116 }
117+ }
118+
119+ macro_rules! impl_replace_lane_ops {
120+ (
121+ $(
122+ ( $ty: ty, $lane_ty: ty, Instruction :: $instr_name: ident, $exec_name: ident, $execute: expr)
123+ ) ,* $( , ) ?
124+ ) => {
125+ $(
126+ #[ doc = concat!( "Executes an [`Instruction::" , stringify!( $instr_name) , "`]." ) ]
127+ pub fn $exec_name( & mut self , result: Reg , input: Reg , lane: $lane_ty) {
128+ let value = self . fetch_register( ) ;
129+ let input = self . get_register_as:: <V128 >( input) ;
130+ let value = self . get_register_as:: <$ty>( value) ;
131+ self . set_register_as:: <V128 >( result, $execute( input, lane, value) ) ;
132+ self . next_instr_at( 2 ) ;
133+ }
134+ ) *
135+ } ;
136+ }
137+
138+ impl Executor < ' _ > {
139+ impl_replace_lane_ops ! {
140+ ( i8 , ImmLaneIdx16 , Instruction :: I8x16ReplaceLane , execute_i8x16_replace_lane, simd:: i8x16_replace_lane) ,
141+ ( i16 , ImmLaneIdx8 , Instruction :: I16x8ReplaceLane , execute_i16x8_replace_lane, simd:: i16x8_replace_lane) ,
142+ ( i32 , ImmLaneIdx4 , Instruction :: I32x4ReplaceLane , execute_i32x4_replace_lane, simd:: i32x4_replace_lane) ,
143+ ( i64 , ImmLaneIdx2 , Instruction :: I64x2ReplaceLane , execute_i64x2_replace_lane, simd:: i64x2_replace_lane) ,
144+ ( f32 , ImmLaneIdx4 , Instruction :: F32x4ReplaceLane , execute_f32x4_replace_lane, simd:: f32x4_replace_lane) ,
145+ ( f64 , ImmLaneIdx2 , Instruction :: F64x2ReplaceLane , execute_f64x2_replace_lane, simd:: f64x2_replace_lane) ,
146+ }
147+
148+ /// Executes an [`Instruction::I8x16ReplaceLaneImm`] instruction.
149+ pub fn execute_i8x16_replace_lane_imm (
150+ & mut self ,
151+ result : Reg ,
152+ input : Reg ,
153+ lane : ImmLaneIdx16 ,
154+ value : i8 ,
155+ ) {
156+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: i8x16_replace_lane)
157+ }
158+
159+ /// Executes an [`Instruction::I16x8ReplaceLaneImm`] instruction.
160+ pub fn execute_i16x8_replace_lane_imm ( & mut self , result : Reg , input : Reg , lane : ImmLaneIdx8 ) {
161+ let value = self . fetch_const32_as :: < i32 > ( ) as i16 ;
162+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: i16x8_replace_lane)
163+ }
164+
165+ /// Executes an [`Instruction::I32x4ReplaceLaneImm`] instruction.
166+ pub fn execute_i32x4_replace_lane_imm ( & mut self , result : Reg , input : Reg , lane : ImmLaneIdx4 ) {
167+ let value = self . fetch_const32_as :: < i32 > ( ) ;
168+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: i32x4_replace_lane)
169+ }
170+
171+ /// Executes an [`Instruction::I64x2ReplaceLaneImm32`] instruction.
172+ pub fn execute_i64x2_replace_lane_imm32 ( & mut self , result : Reg , input : Reg , lane : ImmLaneIdx2 ) {
173+ let value = self . fetch_i64const32 ( ) ;
174+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: i64x2_replace_lane)
175+ }
176+
177+ /// Executes an [`Instruction::F32x4ReplaceLaneImm`] instruction.
178+ pub fn execute_f32x4_replace_lane_imm ( & mut self , result : Reg , input : Reg , lane : ImmLaneIdx4 ) {
179+ let value = self . fetch_const32_as :: < f32 > ( ) ;
180+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: f32x4_replace_lane)
181+ }
182+
183+ /// Executes an [`Instruction::F64x2ReplaceLaneImm32`] instruction.
184+ pub fn execute_f64x2_replace_lane_imm32 ( & mut self , result : Reg , input : Reg , lane : ImmLaneIdx2 ) {
185+ let value = self . fetch_f64const32 ( ) ;
186+ self . execute_replace_lane_impl ( result, input, lane, value, simd:: f64x2_replace_lane)
187+ }
188+
189+ /// Generically execute a SIMD replace lane instruction.
190+ fn execute_replace_lane_impl < T , LaneType > (
191+ & mut self ,
192+ result : Reg ,
193+ input : Reg ,
194+ lane : LaneType ,
195+ value : T ,
196+ eval : fn ( V128 , LaneType , T ) -> V128 ,
197+ ) {
198+ let input = self . get_register_as :: < V128 > ( input) ;
199+ self . set_register_as :: < V128 > ( result, eval ( input, lane, value) ) ;
200+ self . next_instr_at ( 2 ) ;
201+ }
63202
64203 impl_unary_executors ! {
65204 ( Instruction :: V128AnyTrue , execute_v128_any_true, simd:: v128_any_true) ,
0 commit comments