1use std::{collections::HashSet, vec};
2
3use anyhow::Result;
4use wasmparser::{
5 for_each_operator, BlockType, BrTable, FuncType, FunctionBody, Ieee32, Ieee64, MemArg,
6 StorageType, ValType, VisitOperator,
7};
8
9use crate::ir::{
10 builder::Builder,
11 code::{Breakable, Call, Code, Inst, InstKind},
12 module::Module,
13 trap,
14 ty::{Const, CsType},
15 var::{Primary, Var, VarId},
16 PAGE_SIZE,
17};
18
19use super::{
20 pool::{LoopVarPool, PoolLoopVar, PoolPrimary, PoolVar, VarPool},
21 NotSupportedError,
22};
23
24macro_rules! define_single_visit_operator {
25 ( @mvp $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {};
26 ( @saturating_float_to_int $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {};
27 ( @sign_extension $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {};
28 ( @bulk_memory $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {};
29 ( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
30 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
31 panic!(stringify!($proposal))
32 }
33 };
34}
35
36macro_rules! define_visit_operator {
37 ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
38 $(
39 define_single_visit_operator!(@$proposal $op $({ $($arg: $argty),* })? => $visit);
40 )*
41 }
42}
43
44pub struct CodeParser<'input, 'module> {
45 module: &'module Module<'input>,
46 func: usize,
47 blocks: Vec<Block>,
48 builder: Builder,
49 unreachable: i32,
53 var_pool: VarPool,
54 loop_var_pool: LoopVarPool,
55}
56
57struct Block {
58 stack: Vec<PoolPrimary>,
59 result: Option<PoolVar>,
60 loop_var: Option<PoolLoopVar>,
61}
62
63impl<'input, 'module> CodeParser<'input, 'module> {
64 pub(super) fn new(module: &'module Module<'input>, func: usize) -> Self {
65 let header = &module.all_funcs[func].header;
66 Self {
67 module,
68 func,
69 blocks: Vec::new(),
70 builder: Builder::new(header.ty.params()),
71 unreachable: 0,
72 var_pool: VarPool::new(),
73 loop_var_pool: LoopVarPool::new(),
74 }
75 }
76
77 pub fn parse(mut self, body: FunctionBody<'_>) -> Result<Code> {
78 for local in body.get_locals_reader()? {
79 let (count, ty) = local?;
80 for _ in 0..count {
81 let cs_ty = CsType::get(ty);
82 self.builder.new_var(Var {
83 ty: cs_ty,
84 local: true,
85 default: Some(cs_ty.default()),
86 ..Default::default()
87 });
88 }
89 }
90
91 let blockty = {
92 let func = &self.module.all_funcs[self.func];
93 let results = func.header.ty.results();
94 match results.len() {
95 0 => BlockType::Empty,
96 1 => BlockType::Type(results[0]),
97 _ => panic!("multi_value"),
98 }
99 };
100
101 self.visit_block(blockty)?;
103 let result_var = self.blocks[0].result.as_ref().map(|x| x.id());
104
105 for op in body.get_operators_reader()? {
106 let op = op?;
107
108 if self.unreachable > 0 {
109 use wasmparser::Operator::*;
110 match &op {
111 Block { .. } | Loop { .. } | If { .. } | Else | End => {}
112 _ => continue,
113 }
114 }
115 self.visit_operator(&op)?;
116 }
117
118 if let Some(res) = result_var {
119 self.builder.push_return(Some(res.into()));
120 }
121
122 assert!(self.blocks.is_empty());
123
124 #[cfg(debug_assertions)]
125 {
126 self.var_pool.validate();
127 self.loop_var_pool.validate();
128 }
129
130 Ok(self.builder.build())
131 }
132
133 fn new_block(&mut self, blockty: BlockType, is_loop: bool) -> &Block {
134 let result = match blockty {
135 BlockType::Empty => None,
136 BlockType::Type(ty) => {
137 let cs_ty = CsType::get(ty);
138 Some(
139 self.var_pool
140 .take(&mut self.builder, cs_ty, Some(cs_ty.default())),
141 )
142 }
143 BlockType::FuncType(..) => panic!("multi_value"),
144 };
145
146 let loop_var = if is_loop {
147 Some(self.loop_var_pool.take(&mut self.builder))
148 } else {
149 None
150 };
151
152 self.blocks.push(Block {
153 stack: Vec::new(),
154 result,
155 loop_var,
156 });
157 self.blocks.last().unwrap()
158 }
159
160 fn block_result(&mut self, relative_depth: u32, is_br: bool) {
162 let upper_block = &self.blocks[self.blocks.len() - 1 - relative_depth as usize];
163
164 if is_br && upper_block.loop_var.is_some() {
166 return;
167 }
168
169 if let Some(result) = &upper_block.result {
170 let current_block = &self.blocks[self.blocks.len() - 1];
171 let rhs = current_block.stack.last().unwrap();
172 self.builder.push_set(result.id(), rhs.into());
173 }
174 }
175
176 fn push_stack(&mut self, val: PoolPrimary) {
177 self.blocks.last_mut().unwrap().stack.push(val)
178 }
179
180 fn pop_stack(&mut self) -> PoolPrimary {
181 let prim = self.blocks.last_mut().unwrap().stack.pop().unwrap();
182 prim
183 }
184
185 fn last_stack(&self) -> &PoolPrimary {
186 self.blocks.last().unwrap().stack.last().unwrap()
187 }
188
189 fn ty(&self, primary: &PoolPrimary) -> CsType {
190 Primary::from(primary).ty(&self.builder.code.vars)
191 }
192
193 fn call(&mut self, index: usize, ty: FuncType, params: Vec<PoolPrimary>) {
194 let save_vars = self.get_save_vars();
195 let save_loop_vars = self.get_save_loop_vars();
196
197 let result = self.get_result(&ty);
198
199 let call = Call {
200 func: index,
201 recursive: false,
202 save_vars,
203 save_loop_vars,
204 };
205
206 let params = params.into_iter().map(|x| x.into()).collect();
207 self.builder.push_call(call, params, result);
208 }
209
210 fn get_save_vars(&self) -> HashSet<VarId> {
211 let locals = self
212 .builder
213 .code
214 .vars
215 .iter()
216 .filter(|(_, var)| var.local)
217 .map(|(id, _)| id);
218
219 let stack_vars = self.blocks.iter().flat_map(|block| {
220 block.stack.iter().filter_map(|prim| match prim {
221 PoolPrimary::Pool(x) => Some(x.id()),
222 PoolPrimary::Local(x) => Some(*x),
223 PoolPrimary::Const(_) => None,
224 })
225 });
226
227 locals.chain(stack_vars).collect()
228 }
229
230 fn get_save_loop_vars(&self) -> HashSet<u32> {
231 self.blocks
232 .iter()
233 .filter_map(|block| block.loop_var.as_ref())
234 .map(|x| x.index())
235 .collect()
236 }
237
238 fn get_result(&mut self, ty: &FuncType) -> Option<VarId> {
239 match ty.results().len() {
240 0 => None,
241 1 => {
242 let var = self
243 .var_pool
244 .take(&mut self.builder, CsType::get(ty.results()[0]), None);
245 let id = var.id();
246 self.push_stack(var.into());
247 Some(id)
248 }
249 _ => panic!("multi_value"),
250 }
251 }
252
253 fn visit_load(
254 &mut self,
255 memarg: MemArg,
256 result_ty: CsType,
257 storage_ty: StorageType,
258 signed: Option<bool>,
259 ) -> <Self as VisitOperator<'_>>::Output {
260 use {StorageType::*, ValType::*};
261
262 let idx = self.pop_stack();
263 let result = self.var_pool.take(&mut self.builder, result_ty, None);
264
265 let memory = &self.module.memory.as_ref().unwrap().name;
266 let idx_pat = index_pattern(memarg.offset);
267
268 let mut kind = InstKind::Expr;
269
270 let pattern = match (storage_ty, signed) {
271 (I8, Some(false)) => format!("{memory}[{idx_pat}]"),
272 (I8, Some(true)) => {
273 kind = InstKind::Stmt;
274 format!("$r = {memory}[{idx_pat}]; if ($r >= 0x80) $r |= -0x100;")
275 }
276 (I16, Some(false)) => format!("BitConverter.ToUInt16({memory}, {idx_pat})"),
277 (I16, Some(true)) => format!("BitConverter.ToInt16({memory}, {idx_pat})"),
278 (Val(I32), Some(false)) => format!("BitConverter.ToUInt32({memory}, {idx_pat})"),
279 (Val(I32), Some(true) | None) => format!("BitConverter.ToInt32({memory}, {idx_pat})"),
280 (Val(I64), None) => format!("BitConverter.ToInt64({memory}, {idx_pat})"),
281 (Val(F32), None) => format!("BitConverter.ToSingle({memory}, {idx_pat})"),
282 (Val(F64), None) => format!("BitConverter.ToDouble({memory}, {idx_pat})"),
283 _ => unreachable!(),
284 };
285
286 self.builder.push(Inst {
287 kind,
288 pattern,
289 params: vec![idx.into()],
290 result: Some(result.id()),
291 ..Default::default()
292 });
293
294 self.push_stack(result.into());
295 Ok(())
296 }
297
298 fn visit_store(
299 &mut self,
300 memarg: MemArg,
301 storage_ty: StorageType,
302 ) -> <Self as VisitOperator<'_>>::Output {
303 use {StorageType::*, ValType::*};
304
305 let var = self.pop_stack();
306 let idx = self.pop_stack();
307
308 let memory = &self.module.memory.as_ref().unwrap().name;
309 let idx_pat = index_pattern(memarg.offset);
310
311 let pattern = match storage_ty {
312 I8 => format!("{memory}[{idx_pat}] = {}($p1 & 0xff);", CsType::Byte.cast()),
313 I16 => format!("BitConverter.GetBytes(Convert.ToUInt16($p1 & 0xffff)).CopyTo({memory}, {idx_pat});"),
314 Val(I32) => match self.ty(&var) {
315 CsType::Int => format!("BitConverter.GetBytes($p1).CopyTo({memory}, {idx_pat});"),
316 CsType::Long => format!("BitConverter.GetBytes({}($p1 & 0xffffffff)).CopyTo({memory}, {idx_pat});", CsType::UInt.cast()),
317 _ => unreachable!(),
318 },
319 Val(I64) | Val(F32) | Val(F64) => format!("BitConverter.GetBytes($p1).CopyTo({memory}, {idx_pat});"),
320 _ => unreachable!(),
321 };
322
323 self.builder.push(Inst {
324 kind: InstKind::Stmt,
325 pattern,
326 params: vec![idx.into(), var.into()],
327 ..Default::default()
328 });
329 Ok(())
330 }
331
332 fn un_op_vars(&mut self, result_ty: CsType) -> (PoolPrimary, VarId) {
334 let opnd = self.pop_stack();
335 let result = self.var_pool.take(&mut self.builder, result_ty, None);
336 let result_id = result.id();
337 self.push_stack(result.into());
338
339 (opnd, result_id)
340 }
341
342 fn un_op_vars_auto_ty(&mut self) -> (PoolPrimary, VarId) {
344 let opnd = self.pop_stack();
345 let ty = self.ty(&opnd);
346 let result = self.var_pool.take(&mut self.builder, ty, None);
347 let result_id = result.id();
348 self.push_stack(result.into());
349
350 (opnd, result_id)
351 }
352
353 fn bin_op_vars_auto_ty(&mut self) -> (PoolPrimary, PoolPrimary, VarId) {
355 let rhs = self.pop_stack();
356 let lhs = self.pop_stack();
357 let ty = self.ty(&lhs);
358 let result = self.var_pool.take(&mut self.builder, ty, None);
359 let result_id = result.id();
360 self.push_stack(result.into());
361
362 (lhs, rhs, result_id)
363 }
364
365 fn visit_eqz(&mut self) -> <Self as VisitOperator<'_>>::Output {
366 let (opnd, result) = self.un_op_vars(CsType::Int);
367
368 self.builder.push_set_pattern(
369 result,
370 format!("{}($p0 == 0)", self.builder.code.vars[result].ty.cast()),
371 vec![opnd.into()],
372 );
373 Ok(())
374 }
375
376 fn visit_un_op(&mut self, op: &str) -> <Self as VisitOperator<'_>>::Output {
377 let (opnd, result) = self.un_op_vars_auto_ty();
378
379 self.builder
380 .push_set_pattern(result, format!("{op}$p0"), vec![opnd.into()]);
381 Ok(())
382 }
383
384 fn visit_bin_op(
385 &mut self,
386 op: &str,
387 logical: bool,
388 signed: bool,
389 ) -> <Self as VisitOperator<'_>>::Output {
390 let rhs = self.pop_stack();
391 let lhs = self.pop_stack();
392 let result_ty = if logical { CsType::Int } else { self.ty(&lhs) };
393 let result = self.var_pool.take(&mut self.builder, result_ty, None);
394
395 if signed {
396 if logical {
397 self.builder.push_set_pattern(
398 result.id(),
399 format!(
400 "{}($p0 {op} $p1)",
401 self.builder.code.vars[result.id()].ty.cast()
402 ),
403 vec![lhs.into(), rhs.into()],
404 );
405 } else {
406 self.builder.push_set_pattern(
407 result.id(),
408 format!("$p0 {op} $p1"),
409 vec![lhs.into(), rhs.into()],
410 );
411 }
412 } else {
413 let lhs_u_ty = self.ty(&lhs).to_unsigned();
414 let lhs_u = self.var_pool.take(&mut self.builder, lhs_u_ty, None);
415 let rhs_u_ty = self.ty(&rhs).to_unsigned();
416 let rhs_u = self.var_pool.take(&mut self.builder, rhs_u_ty, None);
417 let tmp = self.var_pool.take(
418 &mut self.builder,
419 if logical { CsType::Bool } else { lhs_u_ty },
420 None,
421 );
422
423 self.cast_sign(lhs, lhs_u.id());
424 self.cast_sign(rhs, rhs_u.id());
425 self.builder.push_set_pattern(
426 tmp.id(),
427 format!("$p0 {op} $p1"),
428 vec![lhs_u.id().into(), rhs_u.id().into()],
429 );
430
431 if logical {
432 self.builder.push_set_pattern(
433 result.id(),
434 format!("{}($p0)", self.builder.code.vars[result.id()].ty.cast()),
435 vec![tmp.id().into()],
436 );
437 } else {
438 self.cast_sign(tmp.into(), result.id());
439 }
440 }
441
442 self.push_stack(result.into());
443 Ok(())
444 }
445
446 fn visit_rem_op(&mut self, signed: bool) -> <Self as VisitOperator<'_>>::Output {
447 let (lhs, rhs, result) = self.bin_op_vars_auto_ty();
448
449 if signed {
450 self.builder.push_set_pattern(
451 result,
452 "$p0 - $p0 / $p1 * $p1",
453 vec![lhs.into(), rhs.into()],
454 );
455 } else {
456 let lhs_u_ty = self.ty(&lhs).to_unsigned();
457 let lhs_u = self.var_pool.take(&mut self.builder, lhs_u_ty, None);
458 let rhs_u_ty = self.ty(&rhs).to_unsigned();
459 let rhs_u = self.var_pool.take(&mut self.builder, rhs_u_ty, None);
460 let tmp = self.var_pool.take(&mut self.builder, lhs_u_ty, None);
461
462 self.cast_sign(lhs, lhs_u.id());
463 self.cast_sign(rhs, rhs_u.id());
464 self.builder.push_set_pattern(
465 tmp.id(),
466 "$p0 - $p0 / $p1 * $p1",
467 vec![lhs_u.id().into(), rhs_u.id().into()],
468 );
469 self.cast_sign(tmp.into(), result);
470 };
471
472 Ok(())
473 }
474
475 fn cast_sign(&mut self, opnd: PoolPrimary, result: VarId) {
476 let result_ty = self.builder.code.vars[result].ty;
477 let bits = result_ty.int_bits();
478 let only_msb = 1u64 << (bits - 1);
479 let except_msb = only_msb - 1;
480 let cast_ty = result_ty.cast();
481
482 if result_ty.signed() {
483 self.builder.push_set_pattern(result,
484 format!("$p0 >= {only_msb} ? {cast_ty}($p0 - {only_msb}) | (-{except_msb} - 1) : {cast_ty}($p0)"),
485 vec![opnd.into()],
486 );
487 } else {
488 self.builder.push_set_pattern(
489 result,
490 format!("$p0 < 0 ? {cast_ty}($p0 & {except_msb}) | {only_msb} : {cast_ty}($p0)"),
491 vec![opnd.into()],
492 );
493 }
494 }
495
496 fn visit_shift_op(&mut self, op: &str, signed: bool) -> <Self as VisitOperator<'_>>::Output {
497 let (lhs, rhs, result) = self.bin_op_vars_auto_ty();
498
499 let rhs_int = if self.ty(&rhs) == CsType::Int {
500 rhs
501 } else {
502 let rhs_int = self.var_pool.take(&mut self.builder, CsType::Int, None);
503 self.wrap(rhs, rhs_int.id());
504 rhs_int.into()
505 };
506
507 if signed {
508 self.builder.push_set_pattern(
509 result,
510 format!("$p0 {op} $p1"),
511 vec![lhs.into(), rhs_int.into()],
512 );
513 } else {
514 self.shr_u(&lhs, &rhs_int, result);
515 }
516 Ok(())
517 }
518
519 fn shr_u(&mut self, lhs: &PoolPrimary, rhs_int: &PoolPrimary, result: VarId) {
520 let bits = self.ty(lhs).int_bits();
521 let only_msb = 1u64 << (bits - 1);
522 let except_msb = only_msb - 1;
523
524 self.builder.push_set_pattern(
525 result,
526 format!(
527 "$p0 < 0 ? (($p0 & {except_msb}) >> $p1) | ({} << (-1 - $p1)) : $p0 >> $p1",
528 if self.ty(lhs) == CsType::Long {
529 "1L"
530 } else {
531 "1"
532 }
533 ),
534 vec![lhs.into(), rhs_int.into()],
535 );
536 }
537
538 fn visit_rot_op(&mut self, right: bool) -> <Self as VisitOperator<'_>>::Output {
539 let (lhs, rhs, result) = self.bin_op_vars_auto_ty();
540
541 let bits = self.ty(&lhs).int_bits();
542
543 let rhs_int = if self.ty(&rhs) == CsType::Int {
544 rhs
545 } else {
546 let rhs_int = self.var_pool.take(&mut self.builder, CsType::Int, None);
547 self.wrap(rhs, rhs_int.id());
548 rhs_int.into()
549 };
550
551 let bits_m_rhs = self.var_pool.take(&mut self.builder, CsType::Int, None);
552 self.builder.push_set_pattern(
553 bits_m_rhs.id(),
554 format!("{bits} - $p0"),
555 vec![(&rhs_int).into()],
556 );
557
558 let shr_ty = self.ty(&lhs);
559 let shr = self.var_pool.take(&mut self.builder, shr_ty, None);
560 if right {
561 self.shr_u(&lhs, &rhs_int, shr.id());
562 self.builder.push_set_pattern(
563 result,
564 "$p0 | ($p1 << $p2)",
565 vec![shr.id().into(), lhs.into(), bits_m_rhs.id().into()],
566 );
567 } else {
568 self.shr_u(&lhs, &bits_m_rhs.into(), shr.id());
569 self.builder.push_set_pattern(
570 result,
571 "($p0 << $p1) | $p2",
572 vec![lhs.into(), rhs_int.into(), shr.id().into()],
573 );
574 }
575 Ok(())
576 }
577
578 fn visit_clz(&mut self) -> <Self as VisitOperator<'_>>::Output {
579 let (opnd, result) = self.un_op_vars_auto_ty();
580
581 let bits = self.ty(&opnd).int_bits();
582
583 let mut pattern = format!("$p0 == 0 ? {bits} : ");
584 let cast_ty = cast_from(CsType::Int, self.ty(&opnd));
585 pattern += &format!("{cast_ty}({bits} - Convert.ToString($p0, 2).Length)",);
587
588 self.builder
589 .push_set_pattern(result, pattern, vec![opnd.into()]);
590 Ok(())
591 }
592
593 fn visit_ctz(&mut self) -> <Self as VisitOperator<'_>>::Output {
594 let (opnd, result) = self.un_op_vars_auto_ty();
595
596 let bits = self.ty(&opnd).int_bits();
597
598 let mut pattern = format!("$p0 == 0 ? {bits} : ");
599 let cast_ty = cast_from(CsType::Int, self.ty(&opnd));
600
601 let or_opnd = match self.ty(&opnd) {
604 CsType::Int => (1i32 << (bits - 1)) as i64,
605 CsType::Long => 1i64 << (bits - 1),
606 _ => unreachable!(),
607 } + 1;
608
609 pattern += &format!(
613 "{} - {cast_ty}(Convert.ToString(($p0 | ({or_opnd} - 1)), 2).LastIndexOf('1'))",
614 bits - 1,
615 );
616
617 self.builder
618 .push_set_pattern(result, pattern, vec![opnd.into()]);
619 Ok(())
620 }
621
622 fn visit_popcnt(&mut self) -> <Self as VisitOperator<'_>>::Output {
623 let (opnd, result) = self.un_op_vars_auto_ty();
624
625 let cast_ty = cast_from(CsType::Int, self.ty(&opnd));
626 self.builder.push_set_pattern(
628 result,
629 format!("{cast_ty}(Convert.ToString($p0, 2).Replace(\"0\", \"\").Length)"),
630 vec![opnd.into()],
631 );
632 Ok(())
633 }
634
635 fn visit_math_un_op(&mut self, func: &str) -> <Self as VisitOperator<'_>>::Output {
636 let (opnd, result) = self.un_op_vars_auto_ty();
637
638 self.builder.push_set_pattern(
639 result,
640 format!("{}.{func}($p0)", self.module.math_class(self.ty(&opnd))),
641 vec![opnd.into()],
642 );
643 Ok(())
644 }
645
646 fn visit_math_bin_op(&mut self, func: &str) -> <Self as VisitOperator<'_>>::Output {
647 let (lhs, rhs, result) = self.bin_op_vars_auto_ty();
648
649 self.builder.push_set_pattern(
650 result,
651 format!("{}.{func}($p0, $p1)", self.module.math_class(self.ty(&lhs))),
652 vec![lhs.into(), rhs.into()],
653 );
654 Ok(())
655 }
656
657 fn visit_copysign_op(&mut self) -> <Self as VisitOperator<'_>>::Output {
658 let (lhs, rhs, result) = self.bin_op_vars_auto_ty();
659
660 self.builder.push_set_pattern(
661 result,
662 format!(
663 "{0}.Abs($p0) * (($p1 == 0 ? 1 / $p1 : $p1) > 0 ? 1 : -1)",
664 self.module.math_class(self.ty(&lhs))
665 ),
666 vec![lhs.into(), rhs.into()],
667 );
668 Ok(())
669 }
670
671 fn visit_cast(&mut self, result_ty: CsType) -> <Self as VisitOperator<'_>>::Output {
672 let (opnd, result) = self.un_op_vars(result_ty);
673 let cast_ty = result_ty.cast();
674
675 self.builder
676 .push_set_pattern(result, format!("{cast_ty}($p0)"), vec![opnd.into()]);
677 Ok(())
678 }
679
680 fn wrap(&mut self, opnd: PoolPrimary, result: VarId) {
681 let mut pattern = format!("$r = {}($p0 & 0x7fffffff); ", CsType::Int.cast());
682 pattern += &format!(
683 "if ({}($p0 & 0x80000000)) $r |= -0x7fffffff - 1;",
684 CsType::Bool.cast(),
685 );
686
687 self.builder.push(Inst {
688 kind: InstKind::Stmt,
689 pattern,
690 params: vec![opnd.into()],
691 result: Some(result),
692 ..Default::default()
693 })
694 }
695
696 fn visit_cast_trunc(
697 &mut self,
698 result_ty: CsType,
699 signed: bool,
700 ) -> <Self as VisitOperator<'_>>::Output {
701 let (opnd, result) = self.un_op_vars(result_ty);
702 self.trunc(result_ty, signed, opnd, result);
703 Ok(())
704 }
705
706 fn visit_cast_trunc_sat(
707 &mut self,
708 result_ty: CsType,
709 signed: bool,
710 ) -> <Self as VisitOperator<'_>>::Output {
711 let (opnd, result) = self.un_op_vars(result_ty);
712
713 let (min, max) = match (result_ty, signed) {
714 (CsType::Int, true) => (Const::Int(i32::MIN), Const::Int(i32::MAX)),
715 (CsType::Int, false) => (Const::UInt(u32::MIN), Const::UInt(u32::MAX)),
716 (CsType::Long, true) => (Const::Long(i64::MIN), Const::Long(i64::MAX)),
717 (CsType::Long, false) => (Const::ULong(u64::MIN), Const::ULong(u64::MAX)),
718 _ => unreachable!(),
719 };
720
721 self.builder.push_if_pattern(
722 format!("{}.IsNaN($p0)", self.ty(&opnd)),
723 vec![(&opnd).into()],
724 Breakable::No,
725 );
726 {
727 self.builder.start_block();
729 self.builder.push_set(result, result_ty.default().into());
730 self.builder.end_block();
731 }
732 {
733 self.builder.start_block();
734 self.builder.push_if_pattern(
735 format!("$p0 <= {}", min),
736 vec![(&opnd).into()],
737 Breakable::No,
738 );
739 {
740 self.builder.start_block();
742 self.builder.push_set(result, min.to_signed().into());
743 self.builder.end_block();
744 }
745 {
746 self.builder.start_block();
747 self.builder.push_if_pattern(
748 format!("$p0 >= {}", max),
749 vec![(&opnd).into()],
750 Breakable::No,
751 );
752 {
753 self.builder.start_block();
755 self.builder.push_set(result, max.to_signed().into());
756 self.builder.end_block();
757 }
758 {
759 self.builder.start_block();
760 self.trunc(result_ty, signed, opnd, result);
761 self.builder.end_block();
762 }
763 self.builder.end_block();
764 }
765 self.builder.end_block();
766 }
767
768 Ok(())
769 }
770
771 fn trunc(&mut self, result_ty: CsType, signed: bool, opnd: PoolPrimary, result: VarId) {
772 let tmp = self.var_pool.take(&mut self.builder, CsType::Double, None);
773
774 self.builder.push_set_pattern(
775 tmp.id(),
776 format!(
777 "Math.Truncate({}($p0))",
778 cast_from(self.ty(&opnd), CsType::Double)
779 ),
780 vec![opnd.into()],
781 );
782
783 if signed {
784 let cast_ty = result_ty.cast();
785 self.builder
786 .push_set_pattern(result, format!("{cast_ty}($p0)"), vec![tmp.id().into()]);
787 } else {
788 self.cast_sign(tmp.into(), result);
789 }
790 }
791
792 fn visit_cast_extend(&mut self, signed: bool) -> <Self as VisitOperator<'_>>::Output {
793 let (opnd, result) = self.un_op_vars(CsType::Long);
794 let cast_ty = CsType::Long.cast();
795
796 if signed {
797 self.builder
798 .push_set_pattern(result, format!("{cast_ty}($p0)"), vec![opnd.into()]);
799 } else {
800 self.builder.push_set_pattern(
801 result,
802 format!("$p0 < 0 ? {cast_ty}($p0 & 0x7fffffff) | 0x80000000 : {cast_ty}($p0)"),
803 vec![opnd.into()],
804 );
805 }
806 Ok(())
807 }
808
809 fn visit_cast_convert(
810 &mut self,
811 result_ty: CsType,
812 signed: bool,
813 ) -> <Self as VisitOperator<'_>>::Output {
814 let (opnd, result) = self.un_op_vars(result_ty);
815
816 let cast_ty = result_ty.cast();
817
818 if signed {
819 self.builder
820 .push_set_pattern(result, format!("{cast_ty}($p0)"), vec![opnd.into()]);
821 } else {
822 let bits = self.ty(&opnd).int_bits();
823 let only_msb = 1u64 << (bits - 1);
824
825 if matches!(result_ty, CsType::Float | CsType::Double) {
826 let opnd_ty_u = self.ty(&opnd).to_unsigned();
827 self.builder.push_set_pattern(
828 result,
829 format!(
830 "$p0 < 0 ? {cast_ty}(({opnd_ty_u})($p0 & {}) + {only_msb}) : {cast_ty}($p0)",
831 only_msb - 1
832 ),
833 vec![opnd.into()],
834 );
835 } else {
836 self.builder.push_set_pattern(
837 result,
838 format!(
839 "$p0 < 0 ? {cast_ty}($p0 & {}) + {only_msb} : {cast_ty}($p0)",
840 only_msb - 1
841 ),
842 vec![opnd.into()],
843 );
844 }
845 }
846 Ok(())
847 }
848
849 fn visit_extend(&mut self, ty: StorageType) -> <Self as VisitOperator<'_>>::Output {
850 let opnd = self.pop_stack();
851 let result_ty = self.ty(&opnd);
852 let result = self.var_pool.take(&mut self.builder, result_ty, None);
853
854 use {StorageType::*, ValType::*};
855 let (and, ge, or) = match ty {
856 I8 => ("0xff", "0x80", "-0x100"),
857 I16 => ("0xffff", "0x8000", "-0x10000"),
858 Val(I32) => ("0xffffffff", "0x80000000", "-0x100000000"),
859 _ => unreachable!(),
860 };
861
862 let mut pattern = format!("$r = $p0 & {and}; ");
863 pattern += &format!("if ($r >= {ge}) $r |= {or};");
864
865 self.builder.push(Inst {
866 kind: InstKind::Stmt,
867 pattern,
868 params: vec![opnd.into()],
869 result: Some(result.id()),
870 ..Default::default()
871 });
872
873 self.push_stack(result.into());
874 Ok(())
875 }
876
877 fn visit_br_table_case(&mut self, case: Option<usize>, target: u32) {
878 self.builder.start_block();
879 match case {
880 Some(case) => self.builder.push_case(Const::Int(case as i32).into()),
881 None => self.builder.push_default(),
882 }
883 self.block_result(target, true);
884 self.builder
889 .push_br(if target == 0 { 0 } else { target + 1 });
890 self.builder.end_block();
891 }
892}
893
894fn index_pattern(offset: u64) -> String {
895 if offset == 0 {
896 "$p0".to_string()
897 } else {
898 format!("$p0 + {}", offset as i32)
899 }
900}
901
902impl<'a, 'input, 'module> VisitOperator<'a> for CodeParser<'input, 'module> {
903 type Output = Result<()>;
904
905 for_each_operator!(define_visit_operator);
906
907 fn visit_unreachable(&mut self) -> Self::Output {
908 self.unreachable = 1;
909 self.builder.push_line(trap(self.module, "unreachable"));
910 Ok(())
911 }
912
913 fn visit_nop(&mut self) -> Self::Output {
914 self.builder.push_line("// nop");
915 Ok(())
916 }
917
918 fn visit_block(&mut self, blockty: BlockType) -> Self::Output {
919 if self.unreachable > 0 {
920 self.unreachable += 1;
921 return Ok(());
922 }
923
924 self.new_block(blockty, false);
925
926 self.builder.push_block(Breakable::Multi);
927 self.builder.start_block();
928
929 Ok(())
930 }
931
932 fn visit_loop(&mut self, blockty: BlockType) -> Self::Output {
933 if self.unreachable > 0 {
934 self.unreachable += 1;
935 return Ok(());
936 }
937
938 let block = self.new_block(blockty, true);
939 let loop_var = block.loop_var.as_ref().unwrap().index();
940
941 self.builder.push_loop(loop_var, Breakable::Multi);
942 self.builder.start_block();
943
944 Ok(())
945 }
946
947 fn visit_if(&mut self, blockty: BlockType) -> Self::Output {
948 if self.unreachable > 0 {
949 self.unreachable += 1;
950 return Ok(());
951 }
952
953 let opnd = self.pop_stack();
954 self.new_block(blockty, false);
955
956 self.builder.push_if(opnd.into(), Breakable::Multi);
957 self.builder.start_block();
958
959 Ok(())
960 }
961
962 fn visit_else(&mut self) -> Self::Output {
963 match self.unreachable {
964 0 => self.block_result(0, false),
965 1 => self.unreachable -= 1,
966 _ => return Ok(()),
967 }
968
969 self.blocks.last_mut().unwrap().stack.clear();
970
971 self.builder.end_block();
972 self.builder.start_block();
973
974 Ok(())
975 }
976
977 fn visit_end(&mut self) -> Self::Output {
978 match self.unreachable {
979 0 => self.block_result(0, false),
980 1 => self.unreachable -= 1,
981 _ => {
982 self.unreachable -= 1;
983 return Ok(());
984 }
985 }
986
987 let block = self.blocks.pop().unwrap();
988
989 if !self.blocks.is_empty() {
991 if let Some(result) = block.result {
992 self.push_stack(result.into());
993 }
994 }
995
996 self.builder.end_block();
997 Ok(())
998 }
999
1000 fn visit_br(&mut self, relative_depth: u32) -> Self::Output {
1001 self.block_result(relative_depth, true);
1002 self.unreachable = 1;
1003
1004 self.builder.push_br(relative_depth);
1005 Ok(())
1006 }
1007
1008 fn visit_br_if(&mut self, relative_depth: u32) -> Self::Output {
1009 let opnd = self.pop_stack();
1010
1011 self.builder.push_if(opnd.into(), Breakable::No);
1012 self.builder.start_block();
1013 self.block_result(relative_depth, true);
1014 self.builder.push_br(relative_depth);
1015 self.builder.end_block();
1016 Ok(())
1017 }
1018
1019 fn visit_br_table(&mut self, targets: BrTable<'a>) -> Self::Output {
1020 self.unreachable = 1;
1021 let opnd = self.pop_stack();
1022
1023 self.builder.push_switch(opnd.into(), Breakable::Multi);
1024
1025 for (i, target) in targets.targets().enumerate() {
1026 self.visit_br_table_case(Some(i), target?);
1028 }
1029
1030 self.visit_br_table_case(None, targets.default());
1032
1033 Ok(())
1034 }
1035
1036 fn visit_return(&mut self) -> Self::Output {
1037 self.unreachable = 1;
1038
1039 let results_len = self.module.all_funcs[self.func].header.ty.results().len();
1040 match results_len {
1041 0 => self.builder.push_return(None),
1042 1 => {
1043 let var = self.last_stack();
1044 self.builder.push_return(Some(var.into()));
1045 }
1046 _ => panic!("multi_value"),
1047 }
1048 Ok(())
1049 }
1050
1051 fn visit_call(&mut self, function_index: u32) -> Self::Output {
1052 let index = function_index as usize;
1053 let func = &self.module.all_funcs[index];
1054 let ty = func.header.ty.clone();
1055
1056 let mut params: Vec<PoolPrimary> = ty.params().iter().map(|_| self.pop_stack()).collect();
1059 params.reverse();
1060
1061 self.call(index, ty, params);
1062 Ok(())
1063 }
1064
1065 fn visit_call_indirect(
1066 &mut self,
1067 type_index: u32,
1068 table_index: u32,
1069 _table_byte: u8,
1070 ) -> Self::Output {
1071 debug_assert_eq!(table_index, 0, "reference_types");
1072
1073 let ty = self.module.types[type_index as usize].clone();
1074
1075 let mut params: Vec<PoolPrimary> = (0..ty.params().len() + 1)
1077 .map(|_| self.pop_stack())
1078 .collect();
1079 params.reverse();
1080
1081 match self.module.call_indirects.get(&(type_index as usize)) {
1082 Some(index) => self.call(*index, ty, params),
1083 None => {
1084 self.unreachable = 1;
1085 self.builder
1086 .push_line(trap(self.module, "invalid function type"));
1087 }
1088 }
1089
1090 Ok(())
1091 }
1092
1093 fn visit_drop(&mut self) -> Self::Output {
1094 self.pop_stack();
1095 Ok(())
1096 }
1097
1098 fn visit_select(&mut self) -> Self::Output {
1099 let c = self.pop_stack();
1100 let val2 = self.pop_stack();
1101 let val1 = self.pop_stack();
1102
1103 let result_ty = self.ty(&val1);
1104 let result = self.var_pool.take(&mut self.builder, result_ty, None);
1105
1106 self.builder.push_set_pattern(
1107 result.id(),
1108 format!("{}($p2) ? $p0 : $p1", CsType::Bool.cast()),
1109 vec![val1.into(), val2.into(), c.into()],
1110 );
1111
1112 self.push_stack(result.into());
1113 Ok(())
1114 }
1115
1116 fn visit_local_get(&mut self, local_index: u32) -> Self::Output {
1117 let local_id = VarId::from_u32(local_index);
1118 let local = self.builder.code.vars[local_id];
1119 let var = self.var_pool.take(&mut self.builder, local.ty, None);
1120
1121 self.builder.push_set(var.id(), local_id.into());
1122
1123 self.push_stack(var.into());
1124 Ok(())
1125 }
1126
1127 fn visit_local_set(&mut self, local_index: u32) -> Self::Output {
1128 let local_id = VarId::from_u32(local_index);
1129 let var = self.pop_stack();
1130 self.builder.push_set(local_id, var.into());
1131 Ok(())
1132 }
1133
1134 fn visit_local_tee(&mut self, local_index: u32) -> Self::Output {
1135 let local_id = VarId::from_u32(local_index);
1136 self.builder.push_set(local_id, self.last_stack().into());
1137 Ok(())
1138 }
1139
1140 fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
1141 let global = &self.module.globals[global_index as usize];
1142 let var = self
1143 .var_pool
1144 .take(&mut self.builder, CsType::get(global.ty.content_type), None);
1145
1146 self.builder
1147 .push_set_pattern(var.id(), global.name.clone(), vec![]);
1148
1149 self.push_stack(var.into());
1150 Ok(())
1151 }
1152
1153 fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
1154 let global = &self.module.globals[global_index as usize];
1155 let var = self.pop_stack();
1156
1157 self.builder.push(Inst {
1158 kind: InstKind::Stmt,
1159 pattern: format!("{} = $p0;", global.name),
1160 params: vec![var.into()],
1161 ..Default::default()
1162 });
1163 Ok(())
1164 }
1165
1166 fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
1167 self.visit_load(memarg, CsType::Int, StorageType::Val(ValType::I32), None)
1168 }
1169
1170 fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output {
1171 self.visit_load(memarg, CsType::Long, StorageType::Val(ValType::I64), None)
1172 }
1173
1174 fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output {
1175 self.visit_load(memarg, CsType::Float, StorageType::Val(ValType::F32), None)
1176 }
1177
1178 fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output {
1179 self.visit_load(memarg, CsType::Double, StorageType::Val(ValType::F64), None)
1180 }
1181
1182 fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1183 self.visit_load(memarg, CsType::Int, StorageType::I8, Some(true))
1184 }
1185
1186 fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1187 self.visit_load(memarg, CsType::Int, StorageType::I8, Some(false))
1188 }
1189
1190 fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1191 self.visit_load(memarg, CsType::Int, StorageType::I16, Some(true))
1192 }
1193
1194 fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1195 self.visit_load(memarg, CsType::Int, StorageType::I16, Some(false))
1196 }
1197
1198 fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1199 self.visit_load(memarg, CsType::Long, StorageType::I8, Some(true))
1200 }
1201
1202 fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1203 self.visit_load(memarg, CsType::Long, StorageType::I8, Some(false))
1204 }
1205
1206 fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1207 self.visit_load(memarg, CsType::Long, StorageType::I16, Some(true))
1208 }
1209
1210 fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1211 self.visit_load(memarg, CsType::Long, StorageType::I16, Some(false))
1212 }
1213
1214 fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output {
1215 self.visit_load(
1216 memarg,
1217 CsType::Long,
1218 StorageType::Val(ValType::I32),
1219 Some(true),
1220 )
1221 }
1222
1223 fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output {
1224 self.visit_load(
1225 memarg,
1226 CsType::Long,
1227 StorageType::Val(ValType::I32),
1228 Some(false),
1229 )
1230 }
1231
1232 fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output {
1233 self.visit_store(memarg, StorageType::Val(ValType::I32))
1234 }
1235
1236 fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output {
1237 self.visit_store(memarg, StorageType::Val(ValType::I64))
1238 }
1239
1240 fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output {
1241 self.visit_store(memarg, StorageType::Val(ValType::F32))
1242 }
1243
1244 fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output {
1245 self.visit_store(memarg, StorageType::Val(ValType::F64))
1246 }
1247
1248 fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output {
1249 self.visit_store(memarg, StorageType::I8)
1250 }
1251
1252 fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output {
1253 self.visit_store(memarg, StorageType::I16)
1254 }
1255
1256 fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output {
1257 self.visit_store(memarg, StorageType::I8)
1258 }
1259
1260 fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output {
1261 self.visit_store(memarg, StorageType::I16)
1262 }
1263
1264 fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output {
1265 self.visit_store(memarg, StorageType::Val(ValType::I32))
1266 }
1267
1268 fn visit_memory_size(&mut self, mem: u32, _mem_byte: u8) -> Self::Output {
1269 debug_assert_eq!(mem, 0, "multi_memory");
1270
1271 let result = self.var_pool.take(&mut self.builder, CsType::Int, None);
1272 let memory = &self.module.memory.as_ref().unwrap().name;
1273
1274 self.builder.push_set_pattern(
1275 result.id(),
1276 format!("{memory}.Length / {PAGE_SIZE}"),
1277 vec![],
1278 );
1279
1280 self.push_stack(result.into());
1281 Ok(())
1282 }
1283
1284 fn visit_memory_grow(&mut self, mem: u32, _mem_byte: u8) -> Self::Output {
1285 debug_assert_eq!(mem, 0, "multi_memory");
1286
1287 let size = self.pop_stack();
1288 let result = self.var_pool.take(&mut self.builder, CsType::Int, None);
1289
1290 let memory = &self.module.memory.as_ref().unwrap().name;
1291 let max = self
1292 .module
1293 .memory
1294 .as_ref()
1295 .unwrap()
1296 .ty
1297 .maximum
1298 .unwrap_or(0x10000);
1299
1300 let mut pattern = format!("if ({memory}.Length / {PAGE_SIZE} + $p0 > {max}) {{\n");
1301 {
1302 pattern += "$r = -1;\n";
1304 }
1305 pattern += "} else {\n";
1306 {
1307 pattern += &format!("$r = {memory}.Length / {PAGE_SIZE};\n");
1309
1310 pattern += &format!("var old = {memory};\n");
1312 pattern += &format!("{memory} = new byte[old.Length + $p0 * {PAGE_SIZE}];\n");
1313 pattern += &format!("old.CopyTo({memory}, 0);\n");
1314 }
1315 pattern += "}";
1316
1317 self.builder.push(Inst {
1318 kind: InstKind::Stmt,
1319 pattern,
1320 params: vec![size.into()],
1321 result: Some(result.id()),
1322 ..Default::default()
1323 });
1324
1325 self.push_stack(result.into());
1326 Ok(())
1327 }
1328
1329 fn visit_i32_const(&mut self, value: i32) -> Self::Output {
1330 self.push_stack(Const::Int(value).into());
1331 Ok(())
1332 }
1333
1334 fn visit_i64_const(&mut self, value: i64) -> Self::Output {
1335 self.push_stack(Const::Long(value).into());
1336 Ok(())
1337 }
1338
1339 fn visit_f32_const(&mut self, value: Ieee32) -> Self::Output {
1340 self.push_stack(Const::Float(value.bits()).into());
1341 Ok(())
1342 }
1343
1344 fn visit_f64_const(&mut self, value: Ieee64) -> Self::Output {
1345 self.push_stack(Const::Double(value.bits()).into());
1346 Ok(())
1347 }
1348
1349 fn visit_i32_eqz(&mut self) -> Self::Output {
1350 self.visit_eqz()
1351 }
1352
1353 fn visit_i32_eq(&mut self) -> Self::Output {
1354 self.visit_bin_op("==", true, true)
1355 }
1356
1357 fn visit_i32_ne(&mut self) -> Self::Output {
1358 self.visit_bin_op("!=", true, true)
1359 }
1360
1361 fn visit_i32_lt_s(&mut self) -> Self::Output {
1362 self.visit_bin_op("<", true, true)
1363 }
1364
1365 fn visit_i32_lt_u(&mut self) -> Self::Output {
1366 self.visit_bin_op("<", true, false)
1367 }
1368
1369 fn visit_i32_gt_s(&mut self) -> Self::Output {
1370 self.visit_bin_op(">", true, true)
1371 }
1372
1373 fn visit_i32_gt_u(&mut self) -> Self::Output {
1374 self.visit_bin_op(">", true, false)
1375 }
1376
1377 fn visit_i32_le_s(&mut self) -> Self::Output {
1378 self.visit_bin_op("<=", true, true)
1379 }
1380
1381 fn visit_i32_le_u(&mut self) -> Self::Output {
1382 self.visit_bin_op("<=", true, false)
1383 }
1384
1385 fn visit_i32_ge_s(&mut self) -> Self::Output {
1386 self.visit_bin_op(">=", true, true)
1387 }
1388
1389 fn visit_i32_ge_u(&mut self) -> Self::Output {
1390 self.visit_bin_op(">=", true, false)
1391 }
1392
1393 fn visit_i64_eqz(&mut self) -> Self::Output {
1394 self.visit_eqz()
1395 }
1396
1397 fn visit_i64_eq(&mut self) -> Self::Output {
1398 self.visit_bin_op("==", true, true)
1399 }
1400
1401 fn visit_i64_ne(&mut self) -> Self::Output {
1402 self.visit_bin_op("!=", true, true)
1403 }
1404
1405 fn visit_i64_lt_s(&mut self) -> Self::Output {
1406 self.visit_bin_op("<", true, true)
1407 }
1408
1409 fn visit_i64_lt_u(&mut self) -> Self::Output {
1410 self.visit_bin_op("<", true, false)
1411 }
1412
1413 fn visit_i64_gt_s(&mut self) -> Self::Output {
1414 self.visit_bin_op(">", true, true)
1415 }
1416
1417 fn visit_i64_gt_u(&mut self) -> Self::Output {
1418 self.visit_bin_op(">", true, false)
1419 }
1420
1421 fn visit_i64_le_s(&mut self) -> Self::Output {
1422 self.visit_bin_op("<=", true, true)
1423 }
1424
1425 fn visit_i64_le_u(&mut self) -> Self::Output {
1426 self.visit_bin_op("<=", true, false)
1427 }
1428
1429 fn visit_i64_ge_s(&mut self) -> Self::Output {
1430 self.visit_bin_op(">=", true, true)
1431 }
1432
1433 fn visit_i64_ge_u(&mut self) -> Self::Output {
1434 self.visit_bin_op(">=", true, false)
1435 }
1436
1437 fn visit_f32_eq(&mut self) -> Self::Output {
1438 self.visit_bin_op("==", true, true)
1439 }
1440
1441 fn visit_f32_ne(&mut self) -> Self::Output {
1442 self.visit_bin_op("!=", true, true)
1443 }
1444
1445 fn visit_f32_lt(&mut self) -> Self::Output {
1446 self.visit_bin_op("<", true, true)
1447 }
1448
1449 fn visit_f32_gt(&mut self) -> Self::Output {
1450 self.visit_bin_op(">", true, true)
1451 }
1452
1453 fn visit_f32_le(&mut self) -> Self::Output {
1454 self.visit_bin_op("<=", true, true)
1455 }
1456
1457 fn visit_f32_ge(&mut self) -> Self::Output {
1458 self.visit_bin_op(">=", true, true)
1459 }
1460
1461 fn visit_f64_eq(&mut self) -> Self::Output {
1462 self.visit_bin_op("==", true, true)
1463 }
1464
1465 fn visit_f64_ne(&mut self) -> Self::Output {
1466 self.visit_bin_op("!=", true, true)
1467 }
1468
1469 fn visit_f64_lt(&mut self) -> Self::Output {
1470 self.visit_bin_op("<", true, true)
1471 }
1472
1473 fn visit_f64_gt(&mut self) -> Self::Output {
1474 self.visit_bin_op(">", true, true)
1475 }
1476
1477 fn visit_f64_le(&mut self) -> Self::Output {
1478 self.visit_bin_op("<=", true, true)
1479 }
1480
1481 fn visit_f64_ge(&mut self) -> Self::Output {
1482 self.visit_bin_op(">=", true, true)
1483 }
1484
1485 fn visit_i32_clz(&mut self) -> Self::Output {
1486 self.visit_clz()
1487 }
1488
1489 fn visit_i32_ctz(&mut self) -> Self::Output {
1490 self.visit_ctz()
1491 }
1492
1493 fn visit_i32_popcnt(&mut self) -> Self::Output {
1494 self.visit_popcnt()
1495 }
1496
1497 fn visit_i32_add(&mut self) -> Self::Output {
1498 self.visit_bin_op("+", false, true)
1499 }
1500
1501 fn visit_i32_sub(&mut self) -> Self::Output {
1502 self.visit_bin_op("-", false, true)
1503 }
1504
1505 fn visit_i32_mul(&mut self) -> Self::Output {
1506 self.visit_bin_op("*", false, true)
1507 }
1508
1509 fn visit_i32_div_s(&mut self) -> Self::Output {
1510 self.visit_bin_op("/", false, true)
1511 }
1512
1513 fn visit_i32_div_u(&mut self) -> Self::Output {
1514 self.visit_bin_op("/", false, false)
1515 }
1516
1517 fn visit_i32_rem_s(&mut self) -> Self::Output {
1518 self.visit_bin_op("%", false, true)
1519 }
1520
1521 fn visit_i32_rem_u(&mut self) -> Self::Output {
1522 self.visit_rem_op(false)
1523 }
1524
1525 fn visit_i32_and(&mut self) -> Self::Output {
1526 self.visit_bin_op("&", false, true)
1527 }
1528
1529 fn visit_i32_or(&mut self) -> Self::Output {
1530 self.visit_bin_op("|", false, true)
1531 }
1532
1533 fn visit_i32_xor(&mut self) -> Self::Output {
1534 self.visit_bin_op("^", false, true)
1535 }
1536
1537 fn visit_i32_shl(&mut self) -> Self::Output {
1538 self.visit_shift_op("<<", true)
1539 }
1540
1541 fn visit_i32_shr_s(&mut self) -> Self::Output {
1542 self.visit_shift_op(">>", true)
1543 }
1544
1545 fn visit_i32_shr_u(&mut self) -> Self::Output {
1546 self.visit_shift_op(">>", false)
1547 }
1548
1549 fn visit_i32_rotl(&mut self) -> Self::Output {
1550 self.visit_rot_op(false)
1551 }
1552
1553 fn visit_i32_rotr(&mut self) -> Self::Output {
1554 self.visit_rot_op(true)
1555 }
1556
1557 fn visit_i64_clz(&mut self) -> Self::Output {
1558 self.visit_clz()
1559 }
1560
1561 fn visit_i64_ctz(&mut self) -> Self::Output {
1562 self.visit_ctz()
1563 }
1564
1565 fn visit_i64_popcnt(&mut self) -> Self::Output {
1566 self.visit_popcnt()
1567 }
1568
1569 fn visit_i64_add(&mut self) -> Self::Output {
1570 self.visit_bin_op("+", false, true)
1571 }
1572
1573 fn visit_i64_sub(&mut self) -> Self::Output {
1574 self.visit_bin_op("-", false, true)
1575 }
1576
1577 fn visit_i64_mul(&mut self) -> Self::Output {
1578 self.visit_bin_op("*", false, true)
1579 }
1580
1581 fn visit_i64_div_s(&mut self) -> Self::Output {
1582 self.visit_bin_op("/", false, true)
1583 }
1584
1585 fn visit_i64_div_u(&mut self) -> Self::Output {
1586 self.visit_bin_op("/", false, false)
1587 }
1588
1589 fn visit_i64_rem_s(&mut self) -> Self::Output {
1590 self.visit_rem_op(true)
1591 }
1592
1593 fn visit_i64_rem_u(&mut self) -> Self::Output {
1594 self.visit_rem_op(false)
1595 }
1596
1597 fn visit_i64_and(&mut self) -> Self::Output {
1598 self.visit_bin_op("&", false, true)
1599 }
1600
1601 fn visit_i64_or(&mut self) -> Self::Output {
1602 self.visit_bin_op("|", false, true)
1603 }
1604
1605 fn visit_i64_xor(&mut self) -> Self::Output {
1606 self.visit_bin_op("^", false, true)
1607 }
1608
1609 fn visit_i64_shl(&mut self) -> Self::Output {
1610 self.visit_shift_op("<<", true)
1611 }
1612
1613 fn visit_i64_shr_s(&mut self) -> Self::Output {
1614 self.visit_shift_op(">>", true)
1615 }
1616
1617 fn visit_i64_shr_u(&mut self) -> Self::Output {
1618 self.visit_shift_op(">>", false)
1619 }
1620
1621 fn visit_i64_rotl(&mut self) -> Self::Output {
1622 self.visit_rot_op(false)
1623 }
1624
1625 fn visit_i64_rotr(&mut self) -> Self::Output {
1626 self.visit_rot_op(true)
1627 }
1628
1629 fn visit_f32_abs(&mut self) -> Self::Output {
1630 self.visit_math_un_op("Abs")
1631 }
1632
1633 fn visit_f32_neg(&mut self) -> Self::Output {
1634 self.visit_un_op("-")
1635 }
1636
1637 fn visit_f32_ceil(&mut self) -> Self::Output {
1638 if self.module.test {
1639 self.visit_math_un_op("Ceiling")
1640 } else {
1641 self.visit_math_un_op("Ceil")
1642 }
1643 }
1644
1645 fn visit_f32_floor(&mut self) -> Self::Output {
1646 self.visit_math_un_op("Floor")
1647 }
1648
1649 fn visit_f32_trunc(&mut self) -> Self::Output {
1650 let (opnd, result) = self.un_op_vars_auto_ty();
1651 self.builder.push_set_pattern(
1652 result,
1653 format!(
1654 "{}(Math.Truncate({}($p0)))",
1655 CsType::Float.cast(),
1656 CsType::Double.cast()
1657 ),
1658 vec![opnd.into()],
1659 );
1660 Ok(())
1661 }
1662
1663 fn visit_f32_nearest(&mut self) -> Self::Output {
1664 self.visit_math_un_op("Round")
1665 }
1666
1667 fn visit_f32_sqrt(&mut self) -> Self::Output {
1668 self.visit_math_un_op("Sqrt")
1669 }
1670
1671 fn visit_f32_add(&mut self) -> Self::Output {
1672 self.visit_bin_op("+", false, true)
1673 }
1674
1675 fn visit_f32_sub(&mut self) -> Self::Output {
1676 self.visit_bin_op("-", false, true)
1677 }
1678
1679 fn visit_f32_mul(&mut self) -> Self::Output {
1680 self.visit_bin_op("*", false, true)
1681 }
1682
1683 fn visit_f32_div(&mut self) -> Self::Output {
1684 self.visit_bin_op("/", false, true)
1685 }
1686
1687 fn visit_f32_min(&mut self) -> Self::Output {
1688 self.visit_math_bin_op("Min")
1689 }
1690
1691 fn visit_f32_max(&mut self) -> Self::Output {
1692 self.visit_math_bin_op("Max")
1693 }
1694
1695 fn visit_f32_copysign(&mut self) -> Self::Output {
1696 self.visit_copysign_op()
1697 }
1698
1699 fn visit_f64_abs(&mut self) -> Self::Output {
1700 self.visit_math_un_op("Abs")
1701 }
1702
1703 fn visit_f64_neg(&mut self) -> Self::Output {
1704 self.visit_un_op("-")
1705 }
1706
1707 fn visit_f64_ceil(&mut self) -> Self::Output {
1708 self.visit_math_un_op("Ceiling")
1709 }
1710
1711 fn visit_f64_floor(&mut self) -> Self::Output {
1712 self.visit_math_un_op("Floor")
1713 }
1714
1715 fn visit_f64_trunc(&mut self) -> Self::Output {
1716 self.visit_math_un_op("Truncate")
1717 }
1718
1719 fn visit_f64_nearest(&mut self) -> Self::Output {
1720 self.visit_math_un_op("Round")
1721 }
1722
1723 fn visit_f64_sqrt(&mut self) -> Self::Output {
1724 self.visit_math_un_op("Sqrt")
1725 }
1726
1727 fn visit_f64_add(&mut self) -> Self::Output {
1728 self.visit_bin_op("+", false, true)
1729 }
1730
1731 fn visit_f64_sub(&mut self) -> Self::Output {
1732 self.visit_bin_op("-", false, true)
1733 }
1734
1735 fn visit_f64_mul(&mut self) -> Self::Output {
1736 self.visit_bin_op("*", false, true)
1737 }
1738
1739 fn visit_f64_div(&mut self) -> Self::Output {
1740 self.visit_bin_op("/", false, true)
1741 }
1742
1743 fn visit_f64_min(&mut self) -> Self::Output {
1744 self.visit_math_bin_op("Min")
1745 }
1746
1747 fn visit_f64_max(&mut self) -> Self::Output {
1748 self.visit_math_bin_op("Max")
1749 }
1750
1751 fn visit_f64_copysign(&mut self) -> Self::Output {
1752 self.visit_copysign_op()
1753 }
1754
1755 fn visit_i32_wrap_i64(&mut self) -> Self::Output {
1756 let (opnd, result) = self.un_op_vars(CsType::Int);
1757 self.wrap(opnd, result);
1758 Ok(())
1759 }
1760
1761 fn visit_i32_trunc_f32_s(&mut self) -> Self::Output {
1762 self.visit_cast_trunc(CsType::Int, true)
1763 }
1764
1765 fn visit_i32_trunc_f32_u(&mut self) -> Self::Output {
1766 self.visit_cast_trunc(CsType::Int, false)
1767 }
1768
1769 fn visit_i32_trunc_f64_s(&mut self) -> Self::Output {
1770 self.visit_cast_trunc(CsType::Int, true)
1771 }
1772
1773 fn visit_i32_trunc_f64_u(&mut self) -> Self::Output {
1774 self.visit_cast_trunc(CsType::Int, false)
1775 }
1776
1777 fn visit_i64_extend_i32_s(&mut self) -> Self::Output {
1778 self.visit_cast_extend(true)
1779 }
1780
1781 fn visit_i64_extend_i32_u(&mut self) -> Self::Output {
1782 self.visit_cast_extend(false)
1783 }
1784
1785 fn visit_i64_trunc_f32_s(&mut self) -> Self::Output {
1786 self.visit_cast_trunc(CsType::Long, true)
1787 }
1788
1789 fn visit_i64_trunc_f32_u(&mut self) -> Self::Output {
1790 self.visit_cast_trunc(CsType::Long, false)
1791 }
1792
1793 fn visit_i64_trunc_f64_s(&mut self) -> Self::Output {
1794 self.visit_cast_trunc(CsType::Long, true)
1795 }
1796
1797 fn visit_i64_trunc_f64_u(&mut self) -> Self::Output {
1798 self.visit_cast_trunc(CsType::Long, false)
1799 }
1800
1801 fn visit_f32_convert_i32_s(&mut self) -> Self::Output {
1802 self.visit_cast_convert(CsType::Float, true)
1803 }
1804
1805 fn visit_f32_convert_i32_u(&mut self) -> Self::Output {
1806 self.visit_cast_convert(CsType::Float, false)
1807 }
1808
1809 fn visit_f32_convert_i64_s(&mut self) -> Self::Output {
1810 self.visit_cast_convert(CsType::Float, true)
1811 }
1812
1813 fn visit_f32_convert_i64_u(&mut self) -> Self::Output {
1814 self.visit_cast_convert(CsType::Float, false)
1815 }
1816
1817 fn visit_f32_demote_f64(&mut self) -> Self::Output {
1818 self.visit_cast(CsType::Float)
1819 }
1820
1821 fn visit_f64_convert_i32_s(&mut self) -> Self::Output {
1822 self.visit_cast_convert(CsType::Double, true)
1823 }
1824
1825 fn visit_f64_convert_i32_u(&mut self) -> Self::Output {
1826 self.visit_cast_convert(CsType::Double, false)
1827 }
1828
1829 fn visit_f64_convert_i64_s(&mut self) -> Self::Output {
1830 self.visit_cast_convert(CsType::Double, true)
1831 }
1832
1833 fn visit_f64_convert_i64_u(&mut self) -> Self::Output {
1834 self.visit_cast_convert(CsType::Double, false)
1835 }
1836
1837 fn visit_f64_promote_f32(&mut self) -> Self::Output {
1838 self.visit_cast(CsType::Double)
1839 }
1840
1841 fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {
1842 let (opnd, result) = self.un_op_vars(CsType::Int);
1843 self.builder.push_set_pattern(
1844 result,
1845 "BitConverter.SingleToInt32Bits($p0)",
1846 vec![opnd.into()],
1847 );
1848 Ok(())
1849 }
1850
1851 fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {
1852 let (opnd, result) = self.un_op_vars(CsType::Long);
1853 self.builder.push_set_pattern(
1854 result,
1855 "BitConverter.DoubleToInt64Bits($p0)",
1856 vec![opnd.into()],
1857 );
1858 Ok(())
1859 }
1860
1861 fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {
1862 let (opnd, result) = self.un_op_vars(CsType::Float);
1863 self.builder.push_set_pattern(
1864 result,
1865 "BitConverter.Int32BitsToSingle($p0)",
1866 vec![opnd.into()],
1867 );
1868 Ok(())
1869 }
1870
1871 fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {
1872 let (opnd, result) = self.un_op_vars(CsType::Double);
1873 self.builder.push_set_pattern(
1874 result,
1875 "BitConverter.Int64BitsToDouble($p0)",
1876 vec![opnd.into()],
1877 );
1878 Ok(())
1879 }
1880
1881 fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output {
1882 self.visit_cast_trunc_sat(CsType::Int, true)
1883 }
1884
1885 fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output {
1886 self.visit_cast_trunc_sat(CsType::Int, false)
1887 }
1888
1889 fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output {
1890 self.visit_cast_trunc_sat(CsType::Int, true)
1891 }
1892
1893 fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output {
1894 self.visit_cast_trunc_sat(CsType::Int, false)
1895 }
1896
1897 fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output {
1898 self.visit_cast_trunc_sat(CsType::Long, true)
1899 }
1900
1901 fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output {
1902 self.visit_cast_trunc_sat(CsType::Long, false)
1903 }
1904
1905 fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output {
1906 self.visit_cast_trunc_sat(CsType::Long, true)
1907 }
1908
1909 fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output {
1910 self.visit_cast_trunc_sat(CsType::Long, false)
1911 }
1912
1913 fn visit_i32_extend8_s(&mut self) -> Self::Output {
1914 self.visit_extend(StorageType::I8)
1915 }
1916
1917 fn visit_i32_extend16_s(&mut self) -> Self::Output {
1918 self.visit_extend(StorageType::I16)
1919 }
1920
1921 fn visit_i64_extend8_s(&mut self) -> Self::Output {
1922 self.visit_extend(StorageType::I8)
1923 }
1924
1925 fn visit_i64_extend16_s(&mut self) -> Self::Output {
1926 self.visit_extend(StorageType::I16)
1927 }
1928
1929 fn visit_i64_extend32_s(&mut self) -> Self::Output {
1930 self.visit_extend(StorageType::Val(ValType::I32))
1931 }
1932
1933 fn visit_memory_init(&mut self, _data_index: u32, _mem: u32) -> Self::Output {
1934 Err(NotSupportedError::Instruction("memory.init").into())
1935 }
1936
1937 fn visit_data_drop(&mut self, _data_index: u32) -> Self::Output {
1938 Err(NotSupportedError::Instruction("data.drop").into())
1939 }
1940
1941 fn visit_memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> Self::Output {
1942 debug_assert_eq!(dst_mem, 0, "multi_memory");
1943 debug_assert_eq!(src_mem, 0, "multi_memory");
1944
1945 let len = self.pop_stack();
1946 let src = self.pop_stack();
1947 let dst = self.pop_stack();
1948
1949 let memory = &self.module.memory.as_ref().unwrap().name;
1950
1951 self.builder.push(Inst {
1952 kind: InstKind::Stmt,
1953 pattern: format!("Array.Copy({memory}, $p1, {memory}, $p2, $p0);"),
1954 params: vec![len.into(), src.into(), dst.into()],
1955 ..Default::default()
1956 });
1957 Ok(())
1958 }
1959
1960 fn visit_memory_fill(&mut self, mem: u32) -> Self::Output {
1961 debug_assert_eq!(mem, 0, "multi_memory");
1962
1963 let len = self.pop_stack();
1964 let value = self.pop_stack();
1965 let index = self.pop_stack();
1966
1967 let memory = &self.module.memory.as_ref().unwrap().name;
1968
1969 let mut pattern = "if ($p1 == 0) {\n".to_string();
1971 pattern += &format!("Array.Clear({memory}, $p2, $p0);\n");
1972
1973 pattern += "} else if ($p0 != 0) {\n";
1975 pattern += &format!("{memory}[$p2] = {}($p1 & 0xff);\n", CsType::Byte.cast());
1977 pattern += "int n = 1;\n";
1979 pattern += "for (int max = $p0 / 2; n < max; n *= 2) {\n";
1980 pattern += &format!("Array.Copy({memory}, $p2, {memory}, $p2 + n, n);\n");
1981 pattern += "}\n";
1982 pattern += &format!("Array.Copy({memory}, $p2, {memory}, $p2 + n, $p0 - n);\n");
1984
1985 pattern += "}";
1986
1987 self.builder.push(Inst {
1988 kind: InstKind::Stmt,
1989 pattern,
1990 params: vec![len.into(), value.into(), index.into()],
1991 ..Default::default()
1992 });
1993 Ok(())
1994 }
1995
1996 fn visit_table_init(&mut self, _elem_index: u32, _table: u32) -> Self::Output {
1997 Err(NotSupportedError::Instruction("table.init").into())
1998 }
1999
2000 fn visit_elem_drop(&mut self, _elem_index: u32) -> Self::Output {
2001 Err(NotSupportedError::Instruction("elem.drop").into())
2002 }
2003
2004 fn visit_table_copy(&mut self, _dst_table: u32, _src_table: u32) -> Self::Output {
2005 Err(NotSupportedError::Instruction("table.copy").into())
2006 }
2007}
2008
2009fn cast_from(from: CsType, to: CsType) -> &'static str {
2010 if from == to {
2011 ""
2012 } else {
2013 to.cast()
2014 }
2015}