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}