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/// [`Program`](crate::Program) / [`Fn`](crate::Fn).
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
60            | Opcode::Exit
61            | Opcode::Sleep
62            | Opcode::Receive
63            | Opcode::SelfPid
64            | Opcode::FreshRequestId => {
65                write!(f, "{} r{}", self.op, self.a)
66            }
67            Opcode::Spawn => write!(
68                f,
69                "{} r{}, fn[{}], argc={}, rights={:#x}",
70                self.op, self.a, self.imm, self.b, self.c
71            ),
72            Opcode::Send => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
73            Opcode::ReceiveTimeout | Opcode::ReceiveMatch => {
74                write!(f, "{} r{}, r{}", self.op, self.a, self.b)
75            }
76            Opcode::ReceiveMatchImm => write!(f, "{} r{}, tag={}", self.op, self.a, self.imm),
77            Opcode::ReceiveMatchCorr => write!(
78                f,
79                "{} r{}, tag=r{}, id=r{}",
80                self.op, self.a, self.b, self.c
81            ),
82            Opcode::ReceiveMatchCorrImm => write!(
83                f,
84                "{} r{}, tag={}, id=r{}",
85                self.op, self.a, self.imm, self.b
86            ),
87            Opcode::Ask => write!(
88                f,
89                "{} r{}, r{}, r{}",
90                self.op, self.a, self.b, self.c
91            ),
92            Opcode::AskTimeout => write!(
93                f,
94                "{} r{}, r{}, r{}, timeout=r{}",
95                self.op, self.a, self.b, self.c, self.imm
96            ),
97            Opcode::Monitor | Opcode::Link => {
98                write!(f, "{} r{}, r{}", self.op, self.a, self.b)
99            }
100            Opcode::Demonitor | Opcode::Unlink | Opcode::RegisterName => {
101                write!(f, "{} r{}", self.op, self.a)
102            }
103            Opcode::Whereis => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
104            Opcode::Delegate => write!(
105                f,
106                "{} r{}, r{}, rights={:#x}, native=r{}",
107                self.op, self.a, self.b, self.imm as u32, self.c
108            ),
109            Opcode::Trap => write!(f, "{} {}", self.op, self.imm),
110        }
111    }
112}