mimium_lang/runtime/vm/
bytecode.rs

1use crate::{types::TypeSize, utils::half_float::HFloat};
2
3pub type Reg = u8; // register position
4pub type ConstPos = u16;
5pub type GlobalPos = u8;
6pub type Offset = i16;
7//24bit unsigned integer for shiftsate
8pub type StateOffset = intx::U24;
9/// Instructions for bytecode. Currently, each instructon has the 64 bit size(Tag, up to 3 bytes arguments.)
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum Instruction {
12    /// Move Single Value, Destination, Source
13    Move(Reg, Reg),
14    /// Load Single Value from Constants. Destination, Source
15    MoveConst(Reg, ConstPos),
16    /// Load Immediate float from half precision. Destination, Value
17    MoveImmF(Reg, HFloat),
18    // Move the range of registers (e.g. tuple) Destination, Source, Wordsize
19    MoveRange(Reg, Reg, TypeSize),
20    /// Call to internal function
21    /// Function Address,Nargs,Word Size of Return Value
22    Call(Reg, u8, TypeSize),
23    //call internal closure
24    CallCls(Reg, u8, TypeSize),
25    /// Call external rust functions or closure,
26    /// Currently, The execution branches into the invocation of a raw function item(function pointer), or Rust Closure depending on the information on the VM.
27    /// Previously there was another operation `CallExtCls` for Rust Closure Invocation separately but keeping distinction between raw function pointer and closure at the type checking and program generation stage, makes compiler's design complex thus it was removed.
28    /// The distincion may also be resolved statically at linking time.
29    /// Function Address,Nargs,Nret
30    CallExtFun(Reg, u8, TypeSize),
31    /// Create new closure. Destination, index of inner function prototype in global function table.
32    Closure(Reg, Reg),
33    /// register of the closure to be closed. other local closures will be released with this instruction.
34    Close(Reg),
35    /// destination,source, size
36    GetUpValue(Reg, Reg, TypeSize),
37    SetUpValue(Reg, Reg, TypeSize),
38
39    /// destination,source
40    GetGlobal(Reg, GlobalPos, TypeSize),
41    SetGlobal(GlobalPos, Reg, TypeSize),
42    /// Call internal state over time, destination,source
43    GetState(Reg, TypeSize),
44    SetState(Reg, TypeSize),
45    PushStatePos(StateOffset),
46    PopStatePos(StateOffset),
47
48    /// Return from current function without return value.
49    Return0,
50    /// value start position, Nrets
51    Return(Reg, TypeSize),
52    //dst,src,time,idx
53    Delay(Reg, Reg, Reg),
54    Mem(Reg, Reg),
55
56    /// jump to instruction over the offset.
57    Jmp(Offset),
58    /// jump to instruction over the offset if the value in the first argument was negative.
59    JmpIfNeg(Reg, Offset),
60
61    /// Primitive Operations.
62    /// Destination, Src1, Src2
63    AddF(Reg, Reg, Reg),
64    SubF(Reg, Reg, Reg),
65    MulF(Reg, Reg, Reg),
66    DivF(Reg, Reg, Reg),
67    ModF(Reg, Reg, Reg),
68    NegF(Reg, Reg),
69    AbsF(Reg, Reg),
70    SqrtF(Reg, Reg),
71    SinF(Reg, Reg),
72    CosF(Reg, Reg),
73    PowF(Reg, Reg, Reg),
74    LogF(Reg, Reg),
75
76    // Primitive Operations for int
77    AddI(Reg, Reg, Reg),
78    SubI(Reg, Reg, Reg),
79    MulI(Reg, Reg, Reg),
80    DivI(Reg, Reg, Reg),
81    ModI(Reg, Reg, Reg),
82    NegI(Reg, Reg),
83    AbsI(Reg, Reg),
84
85    PowI(Reg, Reg, Reg),
86    LogI(Reg, Reg, Reg),
87    // primitive Operations for bool
88    Not(Reg, Reg),
89    Eq(Reg, Reg, Reg),
90    Ne(Reg, Reg, Reg),
91    Gt(Reg, Reg, Reg),
92    Ge(Reg, Reg, Reg),
93    Lt(Reg, Reg, Reg),
94    Le(Reg, Reg, Reg),
95    And(Reg, Reg, Reg),
96    Or(Reg, Reg, Reg),
97
98    CastFtoI(Reg, Reg),
99    CastItoF(Reg, Reg),
100    CastItoB(Reg, Reg),
101    /// Allocate new array in the heap.
102    /// Destination, size of array, type size of each element
103    AllocArray(Reg, Reg, TypeSize),
104    /// Get array element: destination, array, index
105    GetArrayElem(Reg, Reg, Reg),
106    /// Set array element. Because the array is immutable, this instruction is mostly used for initialization.
107    /// array, index, value.
108    SetArrayElem(Reg, Reg, Reg),
109
110    /// Dummy instruction for testing
111    Dummy,
112}
113
114impl std::fmt::Display for Instruction {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        match self {
117            Instruction::Return0 => write!(f, "ret0"),
118            Instruction::Jmp(dst) => write!(f, "{:<10} {}", "jmp", dst),
119            Instruction::GetState(dst, size) => write!(f, "{:<10} {} {}", "getstate", dst, size),
120            Instruction::SetState(src, size) => write!(f, "{:<10} {} {}", "setstate", src, size),
121            Instruction::PushStatePos(v) => write!(f, "{:<10} {}", "pushsttpos", v),
122            Instruction::PopStatePos(v) => write!(f, "{:<10} {}", "popsttpos", v),
123            Instruction::Move(dst, src) => write!(f, "{:<10} {} {}", "mov", dst, src),
124            Instruction::MoveConst(dst, num) => write!(f, "{:<10} {} {}", "movc", dst, num),
125            Instruction::MoveImmF(dst, v) => write!(f, "{:<10} {} {}", "movimmF", dst, v),
126            Instruction::MoveRange(dst, src, n) => {
127                write!(
128                    f,
129                    "{:<10} {}-{} {}-{}",
130                    "mov",
131                    dst,
132                    dst + n - 1,
133                    src,
134                    src + n - 1
135                )
136            }
137            Instruction::Closure(dst, src) => {
138                write!(f, "{:<10} {} {}", "closure", dst, src)
139            }
140            Instruction::Close(src) => {
141                write!(f, "{:<10} {}", "close", src)
142            }
143            Instruction::Delay(dst, src, time) => {
144                write!(f, "{:<10} {} {} {}", "delay", dst, src, time)
145            }
146            Instruction::Mem(dst, src) => {
147                write!(f, "{:<10} {} {}", "mem", dst, src)
148            }
149            Instruction::Return(iret, nret) => write!(f, "{:<10} {} {}", "ret", iret, nret),
150            Instruction::GetUpValue(dst, srcup, size) => {
151                write!(f, "{:<10} {} {} {}", "getupv", dst, srcup, size)
152            }
153            Instruction::SetUpValue(dstup, src, size) => {
154                write!(f, "{:<10} {} {} {}", "setupv", dstup, src, size)
155            }
156            Instruction::GetGlobal(dst, src, size) => {
157                write!(f, "{:<10} {} {} {}", "getglobal", dst, src, size)
158            }
159            Instruction::SetGlobal(dst, src, size) => {
160                write!(f, "{:<10} {} {} {}", "setglobal", dst, src, size)
161            }
162            Instruction::JmpIfNeg(dst, cond) => write!(f, "{:<10} {} {}", "jmpifneg", dst, cond),
163            Instruction::AbsF(dst, src) => write!(f, "{:<10} {} {}", "absf", dst, src),
164            Instruction::NegF(dst, src) => write!(f, "{:<10} {} {}", "negf", dst, src),
165            Instruction::SinF(dst, src) => write!(f, "{:<10} {} {}", "sin", dst, src),
166            Instruction::CosF(dst, src) => write!(f, "{:<10} {} {}", "cos", dst, src),
167            Instruction::SqrtF(dst, src) => write!(f, "{:<10} {} {}", "sqrt", dst, src),
168            Instruction::LogF(dst, src) => write!(f, "{:<10} {} {} ", "logf", dst, src),
169            Instruction::AbsI(dst, src) => write!(f, "{:<10} {} {}", "abs", dst, src),
170            Instruction::NegI(dst, src) => write!(f, "{:<10} {} {}", "neg", dst, src),
171            Instruction::Not(dst, src) => write!(f, "{:<10} {} {}", "not", dst, src),
172            Instruction::CastFtoI(dst, src) => write!(f, "{:<10} {} {}", "f2i", dst, src),
173            Instruction::CastItoF(dst, src) => write!(f, "{:<10} {} {}", "i2f", dst, src),
174            Instruction::CastItoB(dst, src) => write!(f, "{:<10} {} {}", "i2b", dst, src),
175            Instruction::Call(func, nargs, nret_req) => {
176                write!(f, "{:<10} {} {} {}", "call", func, nargs, nret_req)
177            }
178            Instruction::CallCls(func, nargs, nret_req) => {
179                write!(f, "{:<10} {} {} {}", "callcls", func, nargs, nret_req)
180            }
181            Instruction::CallExtFun(func, nargs, nret_req) => {
182                write!(f, "{:<10} {} {} {}", "callext", func, nargs, nret_req)
183            }
184            Instruction::LogI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "logi", dst, lhs, rhs),
185            Instruction::PowI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "powi", dst, lhs, rhs),
186            Instruction::AddF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "addf", dst, lhs, rhs),
187            Instruction::SubF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "subf", dst, lhs, rhs),
188            Instruction::MulF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "mulf", dst, lhs, rhs),
189            Instruction::DivF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "divf", dst, lhs, rhs),
190            Instruction::ModF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "modf", dst, lhs, rhs),
191            Instruction::PowF(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "powf", dst, lhs, rhs),
192            Instruction::AddI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "add", dst, lhs, rhs),
193            Instruction::SubI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "sub", dst, lhs, rhs),
194            Instruction::MulI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "mul", dst, lhs, rhs),
195            Instruction::DivI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "div", dst, lhs, rhs),
196            Instruction::ModI(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "mod", dst, lhs, rhs),
197            Instruction::Eq(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "eq", dst, lhs, rhs),
198            Instruction::Ne(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "ne", dst, lhs, rhs),
199            Instruction::Gt(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "gt", dst, lhs, rhs),
200            Instruction::Ge(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "ge", dst, lhs, rhs),
201            Instruction::Lt(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "le", dst, lhs, rhs),
202            Instruction::Le(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "lt", dst, lhs, rhs),
203            Instruction::And(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "and", dst, lhs, rhs),
204            Instruction::Or(dst, lhs, rhs) => write!(f, "{:<10} {} {} {}", "or", dst, lhs, rhs),
205            Instruction::AllocArray(dst, size, typesize) => {
206                write!(f, "{:<10} {} {} {}", "array", dst, size, typesize)
207            }
208            Instruction::GetArrayElem(dst, arr, idx) => {
209                write!(f, "{:<10} {} {} {}", "getarray", dst, arr, idx)
210            }
211            Instruction::SetArrayElem(arr, idx, val) => {
212                write!(f, "{:<10} {} {} {}", "setarray", arr, idx, val)
213            }
214            Instruction::Dummy => write!(f, "dummy"),
215        }
216    }
217}
218
219#[cfg(test)]
220#[test]
221fn ensure_bytecode_size() {
222    let size = std::mem::size_of::<Instruction>();
223    assert_eq!(4, size);
224}