wasm_ast/model/
instruction.rs

1//! WebAssembly instruction set.
2
3use crate::model::{
4    DataIndex, ElementIndex, FloatType, FunctionIndex, GlobalIndex, IntegerType, LabelIndex,
5    LocalIndex, NumberType, ReferenceType, TableIndex, TypeIndex, ValueType,
6};
7
8/// WebAssembly code consists of sequences of instructions.
9/// Its computational model is based on a stack machine in that instructions manipulate values on
10/// an implicit operand stack, consuming (popping) argument values and producing or returning
11/// (pushing) result values.
12/// In addition to dynamic operands from the stack,
13/// some instructions also have static immediate arguments,
14/// typically indices or type annotations, which are part of the instruction itself.
15/// Some instructions are structured in that they bracket nested sequences of instructions.
16/// The following sections group instructions into a number of different categories.
17///
18/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#instructions>
19///
20/// # Examples
21/// See the specific instruction types for examples.
22#[derive(Clone, Debug, PartialEq)]
23pub enum Instruction {
24    Numeric(NumericInstruction),
25    Reference(ReferenceInstruction),
26    Parametric(ParametricInstruction),
27    Variable(VariableInstruction),
28    Table(TableInstruction),
29    Memory(MemoryInstruction),
30    Control(ControlInstruction),
31}
32
33/// Numeric instructions provide basic operations over numeric values of specific type.
34/// These operations closely match respective operations available in hardware.
35///
36/// Some integer instructions come in two flavors,
37/// where a signedness annotation sx distinguishes whether the operands are to be interpreted as
38/// unsigned or signed integers. For the other integer instructions, the use of two’s complement
39/// for the signed interpretation means that they behave the same regardless of signedness.
40///
41/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#numeric-instructions>
42///
43/// # Examples
44/// ## Constant
45/// ```rust
46/// use wasm_ast::{NumericInstruction, Instruction};
47///
48/// assert_eq!(
49///     Instruction::Numeric(NumericInstruction::I32Constant(42)),
50///     42i32.into()
51/// );
52/// assert_eq!(
53///     Instruction::Numeric(NumericInstruction::I64Constant(42i64)),
54///     42i64.into()
55/// );
56/// assert_eq!(
57///     Instruction::Numeric(NumericInstruction::F32Constant(0.1)),
58///     0.1f32.into()
59/// );
60/// assert_eq!(
61///     Instruction::Numeric(NumericInstruction::F64Constant(0.2)),
62///     0.2f64.into()
63/// );
64/// ```
65///
66/// ## Integer
67/// ```rust
68/// use wasm_ast::{NumericInstruction, Instruction, IntegerType, SignExtension};
69///
70/// assert_eq!(
71///     Instruction::Numeric(NumericInstruction::CountLeadingZeros(IntegerType::I32)),
72///     NumericInstruction::CountLeadingZeros(IntegerType::I32).into()
73/// );
74/// assert_eq!(
75///     Instruction::Numeric(NumericInstruction::CountTrailingZeros(IntegerType::I64)),
76///     NumericInstruction::CountTrailingZeros(IntegerType::I64).into()
77/// );
78/// assert_eq!(
79///     Instruction::Numeric(NumericInstruction::CountOnes(IntegerType::I64)),
80///     NumericInstruction::CountOnes(IntegerType::I64).into()
81/// );
82/// assert_eq!(
83///     Instruction::Numeric(NumericInstruction::DivideInteger(IntegerType::I64, SignExtension::Unsigned)),
84///     NumericInstruction::DivideInteger(IntegerType::I64, SignExtension::Unsigned).into()
85/// );
86/// assert_eq!(
87///     Instruction::Numeric(NumericInstruction::Remainder(IntegerType::I64, SignExtension::Unsigned)),
88///     NumericInstruction::Remainder(IntegerType::I64, SignExtension::Unsigned).into()
89/// );
90/// assert_eq!(
91///     Instruction::Numeric(NumericInstruction::And(IntegerType::I64)),
92///     NumericInstruction::And(IntegerType::I64).into()
93/// );
94/// assert_eq!(
95///     Instruction::Numeric(NumericInstruction::Or(IntegerType::I64)),
96///     NumericInstruction::Or(IntegerType::I64).into()
97/// );
98/// assert_eq!(
99///     Instruction::Numeric(NumericInstruction::Xor(IntegerType::I64)),
100///     NumericInstruction::Xor(IntegerType::I64).into()
101/// );
102/// assert_eq!(
103///     Instruction::Numeric(NumericInstruction::ShiftLeft(IntegerType::I64)),
104///     NumericInstruction::ShiftLeft(IntegerType::I64).into()
105/// );
106/// assert_eq!(
107///     Instruction::Numeric(NumericInstruction::ShiftRight(IntegerType::I64, SignExtension::Unsigned)),
108///     NumericInstruction::ShiftRight(IntegerType::I64, SignExtension::Unsigned).into()
109/// );
110/// assert_eq!(
111///     Instruction::Numeric(NumericInstruction::RotateLeft(IntegerType::I64)),
112///     NumericInstruction::RotateLeft(IntegerType::I64).into()
113/// );
114/// assert_eq!(
115///     Instruction::Numeric(NumericInstruction::RotateRight(IntegerType::I64)),
116///     NumericInstruction::RotateRight(IntegerType::I64).into()
117/// );
118/// assert_eq!(
119///     Instruction::Numeric(NumericInstruction::EqualToZero(IntegerType::I64)),
120///     NumericInstruction::EqualToZero(IntegerType::I64).into()
121/// );
122/// assert_eq!(
123///     Instruction::Numeric(NumericInstruction::LessThanInteger(IntegerType::I64, SignExtension::Unsigned)),
124///     NumericInstruction::LessThanInteger(IntegerType::I64, SignExtension::Unsigned).into()
125/// );
126/// assert_eq!(
127///     Instruction::Numeric(NumericInstruction::GreaterThanInteger(IntegerType::I64, SignExtension::Unsigned)),
128///     NumericInstruction::GreaterThanInteger(IntegerType::I64, SignExtension::Unsigned).into()
129/// );
130/// assert_eq!(
131///     Instruction::Numeric(NumericInstruction::LessThanOrEqualToInteger(IntegerType::I64, SignExtension::Unsigned)),
132///     NumericInstruction::LessThanOrEqualToInteger(IntegerType::I64, SignExtension::Unsigned).into()
133/// );
134/// assert_eq!(
135///     Instruction::Numeric(NumericInstruction::GreaterThanOrEqualToInteger(IntegerType::I64, SignExtension::Unsigned)),
136///     NumericInstruction::GreaterThanOrEqualToInteger(IntegerType::I64, SignExtension::Unsigned).into()
137/// );
138/// assert_eq!(
139///     Instruction::Numeric(NumericInstruction::ExtendSigned8(IntegerType::I64)),
140///     NumericInstruction::ExtendSigned8(IntegerType::I64).into()
141/// );
142/// assert_eq!(
143///     Instruction::Numeric(NumericInstruction::ExtendSigned16(IntegerType::I64)),
144///     NumericInstruction::ExtendSigned16(IntegerType::I64).into()
145/// );
146/// assert_eq!(
147///     Instruction::Numeric(NumericInstruction::ExtendSigned32),
148///     NumericInstruction::ExtendSigned32.into()
149/// );
150/// ```
151///
152/// ## Float
153/// ```rust
154/// use wasm_ast::{NumericInstruction, Instruction, FloatType};
155///
156/// assert_eq!(
157///     Instruction::Numeric(NumericInstruction::AbsoluteValue(FloatType::F32)),
158///     NumericInstruction::AbsoluteValue(FloatType::F32).into()
159/// );
160/// assert_eq!(
161///     Instruction::Numeric(NumericInstruction::Negate(FloatType::F64)),
162///     NumericInstruction::Negate(FloatType::F64).into()
163/// );
164/// assert_eq!(
165///     Instruction::Numeric(NumericInstruction::SquareRoot(FloatType::F64)),
166///     NumericInstruction::SquareRoot(FloatType::F64).into()
167/// );
168/// assert_eq!(
169///     Instruction::Numeric(NumericInstruction::Ceiling(FloatType::F32)),
170///     NumericInstruction::Ceiling(FloatType::F32).into()
171/// );
172/// assert_eq!(
173///     Instruction::Numeric(NumericInstruction::Floor(FloatType::F64)),
174///     NumericInstruction::Floor(FloatType::F64).into()
175/// );
176/// assert_eq!(
177///     Instruction::Numeric(NumericInstruction::Truncate(FloatType::F64)),
178///     NumericInstruction::Truncate(FloatType::F64).into()
179/// );
180/// assert_eq!(
181///     Instruction::Numeric(NumericInstruction::Nearest(FloatType::F64)),
182///     NumericInstruction::Nearest(FloatType::F64).into()
183/// );
184/// assert_eq!(
185///     Instruction::Numeric(NumericInstruction::DivideFloat(FloatType::F32)),
186///     NumericInstruction::DivideFloat(FloatType::F32).into()
187/// );
188/// assert_eq!(
189///     Instruction::Numeric(NumericInstruction::Minimum(FloatType::F32)),
190///     NumericInstruction::Minimum(FloatType::F32).into()
191/// );
192/// assert_eq!(
193///     Instruction::Numeric(NumericInstruction::Maximum(FloatType::F32)),
194///     NumericInstruction::Maximum(FloatType::F32).into()
195/// );
196/// assert_eq!(
197///     Instruction::Numeric(NumericInstruction::CopySign(FloatType::F32)),
198///     NumericInstruction::CopySign(FloatType::F32).into()
199/// );
200/// assert_eq!(
201///     Instruction::Numeric(NumericInstruction::LessThanFloat(FloatType::F32)),
202///     NumericInstruction::LessThanFloat(FloatType::F32).into()
203/// );
204/// assert_eq!(
205///     Instruction::Numeric(NumericInstruction::GreaterThanFloat(FloatType::F32)),
206///     NumericInstruction::GreaterThanFloat(FloatType::F32).into()
207/// );
208/// assert_eq!(
209///     Instruction::Numeric(NumericInstruction::LessThanOrEqualToFloat(FloatType::F32)),
210///     NumericInstruction::LessThanOrEqualToFloat(FloatType::F32).into()
211/// );
212/// assert_eq!(
213///     Instruction::Numeric(NumericInstruction::GreaterThanOrEqualToFloat(FloatType::F32)),
214///     NumericInstruction::GreaterThanOrEqualToFloat(FloatType::F32).into()
215/// );
216/// ```
217///
218/// ## Number
219/// ```rust
220/// use wasm_ast::{NumericInstruction, Instruction, NumberType};
221///
222/// assert_eq!(
223///     Instruction::Numeric(NumericInstruction::Add(NumberType::I32)),
224///     NumericInstruction::Add(NumberType::I32).into()
225/// );
226/// assert_eq!(
227///     Instruction::Numeric(NumericInstruction::Subtract(NumberType::I32)),
228///     NumericInstruction::Subtract(NumberType::I32).into()
229/// );
230/// assert_eq!(
231///     Instruction::Numeric(NumericInstruction::Multiply(NumberType::I32)),
232///     NumericInstruction::Multiply(NumberType::I32).into()
233/// );
234/// assert_eq!(
235///     Instruction::Numeric(NumericInstruction::Equal(NumberType::I32)),
236///     NumericInstruction::Equal(NumberType::I32).into()
237/// );
238/// assert_eq!(
239///     Instruction::Numeric(NumericInstruction::NotEqual(NumberType::I32)),
240///     NumericInstruction::NotEqual(NumberType::I32).into()
241/// );
242/// ```
243///
244/// ## Convert
245/// ```rust
246/// use wasm_ast::{NumericInstruction, Instruction, NumberType, SignExtension, IntegerType, FloatType};
247///
248/// assert_eq!(
249///     Instruction::Numeric(NumericInstruction::Wrap),
250///     NumericInstruction::Wrap.into()
251/// );
252/// assert_eq!(
253///     Instruction::Numeric(NumericInstruction::ExtendWithSignExtension(SignExtension::Signed)),
254///     NumericInstruction::ExtendWithSignExtension(SignExtension::Signed).into()
255/// );
256/// assert_eq!(
257///     Instruction::Numeric(NumericInstruction::ConvertAndTruncate(IntegerType::I32, FloatType::F64, SignExtension::Unsigned)),
258///     NumericInstruction::ConvertAndTruncate(IntegerType::I32, FloatType::F64, SignExtension::Unsigned).into()
259/// );
260/// assert_eq!(
261///     Instruction::Numeric(NumericInstruction::ConvertAndTruncateWithSaturation(IntegerType::I32, FloatType::F64, SignExtension::Unsigned)),
262///     NumericInstruction::ConvertAndTruncateWithSaturation(IntegerType::I32, FloatType::F64, SignExtension::Unsigned).into()
263/// );
264/// assert_eq!(
265///     Instruction::Numeric(NumericInstruction::Demote),
266///     NumericInstruction::Demote.into()
267/// );
268/// assert_eq!(
269///     Instruction::Numeric(NumericInstruction::Promote),
270///     NumericInstruction::Promote.into()
271/// );
272/// assert_eq!(
273///     Instruction::Numeric(NumericInstruction::Convert(FloatType::F64, IntegerType::I32, SignExtension::Unsigned)),
274///     NumericInstruction::Convert(FloatType::F64, IntegerType::I32, SignExtension::Unsigned).into()
275/// );
276/// assert_eq!(
277///     Instruction::Numeric(NumericInstruction::ReinterpretFloat(IntegerType::I32)),
278///     NumericInstruction::ReinterpretFloat(IntegerType::I32).into()
279/// );
280/// assert_eq!(
281///     Instruction::Numeric(NumericInstruction::ReinterpretInteger(FloatType::F64)),
282///     NumericInstruction::ReinterpretInteger(FloatType::F64).into()
283/// );
284/// ```
285#[derive(Copy, Clone, Debug, PartialEq)]
286pub enum NumericInstruction {
287    /// i32.const
288    I32Constant(i32),
289    /// i64.const
290    I64Constant(i64),
291    /// f32.const
292    F32Constant(f32),
293    /// f64.const
294    F64Constant(f64),
295    /// inn.clz
296    CountLeadingZeros(IntegerType),
297    /// inn.ctz
298    CountTrailingZeros(IntegerType),
299    /// inn.popcnt
300    CountOnes(IntegerType),
301    /// fnn.abs
302    AbsoluteValue(FloatType),
303    /// fnn.negate
304    Negate(FloatType),
305    /// fnn.sqrt
306    SquareRoot(FloatType),
307    /// fnn.ceil
308    Ceiling(FloatType),
309    /// fnn.floor
310    Floor(FloatType),
311    /// fnn.trunc
312    Truncate(FloatType),
313    /// fnn.nearest
314    Nearest(FloatType),
315    /// xnn.add
316    Add(NumberType),
317    /// xnn.sub
318    Subtract(NumberType),
319    /// xnn.mul
320    Multiply(NumberType),
321    /// inn.div_sx
322    DivideInteger(IntegerType, SignExtension),
323    /// fnn.div
324    DivideFloat(FloatType),
325    /// inn.rem_sx
326    Remainder(IntegerType, SignExtension),
327    /// inn.and
328    And(IntegerType),
329    /// inn.or
330    Or(IntegerType),
331    /// inn.xor
332    Xor(IntegerType),
333    /// inn.shl
334    ShiftLeft(IntegerType),
335    /// inn.shr_sx
336    ShiftRight(IntegerType, SignExtension),
337    /// inn.rotl
338    RotateLeft(IntegerType),
339    /// inn.rotr
340    RotateRight(IntegerType),
341    /// fnn.min
342    Minimum(FloatType),
343    /// fnn.max
344    Maximum(FloatType),
345    /// fnn.copysign
346    CopySign(FloatType),
347    /// inn.eqz
348    EqualToZero(IntegerType),
349    /// xnn.eq
350    Equal(NumberType),
351    /// xnn.ne
352    NotEqual(NumberType),
353    /// inn.lt_sx
354    LessThanInteger(IntegerType, SignExtension),
355    /// fnn.lt
356    LessThanFloat(FloatType),
357    /// inn.gt_sx
358    GreaterThanInteger(IntegerType, SignExtension),
359    /// fnn.gt
360    GreaterThanFloat(FloatType),
361    /// inn.le_sx
362    LessThanOrEqualToInteger(IntegerType, SignExtension),
363    /// fnn.le
364    LessThanOrEqualToFloat(FloatType),
365    /// inn.ge_sx
366    GreaterThanOrEqualToInteger(IntegerType, SignExtension),
367    /// fnn.ge
368    GreaterThanOrEqualToFloat(FloatType),
369    /// inn.extend8_s
370    ExtendSigned8(IntegerType),
371    /// inn.extend16_s
372    ExtendSigned16(IntegerType),
373    /// i64.extend32_s
374    ExtendSigned32,
375    /// i32.wrap_i64
376    Wrap,
377    /// i64.extend_i32_sx
378    ExtendWithSignExtension(SignExtension),
379    /// inn.trunc_fmm_sx
380    ConvertAndTruncate(IntegerType, FloatType, SignExtension),
381    /// inn.trunc_sat_fmm_sx
382    ConvertAndTruncateWithSaturation(IntegerType, FloatType, SignExtension),
383    ///f32.demote_f64
384    Demote,
385    /// f64.promote_f32
386    Promote,
387    /// fnn.convert_imm_sx
388    Convert(FloatType, IntegerType, SignExtension),
389    /// inn.reinterpret_fmm
390    ReinterpretFloat(IntegerType),
391    /// fnn.reinterpret.imm
392    ReinterpretInteger(FloatType),
393}
394
395impl From<NumericInstruction> for Instruction {
396    fn from(instruction: NumericInstruction) -> Self {
397        Instruction::Numeric(instruction)
398    }
399}
400
401impl From<i8> for Instruction {
402    fn from(value: i8) -> Self {
403        Self::Numeric(NumericInstruction::I32Constant(value as i32))
404    }
405}
406
407impl From<i16> for Instruction {
408    fn from(value: i16) -> Self {
409        Self::Numeric(NumericInstruction::I32Constant(value as i32))
410    }
411}
412
413impl From<i32> for Instruction {
414    fn from(value: i32) -> Self {
415        Self::Numeric(NumericInstruction::I32Constant(value))
416    }
417}
418
419impl From<i64> for Instruction {
420    fn from(value: i64) -> Self {
421        Self::Numeric(NumericInstruction::I64Constant(value))
422    }
423}
424
425impl From<u8> for Instruction {
426    fn from(value: u8) -> Self {
427        Self::Numeric(NumericInstruction::I32Constant(value as i32))
428    }
429}
430
431impl From<u16> for Instruction {
432    fn from(value: u16) -> Self {
433        Self::Numeric(NumericInstruction::I32Constant(value as i32))
434    }
435}
436
437impl From<u32> for Instruction {
438    fn from(value: u32) -> Self {
439        Self::Numeric(NumericInstruction::I64Constant(value as i64))
440    }
441}
442
443impl From<f32> for Instruction {
444    fn from(value: f32) -> Self {
445        Self::Numeric(NumericInstruction::F32Constant(value))
446    }
447}
448
449impl From<f64> for Instruction {
450    fn from(value: f64) -> Self {
451        Self::Numeric(NumericInstruction::F64Constant(value))
452    }
453}
454
455/// Instructions in this group are concerned with accessing references.
456/// These instruction produce a null value, check for a null value, or produce a reference to a given function, respectively.
457///
458/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#reference-instructions>
459///
460/// # Examples
461/// ```rust
462/// use wasm_ast::{ReferenceInstruction, Instruction, ReferenceType};
463///
464/// assert_eq!(
465///     Instruction::Reference(ReferenceInstruction::Null(ReferenceType::External)),
466///     ReferenceInstruction::Null(ReferenceType::External).into()
467/// );
468/// assert_eq!(
469///     Instruction::Reference(ReferenceInstruction::IsNull),
470///     ReferenceInstruction::IsNull.into()
471/// );
472/// assert_eq!(
473///     Instruction::Reference(ReferenceInstruction::Function(3)),
474///     ReferenceInstruction::Function(3).into()
475/// );
476/// ```
477#[derive(Copy, Clone, Debug, Eq, PartialEq)]
478pub enum ReferenceInstruction {
479    /// ref.null
480    /// Produce a null value.
481    Null(ReferenceType),
482    /// ref.is_null
483    /// Check for a null value.
484    IsNull,
485    /// ref.func funcidx
486    /// Produce a reference to a given function.
487    Function(FunctionIndex),
488}
489
490impl From<ReferenceInstruction> for Instruction {
491    fn from(instruction: ReferenceInstruction) -> Self {
492        Self::Reference(instruction)
493    }
494}
495
496/// Instructions in this group can operate on operands of any value type.
497///
498/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#parametric-instructions>
499///
500/// # Examples
501/// ```rust
502/// use wasm_ast::{ParametricInstruction, Instruction, ValueType};
503///
504/// assert_eq!(
505///     Instruction::Parametric(ParametricInstruction::Drop),
506///     ParametricInstruction::Drop.into()
507/// );
508/// assert_eq!(
509///     Instruction::Parametric(ParametricInstruction::Select(Some(vec![ValueType::I32]))),
510///     ParametricInstruction::Select(Some(vec![ValueType::I32])).into()
511/// );
512/// assert_eq!(
513///     Instruction::Parametric(ParametricInstruction::Select(Some(vec![]))),
514///     ParametricInstruction::Select(Some(vec![])).into()
515/// );
516/// assert_eq!(
517///     Instruction::Parametric(ParametricInstruction::Select(None)),
518///     ParametricInstruction::Select(None).into()
519/// );
520/// ```
521#[derive(Clone, Debug, Eq, PartialEq)]
522pub enum ParametricInstruction {
523    /// The π–½π—‹π—ˆπ—‰ instruction simply throws away a single operand.
524    Drop,
525    /// The π—Œπ–Ύπ—…π–Ύπ–Όπ— instruction selects one of its first two operands based on whether its third
526    /// operand is zero or not. It may include a value type determining the type of these operands.
527    /// If missing, the operands must be of numeric type.
528    Select(Option<Vec<ValueType>>),
529}
530
531impl From<ParametricInstruction> for Instruction {
532    fn from(instruction: ParametricInstruction) -> Self {
533        Instruction::Parametric(instruction)
534    }
535}
536
537/// Variable instructions are concerned with access to local or global variables.
538/// These instructions get or set the values of variables, respectively.
539/// The π—…π—ˆπ–Όπ–Ίπ—….𝗍𝖾𝖾 instruction is like π—…π—ˆπ–Όπ–Ίπ—….π—Œπ–Ύπ— but also returns its argument.
540///
541/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#variable-instructions>
542///
543/// # Examples
544/// ```rust
545/// use wasm_ast::{VariableInstruction, Instruction, ValueType};
546///
547/// assert_eq!(
548///     Instruction::Variable(VariableInstruction::LocalGet(0)),
549///     VariableInstruction::LocalGet(0).into()
550/// );
551/// assert_eq!(
552///     Instruction::Variable(VariableInstruction::LocalSet(1)),
553///     VariableInstruction::LocalSet(1).into()
554/// );
555/// assert_eq!(
556///     Instruction::Variable(VariableInstruction::LocalTee(1)),
557///     VariableInstruction::LocalTee(1).into()
558/// );
559/// assert_eq!(
560///     Instruction::Variable(VariableInstruction::GlobalGet(0)),
561///     VariableInstruction::GlobalGet(0).into()
562/// );
563/// assert_eq!(
564///     Instruction::Variable(VariableInstruction::GlobalSet(1)),
565///     VariableInstruction::GlobalSet(1).into()
566/// );
567/// ```
568#[derive(Copy, Clone, Debug, Eq, PartialEq)]
569pub enum VariableInstruction {
570    /// local.get localidx
571    /// Get the value of a local variable.
572    LocalGet(LocalIndex),
573    /// local.set localidx
574    /// Set the value of a local variable.
575    LocalSet(LocalIndex),
576    /// local.tee localidx
577    /// The π—…π—ˆπ–Όπ–Ίπ—….𝗍𝖾𝖾 instruction is like π—…π—ˆπ–Όπ–Ίπ—….π—Œπ–Ύπ— but also returns its argument.
578    LocalTee(LocalIndex),
579    /// global.get globalidx
580    /// Get the value of a global variable.
581    GlobalGet(GlobalIndex),
582    /// global.set globalidx
583    /// Set the value of a global variable.
584    GlobalSet(GlobalIndex),
585}
586
587impl From<VariableInstruction> for Instruction {
588    fn from(instruction: VariableInstruction) -> Self {
589        Instruction::Variable(instruction)
590    }
591}
592
593/// Instructions in this group are concerned with tables table.
594/// An additional instruction that accesses a table is the control instruction 𝖼𝖺𝗅𝗅_𝗂𝗇𝖽𝗂𝗋𝖾𝖼𝗍.
595///
596/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#table-instructions>
597///
598/// # Examples
599/// ```rust
600/// use wasm_ast::{TableInstruction, Instruction};
601///
602/// assert_eq!(
603///     Instruction::Table(TableInstruction::Get(1)),
604///     TableInstruction::Get(1).into()
605/// );
606/// assert_eq!(
607///     Instruction::Table(TableInstruction::Set(1)),
608///     TableInstruction::Set(1).into()
609/// );
610/// assert_eq!(
611///     Instruction::Table(TableInstruction::Size(1)),
612///     TableInstruction::Size(1).into()
613/// );
614/// assert_eq!(
615///     Instruction::Table(TableInstruction::Grow(1)),
616///     TableInstruction::Grow(1).into()
617/// );
618/// assert_eq!(
619///     Instruction::Table(TableInstruction::Fill(1)),
620///     TableInstruction::Fill(1).into()
621/// );
622/// assert_eq!(
623///     Instruction::Table(TableInstruction::Copy(0, 1)),
624///     TableInstruction::Copy(0, 1).into()
625/// );
626/// assert_eq!(
627///     Instruction::Table(TableInstruction::Init(0, 0)),
628///     TableInstruction::Init(0, 0).into()
629/// );
630/// assert_eq!(
631///     Instruction::Table(TableInstruction::ElementDrop(0)),
632///     TableInstruction::ElementDrop(0).into()
633/// );
634/// ```
635#[derive(Copy, Clone, Debug, Eq, PartialEq)]
636pub enum TableInstruction {
637    /// The 𝗍𝖺𝖻𝗅𝖾.𝗀𝖾𝗍 instruction loads an element in a table.
638    Get(TableIndex),
639    /// The 𝗍𝖺𝖻𝗅𝖾.π—Œπ–Ύπ— instruction stores an element in a table.
640    Set(TableIndex),
641    /// The 𝗍𝖺𝖻𝗅𝖾.π—Œπ—‚π—“π–Ύ instruction returns the current size of a table.
642    Size(TableIndex),
643    /// The 𝗍𝖺𝖻𝗅𝖾.π—€π—‹π—ˆπ— instruction grows table by a given delta and returns the previous size,
644    /// or βˆ’1 if enough space cannot be allocated.
645    /// It also takes an initialization value for the newly allocated entries.
646    Grow(TableIndex),
647    /// The 𝗍𝖺𝖻𝗅𝖾.𝖿𝗂𝗅𝗅 instruction sets all entries in a range to a given value.
648    Fill(TableIndex),
649    /// The 𝗍𝖺𝖻𝗅𝖾.π–Όπ—ˆπ—‰π—’ instruction copies elements from a source table region to a
650    /// possibly overlapping destination region; the first index denotes the destination.
651    Copy(TableIndex, TableIndex),
652    /// The 𝗍𝖺𝖻𝗅𝖾.𝗂𝗇𝗂𝗍 instruction copies elements from a passive element segment into a table.
653    Init(ElementIndex, TableIndex),
654    /// The 𝖾𝗅𝖾𝗆.π–½π—‹π—ˆπ—‰ instruction prevents further use of a passive element segment.
655    /// This instruction is intended to be used as an optimization hint.
656    /// After an element segment is dropped its elements can no longer be retrieved,
657    /// so the memory used by this segment may be freed.
658    ElementDrop(ElementIndex),
659}
660
661impl From<TableInstruction> for Instruction {
662    fn from(instruction: TableInstruction) -> Self {
663        Instruction::Table(instruction)
664    }
665}
666
667/// Instructions in this group are concerned with linear memory.
668/// Memory is accessed with π—…π—ˆπ–Ίπ–½ and π—Œπ—π—ˆπ—‹π–Ύ instructions for the different value types.
669/// They all take a memory immediate memarg that contains an address offset and
670/// the expected alignment (expressed as the exponent of a power of 2).
671/// Integer loads and stores can optionally specify a storage size that is smaller than
672/// the bit width of the respective value type.
673/// In the case of loads, a sign extension mode sx is then required to select appropriate behavior.
674///
675/// The static address offset is added to the dynamic address operand,
676/// yielding a 33 bit effective address that is the zero-based index at which the memory is accessed.
677/// All values are read and written in little endian byte order.
678/// A trap results if any of the accessed memory bytes lies outside the address range implied by
679/// the memory’s current size.
680///
681/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions>
682///
683/// # Examples
684/// ```rust
685/// use wasm_ast::{MemoryInstruction, Instruction, NumberType, MemoryArgument, IntegerType, SignExtension};
686///
687/// assert_eq!(
688///     Instruction::Memory(MemoryInstruction::Load(NumberType::I32, MemoryArgument::default_offset(4))),
689///     MemoryInstruction::Load(NumberType::I32, MemoryArgument::default_offset(4)).into()
690/// );
691/// assert_eq!(
692///     Instruction::Memory(MemoryInstruction::Load8(IntegerType::I32, SignExtension::Signed, MemoryArgument::default_offset(1))),
693///     MemoryInstruction::Load8(IntegerType::I32, SignExtension::Signed, MemoryArgument::default_offset(1)).into()
694/// );
695/// assert_eq!(
696///     Instruction::Memory(MemoryInstruction::Load16(IntegerType::I64, SignExtension::Unsigned, MemoryArgument::default_offset(2))),
697///     MemoryInstruction::Load16(IntegerType::I64, SignExtension::Unsigned, MemoryArgument::default_offset(2)).into()
698/// );
699/// assert_eq!(
700///     Instruction::Memory(MemoryInstruction::Load32(SignExtension::Signed, MemoryArgument::default_offset(4))),
701///     MemoryInstruction::Load32(SignExtension::Signed, MemoryArgument::default_offset(4)).into()
702/// );
703/// assert_eq!(
704///     Instruction::Memory(MemoryInstruction::Store(NumberType::F64, MemoryArgument::default_offset(8))),
705///     MemoryInstruction::Store(NumberType::F64, MemoryArgument::new(8, 0)).into()
706/// );
707/// assert_eq!(
708///     Instruction::Memory(MemoryInstruction::Store8(IntegerType::I32, MemoryArgument::default_offset(1))),
709///     MemoryInstruction::Store8(IntegerType::I32, MemoryArgument::default_offset(1)).into()
710/// );
711/// assert_eq!(
712///     Instruction::Memory(MemoryInstruction::Store16(IntegerType::I64, MemoryArgument::default_offset(2))),
713///     MemoryInstruction::Store16(IntegerType::I64, MemoryArgument::default_offset(2)).into()
714/// );
715/// assert_eq!(
716///     Instruction::Memory(MemoryInstruction::Store32(MemoryArgument::default_offset(4))),
717///     MemoryInstruction::Store32(MemoryArgument::default_offset(4)).into()
718/// );
719/// assert_eq!(
720///     Instruction::Memory(MemoryInstruction::Size),
721///     MemoryInstruction::Size.into()
722/// );
723/// assert_eq!(
724///     Instruction::Memory(MemoryInstruction::Grow),
725///     MemoryInstruction::Grow.into()
726/// );
727/// assert_eq!(
728///     Instruction::Memory(MemoryInstruction::Fill),
729///     MemoryInstruction::Fill.into()
730/// );
731/// assert_eq!(
732///     Instruction::Memory(MemoryInstruction::Copy),
733///     MemoryInstruction::Copy.into()
734/// );
735/// assert_eq!(
736///     Instruction::Memory(MemoryInstruction::Init(1)),
737///     MemoryInstruction::Init(1).into()
738/// );
739/// assert_eq!(
740///     Instruction::Memory(MemoryInstruction::DataDrop(0)),
741///     MemoryInstruction::DataDrop(0).into()
742/// );
743/// ```
744#[derive(Copy, Clone, Debug, Eq, PartialEq)]
745pub enum MemoryInstruction {
746    /// xnn.load memarg
747    /// Load a number type from memory.
748    Load(NumberType, MemoryArgument),
749    /// xnn.store memarg
750    /// Store a number type from memory.
751    Store(NumberType, MemoryArgument),
752    /// inn.load8_sx memarg
753    /// Integer load that specifies a storage size that is smaller than
754    /// the bit width of the respective value type.
755    Load8(IntegerType, SignExtension, MemoryArgument),
756    /// inn.load16_sx memarg
757    Load16(IntegerType, SignExtension, MemoryArgument),
758    /// i64.load32_sx memarg
759    Load32(SignExtension, MemoryArgument),
760    /// inn.store8 memarg
761    /// Integer store that specifies a storage size that is smaller than
762    /// the bit width of the respective value type.
763    Store8(IntegerType, MemoryArgument),
764    /// inn.store16 memarg
765    Store16(IntegerType, MemoryArgument),
766    /// i64.store32 memarg
767    Store32(MemoryArgument),
768    /// The π—†π–Ύπ—†π—ˆπ—‹π—’.π—Œπ—‚π—“π–Ύ instruction returns the current size of a memory.
769    /// Operates in units of page size.
770    Size,
771    /// The π—†π–Ύπ—†π—ˆπ—‹π—’.π—€π—‹π—ˆπ— instruction grows memory by a given delta and returns the previous size,
772    /// or βˆ’1 if enough memory cannot be allocated.
773    Grow,
774    /// The π—†π–Ύπ—†π—ˆπ—‹π—’.𝖿𝗂𝗅𝗅 instruction sets all values in a region to a given byte.
775    Fill,
776    /// The π—†π–Ύπ—†π—ˆπ—‹π—’.π–Όπ—ˆπ—‰π—’ instruction copies data from a source memory region to
777    /// a possibly overlapping destination region.
778    Copy,
779    /// The π—†π–Ύπ—†π—ˆπ—‹π—’.𝗂𝗇𝗂𝗍 instruction copies data from a passive data segment into a memory.
780    Init(DataIndex),
781    /// he 𝖽𝖺𝗍𝖺.π–½π—‹π—ˆπ—‰ instruction prevents further use of a passive data segment.
782    /// This instruction is intended to be used as an optimization hint.
783    /// After a data segment is dropped its data can no longer be retrieved,
784    /// so the memory used by this segment may be freed.
785    DataDrop(DataIndex),
786}
787
788impl From<MemoryInstruction> for Instruction {
789    fn from(instruction: MemoryInstruction) -> Self {
790        Instruction::Memory(instruction)
791    }
792}
793
794/// Instructions in this group affect the flow of control.
795/// The π–»π—…π—ˆπ–Όπ—„, π—…π—ˆπ—ˆπ—‰ and 𝗂𝖿 instructions are structured instructions.
796/// They bracket nested sequences of instructions, called blocks, terminated with, or separated by,
797/// 𝖾𝗇𝖽 or π–Ύπ—…π—Œπ–Ύ pseudo-instructions. As the grammar prescribes, they must be well-nested.
798///
799/// A structured instruction can consume input and produce output on the operand stack according to
800/// its annotated block type. It is given either as a type index that refers to a suitable function
801/// type, or as an optional value type inline,
802/// which is a shorthand for the function type []β†’[valtype?].
803///
804/// Each structured control instruction introduces an implicit label.
805/// Labels are targets for branch instructions that reference them with label indices.
806/// Unlike with other index spaces, indexing of labels is relative by nesting depth, that is,
807/// label 0 refers to the innermost structured control instruction enclosing the referring branch
808/// instruction, while increasing indices refer to those farther out.
809/// Consequently, labels can only be referenced from within the associated structured control
810/// instruction. This also implies that branches can only be directed outwards,
811/// β€œbreaking” from the block of the control construct they target.
812/// The exact effect depends on that control construct.
813/// In case of π–»π—…π—ˆπ–Όπ—„ or 𝗂𝖿 it is a forward jump, resuming execution after the matching 𝖾𝗇𝖽.
814/// In case of π—…π—ˆπ—ˆπ—‰ it is a backward jump to the beginning of the loop.
815///
816/// Taking a branch unwinds the operand stack up to the height where the targeted structured
817/// control instruction was entered. However, branches may additionally consume operands themselves,
818/// which they push back on the operand stack after unwinding.
819/// Forward branches require operands according to the output of the targeted block’s type, i.e.,
820/// represent the values produced by the terminated block.
821/// Backward branches require operands according to the input of the targeted block’s type, i.e.,
822/// represent the values consumed by the restarted block.
823///
824/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions>
825///
826/// # Examples
827/// ## Simple
828/// ```rust
829/// use wasm_ast::{ControlInstruction, Instruction};
830///
831/// assert_eq!(Instruction::Control(ControlInstruction::Nop), ControlInstruction::Nop.into());
832/// assert_eq!(Instruction::Control(ControlInstruction::Unreachable), ControlInstruction::Unreachable.into());
833/// assert_eq!(Instruction::Control(ControlInstruction::Branch(0)), ControlInstruction::Branch(0).into());
834/// assert_eq!(Instruction::Control(ControlInstruction::BranchIf(1)), ControlInstruction::BranchIf(1).into());
835/// assert_eq!(Instruction::Control(ControlInstruction::BranchTable(vec![0], 1)), ControlInstruction::BranchTable(vec![0], 1).into());
836/// assert_eq!(Instruction::Control(ControlInstruction::Return), ControlInstruction::Return.into());
837/// assert_eq!(Instruction::Control(ControlInstruction::Call(1)), ControlInstruction::Call(1).into());
838/// assert_eq!(Instruction::Control(ControlInstruction::CallIndirect(0, 1)), ControlInstruction::CallIndirect(0, 1).into());
839/// ```
840///
841/// ## Block
842/// ```rust
843/// use wasm_ast::{ControlInstruction, Instruction, Expression, BlockType, ValueType};
844///
845/// let expression = Expression::new(vec![ControlInstruction::Nop.into(), 0i32.into()]);
846///
847/// assert_eq!(
848///     Instruction::Control(ControlInstruction::Block(BlockType::ValueType(ValueType::I32), expression.clone())),
849///     ControlInstruction::Block(BlockType::ValueType(ValueType::I32), expression.clone()).into()
850/// );
851/// ```
852///
853/// ## Loop
854/// ```rust
855/// use wasm_ast::{ControlInstruction, Instruction, BlockType, Expression};
856/// let expression = Expression::new(vec![ControlInstruction::Nop.into(), 0i32.into()]);
857///
858/// assert_eq!(
859///     Instruction::Control(ControlInstruction::Loop(BlockType::Index(0), expression.clone())),
860///     ControlInstruction::Loop(BlockType::Index(0), expression.clone()).into()
861/// );
862/// ```
863///
864/// ## If
865/// ```rust
866/// use wasm_ast::{ControlInstruction, Instruction, Expression, BlockType};
867/// let expression = Expression::new(vec![ControlInstruction::Nop.into()]);
868///
869/// assert_eq!(
870///     Instruction::Control(ControlInstruction::If(BlockType::None, expression.clone(), None)),
871///     ControlInstruction::If(BlockType::None, expression.clone(), None).into()
872/// );
873///
874/// assert_eq!(
875///     Instruction::Control(ControlInstruction::If(BlockType::None, expression.clone(), Some(expression.clone()))),
876///     ControlInstruction::If(BlockType::None, expression.clone(), Some(expression.clone())).into()
877/// );
878/// ```
879#[derive(Clone, Debug, PartialEq)]
880pub enum ControlInstruction {
881    /// The π—‡π—ˆπ—‰ instruction does nothing.
882    Nop,
883    /// The π—Žπ—‡π—‹π–Ύπ–Ίπ–Όπ—π–Ίπ–»π—…π–Ύ instruction causes an unconditional trap.
884    Unreachable,
885    /// A logical grouping used introduce a label around an expression.
886    Block(BlockType, Expression),
887    /// Executes the expression in a loop.
888    Loop(BlockType, Expression),
889    /// Conditionally executes a positive or (optional) negative branch based on a test value.
890    If(BlockType, Expression, Option<Expression>),
891    /// The 𝖻𝗋 instruction performs an unconditional branch.
892    Branch(LabelIndex),
893    /// The 𝖻𝗋_𝗂𝖿 instruction performs a conditional branch
894    BranchIf(LabelIndex),
895    /// The 𝖻𝗋_𝗍𝖺𝖻𝗅𝖾 instruction performs an indirect branch through an operand indexing into
896    /// the label vector that is an immediate to the instruction,
897    /// or to a default target if the operand is out of bounds.
898    BranchTable(Vec<LabelIndex>, LabelIndex),
899    /// The π—‹π–Ύπ—π—Žπ—‹π—‡ instruction is a shortcut for an unconditional branch to the outermost block,
900    /// which implicitly is the body of the current function.
901    Return,
902    /// The 𝖼𝖺𝗅𝗅 instruction invokes another function, consuming the necessary arguments from
903    /// the stack and returning the result values of the call.
904    Call(FunctionIndex),
905    /// The 𝖼𝖺𝗅𝗅_𝗂𝗇𝖽𝗂𝗋𝖾𝖼𝗍 instruction calls a function indirectly through an operand indexing into
906    /// a table that is denoted by a table index and must have type π–Ώπ—Žπ—‡π–Όπ—‹π–Ύπ–Ώ.
907    /// Since it may contain functions of heterogeneous type,
908    /// the callee is dynamically checked against the function type indexed by the instruction’s
909    /// second immediate, and the call is aborted with a trap if it does not match.
910    CallIndirect(TypeIndex, TableIndex),
911}
912
913impl From<ControlInstruction> for Instruction {
914    fn from(instruction: ControlInstruction) -> Self {
915        Instruction::Control(instruction)
916    }
917}
918
919/// A structured instruction can consume input and produce output on the operand stack according to
920/// its annotated block type.
921/// It is given either as a type index that refers to a suitable function type,
922/// or as an optional value type inline, which is a shorthand for the function type []β†’[valtype?].
923///
924/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions>
925#[derive(Copy, Clone, Debug, Eq, PartialEq)]
926pub enum BlockType {
927    None,
928    Index(TypeIndex),
929    ValueType(ValueType),
930}
931
932/// Argument to load and store instructions that contains an address offset and
933/// the expected alignment (expressed as the exponent of a power of 2).
934///
935/// The static address offset is added to the dynamic address operand,
936/// yielding a 33 bit effective address that is the zero-based index at which the memory is accessed.
937///
938/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions>
939///
940/// # Examples
941/// ## With Offset & Alignment
942/// ```rust
943/// use wasm_ast::MemoryArgument;
944///
945/// let argument = MemoryArgument::new(4, 42);
946///
947/// assert_eq!(argument.offset(), 42);
948/// assert_eq!(argument.align(), 4);
949/// ```
950///
951/// ## With Offset Only
952/// ```rust
953/// use wasm_ast::MemoryArgument;
954///
955/// let argument = MemoryArgument::new(1, 42);
956///
957/// assert_eq!(argument.offset(), 42);
958/// assert_eq!(argument.align(), 1);
959/// ```
960///
961/// ## With Alignment Only
962/// ```rust
963/// use wasm_ast::MemoryArgument;
964///
965/// let argument = MemoryArgument::default_offset(4);
966///
967/// assert_eq!(argument.offset(), 0);
968/// assert_eq!(argument.align(), 4);
969/// ```
970///
971/// ## Default
972/// ```rust
973/// use wasm_ast::MemoryArgument;
974///
975/// let argument = MemoryArgument::default_offset(1);
976///
977/// assert_eq!(argument.offset(), 0);
978/// assert_eq!(argument.align(), 1);
979/// ```
980#[derive(Copy, Clone, Debug, Eq, PartialEq)]
981pub struct MemoryArgument {
982    align: u32,
983    offset: u32,
984}
985
986impl MemoryArgument {
987    /// Creates a new memory argument with the given alignment and offset.
988    pub fn new(align: u32, offset: u32) -> Self {
989        MemoryArgument { align, offset }
990    }
991
992    /// Creates a new memory argument with the default offset and the given alignment.
993    pub fn default_offset(align: u32) -> Self {
994        MemoryArgument { offset: 0, align }
995    }
996
997    /// The static address offset of the memory instruction.
998    pub fn offset(&self) -> u32 {
999        self.offset
1000    }
1001
1002    /// The memory alignment of the instruction expressed as the exponent of a power of 2.
1003    pub fn align(&self) -> u32 {
1004        self.align
1005    }
1006}
1007
1008/// Some integer instructions come in two flavors, where a signedness annotation sx distinguishes
1009/// whether the operands are to be interpreted as unsigned or signed integers.
1010/// For the other integer instructions, the use of two’s complement for the signed interpretation
1011/// means that they behave the same regardless of signedness.
1012///
1013/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#numeric-instructions>
1014#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1015pub enum SignExtension {
1016    Signed,
1017    Unsigned,
1018}
1019
1020/// Function bodies, initialization values for globals,
1021/// and offsets of element or data segments are given as expressions, which are sequences of instructions terminated by an 𝖾𝗇𝖽 marker.
1022/// In some places, validation restricts expressions to be constant,
1023/// which limits the set of allowable instructions.
1024///
1025/// See <https://webassembly.github.io/spec/core/syntax/instructions.html#expressions>
1026///
1027/// # Examples
1028/// ## Non-Empty
1029/// ```rust
1030/// use wasm_ast::{Expression, ControlInstruction, NumericInstruction, Instruction};
1031///
1032/// let expression = Expression::new(vec![0i32.into(), ControlInstruction::Nop.into()]);
1033///
1034/// assert_eq!(
1035///     expression,
1036///     Expression::new(vec![
1037///         Instruction::Numeric(NumericInstruction::I32Constant(0 as i32)),
1038///         Instruction::Control(ControlInstruction::Nop),
1039///     ])
1040/// );
1041/// assert_eq!(expression.instructions(), &[
1042///     Instruction::Numeric(NumericInstruction::I32Constant(0)),
1043///     Instruction::Control(ControlInstruction::Nop),
1044/// ]);
1045/// assert_eq!(expression.len(), 2);
1046/// assert!(!expression.is_empty());
1047/// assert_eq!(
1048///     expression,
1049///     vec![
1050///         Instruction::Numeric(NumericInstruction::I32Constant(0)),
1051///         Instruction::Control(ControlInstruction::Nop),
1052///     ].into()
1053/// );
1054/// ```
1055///
1056/// ## Empty
1057/// ```rust
1058/// use wasm_ast::Expression;
1059///
1060/// let expression = Expression::new(vec![]);
1061///
1062/// assert_eq!(expression, Expression::empty());
1063/// assert_eq!(expression, vec![].into());
1064/// assert_eq!(expression.instructions(), &[]);
1065/// assert_eq!(expression.len(), 0);
1066/// assert!(expression.is_empty());
1067/// ```
1068#[derive(Clone, Debug, PartialEq)]
1069pub struct Expression {
1070    instructions: Vec<Instruction>,
1071}
1072
1073impl Expression {
1074    /// Create a new expression from the given instructions.
1075    pub fn new(instructions: Vec<Instruction>) -> Self {
1076        Expression { instructions }
1077    }
1078
1079    /// Create a new empty expression.
1080    pub fn empty() -> Self {
1081        Expression {
1082            instructions: vec![],
1083        }
1084    }
1085
1086    /// The instructions for this expression.
1087    pub fn instructions(&self) -> &[Instruction] {
1088        &self.instructions
1089    }
1090
1091    /// Returns true if this `Expression` has a length of zero, false otherwise.
1092    pub fn is_empty(&self) -> bool {
1093        self.instructions.is_empty()
1094    }
1095
1096    /// Returns the length of this `Expression`, in number of instructions.
1097    pub fn len(&self) -> usize {
1098        self.instructions.len()
1099    }
1100}
1101
1102impl From<Vec<Instruction>> for Expression {
1103    fn from(instructions: Vec<Instruction>) -> Self {
1104        Expression { instructions }
1105    }
1106}