Skip to main content

spacewasm/
compiler.rs

1use crate::*;
2use ::core::marker::PhantomData;
3
4#[derive(Default)]
5pub struct Compiler<'a, const MAX_CONTROL_FRAMES: usize, const MAX_STACK_DEPTH: usize> {
6    _marker: PhantomData<&'a ()>,
7}
8
9macro_rules! validate {
10    ($state:expr, ($($in_ty:ident)*) -> ($($out_ty:ident)*)) => {
11        $(
12            let _ = $state.pop_stack(ValType::$in_ty)?;
13        )*
14
15        $(
16            $state.push_stack(ValType::$out_ty)?;
17        )*
18    };
19}
20
21macro_rules! alignment {
22    (8) => {
23        0
24    };
25    (16) => {
26        1
27    };
28    (32) => {
29        2
30    };
31    (64) => {
32        3
33    };
34}
35
36macro_rules! instruction {
37    // No additional operands
38    ($name:ident, $opcode:expr, ($($in_ty:ident)*) -> ($($out_ty:ident)*)) => {
39        fn $name(&self, state: &mut Self::State) -> Result<(), Self::Error> {
40            validate!(state, ($($in_ty)*) -> ($($out_ty)*));
41            state.instr($opcode)?;
42            Ok(())
43        }
44    };
45
46    // An instruction with a MemArg operand
47    ($name:ident, $opcode:expr, mem, $ty_align:tt, ($($in_ty:ident)*) -> ($($out_ty:ident)*)) => {
48        fn $name(&self, m: MemArg, state: &mut Self::State) -> Result<(), Self::Error> {
49            state.module().check_memory_defined()?;
50            validate!(state, ($($in_ty)*) -> ($($out_ty)*));
51            if m.align > alignment!($ty_align) {
52                return Err(ValidationError::AlignmentLargerThanType);
53            }
54
55            state.instr_mem($opcode, m)?;
56            Ok(())
57        }
58    };
59}
60
61impl<'a, const MAX_CONTROL_FRAMES: usize, const MAX_STACK_DEPTH: usize> WasmVisitor
62    for Compiler<'a, MAX_CONTROL_FRAMES, MAX_STACK_DEPTH>
63{
64    fn drop(&self, state: &mut Self::State) -> Result<(), Self::Error> {
65        let ty = state.pop_stack_t()?;
66        state.instr_imm_8(
67            DROP,
68            match ty {
69                OperandType::Unknown => ValType::I32,
70                OperandType::Known(t) => t,
71            } as u8,
72        )?;
73        Ok(())
74    }
75
76    fn select(&self, state: &mut Self::State) -> Result<(), Self::Error> {
77        let _ = state.pop_stack(ValType::I32)?;
78        let t1 = state.pop_stack_t()?;
79        let t2 = state.pop_stack(t1)?;
80        state.push_stack(t2)?;
81        state.instr_imm_8(SELECT, t2.into())?;
82        Ok(())
83    }
84
85    fn enter_block(
86        &self,
87        block_type: ResultType,
88        state: &mut Self::State,
89    ) -> Result<(), Self::Error> {
90        state.push_control(BlockKind::Block, block_type, block_type)
91    }
92
93    fn exit_block(&self, state: &mut Self::State) -> Result<(), Self::Error> {
94        let results = state.pop_control()?;
95        state.push_result_type(results)?;
96        Ok(())
97    }
98
99    fn finish(&self, state: &mut Self::State) -> Result<(), Self::Error> {
100        // Pop the implicit function control frame and validate
101        // This validates that the function returns the correct type
102        let ty = state.pop_control()?;
103
104        // Emit a return instruction
105        if let Some(ty) = ty.0 {
106            state.instr_imm_8(RETURN, ty.size() as u8 / 4)?;
107        } else {
108            state.instr(RETURN)?;
109        }
110
111        Ok(())
112    }
113
114    fn loop_(&self, block_type: ResultType, state: &mut Self::State) -> Result<(), Self::Error> {
115        state.push_control(BlockKind::Loop, ResultType(None), block_type)?;
116        // Set the loop's target to the current PC (loop start)
117        state.set_control_target(state.pc())?;
118        Ok(())
119    }
120
121    fn if_(&self, block_type: ResultType, state: &mut Self::State) -> Result<(), Self::Error> {
122        let _ = state.pop_stack(ValType::I32)?;
123        state.instr(IF)?;
124        state.push_control(BlockKind::If, block_type, block_type)?;
125        // Emit a placeholder for the false-branch/else target that will be backpatched
126        state.write_if_else_target()?;
127        Ok(())
128    }
129
130    fn else_(&self, state: &mut Self::State) -> Result<(), Self::Error> {
131        // Emit an unconditional branch to skip the else block
132        // This gets added to the if frame's target list (before we pop it)
133        state.instr(BR)?;
134        state.write_label_target(LabelIdx(0))?;
135
136        // Pop the if control frame and patch its false-branch (tail of linked list) to point here
137        // Returns the remaining br chain (including the BR we just emitted)
138        let (results, br_chain) = state.pop_control_and_patch_if()?;
139
140        // Push a new control frame for the else block, inheriting the br chain
141        state.push_control(BlockKind::Block, results, results)?;
142        state.set_control_target(br_chain)?;
143
144        Ok(())
145    }
146
147    fn br(&self, l: LabelIdx, state: &mut Self::State) -> Result<(), Self::Error> {
148        state.instr(BR)?;
149        let lbl_types = state.write_label_target(l)?;
150        state.pop_result_type(lbl_types)?;
151        state.mark_unreachable();
152        Ok(())
153    }
154
155    fn br_if(&self, l: LabelIdx, state: &mut Self::State) -> Result<(), Self::Error> {
156        let _ = state.pop_stack(ValType::I32)?;
157        state.instr(BR_IF)?;
158        let lbl_types = state.write_label_target(l)?;
159        state.pop_result_type(lbl_types)?;
160        state.push_result_type(lbl_types)?;
161        Ok(())
162    }
163
164    fn br_table_start(&self, len: u32, state: &mut Self::State) -> Result<(), Self::Error> {
165        let _ = state.pop_stack(ValType::I32)?;
166        state.instr_imm_8_or_16(BR_TABLE, len)?;
167        Ok(())
168    }
169
170    fn br_table_branch(&self, br: LabelIdx, state: &mut Self::State) -> Result<(), Self::Error> {
171        let case_return = state.write_label_target(br)?;
172        state.check_br_table_result(case_return)?;
173        Ok(())
174    }
175
176    fn br_table_finish(
177        &self,
178        default_: LabelIdx,
179        state: &mut Self::State,
180    ) -> Result<(), Self::Error> {
181        let def_result = state.write_label_target(default_)?;
182        state.check_and_clear_br_table_result(def_result)?;
183        state.pop_result_type(def_result)?;
184        state.mark_unreachable();
185        Ok(())
186    }
187
188    fn return_(&self, state: &mut Self::State) -> Result<(), Self::Error> {
189        // Return instructions also encode the return size from their function's context
190        let ty = state.func().return_ty;
191        if let Some(ty) = ty {
192            let _ = state.pop_stack(ty)?;
193            state.instr_imm_8(RETURN, ty.size() as u8 / 4)?;
194        } else {
195            state.instr(RETURN)?;
196        }
197
198        state.mark_unreachable();
199        Ok(())
200    }
201
202    fn call(&self, x: FuncIdx, state: &mut Self::State) -> Result<(), Self::Error> {
203        let f_ref = state
204            .module()
205            .get_func_ref(x)
206            .ok_or(ValidationError::FunctionIdxOutOfRange)?;
207
208        match f_ref {
209            Ref::Module(index) => {
210                // Check the call signature
211                let f = &state.module().functions[index as usize];
212                let ty = &state.module().types[f.ty.0 as usize];
213
214                for p in ty.params.iter().rev() {
215                    let _ = state.pop_stack(*p)?;
216                }
217
218                for r in ty.returns.iter().rev() {
219                    state.push_stack(r)?;
220                }
221
222                state.instr_imm_8(CALL, 0)?;
223                state.write_16(index)?;
224                Ok(())
225            }
226            Ref::Host { module, index } => {
227                let hm = &state.store().host_modules()[module.0 as usize];
228                let f = &hm.functions[index as usize];
229                for p in f.params().iter().rev() {
230                    let _ = state.pop_stack(p)?;
231                }
232
233                if let Some(r) = f.returns().0 {
234                    state.push_stack(r)?;
235                }
236
237                state.instr_imm_8(CALL_HOST, module.0)?;
238                state.write_16(index)?;
239                Ok(())
240            }
241            Ref::Extern { module, index } => {
242                // Check the call signature
243                let m = &state.store().modules()[module.0 as usize];
244                let f = &m.functions[index as usize];
245                let ty = &m.types[f.ty.0 as usize];
246
247                for p in ty.params.iter().rev() {
248                    let _ = state.pop_stack(p)?;
249                }
250
251                for r in ty.returns.iter().rev() {
252                    state.push_stack(*r)?;
253                }
254
255                state.instr_imm_8(CALL_EXTERN, module.0)?;
256                state.write_16(index)?;
257                Ok(())
258            }
259        }
260    }
261
262    fn call_indirect(&self, x: TypeIdx, state: &mut Self::State) -> Result<(), Self::Error> {
263        if state.module().table.is_none() {
264            return Err(ValidationError::TableNotDefined);
265        }
266
267        let _ = state.pop_stack(ValType::I32)?;
268        let ty = state
269            .module()
270            .types
271            .get(x.0 as usize)
272            .ok_or(ValidationError::TypeIdxOutOfRange)?;
273
274        for p in ty.params.iter().rev() {
275            let _ = state.pop_stack(p)?;
276        }
277
278        for r in &ty.returns {
279            state.push_stack(*r)?;
280        }
281
282        if x.0 > u16::MAX as u32 {
283            return Err(ValidationError::IdxTooLarge);
284        }
285
286        state.instr(CALL_INDIRECT)?;
287        state.write_16(x.0 as u16)?;
288        Ok(())
289    }
290
291    fn local_get(&self, x: LocalIdx, state: &mut Self::State) -> Result<(), Self::Error> {
292        let l = state.get_local(x)?;
293        state.push_stack(l.ty)?;
294        state.instr_imm_8(LOCAL_GET, l.ty as u8)?;
295        state.write_16(l.frame_offset as u16)?;
296        Ok(())
297    }
298
299    fn local_set(&self, x: LocalIdx, state: &mut Self::State) -> Result<(), Self::Error> {
300        let l = state.get_local(x)?;
301        let _ = state.pop_stack(l.ty)?;
302        state.instr_imm_8(LOCAL_SET, l.ty as u8)?;
303        state.write_16(l.frame_offset as u16)?;
304        Ok(())
305    }
306
307    fn local_tee(&self, x: LocalIdx, state: &mut Self::State) -> Result<(), Self::Error> {
308        let l = state.get_local(x)?;
309        let _ = state.pop_stack(l.ty)?;
310        state.push_stack(l.ty)?;
311        state.instr_imm_8(LOCAL_TEE, l.ty as u8)?;
312        state.write_16(l.frame_offset as u16)?;
313        Ok(())
314    }
315
316    fn global_get(&self, x: GlobalIdx, state: &mut Self::State) -> Result<(), Self::Error> {
317        let g = state.get_global(x)?;
318        state.push_stack(g.ty)?;
319        match g.reference {
320            Ref::Module(idx) => {
321                state.instr_imm_8_or_16(GLOBAL_GET, idx as u32)?;
322                Ok(())
323            }
324            Ref::Extern { module, index } => {
325                state.instr_imm_8(GLOBAL_GET_EXTERN, module.0)?;
326                state.write_16(index)?;
327                Ok(())
328            }
329            Ref::Host { module, index } => {
330                state.instr_imm_8(GLOBAL_GET_HOST, module.0)?;
331                state.write_16(index)?;
332                Ok(())
333            }
334        }
335    }
336
337    fn global_set(&self, x: GlobalIdx, state: &mut Self::State) -> Result<(), Self::Error> {
338        let g = state.get_global(x)?;
339        if !g.mutable {
340            Err(ValidationError::GlobalNotMutable)
341        } else {
342            let _ = state.pop_stack(g.ty)?;
343            match g.reference {
344                Ref::Module(idx) => {
345                    state.instr_imm_8_or_16(GLOBAL_SET, idx as u32)?;
346                    Ok(())
347                }
348                Ref::Extern { module, index } => {
349                    state.instr_imm_8(GLOBAL_SET_EXTERN, module.0)?;
350                    state.write_16(index)?;
351                    Ok(())
352                }
353                Ref::Host { module, index } => {
354                    state.instr_imm_8(GLOBAL_SET_HOST, module.0)?;
355                    state.write_16(index)?;
356                    Ok(())
357                }
358            }
359        }
360    }
361
362    // The four `*_reinterpret_*` handlers intentionally emit no IR instruction:
363    // a reinterpret is a bit-level no-op on the raw operand stack, so only the
364    // stack types need validating. The absence of an emitted opcode is deliberate.
365    fn i32_reinterpret_f32(&self, state: &mut Self::State) -> Result<(), Self::Error> {
366        validate!(state, (F32) -> (I32));
367        Ok(())
368    }
369
370    fn f64_reinterpret_i64(&self, state: &mut Self::State) -> Result<(), Self::Error> {
371        validate!(state, (I64) -> (F64));
372        Ok(())
373    }
374
375    fn f32_reinterpret_i32(&self, state: &mut Self::State) -> Result<(), Self::Error> {
376        validate!(state, (I32) -> (F32));
377        Ok(())
378    }
379
380    fn i64_reinterpret_f64(&self, state: &mut Self::State) -> Result<(), Self::Error> {
381        validate!(state, (F64) -> (I64));
382        Ok(())
383    }
384}
385
386impl<'a, const MAX_CONTROL_FRAMES: usize, const MAX_STACK_DEPTH: usize> BaseVisitor
387    for Compiler<'a, MAX_CONTROL_FRAMES, MAX_STACK_DEPTH>
388{
389    type Error = ValidationError;
390    type State = TextBuilder<'a, MAX_CONTROL_FRAMES, MAX_STACK_DEPTH>;
391
392    fn unreachable(&self, state: &mut Self::State) -> Result<(), Self::Error> {
393        state.instr_imm_8(UNREACHABLE, 0)?;
394        state.mark_unreachable();
395        Ok(())
396    }
397
398    fn nop(&self, state: &mut Self::State) -> Result<(), Self::Error> {
399        // No op!
400        let _ = state;
401        Ok(())
402    }
403
404    instruction!(i32_load, I32_LOAD, mem, 32, (I32) -> (I32));
405    instruction!(i64_load, I64_LOAD, mem, 64, (I32) -> (I64));
406    instruction!(f32_load, F32_LOAD, mem, 32, (I32) -> (F32));
407    instruction!(f64_load, F64_LOAD, mem, 64, (I32) -> (F64));
408    instruction!(i32_load8_s, I32_LOAD8_S, mem, 8, (I32) -> (I32));
409    instruction!(i32_load8_u, I32_LOAD8_U, mem, 8, (I32) -> (I32));
410    instruction!(i32_load16_s, I32_LOAD16_S, mem, 16, (I32) -> (I32));
411    instruction!(i32_load16_u, I32_LOAD16_U, mem, 16, (I32) -> (I32));
412    instruction!(i64_load8_s, I64_LOAD8_S, mem, 8, (I32) -> (I64));
413    instruction!(i64_load8_u, I64_LOAD8_U, mem, 8, (I32) -> (I64));
414    instruction!(i64_load16_s, I64_LOAD16_S, mem, 16, (I32) -> (I64));
415    instruction!(i64_load16_u, I64_LOAD16_U, mem, 16, (I32) -> (I64));
416    instruction!(i64_load32_s, I64_LOAD32_S, mem, 32, (I32) -> (I64));
417    instruction!(i64_load32_u, I64_LOAD32_U, mem, 32, (I32) -> (I64));
418
419    instruction!(i32_store, I32_STORE, mem, 32, (I32 I32) -> ());
420    instruction!(i64_store, I64_STORE, mem, 64, (I64 I32) -> ());
421    instruction!(f32_store, F32_STORE, mem, 32, (F32 I32) -> ());
422    instruction!(f64_store, F64_STORE, mem, 64, (F64 I32) -> ());
423    instruction!(i32_store8, I32_STORE8, mem, 8, (I32 I32) -> ());
424    instruction!(i32_store16, I32_STORE16, mem, 16, (I32 I32) -> ());
425    instruction!(i64_store8, I64_STORE8, mem, 8, (I64 I32) -> ());
426    instruction!(i64_store16, I64_STORE16, mem, 16, (I64 I32) -> ());
427    instruction!(i64_store32, I64_STORE32, mem, 32, (I64 I32) -> ());
428
429    fn memory_size(&self, state: &mut Self::State) -> Result<(), Self::Error> {
430        state.module().check_memory_defined()?;
431        validate!(state, () -> (I32));
432        state.instr(MEMORY_SIZE)?;
433        Ok(())
434    }
435
436    fn memory_grow(&self, state: &mut Self::State) -> Result<(), Self::Error> {
437        state.module().check_memory_defined()?;
438        validate!(state, (I32) -> (I32));
439        if state.options().allow_memory_grow {
440            state.instr(MEMORY_GROW)?;
441            Ok(())
442        } else {
443            Err(ValidationError::IllegalMemoryGrow)
444        }
445    }
446
447    fn i32_const(&self, n: i32, state: &mut Self::State) -> Result<(), Self::Error> {
448        validate!(state, () -> (I32));
449        state.instr_imm_8_or_32(I32_CONST, n as u32)?;
450        Ok(())
451    }
452
453    fn i64_const(&self, n: i64, state: &mut Self::State) -> Result<(), Self::Error> {
454        validate!(state, () -> (I64));
455        state.instr_imm_8_or_64(I64_CONST, n as u64)?;
456        Ok(())
457    }
458
459    fn f32_const(&self, z: f32, state: &mut Self::State) -> Result<(), Self::Error> {
460        validate!(state, () -> (F32));
461        state.instr(F32_CONST)?;
462        state.write_32(z.to_bits())?;
463        Ok(())
464    }
465
466    fn f64_const(&self, z: f64, state: &mut Self::State) -> Result<(), Self::Error> {
467        validate!(state, () -> (F64));
468        state.instr(F64_CONST)?;
469        state.write_64(z.to_bits())?;
470        Ok(())
471    }
472
473    instruction!(i32_eqz, I32_EQZ, (I32) -> (I32));
474    instruction!(i32_eq, I32_EQ, (I32 I32) -> (I32));
475    instruction!(i32_ne, I32_NE, (I32 I32) -> (I32));
476    instruction!(i32_lt_s, I32_LT_S, (I32 I32) -> (I32));
477    instruction!(i32_lt_u, I32_LT_U, (I32 I32) -> (I32));
478    instruction!(i32_gt_s, I32_GT_S, (I32 I32) -> (I32));
479    instruction!(i32_gt_u, I32_GT_U, (I32 I32) -> (I32));
480    instruction!(i32_le_s, I32_LE_S, (I32 I32) -> (I32));
481    instruction!(i32_le_u, I32_LE_U, (I32 I32) -> (I32));
482    instruction!(i32_ge_s, I32_GE_S, (I32 I32) -> (I32));
483    instruction!(i32_ge_u, I32_GE_U, (I32 I32) -> (I32));
484
485    instruction!(i64_eqz, I64_EQZ, (I64) -> (I32));
486    instruction!(i64_eq, I64_EQ, (I64 I64) -> (I32));
487    instruction!(i64_ne, I64_NE, (I64 I64) -> (I32));
488    instruction!(i64_lt_s, I64_LT_S, (I64 I64) -> (I32));
489    instruction!(i64_lt_u, I64_LT_U, (I64 I64) -> (I32));
490    instruction!(i64_gt_s, I64_GT_S, (I64 I64) -> (I32));
491    instruction!(i64_gt_u, I64_GT_U, (I64 I64) -> (I32));
492    instruction!(i64_le_s, I64_LE_S, (I64 I64) -> (I32));
493    instruction!(i64_le_u, I64_LE_U, (I64 I64) -> (I32));
494    instruction!(i64_ge_s, I64_GE_S, (I64 I64) -> (I32));
495    instruction!(i64_ge_u, I64_GE_U, (I64 I64) -> (I32));
496
497    instruction!(f32_eq, F32_EQ, (F32 F32) -> (I32));
498    instruction!(f32_ne, F32_NE, (F32 F32) -> (I32));
499    instruction!(f32_lt, F32_LT, (F32 F32) -> (I32));
500    instruction!(f32_gt, F32_GT, (F32 F32) -> (I32));
501    instruction!(f32_le, F32_LE, (F32 F32) -> (I32));
502    instruction!(f32_ge, F32_GE, (F32 F32) -> (I32));
503
504    instruction!(f64_eq, F64_EQ, (F64 F64) -> (I32));
505    instruction!(f64_ne, F64_NE, (F64 F64) -> (I32));
506    instruction!(f64_lt, F64_LT, (F64 F64) -> (I32));
507    instruction!(f64_gt, F64_GT, (F64 F64) -> (I32));
508    instruction!(f64_le, F64_LE, (F64 F64) -> (I32));
509    instruction!(f64_ge, F64_GE, (F64 F64) -> (I32));
510
511    instruction!(i32_clz, I32_CLZ, (I32) -> (I32));
512    instruction!(i32_ctz, I32_CTZ, (I32) -> (I32));
513    instruction!(i32_popcnt, I32_POPCNT, (I32) -> (I32));
514    instruction!(i32_add, I32_ADD, (I32 I32) -> (I32));
515    instruction!(i32_sub, I32_SUB, (I32 I32) -> (I32));
516    instruction!(i32_mul, I32_MUL, (I32 I32) -> (I32));
517    instruction!(i32_div_s, I32_DIV_S, (I32 I32) -> (I32));
518    instruction!(i32_div_u, I32_DIV_U, (I32 I32) -> (I32));
519    instruction!(i32_rem_s, I32_REM_S, (I32 I32) -> (I32));
520    instruction!(i32_rem_u, I32_REM_U, (I32 I32) -> (I32));
521    instruction!(i32_and, I32_AND, (I32 I32) -> (I32));
522    instruction!(i32_or, I32_OR, (I32 I32) -> (I32));
523    instruction!(i32_xor, I32_XOR, (I32 I32) -> (I32));
524    instruction!(i32_shl, I32_SHL, (I32 I32) -> (I32));
525    instruction!(i32_shr_s, I32_SHR_S, (I32 I32) -> (I32));
526    instruction!(i32_shr_u, I32_SHR_U, (I32 I32) -> (I32));
527    instruction!(i32_rotl, I32_ROTL, (I32 I32) -> (I32));
528    instruction!(i32_rotr, I32_ROTR, (I32 I32) -> (I32));
529
530    instruction!(i64_clz, I64_CLZ, (I64) -> (I64));
531    instruction!(i64_ctz, I64_CTZ, (I64) -> (I64));
532    instruction!(i64_popcnt, I64_POPCNT, (I64) -> (I64));
533    instruction!(i64_add, I64_ADD, (I64 I64) -> (I64));
534    instruction!(i64_sub, I64_SUB, (I64 I64) -> (I64));
535    instruction!(i64_mul, I64_MUL, (I64 I64) -> (I64));
536    instruction!(i64_div_s, I64_DIV_S, (I64 I64) -> (I64));
537    instruction!(i64_div_u, I64_DIV_U, (I64 I64) -> (I64));
538    instruction!(i64_rem_s, I64_REM_S, (I64 I64) -> (I64));
539    instruction!(i64_rem_u, I64_REM_U, (I64 I64) -> (I64));
540    instruction!(i64_and, I64_AND, (I64 I64) -> (I64));
541    instruction!(i64_or, I64_OR, (I64 I64) -> (I64));
542    instruction!(i64_xor, I64_XOR, (I64 I64) -> (I64));
543    instruction!(i64_shl, I64_SHL, (I64 I64) -> (I64));
544    instruction!(i64_shr_s, I64_SHR_S, (I64 I64) -> (I64));
545    instruction!(i64_shr_u, I64_SHR_U, (I64 I64) -> (I64));
546    instruction!(i64_rotl, I64_ROTL, (I64 I64) -> (I64));
547    instruction!(i64_rotr, I64_ROTR, (I64 I64) -> (I64));
548
549    instruction!(f32_abs, F32_ABS, (F32) -> (F32));
550    instruction!(f32_neg, F32_NEG, (F32) -> (F32));
551    instruction!(f32_ceil, F32_CEIL, (F32) -> (F32));
552    instruction!(f32_floor, F32_FLOOR, (F32) -> (F32));
553    instruction!(f32_trunc, F32_TRUNC, (F32) -> (F32));
554    instruction!(f32_nearest, F32_NEAREST, (F32) -> (F32));
555    instruction!(f32_sqrt, F32_SQRT, (F32) -> (F32));
556    instruction!(f32_add, F32_ADD, (F32 F32) -> (F32));
557    instruction!(f32_sub, F32_SUB, (F32 F32) -> (F32));
558    instruction!(f32_mul, F32_MUL, (F32 F32) -> (F32));
559    instruction!(f32_div, F32_DIV, (F32 F32) -> (F32));
560    instruction!(f32_min, F32_MIN, (F32 F32) -> (F32));
561    instruction!(f32_max, F32_MAX, (F32 F32) -> (F32));
562    instruction!(f32_copysign, F32_COPYSIGN, (F32 F32) -> (F32));
563
564    instruction!(f64_abs, F64_ABS, (F64) -> (F64));
565    instruction!(f64_neg, F64_NEG, (F64) -> (F64));
566    instruction!(f64_ceil, F64_CEIL, (F64) -> (F64));
567    instruction!(f64_floor, F64_FLOOR, (F64) -> (F64));
568    instruction!(f64_trunc, F64_TRUNC, (F64) -> (F64));
569    instruction!(f64_nearest, F64_NEAREST, (F64) -> (F64));
570    instruction!(f64_sqrt, F64_SQRT, (F64) -> (F64));
571    instruction!(f64_add, F64_ADD, (F64 F64) -> (F64));
572    instruction!(f64_sub, F64_SUB, (F64 F64) -> (F64));
573    instruction!(f64_mul, F64_MUL, (F64 F64) -> (F64));
574    instruction!(f64_div, F64_DIV, (F64 F64) -> (F64));
575    instruction!(f64_min, F64_MIN, (F64 F64) -> (F64));
576    instruction!(f64_max, F64_MAX, (F64 F64) -> (F64));
577    instruction!(f64_copysign, F64_COPYSIGN, (F64 F64) -> (F64));
578
579    instruction!(i32_wrap_i64, I32_WRAP_I64, (I64) -> (I32));
580    instruction!(i32_trunc_f32_s, I32_TRUNC_F32_S, (F32) -> (I32));
581    instruction!(i32_trunc_f32_u, I32_TRUNC_F32_U, (F32) -> (I32));
582    instruction!(i32_trunc_f64_s, I32_TRUNC_F64_S, (F64) -> (I32));
583    instruction!(i32_trunc_f64_u, I32_TRUNC_F64_U, (F64) -> (I32));
584    instruction!(i64_extend_i32_s, I64_EXTEND_I32_S, (I32) -> (I64));
585    instruction!(i64_extend_i32_u, I64_EXTEND_I32_U, (I32) -> (I64));
586    instruction!(i64_trunc_f32_s, I64_TRUNC_F32_S, (F32) -> (I64));
587    instruction!(i64_trunc_f32_u, I64_TRUNC_F32_U, (F32) -> (I64));
588    instruction!(i64_trunc_f64_s, I64_TRUNC_F64_S, (F64) -> (I64));
589    instruction!(i64_trunc_f64_u, I64_TRUNC_F64_U, (F64) -> (I64));
590    instruction!(f32_convert_i32_s, F32_CONVERT_I32_S, (I32) -> (F32));
591    instruction!(f32_convert_i32_u, F32_CONVERT_I32_U, (I32) -> (F32));
592    instruction!(f32_convert_i64_s, F32_CONVERT_I64_S, (I64) -> (F32));
593    instruction!(f32_convert_i64_u, F32_CONVERT_I64_U, (I64) -> (F32));
594    instruction!(f32_demote_f64, F32_DEMOTE_F64, (F64) -> (F32));
595    instruction!(f64_convert_i32_s, F64_CONVERT_I32_S, (I32) -> (F64));
596    instruction!(f64_convert_i32_u, F64_CONVERT_I32_U, (I32) -> (F64));
597    instruction!(f64_convert_i64_s, F64_CONVERT_I64_S, (I64) -> (F64));
598    instruction!(f64_convert_i64_u, F64_CONVERT_I64_U, (I64) -> (F64));
599    instruction!(f64_promote_f32, F64_PROMOTE_F32, (F32) -> (F64));
600}