Skip to main content

byteflow/bytecode/
instruction.rs

1use std::fmt;
2
3use super::opcode::Opcode;
4
5/// A single packed instruction word.
6///
7/// Layout is 8 bytes (`op` + `a`/`b`/`c` + signed `imm`) so a `Vec<Instruction>`
8/// stays dense and the interpreter can fetch with a single aligned load.
9/// Operand meaning is opcode-specific; see [`Opcode`] and [`crate::builder`].
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11pub struct Instruction {
12    pub op: Opcode,
13    pub a: u8,
14    pub b: u8,
15    pub c: u8,
16    pub imm: i32,
17}
18
19impl Instruction {
20    pub fn new(op: Opcode, a: u8, b: u8, c: u8, imm: i32) -> Self {
21        Instruction { op, a, b, c, imm }
22    }
23
24    pub fn nullary(op: Opcode) -> Self {
25        Instruction::new(op, 0, 0, 0, 0)
26    }
27
28    pub fn abc(op: Opcode, a: u8, b: u8, c: u8) -> Self {
29        Instruction::new(op, a, b, c, 0)
30    }
31
32    pub fn a_imm(op: Opcode, a: u8, imm: i32) -> Self {
33        Instruction::new(op, a, 0, 0, imm)
34    }
35
36    pub fn only_imm(op: Opcode, imm: i32) -> Self {
37        Instruction::new(op, 0, 0, 0, imm)
38    }
39}
40
41impl fmt::Display for Instruction {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self.op {
44            Opcode::Halt | Opcode::Yield | Opcode::Nop => write!(f, "{}", self.op),
45            Opcode::LoadConst => write!(f, "{} r{}, const[{}]", self.op, self.a, self.imm),
46            Opcode::Move => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
47            Opcode::LoadImm => write!(f, "{} r{}, {}", self.op, self.a, self.imm),
48            Opcode::Add | Opcode::Sub | Opcode::Mul | Opcode::Div | Opcode::Mod | Opcode::Eq
49            | Opcode::Lt | Opcode::Le => {
50                write!(f, "{} r{}, r{}, r{}", self.op, self.a, self.b, self.c)
51            }
52            Opcode::Neg => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
53            Opcode::Jump => write!(f, "{} {:+}", self.op, self.imm),
54            Opcode::Branch => write!(f, "{} r{}, {:+}", self.op, self.a, self.imm),
55            Opcode::Call | Opcode::CallNative => {
56                write!(f, "{} r{}, fn[{}], argc={}", self.op, self.a, self.imm, self.b)
57            }
58            Opcode::Return | Opcode::Exit | Opcode::Sleep | Opcode::Receive | Opcode::SelfPid => {
59                write!(f, "{} r{}", self.op, self.a)
60            }
61            Opcode::Spawn => write!(
62                f,
63                "{} r{}, fn[{}], argc={}",
64                self.op, self.a, self.imm, self.b
65            ),
66            Opcode::Send => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
67            Opcode::ReceiveTimeout | Opcode::ReceiveMatch => {
68                write!(f, "{} r{}, r{}", self.op, self.a, self.b)
69            }
70            Opcode::ReceiveMatchImm => write!(f, "{} r{}, tag={}", self.op, self.a, self.imm),
71            Opcode::Ask => write!(
72                f,
73                "{} r{}, r{}, r{}",
74                self.op, self.a, self.b, self.c
75            ),
76            Opcode::Trap => write!(f, "{} {}", self.op, self.imm),
77        }
78    }
79}