synth_core/wasm_op.rs
1//! WebAssembly operation patterns — universal input IR for all backends
2//!
3//! Every backend (ARM, aWsm, wasker, w2c2) consumes `WasmOp` sequences.
4//! This enum lives in synth-core so backends can depend on it without
5//! pulling in ARM-specific synthesis types.
6
7use serde::{Deserialize, Serialize};
8
9/// WebAssembly operation patterns
10/// Note: Cannot derive Eq because f32/f64 don't implement Eq (NaN != NaN)
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub enum WasmOp {
13 // Arithmetic
14 I32Add,
15 I32Sub,
16 I32Mul,
17 I32DivS,
18 I32DivU,
19 I32RemS,
20 I32RemU,
21
22 // Bitwise
23 I32And,
24 I32Or,
25 I32Xor,
26 I32Shl,
27 I32ShrS,
28 I32ShrU,
29 I32Rotl, // Rotate left
30 I32Rotr, // Rotate right
31 I32Clz, // Count leading zeros
32 I32Ctz, // Count trailing zeros
33 I32Popcnt, // Population count (count 1 bits)
34
35 // Sign extension
36 I32Extend8S, // Sign-extend low 8 bits to 32 bits
37 I32Extend16S, // Sign-extend low 16 bits to 32 bits
38
39 // Comparison
40 I32Eqz, // Equal to zero (unary)
41 I32Eq,
42 I32Ne,
43 I32LtS,
44 I32LtU,
45 I32LeS,
46 I32LeU,
47 I32GtS,
48 I32GtU,
49 I32GeS,
50 I32GeU,
51
52 // Constants
53 I32Const(i32),
54
55 // Memory
56 I32Load {
57 offset: u32,
58 align: u32,
59 },
60 I32Store {
61 offset: u32,
62 align: u32,
63 },
64
65 // Sub-word loads (i32)
66 I32Load8S {
67 offset: u32,
68 align: u32,
69 }, // byte load, sign-extend to i32
70 I32Load8U {
71 offset: u32,
72 align: u32,
73 }, // byte load, zero-extend to i32
74 I32Load16S {
75 offset: u32,
76 align: u32,
77 }, // halfword load, sign-extend to i32
78 I32Load16U {
79 offset: u32,
80 align: u32,
81 }, // halfword load, zero-extend to i32
82
83 // Sub-word stores (i32)
84 I32Store8 {
85 offset: u32,
86 align: u32,
87 }, // store low byte
88 I32Store16 {
89 offset: u32,
90 align: u32,
91 }, // store low halfword
92
93 // Control flow
94 Block,
95 Loop,
96 Br(u32), // Branch to label
97 BrIf(u32), // Conditional branch
98 BrTable {
99 targets: Vec<u32>,
100 default: u32,
101 },
102 Return,
103 Call(u32),
104 CallIndirect {
105 type_index: u32,
106 table_index: u32,
107 },
108 LocalGet(u32),
109 LocalSet(u32),
110 LocalTee(u32),
111 GlobalGet(u32),
112 GlobalSet(u32),
113
114 // Memory management
115 MemorySize(u32), // returns current memory size in pages (memory index)
116 MemoryGrow(u32), // grow memory by N pages, returns previous size or -1 (memory index)
117
118 // Bulk memory (#374) — single linear memory (memory 0) only; the decoder
119 // loud-skips any non-zero memory index. Each pops (dst, src/val, len) = 3
120 // i32 operands and pushes nothing.
121 MemoryCopy, // memory.copy: copy `len` bytes from `src` to `dst` (memmove semantics)
122 MemoryFill, // memory.fill: set `len` bytes at `dst` to the low byte of `val`
123
124 /// VCR-MEM-002 phase 1 (#406): a load/store whose `memarg` targets a
125 /// NON-DEFAULT linear memory (`memidx > 0`, multi-memory proposal). The
126 /// decoder wraps the plain memory-0 variant instead of DROPPING the index
127 /// (the pre-#406 silent aliasing: every memory lowered to the one R11
128 /// base, so a store to memory `$b` clobbered memory `$a`). Keeping
129 /// memory-0 ops as the bare variants means every existing single-memory
130 /// match arm — and therefore every frozen fixture byte — is untouched by
131 /// construction; the multi-memory-aware path (the `--relocatable` direct
132 /// selector) unwraps this and addresses via the per-memory base symbol
133 /// (`__synth_wasm_data_<k>`), and every other path declines LOUDLY
134 /// (never a silent alias).
135 ///
136 /// `memory.size`/`memory.grow` are NOT wrapped — their variants already
137 /// carry the memory index. Invariant (decoder-enforced): `memory > 0` and
138 /// `op` is never itself a `MultiMemory`.
139 MultiMemory {
140 memory: u32,
141 op: Box<WasmOp>,
142 },
143
144 // More ops
145 Drop,
146 Select,
147 If,
148 Else,
149 End,
150 Unreachable,
151 Nop,
152
153 // ========================================================================
154 // i64 Operations
155 // ========================================================================
156
157 // i64 Arithmetic
158 I64Add,
159 I64Sub,
160 I64Mul,
161 I64DivS,
162 I64DivU,
163 I64RemS,
164 I64RemU,
165
166 // i64 Bitwise
167 I64And,
168 I64Or,
169 I64Xor,
170 I64Shl,
171 I64ShrS,
172 I64ShrU,
173 I64Rotl,
174 I64Rotr,
175 I64Clz,
176 I64Ctz,
177 I64Popcnt,
178
179 // i64 Comparison
180 I64Eqz,
181 I64Eq,
182 I64Ne,
183 I64LtS,
184 I64LtU,
185 I64LeS,
186 I64LeU,
187 I64GtS,
188 I64GtU,
189 I64GeS,
190 I64GeU,
191
192 // i64 Constants and Memory
193 I64Const(i64),
194 I64Load {
195 offset: u32,
196 align: u32,
197 },
198 I64Store {
199 offset: u32,
200 align: u32,
201 },
202
203 // Sub-word loads (i64) — load sub-word, extend to i64
204 I64Load8S {
205 offset: u32,
206 align: u32,
207 },
208 I64Load8U {
209 offset: u32,
210 align: u32,
211 },
212 I64Load16S {
213 offset: u32,
214 align: u32,
215 },
216 I64Load16U {
217 offset: u32,
218 align: u32,
219 },
220 I64Load32S {
221 offset: u32,
222 align: u32,
223 },
224 I64Load32U {
225 offset: u32,
226 align: u32,
227 },
228
229 // Sub-word stores (i64) — store low N bits
230 I64Store8 {
231 offset: u32,
232 align: u32,
233 },
234 I64Store16 {
235 offset: u32,
236 align: u32,
237 },
238 I64Store32 {
239 offset: u32,
240 align: u32,
241 },
242
243 // Conversion operations
244 I64ExtendI32S, // Sign-extend i32 to i64
245 I64ExtendI32U, // Zero-extend i32 to i64
246 I32WrapI64, // Wrap i64 to i32 (truncate)
247
248 // i64 In-place sign extension
249 I64Extend8S, // Sign-extend low 8 bits to 64 bits
250 I64Extend16S, // Sign-extend low 16 bits to 64 bits
251 I64Extend32S, // Sign-extend low 32 bits to 64 bits
252
253 // ========================================================================
254 // f32 Operations
255 // ========================================================================
256
257 // f32 Arithmetic
258 F32Add,
259 F32Sub,
260 F32Mul,
261 F32Div,
262
263 // f32 Comparisons
264 F32Eq,
265 F32Ne,
266 F32Lt,
267 F32Le,
268 F32Gt,
269 F32Ge,
270
271 // f32 Math Functions
272 F32Abs,
273 F32Neg,
274 F32Ceil,
275 F32Floor,
276 F32Trunc,
277 F32Nearest,
278 F32Sqrt,
279 F32Min,
280 F32Max,
281 F32Copysign,
282
283 // f32 Constants and Memory
284 F32Const(f32),
285 F32Load {
286 offset: u32,
287 align: u32,
288 },
289 F32Store {
290 offset: u32,
291 align: u32,
292 },
293
294 // f32 Conversions
295 F32ConvertI32S, // Convert signed i32 to f32
296 F32ConvertI32U, // Convert unsigned i32 to f32
297 F32ConvertI64S, // Convert signed i64 to f32
298 F32ConvertI64U, // Convert unsigned i64 to f32
299 F32DemoteF64, // Convert f64 to f32
300 F32ReinterpretI32, // Reinterpret i32 bits as f32
301 I32ReinterpretF32, // Reinterpret f32 bits as i32
302 I32TruncF32S, // Truncate f32 to signed i32
303 I32TruncF32U, // Truncate f32 to unsigned i32
304
305 // Nontrapping float→int (WASM saturating-float-to-int proposal, 0xFC
306 // prefix). TOTAL ops — never trap: NaN → 0, below INT_MIN → INT_MIN,
307 // above INT_MAX → INT_MAX, else truncate toward zero (§4.3.2 trunc_sat).
308 // Rust emits these for `as` casts, so real modules (falcon, #782) carry
309 // them even when the trapping forms are absent.
310 I32TruncSatF32S, // Saturating truncate f32 to signed i32
311 I32TruncSatF32U, // Saturating truncate f32 to unsigned i32
312 I64TruncSatF32S, // Saturating truncate f32 to signed i64
313 I64TruncSatF32U, // Saturating truncate f32 to unsigned i64
314
315 // ========================================================================
316 // f64 Operations
317 // ========================================================================
318
319 // f64 Arithmetic
320 F64Add,
321 F64Sub,
322 F64Mul,
323 F64Div,
324
325 // f64 Comparisons
326 F64Eq,
327 F64Ne,
328 F64Lt,
329 F64Le,
330 F64Gt,
331 F64Ge,
332
333 // f64 Math Functions
334 F64Abs,
335 F64Neg,
336 F64Ceil,
337 F64Floor,
338 F64Trunc,
339 F64Nearest,
340 F64Sqrt,
341 F64Min,
342 F64Max,
343 F64Copysign,
344
345 // f64 Constants and Memory
346 F64Const(f64),
347 F64Load {
348 offset: u32,
349 align: u32,
350 },
351 F64Store {
352 offset: u32,
353 align: u32,
354 },
355
356 // f64 Conversions
357 F64ConvertI32S, // Convert signed i32 to f64
358 F64ConvertI32U, // Convert unsigned i32 to f64
359 F64ConvertI64S, // Convert signed i64 to f64
360 F64ConvertI64U, // Convert unsigned i64 to f64
361 F64PromoteF32, // Convert f32 to f64
362 F64ReinterpretI64, // Reinterpret i64 bits as f64
363 I64ReinterpretF64, // Reinterpret f64 bits as i64
364 I64TruncF64S, // Truncate f64 to signed i64
365 I64TruncF64U, // Truncate f64 to unsigned i64
366 I32TruncF64S, // Truncate f64 to signed i32
367 I32TruncF64U, // Truncate f64 to unsigned i32
368
369 // Nontrapping f64→int (saturating-float-to-int, §4.3.2 trunc_sat — see
370 // the f32 group above for the semantics).
371 I32TruncSatF64S, // Saturating truncate f64 to signed i32
372 I32TruncSatF64U, // Saturating truncate f64 to unsigned i32
373 I64TruncSatF64S, // Saturating truncate f64 to signed i64
374 I64TruncSatF64U, // Saturating truncate f64 to unsigned i64
375
376 // ========================================================================
377 // v128 SIMD Operations (WASM SIMD proposal)
378 // ========================================================================
379 // Targets ARM Cortex-M55 Helium MVE (M-Profile Vector Extension)
380
381 // v128 Constants and Memory
382 V128Const([u8; 16]), // 128-bit constant
383 V128Load {
384 offset: u32,
385 align: u32,
386 }, // v128.load
387 V128Store {
388 offset: u32,
389 align: u32,
390 }, // v128.store
391
392 // v128 Bitwise operations
393 V128And, // v128.and
394 V128Or, // v128.or
395 V128Xor, // v128.xor
396 V128Not, // v128.not
397 V128AndNot, // v128.andnot
398
399 // i8x16 integer SIMD
400 I8x16Add, // i8x16.add
401 I8x16Sub, // i8x16.sub
402 I8x16Neg, // i8x16.neg
403 I8x16Eq, // i8x16.eq
404 I8x16Ne, // i8x16.ne
405 I8x16LtS, // i8x16.lt_s
406 I8x16LtU, // i8x16.lt_u
407 I8x16GtS, // i8x16.gt_s
408 I8x16GtU, // i8x16.gt_u
409 I8x16LeS, // i8x16.le_s
410 I8x16LeU, // i8x16.le_u
411 I8x16GeS, // i8x16.ge_s
412 I8x16GeU, // i8x16.ge_u
413 I8x16Splat, // i8x16.splat
414 I8x16ExtractLaneS(u8), // i8x16.extract_lane_s
415 I8x16ExtractLaneU(u8), // i8x16.extract_lane_u
416 I8x16ReplaceLane(u8), // i8x16.replace_lane
417 I8x16Shuffle([u8; 16]), // i8x16.shuffle
418 I8x16Swizzle, // i8x16.swizzle
419
420 // i16x8 integer SIMD
421 I16x8Add, // i16x8.add
422 I16x8Sub, // i16x8.sub
423 I16x8Mul, // i16x8.mul
424 I16x8Neg, // i16x8.neg
425 I16x8Eq, // i16x8.eq
426 I16x8Ne, // i16x8.ne
427 I16x8LtS, // i16x8.lt_s
428 I16x8LtU, // i16x8.lt_u
429 I16x8GtS, // i16x8.gt_s
430 I16x8GtU, // i16x8.gt_u
431 I16x8LeS, // i16x8.le_s
432 I16x8LeU, // i16x8.le_u
433 I16x8GeS, // i16x8.ge_s
434 I16x8GeU, // i16x8.ge_u
435 I16x8Splat, // i16x8.splat
436 I16x8ExtractLaneS(u8), // i16x8.extract_lane_s
437 I16x8ExtractLaneU(u8), // i16x8.extract_lane_u
438 I16x8ReplaceLane(u8), // i16x8.replace_lane
439
440 // i32x4 integer SIMD
441 I32x4Add, // i32x4.add
442 I32x4Sub, // i32x4.sub
443 I32x4Mul, // i32x4.mul
444 I32x4Neg, // i32x4.neg
445 I32x4Eq, // i32x4.eq
446 I32x4Ne, // i32x4.ne
447 I32x4LtS, // i32x4.lt_s
448 I32x4LtU, // i32x4.lt_u
449 I32x4GtS, // i32x4.gt_s
450 I32x4GtU, // i32x4.gt_u
451 I32x4LeS, // i32x4.le_s
452 I32x4LeU, // i32x4.le_u
453 I32x4GeS, // i32x4.ge_s
454 I32x4GeU, // i32x4.ge_u
455 I32x4Splat, // i32x4.splat
456 I32x4ExtractLane(u8), // i32x4.extract_lane
457 I32x4ReplaceLane(u8), // i32x4.replace_lane
458
459 // i64x2 integer SIMD
460 I64x2Add, // i64x2.add
461 I64x2Sub, // i64x2.sub
462 I64x2Mul, // i64x2.mul
463 I64x2Neg, // i64x2.neg
464 I64x2Eq, // i64x2.eq
465 I64x2Ne, // i64x2.ne
466 I64x2LtS, // i64x2.lt_s
467 I64x2GtS, // i64x2.gt_s
468 I64x2LeS, // i64x2.le_s
469 I64x2GeS, // i64x2.ge_s
470 I64x2Splat, // i64x2.splat
471 I64x2ExtractLane(u8), // i64x2.extract_lane
472 I64x2ReplaceLane(u8), // i64x2.replace_lane
473
474 // f32x4 floating-point SIMD
475 F32x4Add, // f32x4.add
476 F32x4Sub, // f32x4.sub
477 F32x4Mul, // f32x4.mul
478 F32x4Div, // f32x4.div
479 F32x4Abs, // f32x4.abs
480 F32x4Neg, // f32x4.neg
481 F32x4Sqrt, // f32x4.sqrt
482 F32x4Eq, // f32x4.eq
483 F32x4Ne, // f32x4.ne
484 F32x4Lt, // f32x4.lt
485 F32x4Le, // f32x4.le
486 F32x4Gt, // f32x4.gt
487 F32x4Ge, // f32x4.ge
488 F32x4Splat, // f32x4.splat
489 F32x4ExtractLane(u8), // f32x4.extract_lane
490 F32x4ReplaceLane(u8), // f32x4.replace_lane
491}