Skip to main content

steel_gen/
opcode.rs

1use serde::{Deserialize, Serialize};
2
3macro_rules! declare_opcodes {
4
5    ( { $($variant:tt);* } ) => {
6        // #[repr(u8)]
7        #[derive(Copy, Clone, Debug, Hash, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord)]
8        pub enum OpCode {
9            $($variant),*
10        }
11
12        pub const MAX_OPCODE_SIZE: usize = OpCode::CALLPRIMITIVETAIL as usize + 1;
13
14        pub const OPCODES_ARRAY: [OpCode; MAX_OPCODE_SIZE] = [
15            $(OpCode::$variant),*
16        ];
17    }
18
19}
20
21declare_opcodes! {
22    {
23        VOID;
24        PUSH;
25        IF;
26        JMP;
27        FUNC;
28        SCLOSURE;
29        ECLOSURE;
30        BIND;
31        SDEF;
32        EDEF;
33        POPPURE;
34        POPN;
35        POPSINGLE;
36        PASS;
37        PUSHCONST;
38        NDEFS;
39        PANIC;
40        TAILCALL;
41        SET;
42        READLOCAL;
43        READLOCAL0;
44        READLOCAL1;
45        READLOCAL2;
46        READLOCAL3;
47        SETLOCAL;
48        COPYCAPTURESTACK;
49        COPYCAPTURECLOSURE;
50        COPYHEAPCAPTURECLOSURE;
51        FIRSTCOPYHEAPCAPTURECLOSURE;
52        TCOJMP;
53        CALLGLOBAL;
54        CALLGLOBALTAIL;
55        LOADINT0; // Load const 0
56        LOADINT1;
57        LOADINT2;
58        CGLOCALCONST;
59        MOVEREADLOCAL;
60        MOVEREADLOCAL0;
61        MOVEREADLOCAL1;
62        MOVEREADLOCAL2;
63        MOVEREADLOCAL3;
64        READCAPTURED;
65        BEGINSCOPE;
66        LETENDSCOPE;
67        PUREFUNC;
68        ADD;
69        SUB;
70        MUL;
71        DIV;
72        EQUAL;
73        NUMEQUAL;
74        NULL;
75        LTE;
76        GTE;
77        GT;
78        LT;
79        CONS; // Cons should be... probably specialized
80        LIST;
81        CAR;
82        CDR;
83        NEWBOX;
84        SETBOX;
85        UNBOX;
86        NEWSCLOSURE;
87        ADDREGISTER;
88        SUBREGISTER;
89        LTEREGISTER;
90        SUBREGISTER1;
91        ALLOC;
92        READALLOC;
93        SETALLOC;
94        DynSuperInstruction;
95        Arity;
96        LetVar;
97        ADDIMMEDIATE;
98        SUBIMMEDIATE;
99        LTEIMMEDIATE;
100        BINOPADD;
101        BINOPSUB;
102        LTEIMMEDIATEIF;
103        NOT;
104        VEC;
105        Apply;
106        POPJMP;
107        BINOPADDTAIL;
108        LOADINT0POP; // Load const 0
109        LOADINT1POP;
110        LOADINT2POP;
111        READLOCAL0CALLGLOBAL;
112        READLOCAL1CALLGLOBAL;
113        LISTREF;
114        VECTORREF;
115        TRUE;
116        FALSE;
117        NULLIF;
118        UNBOXCALL;
119        UNBOXTAIL;
120        EQUALCONST;
121        EQUAL2;
122        // Calling functions w/o arity checks, if we can statically assert
123        // that the arity check is correct. If the arity check _isn't_
124        // correct, then we won't report it at compile time.
125        CALLGLOBALNOARITY;
126        CALLGLOBALTAILNOARITY;
127        FUNCNOARITY;
128        TAILCALLNOARITY;
129        SELFTAILCALLNOARITY;
130        CALLPRIMITIVE;
131        CALLPRIMITIVETAIL
132    }
133
134    // Super instructions
135    // {
136
137
138        // [
139        //     CaseLambdaDispatch =>
140        //                           (OpCode::BEGINSCOPE, 0),
141        //                           (OpCode::READLOCAL0, 0),
142        //                           (OpCode::CALLGLOBAL, 75),
143        //                           (OpCode::FUNC, 1),
144        //                           (OpCode::READLOCAL1, 1),
145        //                           (OpCode::PUSHCONST, 565),
146        //                           (OpCode::CALLGLOBAL, 75),
147        //                           (OpCode::FUNC, 1),
148        //                           (OpCode::NUMEQUAL, 2),
149        //                           (OpCode::PASS, 2),
150        //                           (OpCode::IF, 22),
151        // ]
152
153        // [
154        //     ReadLocal1PushConstEqualIf => (OpCode::READLOCAL1, 1),
155        //                                   (OpCode::PUSHCONST, 335),
156        //                                   (OpCode::EQUAL, 2),
157        //                                   (OpCode::PASS, 0),
158        //                                   (OpCode::IF, 8),
159        // ];
160
161        // [
162        //     ReadLocal2CallGlobalIf => (OpCode::READLOCAL2, 2),
163        //                               (OpCode::CALLGLOBAL, 1),
164        //                               (OpCode::FUNC, 1),
165        //                               (OpCode::IF, 8),
166        // ]
167
168        // 16    READLOCAL0         : 0      ##args
169        // 17    CALLGLOBAL         : 1      length
170        // 18    Arity              : 82     length
171        // 19    READLOCAL1         : 1      l
172        // 20    LOADINT0           : 274    0
173        // 21    CALLGLOBAL         : 2      =
174        // 22    Arity              : 180    =
175        // 23    IF                 : 22
176
177        // [
178        //     CaseLambdaDispatch => (OpCode::READLOCAL0, 0),
179        //                           (OpCode::CALLGLOBAL, 1),
180        //                           (OpCode::Arity, 92),
181        //                           (OpCode::READLOCAL1, 1),
182        //                           (OpCode::LOADINT0, 0),
183        //                           (OpCode::CALLGLOBAL, 2),
184        //                           (OpCode::Arity, 181),
185        //                           (OpCode::IF, 22),
186        // ]
187
188        // [ MOVERLLIS2CG => (OpCode::MOVEREADLOCAL, 0), (OpCode::LOADINT2, 225), (OpCode::SUB, 2), (OpCode::CALLGLOBAL, 1), ];
189
190        // [ MOVERLLIS2CGFOO => (OpCode::MOVEREADLOCAL, 1), (OpCode::LOADINT2, 225), (OpCode::SUB, 2), (OpCode::CALLGLOBAL, 1), ]
191
192
193        //         (MOVEREADLOCAL0, 0),
194        //         (LOADINT2, 225),
195        //         (SUB, 2),
196        //         (CALLGLOBAL, 1),
197
198    // }
199}
200
201// // expansion
202// enum EntryPoints {
203//     SomeLibCallback(u64),
204
205//     A(),
206//     B(),
207// }
208
209impl OpCode {
210    /// Is this op code created as part of the aggregation of multiple op codes?
211    pub fn is_super_instruction(&self) -> bool {
212        // TODO: Check where super instructions start!
213        *self as u32 > Self::LTEIMMEDIATEIF as u32
214    }
215
216    /// Statically create the mapping we need for super instruction. Also, as part of the op code map generating,
217    /// the macro used for calling super instructions should also be generated.
218    pub fn super_instructions(&self) -> &'static [&'static [(OpCode, usize)]] {
219        todo!()
220    }
221
222    pub fn is_ephemeral_opcode(&self) -> bool {
223        use OpCode::*;
224
225        matches!(
226            self,
227            ECLOSURE
228                | PASS
229                | Arity
230                | NDEFS
231                | COPYCAPTURECLOSURE
232                | COPYCAPTURESTACK
233                | COPYHEAPCAPTURECLOSURE,
234        )
235    }
236
237    // TODO better error handling here
238    pub fn from(s: &str) -> Self {
239        use OpCode::*;
240        match s {
241            "VOID" => VOID,
242            "PUSH" => PUSH,
243            "IF" => IF,
244            "JMP" => JMP,
245            "FUNC" => FUNC,
246            "SCLOSURE" => SCLOSURE,
247            "ECLOSURE" => ECLOSURE,
248            // "STRUCT" => STRUCT,
249            "BIND" => BIND,
250            "SDEF" => SDEF,
251            "EDEF" => EDEF,
252            "PASS" => PASS,
253            "PUSHCONST" => PUSHCONST,
254            "NDEFS" => NDEFS,
255            "PANIC" => PANIC,
256            "TAILCALL" => TAILCALL,
257            "SET" => SET,
258            "READLOCAL" => READLOCAL,
259            "SETLOCAL" => SETLOCAL,
260            "TCOJMP" => TCOJMP,
261            "CALLGLOBAL" => CALLGLOBAL,
262            "CALLGLOBALTAIL" => CALLGLOBALTAIL,
263            "LOADINT0" => LOADINT0, // Load const 0
264            "LOADINT1" => LOADINT1,
265            "LOADINT2" => LOADINT2,
266            "CGLOCALCONST" => CGLOCALCONST,
267            "MOVEREADLOCAL" => MOVEREADLOCAL,
268            "BEGINSCOPE" => BEGINSCOPE,
269            "ADD" => ADD,
270            "SUB" => SUB,
271            "MUL" => MUL,
272            "DIV" => DIV,
273            "EQUAL" => EQUAL,
274            "LTE" => LTE,
275            "LETENDSCOPE" => LETENDSCOPE,
276            "PUREFUNC" => PUREFUNC,
277            "POP_PURE" => POPPURE,
278            "READCAPTURED" => READCAPTURED,
279            "COPYCAPTURESTACK" => COPYCAPTURESTACK,
280            "COPYCAPTURECLOSURE" => COPYCAPTURECLOSURE,
281            "COPYHEAPCAPTURECLOSURE" => COPYHEAPCAPTURECLOSURE,
282            "NEWSCLOSURE" => NEWSCLOSURE,
283            "ADDREGISTER" => ADDREGISTER,
284            "SUBREGISTER" => SUBREGISTER,
285            "LTEREGISTER" => LTEREGISTER,
286            "SUBREGISTER1" => SUBREGISTER1,
287            "ALLOC" => ALLOC,
288            "READALLOC" => READALLOC,
289            "SETALLOC" => SETALLOC,
290            _ => panic!("Unable to map string to opcode"),
291        }
292    }
293
294    pub fn width(&self) -> Option<usize> {
295        match self {
296            OpCode::VOID => Some(1),
297            OpCode::PUSH => Some(1),
298            OpCode::IF => None,
299            OpCode::JMP => None,
300            OpCode::FUNC => Some(1),
301            OpCode::SCLOSURE => None,
302            OpCode::ECLOSURE => Some(1),
303            OpCode::BIND => Some(1),
304            OpCode::SDEF => Some(1),
305            OpCode::EDEF => Some(1),
306            OpCode::POPPURE => Some(1),
307            OpCode::POPN => Some(1),
308            OpCode::POPSINGLE => Some(1),
309            OpCode::PASS => Some(1),
310            OpCode::PUSHCONST => Some(1),
311            OpCode::NDEFS => todo!(),
312            OpCode::PANIC => todo!(),
313            OpCode::TAILCALL => Some(1),
314            OpCode::SET => Some(1),
315            OpCode::READLOCAL => Some(1),
316            OpCode::READLOCAL0 => Some(1),
317            OpCode::READLOCAL1 => Some(1),
318            OpCode::READLOCAL2 => Some(1),
319            OpCode::READLOCAL3 => Some(1),
320            OpCode::SETLOCAL => todo!(),
321            OpCode::COPYCAPTURESTACK => todo!(),
322            OpCode::COPYCAPTURECLOSURE => todo!(),
323            OpCode::COPYHEAPCAPTURECLOSURE => todo!(),
324            OpCode::FIRSTCOPYHEAPCAPTURECLOSURE => todo!(),
325            OpCode::TCOJMP => None,
326            OpCode::CALLGLOBAL => Some(2),
327            OpCode::CALLGLOBALTAIL => None,
328            OpCode::LOADINT0 => Some(1),
329            OpCode::LOADINT1 => Some(1),
330            OpCode::LOADINT2 => Some(1),
331            OpCode::MOVEREADLOCAL => Some(1),
332            OpCode::MOVEREADLOCAL0 => Some(1),
333            OpCode::MOVEREADLOCAL1 => Some(1),
334            OpCode::MOVEREADLOCAL2 => Some(1),
335            OpCode::MOVEREADLOCAL3 => Some(1),
336            OpCode::READCAPTURED => Some(1),
337            OpCode::BEGINSCOPE => Some(1),
338            OpCode::LETENDSCOPE => Some(1),
339            OpCode::PUREFUNC => None,
340            OpCode::ADD => Some(2),
341            OpCode::SUB => Some(2),
342            OpCode::MUL => Some(2),
343            OpCode::DIV => Some(2),
344            OpCode::EQUAL => Some(2),
345            OpCode::NUMEQUAL => Some(2),
346            OpCode::NULL => Some(2),
347            OpCode::LTE => Some(2),
348            OpCode::GTE => Some(2),
349            OpCode::GT => Some(2),
350            OpCode::LT => Some(2),
351            OpCode::CONS => Some(2),
352            OpCode::LIST => Some(2),
353            OpCode::CAR => Some(2),
354            OpCode::CDR => Some(2),
355            OpCode::NEWBOX => Some(2),
356            OpCode::SETBOX => Some(2),
357            OpCode::UNBOX => Some(2),
358            OpCode::NEWSCLOSURE => None,
359            OpCode::ADDREGISTER => Some(2),
360            OpCode::SUBREGISTER => Some(2),
361            OpCode::LTEREGISTER => Some(2),
362            OpCode::SUBREGISTER1 => Some(2),
363            OpCode::ALLOC => todo!(),
364            OpCode::READALLOC => todo!(),
365            OpCode::SETALLOC => todo!(),
366            OpCode::DynSuperInstruction => todo!(),
367            OpCode::Arity => todo!(),
368            OpCode::LetVar => todo!(),
369            OpCode::ADDIMMEDIATE => Some(2),
370            OpCode::SUBIMMEDIATE => Some(2),
371            OpCode::LTEIMMEDIATE => Some(2),
372            OpCode::BINOPADD => Some(2),
373            OpCode::BINOPSUB => Some(2),
374            OpCode::LTEIMMEDIATEIF => None,
375            OpCode::NOT => Some(2),
376            OpCode::VEC => todo!(),
377            OpCode::Apply => todo!(),
378            OpCode::POPJMP => todo!(),
379            OpCode::BINOPADDTAIL => todo!(),
380            OpCode::LOADINT0POP => todo!(),
381            OpCode::LOADINT1POP => todo!(),
382            OpCode::LOADINT2POP => todo!(),
383            _ => todo!(),
384        }
385    }
386}