22//!
33//! These macros are used to generate the actual instruction implementations.
44
5+ /// Load a value from memory
56macro_rules! mem_load {
67 ( $type: ty, $arg: ident, $stack: ident, $store: ident, $module: ident) => { {
78 mem_load!( $type, $type, $arg, $stack, $store, $module)
89 } } ;
910
1011 ( $load_type: ty, $target_type: ty, $arg: ident, $stack: ident, $store: ident, $module: ident) => { {
12+ // TODO: there could be a lot of performance improvements here
1113 let mem_idx = $module. resolve_mem_addr( $arg. mem_addr) ;
1214 let mem = $store. get_mem( mem_idx as usize ) ?;
1315
@@ -28,14 +30,6 @@ macro_rules! mem_load {
2830 } } ;
2931}
3032
31- /// Convert the top value on the stack to a specific type
32- macro_rules! conv_1 {
33- ( $from: ty, $to: ty, $stack: ident) => { {
34- let a: $from = $stack. values. pop( ) ?. into( ) ;
35- $stack. values. push( ( a as $to) . into( ) ) ;
36- } } ;
37- }
38-
3933/// Doing the actual conversion from float to int is a bit tricky, because
4034/// we need to check for overflow. This macro generates the min/max values
4135/// for a specific conversion, which are then used in the actual conversion.
@@ -71,75 +65,56 @@ macro_rules! float_min_max {
7165 } ;
7266}
7367
74- // Convert a float to an int, checking for overflow
75- macro_rules! checked_float_conv_1 {
76- ( $from: tt, $to: tt, $stack: ident) => { {
77- let ( min, max) = float_min_max!( $from, $to) ;
68+ /// Convert a value on the stack
69+ macro_rules! conv {
70+ ( $from: ty, $intermediate: ty, $to: ty, $stack: ident) => { {
71+ let a: $from = $stack. values. pop( ) ?. into( ) ;
72+ $stack. values. push( ( a as $intermediate as $to) . into( ) ) ;
73+ } } ;
74+ ( $from: ty, $to: ty, $stack: ident) => { {
7875 let a: $from = $stack. values. pop( ) ?. into( ) ;
79-
80- if a. is_nan( ) {
81- return Err ( Error :: Trap ( crate :: Trap :: InvalidConversionToInt ) ) ;
82- }
83-
84- if a <= min || a >= max {
85- return Err ( Error :: Trap ( crate :: Trap :: IntegerOverflow ) ) ;
86- }
87-
8876 $stack. values. push( ( a as $to) . into( ) ) ;
8977 } } ;
9078}
9179
92- // Convert a float to an int, checking for overflow
93- macro_rules! checked_float_conv_2 {
94- ( $from: tt, $uty: tt, $to: tt, $stack: ident) => { {
95- let ( min, max) = float_min_max!( $from, $uty) ;
80+ /// Convert a value on the stack with error checking
81+ macro_rules! checked_conv_float {
82+ // Direct conversion with error checking (two types)
83+ ( $from: tt, $to: tt, $stack: ident) => { {
84+ checked_conv_float!( $from, $to, $to, $stack)
85+ } } ;
86+ // Conversion with an intermediate unsigned type and error checking (three types)
87+ ( $from: tt, $intermediate: tt, $to: tt, $stack: ident) => { {
88+ let ( min, max) = float_min_max!( $from, $intermediate) ;
9689 let a: $from = $stack. values. pop( ) ?. into( ) ;
9790
9891 if a. is_nan( ) {
9992 return Err ( Error :: Trap ( crate :: Trap :: InvalidConversionToInt ) ) ;
10093 }
10194
102- log:: info!( "a: {}" , a) ;
103- log:: info!( "min: {}" , min) ;
104- log:: info!( "max: {}" , max) ;
105-
10695 if a <= min || a >= max {
10796 return Err ( Error :: Trap ( crate :: Trap :: IntegerOverflow ) ) ;
10897 }
10998
110- $stack. values. push( ( a as $uty as $to) . into( ) ) ;
111- } } ;
112- }
113-
114- /// Convert the unsigned value on the top of the stack to a specific type
115- macro_rules! conv_2 {
116- ( $ty: ty, $uty: ty, $to: ty, $stack: ident) => { {
117- let a: $ty = $stack. values. pop( ) ?. into( ) ;
118- $stack. values. push( ( a as $uty as $to) . into( ) ) ;
99+ $stack. values. push( ( a as $intermediate as $to) . into( ) ) ;
119100 } } ;
120101}
121102
122103/// Compare two values on the stack
123104macro_rules! comp {
124105 ( $op: tt, $ty: ty, $stack: ident) => { {
125- let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
126- let a: $ty = a. into( ) ;
127- let b: $ty = b. into( ) ;
128- $stack. values. push( ( ( a $op b) as i32 ) . into( ) ) ;
106+ comp!( $op, $ty, $ty, $stack)
129107 } } ;
130- }
131108
132- /// Compare two values on the stack (cast to ty2 before comparison)
133- macro_rules! comp_cast {
134- ( $op: tt, $ty: ty, $ty2: ty, $stack: ident) => { {
109+ ( $op: tt, $intermediate: ty, $to: ty, $stack: ident) => { {
135110 let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
136- let a: $ty = a. into( ) ;
137- let b: $ty = b. into( ) ;
111+ let a: $intermediate = a. into( ) ;
112+ let b: $intermediate = b. into( ) ;
138113
139114 // Cast to unsigned type before comparison
140- let a_unsigned : $ty2 = a as $ty2 ;
141- let b_unsigned : $ty2 = b as $ty2 ;
142- $stack. values. push( ( ( a_unsigned $op b_unsigned ) as i32 ) . into( ) ) ;
115+ let a = a as $to ;
116+ let b = b as $to ;
117+ $stack. values. push( ( ( a $op b ) as i32 ) . into( ) ) ;
143118 } } ;
144119}
145120
@@ -151,95 +126,70 @@ macro_rules! comp_zero {
151126 } } ;
152127}
153128
154- /// Apply an arithmetic operation to two values on the stack
155- macro_rules! arithmetic_op {
129+ /// Apply an arithmetic method to two values on the stack
130+ macro_rules! arithmetic {
131+ ( $op: ident, $ty: ty, $stack: ident) => { {
132+ arithmetic!( $op, $ty, $ty, $stack)
133+ } } ;
134+
135+ // also allow operators such as +, -
156136 ( $op: tt, $ty: ty, $stack: ident) => { {
157137 let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
158138 let a: $ty = a. into( ) ;
159139 let b: $ty = b. into( ) ;
160140 $stack. values. push( ( a $op b) . into( ) ) ;
161141 } } ;
162- }
163142
164- macro_rules! arithmetic_method {
165- ( $op: ident, $ty: ty, $stack: ident) => { {
143+ ( $op: ident, $intermediate: ty, $to: ty, $stack: ident) => { {
166144 let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
167- let a: $ty = a. into( ) ;
168- let b: $ty = b. into( ) ;
145+ let a: $to = a. into( ) ;
146+ let b: $to = b. into( ) ;
147+
148+ let a = a as $intermediate;
149+ let b = b as $intermediate;
150+
169151 let result = a. $op( b) ;
170- $stack. values. push( result. into( ) ) ;
152+ $stack. values. push( ( result as $to ) . into( ) ) ;
171153 } } ;
172154}
173155
174- macro_rules! arithmetic_method_self {
156+ /// Apply an arithmetic method to a single value on the stack
157+ macro_rules! arithmetic_single {
175158 ( $op: ident, $ty: ty, $stack: ident) => { {
176159 let a: $ty = $stack. values. pop( ) ?. into( ) ;
177160 let result = a. $op( ) ;
178161 $stack. values. push( ( result as $ty) . into( ) ) ;
179162 } } ;
180163}
181164
182- macro_rules! arithmetic_method_cast {
183- ( $op: ident, $ty: ty, $ty2: ty, $stack: ident) => { {
184- let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
185- let a: $ty = a. into( ) ;
186- let b: $ty = b. into( ) ;
187-
188- // Cast to unsigned type before operation
189- let a_unsigned: $ty2 = a as $ty2;
190- let b_unsigned: $ty2 = b as $ty2;
191-
192- let result = a_unsigned. $op( b_unsigned) ;
193- $stack. values. push( ( result as $ty) . into( ) ) ;
165+ /// Apply an arithmetic operation to two values on the stack with error checking
166+ macro_rules! checked_arithmetic {
167+ // Direct conversion with error checking (two types)
168+ ( $from: tt, $to: tt, $stack: ident, $trap: expr) => { {
169+ checked_arithmetic!( $from, $to, $to, $stack, $trap)
194170 } } ;
195- }
196171
197- /// Apply an arithmetic operation to two values on the stack
198- macro_rules! checked_arithmetic_method {
199- ( $op: ident, $ty: ty, $stack: ident, $trap: expr) => { {
172+ ( $op: ident, $from: ty, $to: ty, $stack: ident, $trap: expr) => { {
200173 let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
201- let a: $ty = a. into( ) ;
202- let b: $ty = b. into( ) ;
203- let result = a. $op( b) . ok_or_else( || Error :: Trap ( $trap) ) ?;
204- debug!(
205- "checked_arithmetic_method: {}, a: {}, b: {}, res: {}" ,
206- stringify!( $op) ,
207- a,
208- b,
209- result
210- ) ;
211- $stack. values. push( result. into( ) ) ;
212- } } ;
213- }
174+ let a: $from = a. into( ) ;
175+ let b: $from = b. into( ) ;
214176
215- /// Apply an arithmetic operation to two values on the stack (cast to ty2 before operation)
216- macro_rules! checked_arithmetic_method_cast {
217- ( $op: ident, $ty: ty, $ty2: ty, $stack: ident, $trap: expr) => { {
218- let [ a, b] = $stack. values. pop_n_const:: <2 >( ) ?;
219- let a: $ty = a. into( ) ;
220- let b: $ty = b. into( ) ;
177+ let a_casted: $to = a as $to;
178+ let b_casted: $to = b as $to;
221179
222- // Cast to unsigned type before operation
223- let a_unsigned: $ty2 = a as $ty2;
224- let b_unsigned: $ty2 = b as $ty2;
180+ let result = a_casted. $op( b_casted) . ok_or_else( || Error :: Trap ( $trap) ) ?;
225181
226- let result = a_unsigned . $op ( b_unsigned ) . ok_or_else ( || Error :: Trap ( $trap ) ) ? ;
227- $stack. values. push( ( result as $ty ) . into( ) ) ;
182+ // Cast back to original type if different
183+ $stack. values. push( ( result as $from ) . into( ) ) ;
228184 } } ;
229185}
230186
231- pub ( super ) use arithmetic_method;
232- pub ( super ) use arithmetic_method_cast;
233- pub ( super ) use arithmetic_method_self;
234- pub ( super ) use arithmetic_op;
235- pub ( super ) use checked_arithmetic_method;
236- pub ( super ) use checked_arithmetic_method_cast;
237- pub ( super ) use checked_float_conv_1;
238- pub ( super ) use checked_float_conv_2;
187+ pub ( super ) use arithmetic;
188+ pub ( super ) use arithmetic_single;
189+ pub ( super ) use checked_arithmetic;
190+ pub ( super ) use checked_conv_float;
239191pub ( super ) use comp;
240- pub ( super ) use comp_cast;
241192pub ( super ) use comp_zero;
242- pub ( super ) use conv_1;
243- pub ( super ) use conv_2;
193+ pub ( super ) use conv;
244194pub ( super ) use float_min_max;
245195pub ( super ) use mem_load;
0 commit comments