sphinx/codegen/
opcodes.rs

1use core::mem::size_of;
2
3
4pub type LocalIndex = u16;
5pub type UpvalueIndex = u16;
6
7
8// Opcodes
9
10// Rust enums are not like C enums! They're more like unions.
11// So if we want to convert between them and integer constants easily, 
12// we need to explictly define each value as a const
13
14// 0x00-07        Control
15
16                           // width set here so that the longest mnemonic is 16 chars
17const OP_NOP:              u8 = 0x00;
18const OP_EXIT:             u8 = 0x01;  // _ => !
19const OP_ERROR:            u8 = 0x02;  // T[ error ] => !
20
21const OP_RETURN:           u8 = 0x08;  // T[ ...call frame... ret_value ] => [ ret_value ]
22
23// [ callee arg[0] ... arg[n] nargs ] => [ ret_value ] 
24const OP_CALL:             u8 = 0x09;
25const OP_IN_ARGS:          u8 = 0x0A;
26
27// 0x10-17        Immediate Values
28
29const OP_POP:              u8 = 0x10;  // [ _ ] => []
30const OP_DROP:             u8 = 0x11;  // (u8); [ value[0] ... value[N] ] => []
31const OP_DROPN:            u8 = 0x12;  // [ value[0] ... value[N] N ] => []
32const OP_CLONE:            u8 = 0x13;  // [ value ] => [ value value ]
33const OP_SWAP:             u8 = 0x14;  // (u8); [ value[A] ... value[B] ] => [ value[B] ... value[A] ]
34const OP_SHIFT:            u8 = 0x15;  // (u8); [ value[A] ... value[B] ] => [ ... value[B] value[A] ]
35
36const OP_TUPLE:            u8 = 0x18;  // (u8); [ item[0] ... item[N] ] => [ tuple ]
37const OP_TUPLEN:           u8 = 0x19;  // [ item[0] ... item[N] N ] => [ tuple ]
38
39// 0x18-1F        Iteration
40
41const OP_ITER_INIT:        u8 = 0x1A;  // [ iterable ] => [ iter state[0] ]
42const OP_ITER_NEXT:        u8 = 0x1B;  // [ iter state[N] ] => [ iter state[N+1] value[N] ]
43const OP_ITER_UNPACK:      u8 = 0x1C;  // [ iter state[N] ] => [ value[N] ... value[M] (M-N) ]
44
45// 0x40-5F        Load/Store
46
47const OP_LD_FUN:           u8 = 0x40;  // (u8);  _ => [ function ]
48const OP_LD_FUN_16:        u8 = 0x41;  // (u16); _ => [ function ]
49
50const OP_LD_CONST:         u8 = 0x42;  // (u8);  _ => [ value ]
51const OP_LD_CONST_16:      u8 = 0x43;  // (u16); _ => [ value ]
52// const OP_LD_CONST_32:   u8 = 0x44;  // (u32); _ => [ value ]
53
54const OP_IN_GLOBAL_IM:     u8 = 0x48;  // [ value name ] => [ value ]
55const OP_IN_GLOBAL_MUT:    u8 = 0x49;  // [ value name ] => [ value ]
56const OP_ST_GLOBAL:        u8 = 0x4A;  // [ value name ] => [ value ]
57const OP_LD_GLOBAL:        u8 = 0x4B;  // [ name ] => [ value ]
58const OP_DP_GLOBAL:        u8 = 0x4C;  // [ name ] => []
59
60const OP_IN_LOCAL:         u8 = 0x50;  // [ value ] => [ value ];
61const OP_ST_LOCAL:         u8 = 0x51;  // (u8);  [ value ] => [ value ]
62const OP_ST_LOCAL_16:      u8 = 0x52;  // (u16); [ value ] => [ value ]
63const OP_LD_LOCAL:         u8 = 0x53;  // (u8);  _ => [ value ]
64const OP_LD_LOCAL_16:      u8 = 0x54;  // (u16); _ => [ value ]
65const OP_DP_LOCALS:        u8 = 0x55;  // (u8); vm.locals -= N
66
67const OP_ST_UPVAL:         u8 = 0x58;  // (u8);  [ value ] => [ value ]
68const OP_ST_UPVAL_16:      u8 = 0x59;  // (u16); [ value ] => [ value ]
69const OP_LD_UPVAL:         u8 = 0x5A;  // (u8);  _ => [ value ]
70const OP_LD_UPVAL_16:      u8 = 0x5B;  // (u16); _ => [ value ]
71
72const OP_CLOSE_UPVAL:      u8 = 0x5C;  // (u8);
73const OP_CLOSE_UPVAL_16:   u8 = 0x5D;  // (u16);
74
75// 0x60-F      Values
76
77const OP_LD_NIL:           u8 = 0x60;  // _ => [ nil ]
78const OP_LD_FALSE:         u8 = 0x61;  // _ => [ false ]
79const OP_LD_TRUE:          u8 = 0x62;  // _ => [ true ]
80const OP_LD_EMPTY:         u8 = 0x63;  // _ => [ () ]
81
82// small numbers
83const OP_LD_U8:            u8 = 0x64;  // (u8); _ => [ value ]
84const OP_LD_I8:            u8 = 0x65;  // (i8); _ => [ value ]
85const OP_LD_I16:           u8 = 0x66;  // (i16); _ => [ value ]
86
87// 0x70-77      Unary Operations
88
89const OP_NEG:              u8 = 0x70;  // [ operand ] => [ result ]
90const OP_POS:              u8 = 0x71;
91const OP_INV:              u8 = 0x72;
92const OP_NOT:              u8 = 0x73;
93
94// 0x78-8F      Binary Operations
95
96const OP_AND:              u8 = 0x78;  // [ lhs rhs ] => [ result ]
97const OP_XOR:              u8 = 0x79;
98const OP_OR:               u8 = 0x7A;
99const OP_SHL:              u8 = 0x7B;
100const OP_SHR:              u8 = 0x7C;
101
102const OP_ADD:              u8 = 0x80;
103const OP_SUB:              u8 = 0x81;
104const OP_MUL:              u8 = 0x82;
105const OP_DIV:              u8 = 0x83;
106const OP_MOD:              u8 = 0x84;
107
108const OP_EQ:               u8 = 0x88;
109const OP_NE:               u8 = 0x89;
110const OP_LT:               u8 = 0x8A;
111const OP_LE:               u8 = 0x8B;
112const OP_GE:               u8 = 0x8C;
113const OP_GT:               u8 = 0x8D;
114
115// 0x90-9F      Jumps
116
117const OP_JUMP:             u8 = 0x90;  // (i16);
118const OP_JUMP_FALSE:       u8 = 0x91;  // (i16); [ cond ] => [ cond ]
119const OP_JUMP_TRUE:        u8 = 0x92;  // (i16); [ cond ] => [ cond ]
120const OP_PJMP_FALSE:       u8 = 0x93;  // (i16); [ cond ] => []
121const OP_PJMP_TRUE:        u8 = 0x94;  // (i16); [ cond ] => []
122
123const OP_LJUMP:            u8 = 0x98;  // (i32);
124const OP_LJUMP_FALSE:      u8 = 0x99;  // (i32); [ cond ] => [ cond ]
125const OP_LJUMP_TRUE:       u8 = 0x9A;  // (i32); [ cond ] => [ cond ]
126const OP_PLJMP_FALSE:      u8 = 0x9B;  // (i32); [ cond ] => []
127const OP_PLJMP_TRUE:       u8 = 0x9C;  // (i32); [ cond ] => []
128
129// 0xF0-FF      Debugging/Tracing/Misc
130
131const DBG_INSPECT:         u8 = 0xF0;
132const DBG_ASSERT:          u8 = 0xF1;
133const DBG_DUMP_STACK:      u8 = 0xF2;
134const DBG_DUMP_GLOBALS:    u8 = 0xF3;
135const DBG_DUMP_STRINGS:    u8 = 0xF4;
136
137
138#[repr(u8)]
139#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
140pub enum OpCode {
141    Nop = OP_NOP,
142    Exit = OP_EXIT,
143    Error = OP_ERROR,
144    
145    Return = OP_RETURN, 
146    Call = OP_CALL,
147    InsertArgs = OP_IN_ARGS,
148    
149    Pop = OP_POP,
150    Drop = OP_DROP,
151    DropN = OP_DROPN,
152    Clone = OP_CLONE,
153    
154    Tuple = OP_TUPLE,
155    TupleN = OP_TUPLEN,
156    
157    IterInit = OP_ITER_INIT,
158    IterNext = OP_ITER_NEXT,
159    IterUnpack = OP_ITER_UNPACK,
160    
161    LoadFunction = OP_LD_FUN,
162    LoadFunction16 = OP_LD_FUN_16,
163    
164    LoadConst  = OP_LD_CONST,
165    LoadConst16 = OP_LD_CONST_16,
166    
167    InsertGlobal = OP_IN_GLOBAL_IM,
168    InsertGlobalMut = OP_IN_GLOBAL_MUT,
169    StoreGlobal = OP_ST_GLOBAL,
170    LoadGlobal = OP_LD_GLOBAL,
171    
172    InsertLocal = OP_IN_LOCAL,
173    StoreLocal = OP_ST_LOCAL,
174    StoreLocal16 = OP_ST_LOCAL_16,
175    LoadLocal = OP_LD_LOCAL,
176    LoadLocal16 = OP_LD_LOCAL_16,
177    DropLocals = OP_DP_LOCALS,
178    
179    StoreUpvalue = OP_ST_UPVAL,
180    StoreUpvalue16 = OP_ST_UPVAL_16,
181    LoadUpvalue = OP_LD_UPVAL,
182    LoadUpvalue16 = OP_LD_UPVAL_16,
183    
184    CloseUpvalue = OP_CLOSE_UPVAL,
185    CloseUpvalue16 = OP_CLOSE_UPVAL_16,
186    
187    Nil = OP_LD_NIL,
188    True = OP_LD_TRUE,
189    False = OP_LD_FALSE,
190    Empty = OP_LD_EMPTY,
191    
192    UInt8 = OP_LD_U8,
193    Int8 = OP_LD_I8,
194    Int16 = OP_LD_I16,
195    
196    Neg = OP_NEG,
197    Pos = OP_POS,
198    Inv = OP_INV,
199    Not = OP_NOT,
200    
201    And = OP_AND,
202    Xor = OP_XOR,
203    Or = OP_OR,
204    Shl = OP_SHL,
205    Shr = OP_SHR,
206    Add = OP_ADD,
207    Sub = OP_SUB,
208    Mul = OP_MUL,
209    Div = OP_DIV,
210    Mod = OP_MOD,
211    EQ = OP_EQ,
212    NE = OP_NE,
213    LT = OP_LT,
214    LE = OP_LE,
215    GE = OP_GE,
216    GT = OP_GT,
217    
218    Jump = OP_JUMP,
219    JumpIfFalse = OP_JUMP_FALSE,
220    JumpIfTrue = OP_JUMP_TRUE,
221    PopJumpIfFalse = OP_PJMP_FALSE,
222    PopJumpIfTrue = OP_PJMP_TRUE,
223    
224    LongJump = OP_LJUMP,
225    LongJumpIfFalse = OP_LJUMP_FALSE,
226    LongJumpIfTrue = OP_LJUMP_TRUE,
227    PopLongJumpIfFalse = OP_PLJMP_FALSE,
228    PopLongJumpIfTrue = OP_PLJMP_TRUE,
229    
230    Inspect = DBG_INSPECT,
231    Assert = DBG_ASSERT,
232}
233
234impl OpCode {
235    #[inline]
236    pub fn from_byte(byte: u8) -> Option<OpCode> {
237        let opcode = match byte {
238            OP_NOP => Self::Nop,
239            OP_EXIT => Self::Exit,
240            OP_ERROR => Self::Error,
241            
242            OP_RETURN => Self::Return,
243            OP_CALL => Self::Call,
244            OP_IN_ARGS => Self::InsertArgs,
245            
246            OP_POP => Self::Pop,
247            OP_DROP => Self::Drop,
248            OP_DROPN => Self::DropN,
249            OP_CLONE => Self::Clone,
250            
251            OP_TUPLE => Self::Tuple,
252            OP_TUPLEN => Self::TupleN,
253            
254            OP_ITER_INIT => Self::IterInit,
255            OP_ITER_NEXT => Self::IterNext,
256            OP_ITER_UNPACK => Self::IterUnpack,
257            
258            OP_LD_FUN => Self::LoadFunction,
259            OP_LD_FUN_16 => Self::LoadFunction16,
260            
261            OP_LD_CONST => Self::LoadConst,
262            OP_LD_CONST_16 => Self::LoadConst16,
263            
264            OP_IN_GLOBAL_IM => Self::InsertGlobal,
265            OP_IN_GLOBAL_MUT => Self::InsertGlobalMut,
266            OP_ST_GLOBAL => Self::StoreGlobal,
267            OP_LD_GLOBAL => Self::LoadGlobal,
268            
269            OP_IN_LOCAL => Self::InsertLocal,
270            OP_ST_LOCAL => Self::StoreLocal,
271            OP_ST_LOCAL_16 => Self::StoreLocal16,
272            OP_LD_LOCAL => Self::LoadLocal,
273            OP_LD_LOCAL_16 => Self::LoadLocal16,
274            OP_DP_LOCALS => Self::DropLocals,
275            
276            OP_ST_UPVAL => Self::StoreUpvalue,
277            OP_ST_UPVAL_16 => Self::StoreUpvalue16,
278            OP_LD_UPVAL => Self::LoadUpvalue,
279            OP_LD_UPVAL_16 => Self::LoadUpvalue16,
280            
281            OP_CLOSE_UPVAL => Self::CloseUpvalue,
282            OP_CLOSE_UPVAL_16 => Self::CloseUpvalue16,
283            
284            OP_LD_NIL => Self::Nil,
285            OP_LD_TRUE => Self::True,
286            OP_LD_FALSE => Self::False,
287            OP_LD_EMPTY => Self::Empty,
288            OP_LD_U8 => Self::UInt8,
289            OP_LD_I8 => Self::Int8,
290            OP_LD_I16 => Self::Int16,
291            
292            OP_NEG => Self::Neg,
293            OP_POS => Self::Pos,
294            OP_INV => Self::Inv,
295            OP_NOT => Self::Not,
296            
297            OP_AND => Self::And,
298            OP_XOR => Self::Xor,
299            OP_OR => Self::Or,
300            OP_SHL => Self::Shl,
301            OP_SHR => Self::Shr,
302            OP_ADD => Self::Add,
303            OP_SUB => Self::Sub,
304            OP_MUL => Self::Mul,
305            OP_DIV => Self::Div,
306            OP_MOD => Self::Mod,
307            OP_EQ => Self::EQ,
308            OP_NE => Self::NE,
309            OP_LT => Self::LT,
310            OP_LE => Self::LE,
311            OP_GE => Self::GE,
312            OP_GT => Self::GT,
313            
314            OP_JUMP => Self::Jump,
315            OP_JUMP_FALSE => Self::JumpIfFalse,
316            OP_JUMP_TRUE => Self::JumpIfTrue,
317            OP_PJMP_FALSE => Self::PopJumpIfFalse,
318            OP_PJMP_TRUE => Self::PopJumpIfTrue,
319            
320            OP_LJUMP => Self::LongJump,
321            OP_LJUMP_FALSE => Self::LongJumpIfFalse,
322            OP_LJUMP_TRUE => Self::LongJumpIfTrue,
323            OP_PLJMP_FALSE => Self::PopLongJumpIfFalse,
324            OP_PLJMP_TRUE => Self::PopLongJumpIfTrue,
325            
326            DBG_INSPECT => Self::Inspect,
327            DBG_ASSERT => Self::Assert,
328            
329            _ => return None,
330        };
331        Some(opcode)
332    }
333    
334    #[inline]
335    pub const fn instr_len(&self) -> usize {
336        match self {
337            // don't really need size_of() for most of these, but it's a nice little bit of self-documentation
338
339            Self::Drop           => 1 + size_of::<u8>(),
340            
341            Self::LoadFunction   => 1 + size_of::<u8>(),
342            Self::LoadFunction16 => 1 + size_of::<u16>(),
343            
344            Self::LoadConst      => 1 + size_of::<u8>(),
345            Self::LoadConst16    => 1 + size_of::<u16>(),
346            
347            Self::StoreLocal     => 1 + size_of::<u8>(),
348            Self::StoreLocal16   => 1 + size_of::<u16>(),
349            Self::LoadLocal      => 1 + size_of::<u8>(),
350            Self::LoadLocal16    => 1 + size_of::<u16>(),
351            Self::DropLocals     => 1 + size_of::<u8>(),
352            
353            Self::StoreUpvalue   => 1 + size_of::<u8>(),
354            Self::StoreUpvalue16 => 1 + size_of::<u16>(),
355            Self::LoadUpvalue    => 1 + size_of::<u8>(),
356            Self::LoadUpvalue16  => 1 + size_of::<u16>(),
357            
358            Self::CloseUpvalue   => 1 + size_of::<u8>(),
359            Self::CloseUpvalue16 => 1 + size_of::<u16>(),
360            
361            Self::Tuple          => 1 + size_of::<u8>(),
362            Self::UInt8          => 1 + size_of::<u8>(),
363            Self::Int8           => 1 + size_of::<i8>(),
364            Self::Int16          => 1 + size_of::<i16>(),
365            
366            Self::Jump           => 1 + size_of::<i16>(),
367            Self::JumpIfFalse    => 1 + size_of::<i16>(),
368            Self::JumpIfTrue     => 1 + size_of::<i16>(),
369            Self::PopJumpIfFalse => 1 + size_of::<i16>(),
370            Self::PopJumpIfTrue  => 1 + size_of::<i16>(),
371            
372            _ => 1,
373        }
374    }
375}
376
377impl From<OpCode> for u8 {
378    fn from(opcode: OpCode) -> Self { opcode as u8 }
379}
380
381impl TryFrom<u8> for OpCode {
382    type Error = u8;
383    fn try_from(byte: u8) -> Result<Self, u8> {
384        if let Some(opcode) = OpCode::from_byte(byte) {
385            Ok(opcode)
386        } else {
387            Err(byte)
388        }
389    }
390}
391
392impl PartialEq<u8> for OpCode {
393    fn eq(&self, other: &u8) -> bool { *other == (*self).into() }
394}
395
396// For disassembly/debugging
397impl core::fmt::Display for OpCode {
398    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
399        let mnemonic = match *self {
400            Self::Nop => "NOP",
401            Self::Exit => "EXIT",
402            Self::Error => "ERROR",
403            
404            Self::Return => "RETURN",
405            Self::Call => "CALL",
406            Self::InsertArgs => "IN_ARGS",
407            
408            Self::Pop => "POP",
409            Self::Drop => "DROP",
410            Self::DropN => "DROPN",
411            Self::Clone => "CLONE",
412            
413            Self::Tuple => "TUPLE",
414            Self::TupleN => "TUPLEN",
415            
416            Self::IterInit => "ITER_INIT",
417            Self::IterNext => "ITER_NEXT",
418            Self::IterUnpack => "ITER_UNPACK",
419            
420            Self::LoadFunction => "LD_FUN",
421            Self::LoadFunction16 => "LD_FUN_16",
422            
423            Self::LoadConst => "LD_CONST",
424            Self::LoadConst16 => "LD_CONST_16",
425            
426            Self::InsertGlobal => "IN_GLOBAL_IM",
427            Self::InsertGlobalMut => "IN_GLOBAL_MUT",
428            Self::StoreGlobal => "ST_GLOBAL",
429            Self::LoadGlobal => "LD_GLOBAL",
430            
431            Self::InsertLocal => "IN_LOCAL",
432            Self::StoreLocal => "ST_LOCAL",
433            Self::StoreLocal16 => "ST_LOCAL_16",
434            Self::LoadLocal => "LD_LOCAL",
435            Self::LoadLocal16 => "LD_LOCAL_16",
436            Self::DropLocals => "DP_LOCALS",
437            
438            Self::StoreUpvalue => "ST_UPVAL",
439            Self::StoreUpvalue16 => "ST_UPVAL_16",
440            Self::LoadUpvalue => "LD_UPVAL",
441            Self::LoadUpvalue16 => "LD_UPVAL_16",
442            
443            Self::CloseUpvalue => "CLOSE_UPVAL",
444            Self::CloseUpvalue16 => "CLOSE_UPVAL_16",
445            
446            Self::Nil => "LD_NIL",
447            Self::True => "LD_TRUE",
448            Self::False => "LD_FALSE",
449            Self::Empty => "LD_EMPTY",
450            Self::UInt8 => "LD_U8",
451            Self::Int8 => "LD_I8",
452            Self::Int16 => "LD_I16",
453            
454            Self::Neg => "NEG",
455            Self::Pos => "POS",
456            Self::Inv => "INV",
457            Self::Not => "NOT",
458            
459            Self::And => "AND",
460            Self::Xor => "XOR",
461            Self::Or =>  "OR",
462            Self::Shl => "SHL",
463            Self::Shr => "SHR",
464            Self::Add => "ADD",
465            Self::Sub => "SUB",
466            Self::Mul => "MUL",
467            Self::Div => "DIV",
468            Self::Mod => "MOD",
469            Self::EQ => "CMP_EQ",
470            Self::NE => "CMP_NE",
471            Self::LT => "CMP_LT",
472            Self::LE => "CMP_LE",
473            Self::GE => "CMP_GE",
474            Self::GT => "CMP_GT",
475            
476            Self::Jump => "JUMP",
477            Self::JumpIfFalse => "JUMP_FALSE",
478            Self::JumpIfTrue => "JUMP_TRUE",
479            Self::PopJumpIfFalse => "PJMP_FALSE",
480            Self::PopJumpIfTrue => "PJMP_TRUE",
481            
482            Self::LongJump => "LJUMP",
483            Self::LongJumpIfFalse => "LJUMP_FALSE",
484            Self::LongJumpIfTrue => "LJUMP_TRUE",
485            Self::PopLongJumpIfFalse => "PLJMP_FALSE",
486            Self::PopLongJumpIfTrue => "PLJMP_TRUE",
487            
488            Self::Inspect => "DBG_INSPECT",
489            Self::Assert => "DBG_ASSERT",
490        };
491        
492        if let Some(width) = fmt.width() {
493            write!(fmt, "{:1$}", mnemonic, width)
494        } else {
495            fmt.write_str(mnemonic)
496        }
497    }
498}