wasm2usharp/parse/
code.rs

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    /// brの後など、到達不可能なコードの処理時に1加算。
50    /// unreachableが1以上の場合のブロックの出現ごとに1加算。
51    /// ブロックの終了時に1減算。
52    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        // 関数の最上位のブロック
102        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    /// ブロックに戻り値があれば、戻り値を代入する命令を追加する
161    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        // brでループを再開する場合は戻り値を取らない
165        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    /// (opnd, result)を返す
333    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    /// (opnd, result)を返し、opndの型をresultの型とする
343    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    /// (lhs, rhs, result)を返し、lhsの型をresultの型とする
354    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        // 2進で文字列化して文字数を数える
586        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        // 符号付き整数の最小値のリテラルはUdonSharpではエラーとなるので
602        // `-最大値 - 1` で表現する
603        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        // 1. 文字数を揃えるため、MSBだけが1の数とopndのORをとる
610        // 2. 2進で文字列化する
611        // 3. 最後に1が出現するインデックスを求める
612        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        // 2進で文字列化して、0を除去した後の文字数を数える
627        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            // NaNなら0にする
728            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                // 最小値
741                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                    // 最大値
754                    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        // targetが0の場合、switchブロックがbreakされた後に続きの外のブロックが
885        // そのまま実行されるので再度breakする必要はない。
886        // targetが1以上の場合、Wasmでは存在しないswitchブロックをbreakするため、
887        // targetにswitchブロックの分の1を足している
888        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        // 最も外側のブロックのendでない場合のみ
990        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            // case i:
1027            self.visit_br_table_case(Some(i), target?);
1028        }
1029
1030        // default:
1031        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        // mapは遅延評価であるため、mapの後にrevを呼んだ場合ではpop_stackで得る値が逆順にならない
1057        // そのため、一度collectでVecにした後、reverseで逆順にしている
1058        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        // Iteratorのrevを使わない理由はvisit_callのコメントを参照
1076        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            // 新しいメモリサイズが最大値を超えていれば-1を返す
1303            pattern += "$r = -1;\n";
1304        }
1305        pattern += "} else {\n";
1306        {
1307            // 前のサイズを返す
1308            pattern += &format!("$r = {memory}.Length / {PAGE_SIZE};\n");
1309
1310            // メモリをsizeだけ拡張
1311            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        // 0で埋めるならArray.Clearを使う
1970        let mut pattern = "if ($p1 == 0) {\n".to_string();
1971        pattern += &format!("Array.Clear({memory}, $p2, $p0);\n");
1972
1973        // 0以外で埋める場合
1974        pattern += "} else if ($p0 != 0) {\n";
1975        // 最初に1つの要素をvalueにする
1976        pattern += &format!("{memory}[$p2] = {}($p1 & 0xff);\n", CsType::Byte.cast());
1977        // Array.Copyでvalueの要素数を2倍にするのを繰り返す
1978        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        // 2の累乗の数に合わない残りをコピーする
1983        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}