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
10/// [`ChunkBuilder`](crate::ChunkBuilder).
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12pub struct Instruction {
13    pub op: Opcode,
14    pub a: u8,
15    pub b: u8,
16    pub c: u8,
17    pub imm: i32,
18}
19
20impl Instruction {
21    pub fn new(op: Opcode, a: u8, b: u8, c: u8, imm: i32) -> Self {
22        Instruction { op, a, b, c, imm }
23    }
24
25    pub fn nullary(op: Opcode) -> Self {
26        Instruction::new(op, 0, 0, 0, 0)
27    }
28
29    pub fn abc(op: Opcode, a: u8, b: u8, c: u8) -> Self {
30        Instruction::new(op, a, b, c, 0)
31    }
32
33    pub fn a_imm(op: Opcode, a: u8, imm: i32) -> Self {
34        Instruction::new(op, a, 0, 0, imm)
35    }
36
37    pub fn only_imm(op: Opcode, imm: i32) -> Self {
38        Instruction::new(op, 0, 0, 0, imm)
39    }
40}
41
42impl fmt::Display for Instruction {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self.op {
45            Opcode::Halt | Opcode::Yield | Opcode::Nop => write!(f, "{}", self.op),
46            Opcode::LoadConst => write!(f, "{} r{}, const[{}]", self.op, self.a, self.imm),
47            Opcode::Move => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
48            Opcode::LoadImm => write!(f, "{} r{}, {}", self.op, self.a, self.imm),
49            Opcode::Add | Opcode::Sub | Opcode::Mul | Opcode::Div | Opcode::Mod | Opcode::Eq
50            | Opcode::Lt | Opcode::Le => {
51                write!(f, "{} r{}, r{}, r{}", self.op, self.a, self.b, self.c)
52            }
53            Opcode::Neg => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
54            Opcode::Jump => write!(f, "{} {:+}", self.op, self.imm),
55            Opcode::Branch => write!(f, "{} r{}, {:+}", self.op, self.a, self.imm),
56            Opcode::Call | Opcode::CallNative => {
57                write!(f, "{} r{}, fn[{}], argc={}", self.op, self.a, self.imm, self.b)
58            }
59            Opcode::Return | Opcode::Exit | Opcode::Sleep | Opcode::Receive | Opcode::SelfPid => {
60                write!(f, "{} r{}", self.op, self.a)
61            }
62            Opcode::Spawn => write!(
63                f,
64                "{} r{}, fn[{}], argc={}",
65                self.op, self.a, self.imm, self.b
66            ),
67            Opcode::Send => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
68            Opcode::ReceiveTimeout | Opcode::ReceiveMatch => {
69                write!(f, "{} r{}, r{}", self.op, self.a, self.b)
70            }
71            Opcode::ReceiveMatchImm => write!(f, "{} r{}, tag={}", self.op, self.a, self.imm),
72            Opcode::Ask => write!(
73                f,
74                "{} r{}, r{}, r{}",
75                self.op, self.a, self.b, self.c
76            ),
77            Opcode::Trap => write!(f, "{} {}", self.op, self.imm),
78        }
79    }
80}