1use core::ops::ControlFlow;
2
3use crate::{
4 assert_validated::UnwrapValidatedExt,
5 core::reader::types::opcode,
6 execution::interpreter_loop::{define_instruction_fn, Args},
7 value::{self, F32, F64},
8 TrapError,
9};
10
11define_instruction_fn! {
13 i32_const,
14 fuel_check = flat(opcode::I32_CONST),
15 |Args {
16 resumable, wasm, ..
17 }| {
18 let constant = wasm.read_var_i32().unwrap_validated();
19 trace!("Instruction: i32.const [] -> [{constant}]");
20 resumable.stack.push_value(constant.into())?;
21 Ok(ControlFlow::Continue(()))
22 }
23}
24
25define_instruction_fn! {
26 i64_const,
27 fuel_check = flat(opcode::I64_CONST),
28 |Args {
29 wasm, resumable, ..
30 }| {
31 let constant = wasm.read_var_i64().unwrap_validated();
32 trace!("Instruction: i64.const [] -> [{constant}]");
33 resumable.stack.push_value(constant.into())?;
34 Ok(ControlFlow::Continue(()))
35 }
36}
37
38define_instruction_fn! {
39 f32_const,
40 fuel_check = flat(opcode::F32_CONST),
41 |Args {
42 resumable, wasm, ..
43 }| {
44 let constant = F32::from_bits(wasm.read_f32().unwrap_validated());
45 trace!("Instruction: f32.const [] -> [{constant:.7}]");
46 resumable.stack.push_value(constant.into())?;
47 Ok(ControlFlow::Continue(()))
48 }
49}
50
51define_instruction_fn! {
52 f64_const,
53 fuel_check = flat(opcode::F64_CONST),
54 |Args {
55 wasm, resumable, ..
56 }| {
57 let constant = F64::from_bits(wasm.read_f64().unwrap_validated());
58 trace!("Instruction: f64.const [] -> [{constant}]");
59 resumable.stack.push_value(constant.into())?;
60 Ok(ControlFlow::Continue(()))
61 }
62}
63
64define_instruction_fn! {
66 i32_clz,
67 fuel_check = flat(opcode::I32_CLZ),
68 |Args { resumable, .. }| {
69 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
70 let res = v1.leading_zeros() as i32;
71
72 trace!("Instruction: i32.clz [{v1}] -> [{res}]");
73 resumable.stack.push_value(res.into())?;
74 Ok(ControlFlow::Continue(()))
75 }
76}
77
78define_instruction_fn! {
79 i32_ctz,
80 fuel_check = flat(opcode::I32_CTZ),
81 |Args { resumable, .. }| {
82 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
83 let res = v1.trailing_zeros() as i32;
84
85 trace!("Instruction: i32.ctz [{v1}] -> [{res}]");
86 resumable.stack.push_value(res.into())?;
87 Ok(ControlFlow::Continue(()))
88 }
89}
90
91define_instruction_fn! {
92 i32_popcnt,
93 fuel_check = flat(opcode::I32_POPCNT),
94 |Args { resumable, .. }| {
95 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
96 let res = v1.count_ones() as i32;
97
98 trace!("Instruction: i32.popcnt [{v1}] -> [{res}]");
99 resumable.stack.push_value(res.into())?;
100 Ok(ControlFlow::Continue(()))
101 }
102}
103
104define_instruction_fn! {
106 i64_clz,
107 fuel_check = flat(opcode::I64_CLZ),
108 |Args { resumable, .. }| {
109 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
110 let res = v1.leading_zeros() as i64;
111
112 trace!("Instruction: i64.clz [{v1}] -> [{res}]");
113 resumable.stack.push_value(res.into())?;
114 Ok(ControlFlow::Continue(()))
115 }
116}
117
118define_instruction_fn! {
119 i64_ctz,
120 fuel_check = flat(opcode::I64_CTZ),
121 |Args { resumable, .. }| {
122 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
123 let res = v1.trailing_zeros() as i64;
124
125 trace!("Instruction: i64.ctz [{v1}] -> [{res}]");
126 resumable.stack.push_value(res.into())?;
127 Ok(ControlFlow::Continue(()))
128 }
129}
130
131define_instruction_fn! {
132 i64_popcnt,
133 fuel_check = flat(opcode::I64_POPCNT),
134 |Args { resumable, .. }| {
135 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
136 let res = v1.count_ones() as i64;
137
138 trace!("Instruction: i64.popcnt [{v1}] -> [{res}]");
139 resumable.stack.push_value(res.into())?;
140 Ok(ControlFlow::Continue(()))
141 }
142}
143
144define_instruction_fn! {
146 f32_abs,
147 fuel_check = flat(opcode::F32_ABS),
148 |Args { resumable, .. }| {
149 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
150 let res: value::F32 = v1.abs();
151
152 trace!("Instruction: f32.abs [{v1}] -> [{res}]");
153 resumable.stack.push_value(res.into())?;
154 Ok(ControlFlow::Continue(()))
155 }
156}
157
158define_instruction_fn! {
159 f32_neg,
160 fuel_check = flat(opcode::F32_NEG),
161 |Args { resumable, .. }| {
162 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
163 let res: value::F32 = v1.neg();
164
165 trace!("Instruction: f32.neg [{v1}] -> [{res}]");
166 resumable.stack.push_value(res.into())?;
167 Ok(ControlFlow::Continue(()))
168 }
169}
170
171define_instruction_fn! {
172 f32_ceil,
173 fuel_check = flat(opcode::F32_CEIL),
174 |Args { resumable, .. }| {
175 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
176 let res: value::F32 = v1.ceil();
177
178 trace!("Instruction: f32.ceil [{v1}] -> [{res}]");
179 resumable.stack.push_value(res.into())?;
180 Ok(ControlFlow::Continue(()))
181 }
182}
183
184define_instruction_fn! {
185 f32_floor,
186 fuel_check = flat(opcode::F32_FLOOR),
187 |Args { resumable, .. }| {
188 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
189 let res: value::F32 = v1.floor();
190
191 trace!("Instruction: f32.floor [{v1}] -> [{res}]");
192 resumable.stack.push_value(res.into())?;
193 Ok(ControlFlow::Continue(()))
194 }
195}
196
197define_instruction_fn! {
198 f32_trunc,
199 fuel_check = flat(opcode::F32_TRUNC),
200 |Args { resumable, .. }| {
201 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
202 let res: value::F32 = v1.trunc();
203
204 trace!("Instruction: f32.trunc [{v1}] -> [{res}]");
205 resumable.stack.push_value(res.into())?;
206 Ok(ControlFlow::Continue(()))
207 }
208}
209
210define_instruction_fn! {
211 f32_nearest,
212 fuel_check = flat(opcode::F32_NEAREST),
213 |Args { resumable, .. }| {
214 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
215 let res: value::F32 = v1.nearest();
216
217 trace!("Instruction: f32.nearest [{v1}] -> [{res}]");
218 resumable.stack.push_value(res.into())?;
219 Ok(ControlFlow::Continue(()))
220 }
221}
222
223define_instruction_fn! {
224 f32_sqrt,
225 fuel_check = flat(opcode::F32_SQRT),
226 |Args { resumable, .. }| {
227 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
228 let res: value::F32 = v1.sqrt();
229
230 trace!("Instruction: f32.sqrt [{v1}] -> [{res}]");
231 resumable.stack.push_value(res.into())?;
232 Ok(ControlFlow::Continue(()))
233 }
234}
235
236define_instruction_fn! {
238 f64_abs,
239 fuel_check = flat(opcode::F64_ABS),
240 |Args { resumable, .. }| {
241 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
242 let res: value::F64 = v1.abs();
243
244 trace!("Instruction: f64.abs [{v1}] -> [{res}]");
245 resumable.stack.push_value(res.into())?;
246 Ok(ControlFlow::Continue(()))
247 }
248}
249
250define_instruction_fn! {
251 f64_neg,
252 fuel_check = flat(opcode::F64_NEG),
253 |Args { resumable, .. }| {
254 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
255 let res: value::F64 = v1.neg();
256
257 trace!("Instruction: f64.neg [{v1}] -> [{res}]");
258 resumable.stack.push_value(res.into())?;
259 Ok(ControlFlow::Continue(()))
260 }
261}
262
263define_instruction_fn! {
264 f64_ceil,
265 fuel_check = flat(opcode::F64_CEIL),
266 |Args { resumable, .. }| {
267 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
268 let res: value::F64 = v1.ceil();
269
270 trace!("Instruction: f64.ceil [{v1}] -> [{res}]");
271 resumable.stack.push_value(res.into())?;
272 Ok(ControlFlow::Continue(()))
273 }
274}
275
276define_instruction_fn! {
277 f64_floor,
278 fuel_check = flat(opcode::F64_FLOOR),
279 |Args { resumable, .. }| {
280 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
281 let res: value::F64 = v1.floor();
282
283 trace!("Instruction: f64.floor [{v1}] -> [{res}]");
284 resumable.stack.push_value(res.into())?;
285 Ok(ControlFlow::Continue(()))
286 }
287}
288
289define_instruction_fn! {
290 f64_trunc,
291 fuel_check = flat(opcode::F64_TRUNC),
292 |Args { resumable, .. }| {
293 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
294 let res: value::F64 = v1.trunc();
295
296 trace!("Instruction: f64.trunc [{v1}] -> [{res}]");
297 resumable.stack.push_value(res.into())?;
298 Ok(ControlFlow::Continue(()))
299 }
300}
301
302define_instruction_fn! {
303 f64_nearest,
304 fuel_check = flat(opcode::F64_NEAREST),
305 |Args { resumable, .. }| {
306 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
307 let res: value::F64 = v1.nearest();
308
309 trace!("Instruction: f64.nearest [{v1}] -> [{res}]");
310 resumable.stack.push_value(res.into())?;
311 Ok(ControlFlow::Continue(()))
312 }
313}
314
315define_instruction_fn! {
316 f64_sqrt,
317 fuel_check = flat(opcode::F64_SQRT),
318 |Args { resumable, .. }| {
319 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
320 let res: value::F64 = v1.sqrt();
321
322 trace!("Instruction: f64.sqrt [{v1}] -> [{res}]");
323 resumable.stack.push_value(res.into())?;
324 Ok(ControlFlow::Continue(()))
325 }
326}
327
328define_instruction_fn! {
330 i32_add,
331 fuel_check = flat(opcode::I32_ADD),
332 |Args { resumable, .. }| {
333 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
334 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
335 let res = v1.wrapping_add(v2);
336
337 trace!("Instruction: i32.add [{v1} {v2}] -> [{res}]");
338 resumable.stack.push_value(res.into())?;
339 Ok(ControlFlow::Continue(()))
340 }
341}
342
343define_instruction_fn! {
344 i32_sub,
345 fuel_check = flat(opcode::I32_SUB),
346 |Args { resumable, .. }| {
347 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
348 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
349 let res = v1.wrapping_sub(v2);
350
351 trace!("Instruction: i32.sub [{v1} {v2}] -> [{res}]");
352 resumable.stack.push_value(res.into())?;
353 Ok(ControlFlow::Continue(()))
354 }
355}
356
357define_instruction_fn! {
358 i32_mul,
359 fuel_check = flat(opcode::I32_MUL),
360 |Args { resumable, .. }| {
361 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
362 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
363 let res = v1.wrapping_mul(v2);
364
365 trace!("Instruction: i32.mul [{v1} {v2}] -> [{res}]");
366 resumable.stack.push_value(res.into())?;
367 Ok(ControlFlow::Continue(()))
368 }
369}
370
371define_instruction_fn! {
372 i32_div_s,
373 fuel_check = flat(opcode::I32_DIV_S),
374 |Args { resumable, .. }| {
375 let dividend: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
376 let divisor: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
377
378 if dividend == 0 {
379 return Err(TrapError::DivideBy0.into());
380 }
381 if divisor == i32::MIN && dividend == -1 {
382 return Err(TrapError::UnrepresentableResult.into());
383 }
384
385 let res = divisor / dividend;
386
387 trace!("Instruction: i32.div_s [{divisor} {dividend}] -> [{res}]");
388 resumable.stack.push_value(res.into())?;
389 Ok(ControlFlow::Continue(()))
390 }
391}
392
393define_instruction_fn! {
394 i32_div_u,
395 fuel_check = flat(opcode::I32_DIV_U),
396 |Args { resumable, .. }| {
397 let dividend: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
398 let divisor: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
399
400 let dividend = dividend as u32;
401 let divisor = divisor as u32;
402
403 if dividend == 0 {
404 return Err(TrapError::DivideBy0.into());
405 }
406
407 let res = (divisor / dividend) as i32;
408
409 trace!("Instruction: i32.div_u [{divisor} {dividend}] -> [{res}]");
410 resumable.stack.push_value(res.into())?;
411 Ok(ControlFlow::Continue(()))
412 }
413}
414
415define_instruction_fn! {
416 i32_rem_s,
417 fuel_check = flat(opcode::I32_REM_S),
418 |Args { resumable, .. }| {
419 let dividend: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
420 let divisor: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
421
422 if dividend == 0 {
423 return Err(TrapError::DivideBy0.into());
424 }
425
426 let res = divisor.checked_rem(dividend);
427 let res = res.unwrap_or_default();
428
429 trace!("Instruction: i32.rem_s [{divisor} {dividend}] -> [{res}]");
430 resumable.stack.push_value(res.into())?;
431 Ok(ControlFlow::Continue(()))
432 }
433}
434
435define_instruction_fn! {
436 i32_rem_u,
437 fuel_check = flat(opcode::I32_REM_U),
438 |Args { resumable, .. }| {
439 let dividend: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
440 let divisor: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
441
442 let dividend = dividend as u32;
443 let divisor = divisor as u32;
444
445 if dividend == 0 {
446 return Err(TrapError::DivideBy0.into());
447 }
448
449 let res = divisor.checked_rem(dividend);
450 let res = res.unwrap_or_default() as i32;
451
452 trace!("Instruction: i32.rem_u [{divisor} {dividend}] -> [{res}]");
453 resumable.stack.push_value(res.into())?;
454 Ok(ControlFlow::Continue(()))
455 }
456}
457
458define_instruction_fn! {
459 i32_and,
460 fuel_check = flat(opcode::I32_AND),
461 |Args { resumable, .. }| {
462 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
463 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
464 let res = v1 & v2;
465
466 trace!("Instruction: i32.and [{v1} {v2}] -> [{res}]");
467 resumable.stack.push_value(res.into())?;
468 Ok(ControlFlow::Continue(()))
469 }
470}
471
472define_instruction_fn! {
473 i32_or,
474 fuel_check = flat(opcode::I32_OR),
475 |Args { resumable, .. }| {
476 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
477 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
478 let res = v1 | v2;
479
480 trace!("Instruction: i32.or [{v1} {v2}] -> [{res}]");
481 resumable.stack.push_value(res.into())?;
482 Ok(ControlFlow::Continue(()))
483 }
484}
485
486define_instruction_fn! {
487 i32_xor,
488 fuel_check = flat(opcode::I32_XOR),
489 |Args { resumable, .. }| {
490 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
491 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
492 let res = v1 ^ v2;
493
494 trace!("Instruction: i32.xor [{v1} {v2}] -> [{res}]");
495 resumable.stack.push_value(res.into())?;
496 Ok(ControlFlow::Continue(()))
497 }
498}
499
500define_instruction_fn! {
501 i32_shl,
502 fuel_check = flat(opcode::I32_SHL),
503 |Args { resumable, .. }| {
504 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
505 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
506 let res = v2.wrapping_shl(v1 as u32);
507
508 trace!("Instruction: i32.shl [{v2} {v1}] -> [{res}]");
509 resumable.stack.push_value(res.into())?;
510 Ok(ControlFlow::Continue(()))
511 }
512}
513
514define_instruction_fn! {
515 i32_shr_s,
516 fuel_check = flat(opcode::I32_SHR_S),
517 |Args { resumable, .. }| {
518 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
519 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
520
521 let res = v2.wrapping_shr(v1 as u32);
522
523 trace!("Instruction: i32.shr_s [{v2} {v1}] -> [{res}]");
524 resumable.stack.push_value(res.into())?;
525 Ok(ControlFlow::Continue(()))
526 }
527}
528
529define_instruction_fn! {
530 i32_shr_u,
531 fuel_check = flat(opcode::I32_SHR_U),
532 |Args { resumable, .. }| {
533 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
534 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
535
536 let res = (v2 as u32).wrapping_shr(v1 as u32) as i32;
537
538 trace!("Instruction: i32.shr_u [{v2} {v1}] -> [{res}]");
539 resumable.stack.push_value(res.into())?;
540 Ok(ControlFlow::Continue(()))
541 }
542}
543
544define_instruction_fn! {
545 i32_rotl,
546 fuel_check = flat(opcode::I32_ROTL),
547 |Args { resumable, .. }| {
548 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
549 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
550
551 let res = v2.rotate_left(v1 as u32);
552
553 trace!("Instruction: i32.rotl [{v2} {v1}] -> [{res}]");
554 resumable.stack.push_value(res.into())?;
555 Ok(ControlFlow::Continue(()))
556 }
557}
558
559define_instruction_fn! {
560 i32_rotr,
561 fuel_check = flat(opcode::I32_ROTR),
562 |Args { resumable, .. }| {
563 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
564 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
565
566 let res = v2.rotate_right(v1 as u32);
567
568 trace!("Instruction: i32.rotr [{v2} {v1}] -> [{res}]");
569 resumable.stack.push_value(res.into())?;
570 Ok(ControlFlow::Continue(()))
571 }
572}
573
574define_instruction_fn! {
576 i64_add,
577 fuel_check = flat(opcode::I64_ADD),
578 |Args { resumable, .. }| {
579 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
580 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
581 let res = v1.wrapping_add(v2);
582
583 trace!("Instruction: i64.add [{v1} {v2}] -> [{res}]");
584 resumable.stack.push_value(res.into())?;
585 Ok(ControlFlow::Continue(()))
586 }
587}
588
589define_instruction_fn! {
590 i64_sub,
591 fuel_check = flat(opcode::I64_SUB),
592 |Args { resumable, .. }| {
593 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
594 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
595 let res = v1.wrapping_sub(v2);
596
597 trace!("Instruction: i64.sub [{v1} {v2}] -> [{res}]");
598 resumable.stack.push_value(res.into())?;
599 Ok(ControlFlow::Continue(()))
600 }
601}
602
603define_instruction_fn! {
604 i64_mul,
605 fuel_check = flat(opcode::I64_MUL),
606 |Args { resumable, .. }| {
607 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
608 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
609 let res = v1.wrapping_mul(v2);
610
611 trace!("Instruction: i64.mul [{v1} {v2}] -> [{res}]");
612 resumable.stack.push_value(res.into())?;
613 Ok(ControlFlow::Continue(()))
614 }
615}
616
617define_instruction_fn! {
618 i64_div_s,
619 fuel_check = flat(opcode::I64_DIV_S),
620 |Args { resumable, .. }| {
621 let dividend: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
622 let divisor: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
623
624 if dividend == 0 {
625 return Err(TrapError::DivideBy0.into());
626 }
627 if divisor == i64::MIN && dividend == -1 {
628 return Err(TrapError::UnrepresentableResult.into());
629 }
630
631 let res = divisor / dividend;
632
633 trace!("Instruction: i64.div_s [{divisor} {dividend}] -> [{res}]");
634 resumable.stack.push_value(res.into())?;
635 Ok(ControlFlow::Continue(()))
636 }
637}
638
639define_instruction_fn! {
640 i64_div_u,
641 fuel_check = flat(opcode::I64_DIV_U),
642 |Args { resumable, .. }| {
643 let dividend: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
644 let divisor: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
645
646 let dividend = dividend as u64;
647 let divisor = divisor as u64;
648
649 if dividend == 0 {
650 return Err(TrapError::DivideBy0.into());
651 }
652
653 let res = (divisor / dividend) as i64;
654
655 trace!("Instruction: i64.div_u [{divisor} {dividend}] -> [{res}]");
656 resumable.stack.push_value(res.into())?;
657 Ok(ControlFlow::Continue(()))
658 }
659}
660
661define_instruction_fn! {
662 i64_rem_s,
663 fuel_check = flat(opcode::I64_REM_S),
664 |Args { resumable, .. }| {
665 let dividend: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
666 let divisor: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
667
668 if dividend == 0 {
669 return Err(TrapError::DivideBy0.into());
670 }
671
672 let res = divisor.checked_rem(dividend);
673 let res = res.unwrap_or_default();
674
675 trace!("Instruction: i64.rem_s [{divisor} {dividend}] -> [{res}]");
676 resumable.stack.push_value(res.into())?;
677 Ok(ControlFlow::Continue(()))
678 }
679}
680
681define_instruction_fn! {
682 i64_rem_u,
683 fuel_check = flat(opcode::I64_REM_U),
684 |Args { resumable, .. }| {
685 let dividend: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
686 let divisor: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
687
688 let dividend = dividend as u64;
689 let divisor = divisor as u64;
690
691 if dividend == 0 {
692 return Err(TrapError::DivideBy0.into());
693 }
694
695 let res = (divisor % dividend) as i64;
696
697 trace!("Instruction: i64.rem_u [{divisor} {dividend}] -> [{res}]");
698 resumable.stack.push_value(res.into())?;
699 Ok(ControlFlow::Continue(()))
700 }
701}
702
703define_instruction_fn! {
704 i64_and,
705 fuel_check = flat(opcode::I64_AND),
706 |Args { resumable, .. }| {
707 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
708 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
709
710 let res = v1 & v2;
711
712 trace!("Instruction: i64.and [{v1} {v2}] -> [{res}]");
713 resumable.stack.push_value(res.into())?;
714 Ok(ControlFlow::Continue(()))
715 }
716}
717
718define_instruction_fn! {
719 i64_or,
720 fuel_check = flat(opcode::I64_OR),
721 |Args { resumable, .. }| {
722 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
723 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
724
725 let res = v1 | v2;
726
727 trace!("Instruction: i64.or [{v1} {v2}] -> [{res}]");
728 resumable.stack.push_value(res.into())?;
729 Ok(ControlFlow::Continue(()))
730 }
731}
732
733define_instruction_fn! {
734 i64_xor,
735 fuel_check = flat(opcode::I64_XOR),
736 |Args { resumable, .. }| {
737 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
738 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
739
740 let res = v1 ^ v2;
741
742 trace!("Instruction: i64.xor [{v1} {v2}] -> [{res}]");
743 resumable.stack.push_value(res.into())?;
744 Ok(ControlFlow::Continue(()))
745 }
746}
747
748define_instruction_fn! {
749 i64_shl,
750 fuel_check = flat(opcode::I64_SHL),
751 |Args { resumable, .. }| {
752 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
753 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
754
755 let res = v1.wrapping_shl((v2 & 63) as u32);
756
757 trace!("Instruction: i64.shl [{v1} {v2}] -> [{res}]");
758 resumable.stack.push_value(res.into())?;
759 Ok(ControlFlow::Continue(()))
760 }
761}
762
763define_instruction_fn! {
764 i64_shr_s,
765 fuel_check = flat(opcode::I64_SHR_S),
766 |Args { resumable, .. }| {
767 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
768 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
769
770 let res = v1.wrapping_shr((v2 & 63) as u32);
771
772 trace!("Instruction: i64.shr_s [{v1} {v2}] -> [{res}]");
773 resumable.stack.push_value(res.into())?;
774 Ok(ControlFlow::Continue(()))
775 }
776}
777
778define_instruction_fn! {
779 i64_shr_u,
780 fuel_check = flat(opcode::I64_SHR_U),
781 |Args { resumable, .. }| {
782 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
783 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
784
785 let res = (v1 as u64).wrapping_shr((v2 & 63) as u32);
786
787 trace!("Instruction: i64.shr_u [{v1} {v2}] -> [{res}]");
788 resumable.stack.push_value(res.into())?;
789 Ok(ControlFlow::Continue(()))
790 }
791}
792
793define_instruction_fn! {
794 i64_rotl,
795 fuel_check = flat(opcode::I64_ROTL),
796 |Args { resumable, .. }| {
797 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
798 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
799
800 let res = v1.rotate_left((v2 & 63) as u32);
801
802 trace!("Instruction: i64.rotl [{v1} {v2}] -> [{res}]");
803 resumable.stack.push_value(res.into())?;
804 Ok(ControlFlow::Continue(()))
805 }
806}
807
808define_instruction_fn! {
809 i64_rotr,
810 fuel_check = flat(opcode::I64_ROTR),
811 |Args { resumable, .. }| {
812 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
813 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
814
815 let res = v1.rotate_right((v2 & 63) as u32);
816
817 trace!("Instruction: i64.rotr [{v1} {v2}] -> [{res}]");
818 resumable.stack.push_value(res.into())?;
819 Ok(ControlFlow::Continue(()))
820 }
821}
822
823define_instruction_fn! {
825 f32_add,
826 fuel_check = flat(opcode::F32_ADD),
827 |Args { resumable, .. }| {
828 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
829 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
830 let res: value::F32 = v1 + v2;
831
832 trace!("Instruction: f32.add [{v1} {v2}] -> [{res}]");
833 resumable.stack.push_value(res.into())?;
834 Ok(ControlFlow::Continue(()))
835 }
836}
837
838define_instruction_fn! {
839 f32_sub,
840 fuel_check = flat(opcode::F32_SUB),
841 |Args { resumable, .. }| {
842 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
843 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
844 let res: value::F32 = v1 - v2;
845
846 trace!("Instruction: f32.sub [{v1} {v2}] -> [{res}]");
847 resumable.stack.push_value(res.into())?;
848 Ok(ControlFlow::Continue(()))
849 }
850}
851
852define_instruction_fn! {
853 f32_mul,
854 fuel_check = flat(opcode::F32_MUL),
855 |Args { resumable, .. }| {
856 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
857 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
858 let res: value::F32 = v1 * v2;
859
860 trace!("Instruction: f32.mul [{v1} {v2}] -> [{res}]");
861 resumable.stack.push_value(res.into())?;
862 Ok(ControlFlow::Continue(()))
863 }
864}
865
866define_instruction_fn! {
867 f32_div,
868 fuel_check = flat(opcode::F32_DIV),
869 |Args { resumable, .. }| {
870 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
871 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
872 let res: value::F32 = v1 / v2;
873
874 trace!("Instruction: f32.div [{v1} {v2}] -> [{res}]");
875 resumable.stack.push_value(res.into())?;
876 Ok(ControlFlow::Continue(()))
877 }
878}
879
880define_instruction_fn! {
881 f32_min,
882 fuel_check = flat(opcode::F32_MIN),
883 |Args { resumable, .. }| {
884 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
885 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
886 let res: value::F32 = v1.min(v2);
887
888 trace!("Instruction: f32.min [{v1} {v2}] -> [{res}]");
889 resumable.stack.push_value(res.into())?;
890 Ok(ControlFlow::Continue(()))
891 }
892}
893
894define_instruction_fn! {
895 f32_max,
896 fuel_check = flat(opcode::F32_MAX),
897 |Args { resumable, .. }| {
898 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
899 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
900 let res: value::F32 = v1.max(v2);
901
902 trace!("Instruction: f32.max [{v1} {v2}] -> [{res}]");
903 resumable.stack.push_value(res.into())?;
904 Ok(ControlFlow::Continue(()))
905 }
906}
907
908define_instruction_fn! {
909 f32_copysign,
910 fuel_check = flat(opcode::F32_COPYSIGN),
911 |Args { resumable, .. }| {
912 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
913 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
914 let res: value::F32 = v1.copysign(v2);
915
916 trace!("Instruction: f32.copysign [{v1} {v2}] -> [{res}]");
917 resumable.stack.push_value(res.into())?;
918 Ok(ControlFlow::Continue(()))
919 }
920}
921
922define_instruction_fn! {
924 f64_add,
925 fuel_check = flat(opcode::F64_ADD),
926 |Args { resumable, .. }| {
927 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
928 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
929 let res: value::F64 = v1 + v2;
930
931 trace!("Instruction: f64.add [{v1} {v2}] -> [{res}]");
932 resumable.stack.push_value(res.into())?;
933 Ok(ControlFlow::Continue(()))
934 }
935}
936
937define_instruction_fn! {
938 f64_sub,
939 fuel_check = flat(opcode::F64_SUB),
940 |Args { resumable, .. }| {
941 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
942 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
943 let res: value::F64 = v1 - v2;
944
945 trace!("Instruction: f64.sub [{v1} {v2}] -> [{res}]");
946 resumable.stack.push_value(res.into())?;
947 Ok(ControlFlow::Continue(()))
948 }
949}
950
951define_instruction_fn! {
952 f64_mul,
953 fuel_check = flat(opcode::F64_MUL),
954 |Args { resumable, .. }| {
955 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
956 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
957 let res: value::F64 = v1 * v2;
958
959 trace!("Instruction: f64.mul [{v1} {v2}] -> [{res}]");
960 resumable.stack.push_value(res.into())?;
961 Ok(ControlFlow::Continue(()))
962 }
963}
964
965define_instruction_fn! {
966 f64_div,
967 fuel_check = flat(opcode::F64_DIV),
968 |Args { resumable, .. }| {
969 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
970 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
971 let res: value::F64 = v1 / v2;
972
973 trace!("Instruction: f64.div [{v1} {v2}] -> [{res}]");
974 resumable.stack.push_value(res.into())?;
975 Ok(ControlFlow::Continue(()))
976 }
977}
978
979define_instruction_fn! {
980 f64_min,
981 fuel_check = flat(opcode::F64_MIN),
982 |Args { resumable, .. }| {
983 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
984 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
985 let res: value::F64 = v1.min(v2);
986
987 trace!("Instruction: f64.min [{v1} {v2}] -> [{res}]");
988 resumable.stack.push_value(res.into())?;
989 Ok(ControlFlow::Continue(()))
990 }
991}
992
993define_instruction_fn! {
994 f64_max,
995 fuel_check = flat(opcode::F64_MAX),
996 |Args { resumable, .. }| {
997 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
998 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
999 let res: value::F64 = v1.max(v2);
1000
1001 trace!("Instruction: f64.max [{v1} {v2}] -> [{res}]");
1002 resumable.stack.push_value(res.into())?;
1003 Ok(ControlFlow::Continue(()))
1004 }
1005}
1006
1007define_instruction_fn! {
1008 f64_copysign,
1009 fuel_check = flat(opcode::F64_COPYSIGN),
1010 |Args { resumable, .. }| {
1011 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1012 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1013 let res: value::F64 = v1.copysign(v2);
1014
1015 trace!("Instruction: f64.copysign [{v1} {v2}] -> [{res}]");
1016 resumable.stack.push_value(res.into())?;
1017 Ok(ControlFlow::Continue(()))
1018 }
1019}
1020
1021define_instruction_fn! {
1023 i32_eqz,
1024 fuel_check = flat(opcode::I32_EQZ),
1025 |Args { resumable, .. }| {
1026 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1027
1028 let res = if v1 == 0 { 1 } else { 0 };
1029
1030 trace!("Instruction: i32.eqz [{v1}] -> [{res}]");
1031 resumable.stack.push_value(res.into())?;
1032 Ok(ControlFlow::Continue(()))
1033 }
1034}
1035
1036define_instruction_fn! {
1038 i64_eqz,
1039 fuel_check = flat(opcode::I64_EQZ),
1040 |Args { resumable, .. }| {
1041 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1042
1043 let res = if v1 == 0 { 1 } else { 0 };
1044
1045 trace!("Instruction: i64.eqz [{v1}] -> [{res}]");
1046 resumable.stack.push_value(res.into())?;
1047 Ok(ControlFlow::Continue(()))
1048 }
1049}
1050
1051define_instruction_fn! {
1053 i32_eq,
1054 fuel_check = flat(opcode::I32_EQ),
1055 |Args { resumable, .. }| {
1056 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1057 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1058
1059 let res = if v1 == v2 { 1 } else { 0 };
1060
1061 trace!("Instruction: i32.eq [{v1} {v2}] -> [{res}]");
1062 resumable.stack.push_value(res.into())?;
1063 Ok(ControlFlow::Continue(()))
1064 }
1065}
1066
1067define_instruction_fn! {
1068 i32_ne,
1069 fuel_check = flat(opcode::I32_NE),
1070 |Args { resumable, .. }| {
1071 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1072 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1073
1074 let res = if v1 != v2 { 1 } else { 0 };
1075
1076 trace!("Instruction: i32.ne [{v1} {v2}] -> [{res}]");
1077 resumable.stack.push_value(res.into())?;
1078 Ok(ControlFlow::Continue(()))
1079 }
1080}
1081
1082define_instruction_fn! {
1083 i32_lt_s,
1084 fuel_check = flat(opcode::I32_LT_S),
1085 |Args { resumable, .. }| {
1086 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1087 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1088
1089 let res = if v1 < v2 { 1 } else { 0 };
1090
1091 trace!("Instruction: i32.lt_s [{v1} {v2}] -> [{res}]");
1092 resumable.stack.push_value(res.into())?;
1093 Ok(ControlFlow::Continue(()))
1094 }
1095}
1096
1097define_instruction_fn! {
1098 i32_lt_u,
1099 fuel_check = flat(opcode::I32_LT_U),
1100 |Args { resumable, .. }| {
1101 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1102 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1103
1104 let res = if (v1 as u32) < (v2 as u32) { 1 } else { 0 };
1105
1106 trace!("Instruction: i32.lt_u [{v1} {v2}] -> [{res}]");
1107 resumable.stack.push_value(res.into())?;
1108 Ok(ControlFlow::Continue(()))
1109 }
1110}
1111
1112define_instruction_fn! {
1113 i32_gt_s,
1114 fuel_check = flat(opcode::I32_GT_S),
1115 |Args { resumable, .. }| {
1116 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1117 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1118
1119 let res = if v1 > v2 { 1 } else { 0 };
1120
1121 trace!("Instruction: i32.gt_s [{v1} {v2}] -> [{res}]");
1122 resumable.stack.push_value(res.into())?;
1123 Ok(ControlFlow::Continue(()))
1124 }
1125}
1126
1127define_instruction_fn! {
1128 i32_gt_u,
1129 fuel_check = flat(opcode::I32_GT_U),
1130 |Args { resumable, .. }| {
1131 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1132 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1133
1134 let res = if (v1 as u32) > (v2 as u32) { 1 } else { 0 };
1135
1136 trace!("Instruction: i32.gt_u [{v1} {v2}] -> [{res}]");
1137 resumable.stack.push_value(res.into())?;
1138 Ok(ControlFlow::Continue(()))
1139 }
1140}
1141
1142define_instruction_fn! {
1143 i32_le_s,
1144 fuel_check = flat(opcode::I32_LE_S),
1145 |Args { resumable, .. }| {
1146 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1147 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1148
1149 let res = if v1 <= v2 { 1 } else { 0 };
1150
1151 trace!("Instruction: i32.le_s [{v1} {v2}] -> [{res}]");
1152 resumable.stack.push_value(res.into())?;
1153 Ok(ControlFlow::Continue(()))
1154 }
1155}
1156
1157define_instruction_fn! {
1158 i32_le_u,
1159 fuel_check = flat(opcode::I32_LE_U),
1160 |Args { resumable, .. }| {
1161 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1162 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1163
1164 let res = if (v1 as u32) <= (v2 as u32) { 1 } else { 0 };
1165
1166 trace!("Instruction: i32.le_u [{v1} {v2}] -> [{res}]");
1167 resumable.stack.push_value(res.into())?;
1168 Ok(ControlFlow::Continue(()))
1169 }
1170}
1171
1172define_instruction_fn! {
1173 i32_ge_s,
1174 fuel_check = flat(opcode::I32_GE_S),
1175 |Args { resumable, .. }| {
1176 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1177 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1178
1179 let res = if v1 >= v2 { 1 } else { 0 };
1180
1181 trace!("Instruction: i32.ge_s [{v1} {v2}] -> [{res}]");
1182 resumable.stack.push_value(res.into())?;
1183 Ok(ControlFlow::Continue(()))
1184 }
1185}
1186
1187define_instruction_fn! {
1188 i32_ge_u,
1189 fuel_check = flat(opcode::I32_GE_U),
1190 |Args { resumable, .. }| {
1191 let v2: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1192 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1193
1194 let res = if (v1 as u32) >= (v2 as u32) { 1 } else { 0 };
1195
1196 trace!("Instruction: i32.ge_u [{v1} {v2}] -> [{res}]");
1197 resumable.stack.push_value(res.into())?;
1198 Ok(ControlFlow::Continue(()))
1199 }
1200}
1201
1202define_instruction_fn! {
1204 i64_eq,
1205 fuel_check = flat(opcode::I64_EQ),
1206 |Args { resumable, .. }| {
1207 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1208 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1209
1210 let res = if v1 == v2 { 1 } else { 0 };
1211
1212 trace!("Instruction: i64.eq [{v1} {v2}] -> [{res}]");
1213 resumable.stack.push_value(res.into())?;
1214 Ok(ControlFlow::Continue(()))
1215 }
1216}
1217
1218define_instruction_fn! {
1219 i64_ne,
1220 fuel_check = flat(opcode::I64_NE),
1221 |Args { resumable, .. }| {
1222 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1223 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1224
1225 let res = if v1 != v2 { 1 } else { 0 };
1226
1227 trace!("Instruction: i64.ne [{v1} {v2}] -> [{res}]");
1228 resumable.stack.push_value(res.into())?;
1229 Ok(ControlFlow::Continue(()))
1230 }
1231}
1232
1233define_instruction_fn! {
1234 i64_lt_s,
1235 fuel_check = flat(opcode::I64_LT_S),
1236 |Args { resumable, .. }| {
1237 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1238 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1239
1240 let res = if v1 < v2 { 1 } else { 0 };
1241
1242 trace!("Instruction: i64.lt_s [{v1} {v2}] -> [{res}]");
1243 resumable.stack.push_value(res.into())?;
1244 Ok(ControlFlow::Continue(()))
1245 }
1246}
1247
1248define_instruction_fn! {
1249 i64_lt_u,
1250 fuel_check = flat(opcode::I64_LT_U),
1251 |Args { resumable, .. }| {
1252 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1253 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1254
1255 let res = if (v1 as u64) < (v2 as u64) { 1 } else { 0 };
1256
1257 trace!("Instruction: i64.lt_u [{v1} {v2}] -> [{res}]");
1258 resumable.stack.push_value(res.into())?;
1259 Ok(ControlFlow::Continue(()))
1260 }
1261}
1262
1263define_instruction_fn! {
1264 i64_gt_s,
1265 fuel_check = flat(opcode::I64_GT_S),
1266 |Args { resumable, .. }| {
1267 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1268 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1269
1270 let res = if v1 > v2 { 1 } else { 0 };
1271
1272 trace!("Instruction: i64.gt_s [{v1} {v2}] -> [{res}]");
1273 resumable.stack.push_value(res.into())?;
1274 Ok(ControlFlow::Continue(()))
1275 }
1276}
1277
1278define_instruction_fn! {
1279 i64_gt_u,
1280 fuel_check = flat(opcode::I64_GT_U),
1281 |Args { resumable, .. }| {
1282 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1283 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1284
1285 let res = if (v1 as u64) > (v2 as u64) { 1 } else { 0 };
1286
1287 trace!("Instruction: i64.gt_u [{v1} {v2}] -> [{res}]");
1288 resumable.stack.push_value(res.into())?;
1289 Ok(ControlFlow::Continue(()))
1290 }
1291}
1292
1293define_instruction_fn! {
1294 i64_le_s,
1295 fuel_check = flat(opcode::I64_LE_S),
1296 |Args { resumable, .. }| {
1297 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1298 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1299
1300 let res = if v1 <= v2 { 1 } else { 0 };
1301
1302 trace!("Instruction: i64.le_s [{v1} {v2}] -> [{res}]");
1303 resumable.stack.push_value(res.into())?;
1304 Ok(ControlFlow::Continue(()))
1305 }
1306}
1307
1308define_instruction_fn! {
1309 i64_le_u,
1310 fuel_check = flat(opcode::I64_LE_U),
1311 |Args { resumable, .. }| {
1312 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1313 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1314
1315 let res = if (v1 as u64) <= (v2 as u64) { 1 } else { 0 };
1316
1317 trace!("Instruction: i64.le_u [{v1} {v2}] -> [{res}]");
1318 resumable.stack.push_value(res.into())?;
1319 Ok(ControlFlow::Continue(()))
1320 }
1321}
1322
1323define_instruction_fn! {
1324 i64_ge_s,
1325 fuel_check = flat(opcode::I64_GE_S),
1326 |Args { resumable, .. }| {
1327 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1328 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1329
1330 let res = if v1 >= v2 { 1 } else { 0 };
1331
1332 trace!("Instruction: i64.ge_s [{v1} {v2}] -> [{res}]");
1333 resumable.stack.push_value(res.into())?;
1334 Ok(ControlFlow::Continue(()))
1335 }
1336}
1337
1338define_instruction_fn! {
1339 i64_ge_u,
1340 fuel_check = flat(opcode::I64_GE_U),
1341 |Args { resumable, .. }| {
1342 let v2: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1343 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1344
1345 let res = if (v1 as u64) >= (v2 as u64) { 1 } else { 0 };
1346
1347 trace!("Instruction: i64.ge_u [{v1} {v2}] -> [{res}]");
1348 resumable.stack.push_value(res.into())?;
1349 Ok(ControlFlow::Continue(()))
1350 }
1351}
1352
1353define_instruction_fn! {
1355 f32_eq,
1356 fuel_check = flat(opcode::F32_EQ),
1357 |Args { resumable, .. }| {
1358 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1359 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1360
1361 let res = if v1 == v2 { 1 } else { 0 };
1362
1363 trace!("Instruction: f32.eq [{v1} {v2}] -> [{res}]");
1364 resumable.stack.push_value(res.into())?;
1365 Ok(ControlFlow::Continue(()))
1366 }
1367}
1368
1369define_instruction_fn! {
1370 f32_ne,
1371 fuel_check = flat(opcode::F32_NE),
1372 |Args { resumable, .. }| {
1373 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1374 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1375
1376 let res = if v1 != v2 { 1 } else { 0 };
1377
1378 trace!("Instruction: f32.ne [{v1} {v2}] -> [{res}]");
1379 resumable.stack.push_value(res.into())?;
1380 Ok(ControlFlow::Continue(()))
1381 }
1382}
1383
1384define_instruction_fn! {
1385 f32_lt,
1386 fuel_check = flat(opcode::F32_LT),
1387 |Args { resumable, .. }| {
1388 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1389 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1390
1391 let res = if v1 < v2 { 1 } else { 0 };
1392
1393 trace!("Instruction: f32.lt [{v1} {v2}] -> [{res}]");
1394 resumable.stack.push_value(res.into())?;
1395 Ok(ControlFlow::Continue(()))
1396 }
1397}
1398
1399define_instruction_fn! {
1400 f32_gt,
1401 fuel_check = flat(opcode::F32_GT),
1402 |Args { resumable, .. }| {
1403 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1404 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1405
1406 let res = if v1 > v2 { 1 } else { 0 };
1407
1408 trace!("Instruction: f32.gt [{v1} {v2}] -> [{res}]");
1409 resumable.stack.push_value(res.into())?;
1410 Ok(ControlFlow::Continue(()))
1411 }
1412}
1413
1414define_instruction_fn! {
1415 f32_le,
1416 fuel_check = flat(opcode::F32_LE),
1417 |Args { resumable, .. }| {
1418 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1419 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1420
1421 let res = if v1 <= v2 { 1 } else { 0 };
1422
1423 trace!("Instruction: f32.le [{v1} {v2}] -> [{res}]");
1424 resumable.stack.push_value(res.into())?;
1425 Ok(ControlFlow::Continue(()))
1426 }
1427}
1428
1429define_instruction_fn! {
1430 f32_ge,
1431 fuel_check = flat(opcode::F32_GE),
1432 |Args { resumable, .. }| {
1433 let v2: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1434 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1435
1436 let res = if v1 >= v2 { 1 } else { 0 };
1437
1438 trace!("Instruction: f32.ge [{v1} {v2}] -> [{res}]");
1439 resumable.stack.push_value(res.into())?;
1440 Ok(ControlFlow::Continue(()))
1441 }
1442}
1443
1444define_instruction_fn! {
1446 f64_eq,
1447 fuel_check = flat(opcode::F64_EQ),
1448 |Args { resumable, .. }| {
1449 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1450 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1451
1452 let res = if v1 == v2 { 1 } else { 0 };
1453
1454 trace!("Instruction: f64.eq [{v1} {v2}] -> [{res}]");
1455 resumable.stack.push_value(res.into())?;
1456 Ok(ControlFlow::Continue(()))
1457 }
1458}
1459
1460define_instruction_fn! {
1461 f64_ne,
1462 fuel_check = flat(opcode::F64_NE),
1463 |Args { resumable, .. }| {
1464 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1465 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1466
1467 let res = if v1 != v2 { 1 } else { 0 };
1468
1469 trace!("Instruction: f64.ne [{v1} {v2}] -> [{res}]");
1470 resumable.stack.push_value(res.into())?;
1471 Ok(ControlFlow::Continue(()))
1472 }
1473}
1474
1475define_instruction_fn! {
1476 f64_lt,
1477 fuel_check = flat(opcode::F64_LT),
1478 |Args { resumable, .. }| {
1479 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1480 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1481
1482 let res = if v1 < v2 { 1 } else { 0 };
1483
1484 trace!("Instruction: f64.lt [{v1} {v2}] -> [{res}]");
1485 resumable.stack.push_value(res.into())?;
1486 Ok(ControlFlow::Continue(()))
1487 }
1488}
1489
1490define_instruction_fn! {
1491 f64_gt,
1492 fuel_check = flat(opcode::F64_GT),
1493 |Args { resumable, .. }| {
1494 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1495 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1496
1497 let res = if v1 > v2 { 1 } else { 0 };
1498
1499 trace!("Instruction: f64.gt [{v1} {v2}] -> [{res}]");
1500 resumable.stack.push_value(res.into())?;
1501 Ok(ControlFlow::Continue(()))
1502 }
1503}
1504
1505define_instruction_fn! {
1506 f64_le,
1507 fuel_check = flat(opcode::F64_LE),
1508 |Args { resumable, .. }| {
1509 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1510 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1511
1512 let res = if v1 <= v2 { 1 } else { 0 };
1513
1514 trace!("Instruction: f64.le [{v1} {v2}] -> [{res}]");
1515 resumable.stack.push_value(res.into())?;
1516 Ok(ControlFlow::Continue(()))
1517 }
1518}
1519
1520define_instruction_fn! {
1521 f64_ge,
1522 fuel_check = flat(opcode::F64_GE),
1523 |Args { resumable, .. }| {
1524 let v2: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1525 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1526
1527 let res = if v1 >= v2 { 1 } else { 0 };
1528
1529 trace!("Instruction: f64.ge [{v1} {v2}] -> [{res}]");
1530 resumable.stack.push_value(res.into())?;
1531 Ok(ControlFlow::Continue(()))
1532 }
1533}
1534
1535define_instruction_fn! {
1537 i32_wrap_i64,
1538 fuel_check = flat(opcode::I32_WRAP_I64),
1539 |Args { resumable, .. }| {
1540 let v: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
1541 let res: i32 = v as i32;
1542
1543 trace!("Instruction: i32.wrap_i64 [{v}] -> [{res}]");
1544 resumable.stack.push_value(res.into())?;
1545 Ok(ControlFlow::Continue(()))
1546 }
1547}
1548
1549define_instruction_fn! {
1550 i32_trunc_f32_s,
1551 fuel_check = flat(opcode::I32_TRUNC_F32_S),
1552 |Args { resumable, .. }| {
1553 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1554 if v.is_infinity() {
1555 return Err(TrapError::UnrepresentableResult.into());
1556 }
1557 if v.is_nan() {
1558 return Err(TrapError::BadConversionToInteger.into());
1559 }
1560 if v >= value::F32(2147483648.0) || v <= value::F32(-2147483904.0) {
1561 return Err(TrapError::UnrepresentableResult.into());
1562 }
1563
1564 let res: i32 = v.as_i32();
1565
1566 trace!("Instruction: i32.trunc_f32_s [{v:.7}] -> [{res}]");
1567 resumable.stack.push_value(res.into())?;
1568 Ok(ControlFlow::Continue(()))
1569 }
1570}
1571
1572define_instruction_fn! {
1573 i32_trunc_f32_u,
1574 fuel_check = flat(opcode::I32_TRUNC_F32_U),
1575 |Args { resumable, .. }| {
1576 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1577 if v.is_infinity() {
1578 return Err(TrapError::UnrepresentableResult.into());
1579 }
1580 if v.is_nan() {
1581 return Err(TrapError::BadConversionToInteger.into());
1582 }
1583 if v >= value::F32(4294967296.0) || v <= value::F32(-1.0) {
1584 return Err(TrapError::UnrepresentableResult.into());
1585 }
1586
1587 let res: i32 = v.as_u32() as i32;
1588
1589 trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1590 resumable.stack.push_value(res.into())?;
1591 Ok(ControlFlow::Continue(()))
1592 }
1593}
1594
1595define_instruction_fn! {
1596 i32_trunc_f64_s,
1597 fuel_check = flat(opcode::I32_TRUNC_F64_S),
1598 |Args { resumable, .. }| {
1599 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1600 if v.is_infinity() {
1601 return Err(TrapError::UnrepresentableResult.into());
1602 }
1603 if v.is_nan() {
1604 return Err(TrapError::BadConversionToInteger.into());
1605 }
1606 if v >= value::F64(2147483648.0) || v <= value::F64(-2147483649.0) {
1607 return Err(TrapError::UnrepresentableResult.into());
1608 }
1609
1610 let res: i32 = v.as_i32();
1611
1612 trace!("Instruction: i32.trunc_f64_s [{v:.7}] -> [{res}]");
1613 resumable.stack.push_value(res.into())?;
1614 Ok(ControlFlow::Continue(()))
1615 }
1616}
1617
1618define_instruction_fn! {
1619 i32_trunc_f64_u,
1620 fuel_check = flat(opcode::I32_TRUNC_F64_U),
1621 |Args { resumable, .. }| {
1622 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1623 if v.is_infinity() {
1624 return Err(TrapError::UnrepresentableResult.into());
1625 }
1626 if v.is_nan() {
1627 return Err(TrapError::BadConversionToInteger.into());
1628 }
1629 if v >= value::F64(4294967296.0) || v <= value::F64(-1.0) {
1630 return Err(TrapError::UnrepresentableResult.into());
1631 }
1632
1633 let res: i32 = v.as_u32() as i32;
1634
1635 trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1636 resumable.stack.push_value(res.into())?;
1637 Ok(ControlFlow::Continue(()))
1638 }
1639}
1640
1641define_instruction_fn! {
1642 i32_reinterpret_f32,
1643 fuel_check = flat(opcode::I32_REINTERPRET_F32),
1644 |Args { resumable, .. }| {
1645 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1646 let res: i32 = v.reinterpret_as_i32();
1647
1648 trace!("Instruction: i32.reinterpret_f32 [{v:.7}] -> [{res}]");
1649 resumable.stack.push_value(res.into())?;
1650 Ok(ControlFlow::Continue(()))
1651 }
1652}
1653
1654define_instruction_fn! {
1655 i32_extend8_s,
1656 fuel_check = flat(opcode::I32_EXTEND8_S),
1657 |Args { resumable, .. }| {
1658 let mut v: u32 = resumable.stack.pop_value().try_into().unwrap_validated();
1659
1660 if v | 0xFF != 0xFF {
1661 trace!("Number v ({}) not contained in 8 bits, truncating", v);
1662 v &= 0xFF;
1663 }
1664
1665 let res = if v | 0x7F != 0x7F { v | 0xFFFFFF00 } else { v };
1666
1667 resumable.stack.push_value(res.into())?;
1668
1669 trace!("Instruction i32.extend8_s [{}] -> [{}]", v, res);
1670 Ok(ControlFlow::Continue(()))
1671 }
1672}
1673
1674define_instruction_fn! {
1675 i32_extend16_s,
1676 fuel_check = flat(opcode::I32_EXTEND16_S),
1677 |Args { resumable, .. }| {
1678 let mut v: u32 = resumable.stack.pop_value().try_into().unwrap_validated();
1679
1680 if v | 0xFFFF != 0xFFFF {
1681 trace!("Number v ({}) not contained in 16 bits, truncating", v);
1682 v &= 0xFFFF;
1683 }
1684
1685 let res = if v | 0x7FFF != 0x7FFF {
1686 v | 0xFFFF0000
1687 } else {
1688 v
1689 };
1690
1691 resumable.stack.push_value(res.into())?;
1692
1693 trace!("Instruction i32.extend16_s [{}] -> [{}]", v, res);
1694 Ok(ControlFlow::Continue(()))
1695 }
1696}
1697
1698define_instruction_fn! {
1699 i32_trunc_sat_f32_s,
1700 fuel_check = flat_fc(opcode::fc_extensions::I32_TRUNC_SAT_F32_S),
1701 |Args { resumable, .. }| {
1702 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1703 let res = {
1704 if v1.is_nan() {
1705 0
1706 } else if v1.is_negative_infinity() {
1707 i32::MIN
1708 } else if v1.is_infinity() {
1709 i32::MAX
1710 } else {
1711 v1.as_i32()
1712 }
1713 };
1714
1715 trace!("Instruction: i32.trunc_sat_f32_s [{v1}] -> [{res}]");
1716 resumable.stack.push_value(res.into())?;
1717 Ok(ControlFlow::Continue(()))
1718 }
1719}
1720
1721define_instruction_fn! {
1722 i32_trunc_sat_f32_u,
1723 fuel_check = flat_fc(opcode::fc_extensions::I32_TRUNC_SAT_F32_U),
1724 |Args { resumable, .. }| {
1725 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1726 let res = {
1727 if v1.is_nan() || v1.is_negative_infinity() {
1728 0
1729 } else if v1.is_infinity() {
1730 u32::MAX as i32
1731 } else {
1732 v1.as_u32() as i32
1733 }
1734 };
1735
1736 trace!("Instruction: i32.trunc_sat_f32_u [{v1}] -> [{res}]");
1737 resumable.stack.push_value(res.into())?;
1738 Ok(ControlFlow::Continue(()))
1739 }
1740}
1741
1742define_instruction_fn! {
1743 i32_trunc_sat_f64_s,
1744 fuel_check = flat_fc(opcode::fc_extensions::I32_TRUNC_SAT_F64_S),
1745 |Args { resumable, .. }| {
1746 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1747 let res = {
1748 if v1.is_nan() {
1749 0
1750 } else if v1.is_negative_infinity() {
1751 i32::MIN
1752 } else if v1.is_infinity() {
1753 i32::MAX
1754 } else {
1755 v1.as_i32()
1756 }
1757 };
1758
1759 trace!("Instruction: i32.trunc_sat_f64_s [{v1}] -> [{res}]");
1760 resumable.stack.push_value(res.into())?;
1761 Ok(ControlFlow::Continue(()))
1762 }
1763}
1764
1765define_instruction_fn! {
1766 i32_trunc_sat_f64_u,
1767 fuel_check = flat_fc(opcode::fc_extensions::I32_TRUNC_SAT_F64_U),
1768 |Args { resumable, .. }| {
1769 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1770 let res = {
1771 if v1.is_nan() || v1.is_negative_infinity() {
1772 0
1773 } else if v1.is_infinity() {
1774 u32::MAX as i32
1775 } else {
1776 v1.as_u32() as i32
1777 }
1778 };
1779
1780 trace!("Instruction: i32.trunc_sat_f64_u [{v1}] -> [{res}]");
1781 resumable.stack.push_value(res.into())?;
1782 Ok(ControlFlow::Continue(()))
1783 }
1784}
1785
1786define_instruction_fn! {
1788 i64_extend_i32_s,
1789 fuel_check = flat(opcode::I64_EXTEND_I32_S),
1790 |Args { resumable, .. }| {
1791 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1792
1793 let res: i64 = v as i64;
1794
1795 trace!("Instruction: i64.extend_i32_s [{v}] -> [{res}]");
1796 resumable.stack.push_value(res.into())?;
1797 Ok(ControlFlow::Continue(()))
1798 }
1799}
1800
1801define_instruction_fn! {
1802 i64_extend_i32_u,
1803 fuel_check = flat(opcode::I64_EXTEND_I32_U),
1804 |Args { resumable, .. }| {
1805 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
1806
1807 let res: i64 = v as u32 as i64;
1808
1809 trace!("Instruction: i64.extend_i32_u [{v}] -> [{res}]");
1810 resumable.stack.push_value(res.into())?;
1811 Ok(ControlFlow::Continue(()))
1812 }
1813}
1814
1815define_instruction_fn! {
1816 i64_trunc_f32_s,
1817 fuel_check = flat(opcode::I64_TRUNC_F32_S),
1818 |Args { resumable, .. }| {
1819 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1820 if v.is_infinity() {
1821 return Err(TrapError::UnrepresentableResult.into());
1822 }
1823 if v.is_nan() {
1824 return Err(TrapError::BadConversionToInteger.into());
1825 }
1826 if v >= value::F32(9223372036854775808.0) || v <= value::F32(-9223373136366403584.0) {
1827 return Err(TrapError::UnrepresentableResult.into());
1828 }
1829
1830 let res: i64 = v.as_i64();
1831
1832 trace!("Instruction: i64.trunc_f32_s [{v:.7}] -> [{res}]");
1833 resumable.stack.push_value(res.into())?;
1834 Ok(ControlFlow::Continue(()))
1835 }
1836}
1837
1838define_instruction_fn! {
1839 i64_trunc_f32_u,
1840 fuel_check = flat(opcode::I64_TRUNC_F32_U),
1841 |Args { resumable, .. }| {
1842 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1843 if v.is_infinity() {
1844 return Err(TrapError::UnrepresentableResult.into());
1845 }
1846 if v.is_nan() {
1847 return Err(TrapError::BadConversionToInteger.into());
1848 }
1849 if v >= value::F32(18446744073709551616.0) || v <= value::F32(-1.0) {
1850 return Err(TrapError::UnrepresentableResult.into());
1851 }
1852
1853 let res: i64 = v.as_u64() as i64;
1854
1855 trace!("Instruction: i64.trunc_f32_u [{v:.7}] -> [{res}]");
1856 resumable.stack.push_value(res.into())?;
1857 Ok(ControlFlow::Continue(()))
1858 }
1859}
1860
1861define_instruction_fn! {
1862 i64_trunc_f64_s,
1863 fuel_check = flat(opcode::I64_TRUNC_F64_S),
1864 |Args { resumable, .. }| {
1865 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1866 if v.is_infinity() {
1867 return Err(TrapError::UnrepresentableResult.into());
1868 }
1869 if v.is_nan() {
1870 return Err(TrapError::BadConversionToInteger.into());
1871 }
1872 if v >= value::F64(9223372036854775808.0) || v <= value::F64(-9223372036854777856.0) {
1873 return Err(TrapError::UnrepresentableResult.into());
1874 }
1875
1876 let res: i64 = v.as_i64();
1877
1878 trace!("Instruction: i64.trunc_f64_s [{v:.17}] -> [{res}]");
1879 resumable.stack.push_value(res.into())?;
1880 Ok(ControlFlow::Continue(()))
1881 }
1882}
1883
1884define_instruction_fn! {
1885 i64_trunc_f64_u,
1886 fuel_check = flat(opcode::I64_TRUNC_F64_U),
1887 |Args { resumable, .. }| {
1888 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1889 if v.is_infinity() {
1890 return Err(TrapError::UnrepresentableResult.into());
1891 }
1892 if v.is_nan() {
1893 return Err(TrapError::BadConversionToInteger.into());
1894 }
1895 if v >= value::F64(18446744073709551616.0) || v <= value::F64(-1.0) {
1896 return Err(TrapError::UnrepresentableResult.into());
1897 }
1898
1899 let res: i64 = v.as_u64() as i64;
1900
1901 trace!("Instruction: i64.trunc_f64_u [{v:.17}] -> [{res}]");
1902 resumable.stack.push_value(res.into())?;
1903 Ok(ControlFlow::Continue(()))
1904 }
1905}
1906
1907define_instruction_fn! {
1908 i64_reinterpret_f64,
1909 fuel_check = flat(opcode::I64_REINTERPRET_F64),
1910 |Args { resumable, .. }| {
1911 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
1912 let res: i64 = v.reinterpret_as_i64();
1913
1914 trace!("Instruction: i64.reinterpret_f64 [{v:.17}] -> [{res}]");
1915 resumable.stack.push_value(res.into())?;
1916 Ok(ControlFlow::Continue(()))
1917 }
1918}
1919
1920define_instruction_fn! {
1921 i64_extend8_s,
1922 fuel_check = flat(opcode::I64_EXTEND8_S),
1923 |Args { resumable, .. }| {
1924 let mut v: u64 = resumable.stack.pop_value().try_into().unwrap_validated();
1925
1926 if v | 0xFF != 0xFF {
1927 trace!("Number v ({}) not contained in 8 bits, truncating", v);
1928 v &= 0xFF;
1929 }
1930
1931 let res = if v | 0x7F != 0x7F {
1932 v | 0xFFFFFFFF_FFFFFF00
1933 } else {
1934 v
1935 };
1936
1937 resumable.stack.push_value(res.into())?;
1938
1939 trace!("Instruction i64.extend8_s [{}] -> [{}]", v, res);
1940 Ok(ControlFlow::Continue(()))
1941 }
1942}
1943
1944define_instruction_fn! {
1945 i64_extend16_s,
1946 fuel_check = flat(opcode::I64_EXTEND16_S),
1947 |Args { resumable, .. }| {
1948 let mut v: u64 = resumable.stack.pop_value().try_into().unwrap_validated();
1949
1950 if v | 0xFFFF != 0xFFFF {
1951 trace!("Number v ({}) not contained in 16 bits, truncating", v);
1952 v &= 0xFFFF;
1953 }
1954
1955 let res = if v | 0x7FFF != 0x7FFF {
1956 v | 0xFFFFFFFF_FFFF0000
1957 } else {
1958 v
1959 };
1960
1961 resumable.stack.push_value(res.into())?;
1962
1963 trace!("Instruction i64.extend16_s [{}] -> [{}]", v, res);
1964 Ok(ControlFlow::Continue(()))
1965 }
1966}
1967
1968define_instruction_fn! {
1969 i64_extend32_s,
1970 fuel_check = flat(opcode::I64_EXTEND32_S),
1971 |Args { resumable, .. }| {
1972 let mut v: u64 = resumable.stack.pop_value().try_into().unwrap_validated();
1973
1974 if v | 0xFFFF_FFFF != 0xFFFF_FFFF {
1975 trace!("Number v ({}) not contained in 32 bits, truncating", v);
1976 v &= 0xFFFF_FFFF;
1977 }
1978
1979 let res = if v | 0x7FFF_FFFF != 0x7FFF_FFFF {
1980 v | 0xFFFFFFFF_00000000
1981 } else {
1982 v
1983 };
1984
1985 resumable.stack.push_value(res.into())?;
1986
1987 trace!("Instruction i64.extend32_s [{}] -> [{}]", v, res);
1988 Ok(ControlFlow::Continue(()))
1989 }
1990}
1991
1992define_instruction_fn! {
1993 i64_trunc_sat_f32_s,
1994 fuel_check = flat_fc(opcode::fc_extensions::I64_TRUNC_SAT_F32_S),
1995 |Args { resumable, .. }| {
1996 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
1997 let res = {
1998 if v1.is_nan() {
1999 0
2000 } else if v1.is_negative_infinity() {
2001 i64::MIN
2002 } else if v1.is_infinity() {
2003 i64::MAX
2004 } else {
2005 v1.as_i64()
2006 }
2007 };
2008
2009 trace!("Instruction: i64.trunc_sat_f32_s [{v1}] -> [{res}]");
2010 resumable.stack.push_value(res.into())?;
2011 Ok(ControlFlow::Continue(()))
2012 }
2013}
2014
2015define_instruction_fn! {
2016 i64_trunc_sat_f32_u,
2017 fuel_check = flat_fc(opcode::fc_extensions::I64_TRUNC_SAT_F32_U),
2018 |Args { resumable, .. }| {
2019 let v1: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
2020 let res = {
2021 if v1.is_nan() || v1.is_negative_infinity() {
2022 0
2023 } else if v1.is_infinity() {
2024 u64::MAX as i64
2025 } else {
2026 v1.as_u64() as i64
2027 }
2028 };
2029
2030 trace!("Instruction: i64.trunc_sat_f32_u [{v1}] -> [{res}]");
2031 resumable.stack.push_value(res.into())?;
2032 Ok(ControlFlow::Continue(()))
2033 }
2034}
2035
2036define_instruction_fn! {
2037 i64_trunc_sat_f64_s,
2038 fuel_check = flat_fc(opcode::fc_extensions::I64_TRUNC_SAT_F64_S),
2039 |Args { resumable, .. }| {
2040 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
2041 let res = {
2042 if v1.is_nan() {
2043 0
2044 } else if v1.is_negative_infinity() {
2045 i64::MIN
2046 } else if v1.is_infinity() {
2047 i64::MAX
2048 } else {
2049 v1.as_i64()
2050 }
2051 };
2052
2053 trace!("Instruction: i64.trunc_sat_f64_s [{v1}] -> [{res}]");
2054 resumable.stack.push_value(res.into())?;
2055 Ok(ControlFlow::Continue(()))
2056 }
2057}
2058
2059define_instruction_fn! {
2060 i64_trunc_sat_f64_u,
2061 fuel_check = flat_fc(opcode::fc_extensions::I64_TRUNC_SAT_F64_U),
2062 |Args { resumable, .. }| {
2063 let v1: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
2064 let res = {
2065 if v1.is_nan() || v1.is_negative_infinity() {
2066 0
2067 } else if v1.is_infinity() {
2068 u64::MAX as i64
2069 } else {
2070 v1.as_u64() as i64
2071 }
2072 };
2073
2074 trace!("Instruction: i64.trunc_sat_f64_u [{v1}] -> [{res}]");
2075 resumable.stack.push_value(res.into())?;
2076 Ok(ControlFlow::Continue(()))
2077 }
2078}
2079
2080define_instruction_fn! {
2082 f32_convert_i32_s,
2083 fuel_check = flat(opcode::F32_CONVERT_I32_S),
2084 |Args { resumable, .. }| {
2085 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
2086 let res: value::F32 = value::F32(v as f32);
2087
2088 trace!("Instruction: f32.convert_i32_s [{v}] -> [{res}]");
2089 resumable.stack.push_value(res.into())?;
2090 Ok(ControlFlow::Continue(()))
2091 }
2092}
2093
2094define_instruction_fn! {
2095 f32_convert_i32_u,
2096 fuel_check = flat(opcode::F32_CONVERT_I32_U),
2097 |Args { resumable, .. }| {
2098 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
2099 let res: value::F32 = value::F32(v as u32 as f32);
2100
2101 trace!("Instruction: f32.convert_i32_u [{v}] -> [{res}]");
2102 resumable.stack.push_value(res.into())?;
2103 Ok(ControlFlow::Continue(()))
2104 }
2105}
2106
2107define_instruction_fn! {
2108 f32_convert_i64_s,
2109 fuel_check = flat(opcode::F32_CONVERT_I64_S),
2110 |Args { resumable, .. }| {
2111 let v: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
2112 let res: value::F32 = value::F32(v as f32);
2113
2114 trace!("Instruction: f32.convert_i64_s [{v}] -> [{res}]");
2115 resumable.stack.push_value(res.into())?;
2116 Ok(ControlFlow::Continue(()))
2117 }
2118}
2119
2120define_instruction_fn! {
2121 f32_convert_i64_u,
2122 fuel_check = flat(opcode::F32_CONVERT_I64_U),
2123 |Args { resumable, .. }| {
2124 let v: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
2125 let res: value::F32 = value::F32(v as u64 as f32);
2126
2127 trace!("Instruction: f32.convert_i64_u [{v}] -> [{res}]");
2128 resumable.stack.push_value(res.into())?;
2129 Ok(ControlFlow::Continue(()))
2130 }
2131}
2132
2133define_instruction_fn! {
2134 f32_demote_f64,
2135 fuel_check = flat(opcode::F32_DEMOTE_F64),
2136 |Args { resumable, .. }| {
2137 let v: value::F64 = resumable.stack.pop_value().try_into().unwrap_validated();
2138 let res: value::F32 = v.as_f32();
2139
2140 trace!("Instruction: f32.demote_f64 [{v:.17}] -> [{res:.7}]");
2141 resumable.stack.push_value(res.into())?;
2142 Ok(ControlFlow::Continue(()))
2143 }
2144}
2145
2146define_instruction_fn! {
2147 f32_reinterpret_i32,
2148 fuel_check = flat(opcode::F32_REINTERPRET_I32),
2149 |Args { resumable, .. }| {
2150 let v1: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
2151 let res: value::F32 = value::F32::from_bits(v1 as u32);
2152
2153 trace!("Instruction: f32.reinterpret_i32 [{v1}] -> [{res:.7}]");
2154 resumable.stack.push_value(res.into())?;
2155 Ok(ControlFlow::Continue(()))
2156 }
2157}
2158
2159define_instruction_fn! {
2161 f64_convert_i32_s,
2162 fuel_check = flat(opcode::F64_CONVERT_I32_S),
2163 |Args { resumable, .. }| {
2164 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
2165 let res: value::F64 = value::F64(v as f64);
2166
2167 trace!("Instruction: f64.convert_i32_s [{v}] -> [{res:.17}]");
2168 resumable.stack.push_value(res.into())?;
2169 Ok(ControlFlow::Continue(()))
2170 }
2171}
2172
2173define_instruction_fn! {
2174 f64_convert_i32_u,
2175 fuel_check = flat(opcode::F64_CONVERT_I32_U),
2176 |Args { resumable, .. }| {
2177 let v: i32 = resumable.stack.pop_value().try_into().unwrap_validated();
2178 let res: value::F64 = value::F64(v as u32 as f64);
2179
2180 trace!("Instruction: f64.convert_i32_u [{v}] -> [{res:.17}]");
2181 resumable.stack.push_value(res.into())?;
2182 Ok(ControlFlow::Continue(()))
2183 }
2184}
2185
2186define_instruction_fn! {
2187 f64_convert_i64_s,
2188 fuel_check = flat(opcode::F64_CONVERT_I64_S),
2189 |Args { resumable, .. }| {
2190 let v: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
2191 let res: value::F64 = value::F64(v as f64);
2192
2193 trace!("Instruction: f64.convert_i64_s [{v}] -> [{res:.17}]");
2194 resumable.stack.push_value(res.into())?;
2195 Ok(ControlFlow::Continue(()))
2196 }
2197}
2198
2199define_instruction_fn! {
2200 f64_convert_i64_u,
2201 fuel_check = flat(opcode::F64_CONVERT_I64_U),
2202 |Args { resumable, .. }| {
2203 let v: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
2204 let res: value::F64 = value::F64(v as u64 as f64);
2205
2206 trace!("Instruction: f64.convert_i64_u [{v}] -> [{res:.17}]");
2207 resumable.stack.push_value(res.into())?;
2208 Ok(ControlFlow::Continue(()))
2209 }
2210}
2211
2212define_instruction_fn! {
2213 f64_promote_f32,
2214 fuel_check = flat(opcode::F64_PROMOTE_F32),
2215 |Args { resumable, .. }| {
2216 let v: value::F32 = resumable.stack.pop_value().try_into().unwrap_validated();
2217 let res: value::F64 = v.as_f64();
2218
2219 trace!("Instruction: f64.promote_f32 [{v:.7}] -> [{res:.17}]");
2220 resumable.stack.push_value(res.into())?;
2221 Ok(ControlFlow::Continue(()))
2222 }
2223}
2224
2225define_instruction_fn! {
2226 f64_reinterpret_i64,
2227 fuel_check = flat(opcode::F64_REINTERPRET_I64),
2228 |Args { resumable, .. }| {
2229 let v1: i64 = resumable.stack.pop_value().try_into().unwrap_validated();
2230 let res: value::F64 = value::F64::from_bits(v1 as u64);
2231
2232 trace!("Instruction: f64.reinterpret_i64 [{v1}] -> [{res:.17}]");
2233 resumable.stack.push_value(res.into())?;
2234 Ok(ControlFlow::Continue(()))
2235 }
2236}