diff options
Diffstat (limited to 'src/vm.c')
-rw-r--r-- | src/vm.c | 253 |
1 files changed, 5 insertions, 248 deletions
@@ -1,143 +1,8 @@ | |||
1 | #include "badlib.h" | 1 | #ifndef VM_C |
2 | #include "parser.c" | 2 | #define VM_C |
3 | |||
4 | typedef struct Instruction { | ||
5 | u8 dst; | ||
6 | u8 a; | ||
7 | u8 b; | ||
8 | u8 op; | ||
9 | } Instruction; | ||
10 | |||
11 | typedef union Constant { | ||
12 | s64 i; | ||
13 | u64 u; | ||
14 | double f; | ||
15 | ptrsize ptr; | ||
16 | } Constant; | ||
17 | |||
18 | typedef struct Chunk { | ||
19 | Instruction *code; | ||
20 | |||
21 | // Constant values that fit in 64 bits. | ||
22 | Constant *constants; | ||
23 | IntIntMap *intmap; | ||
24 | sz const_idx; | ||
25 | |||
26 | // Constant strings. | ||
27 | Str *strings; | ||
28 | StrIntMap *strmap; | ||
29 | sz str_idx; | ||
30 | 3 | ||
31 | // Number of registers currently used in this chunk. | 4 | #include "badlib.h" |
32 | sz reg_idx; | 5 | #include "compiler.c" |
33 | |||
34 | // Debugging. | ||
35 | Str file_name; | ||
36 | Arena *storage; | ||
37 | // TODO: line/col info for debugging. | ||
38 | } Chunk; | ||
39 | |||
40 | typedef enum OpCode { | ||
41 | // OP DST A B | ||
42 | // --------------------------------------------------------------- | ||
43 | OP_HALT, // halt | ||
44 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca | ||
45 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca | ||
46 | OP_LD32K, // ld32k rx, ca -> u32 rx = ca | ||
47 | OP_LD64K, // ld64k rx, ca -> u64 rx = ca | ||
48 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] | ||
49 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] | ||
50 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] | ||
51 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] | ||
52 | OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] | ||
53 | OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] | ||
54 | OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] | ||
55 | OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] | ||
56 | OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx | ||
57 | OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx | ||
58 | OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx | ||
59 | OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx | ||
60 | OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx | ||
61 | OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx | ||
62 | OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx | ||
63 | OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx | ||
64 | OP_ADDI, // addk rx, ra, cb | ||
65 | OP_SUBI, // subk rx, ra, cb | ||
66 | OP_MULI, // mulk rx, ra, cb | ||
67 | OP_DIVI, // divk rx, ra, cb | ||
68 | OP_MODI, // modk rx, ra, cb | ||
69 | OP_ADD, // add rx, ra, rb | ||
70 | OP_SUB, // sub rx, ra, rb | ||
71 | OP_MUL, // mul rx, ra, rb | ||
72 | OP_DIV, // div rx, ra, rb | ||
73 | OP_MOD, // mod rx, ra, rb | ||
74 | OP_ADDFI, // addk rx, ra, cb | ||
75 | OP_SUBFI, // subk rx, ra, cb | ||
76 | OP_MULFI, // mulk rx, ra, cb | ||
77 | OP_DIVFI, // divk rx, ra, cb | ||
78 | OP_MODFI, // modk rx, ra, cb | ||
79 | OP_ADDF, // add rx, ra, rb | ||
80 | OP_SUBF, // sub rx, ra, rb | ||
81 | OP_MULF, // mul rx, ra, rb | ||
82 | OP_DIVF, // div rx, ra, rb | ||
83 | OP_MODF, // mod rx, ra, rb | ||
84 | OP_MOV8, // mov8 rx, ra -> rx = ra & 0xFF | ||
85 | OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF | ||
86 | OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF | ||
87 | OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF | ||
88 | } OpCode; | ||
89 | |||
90 | Str op_str[] = { | ||
91 | [OP_HALT] = cstr("HALT "), | ||
92 | // Load ops. | ||
93 | [OP_LD8K] = cstr("LD8K "), | ||
94 | [OP_LD16K] = cstr("LD16K "), | ||
95 | [OP_LD32K] = cstr("LD32K "), | ||
96 | [OP_LD64K] = cstr("LD64K "), | ||
97 | [OP_LD8I] = cstr("LD8I "), | ||
98 | [OP_LD16I] = cstr("LD16I "), | ||
99 | [OP_LD32I] = cstr("LD32I "), | ||
100 | [OP_LD64I] = cstr("LD64I "), | ||
101 | [OP_LD8] = cstr("LD8 "), | ||
102 | [OP_LD16] = cstr("LD16 "), | ||
103 | [OP_LD32] = cstr("LD32 "), | ||
104 | [OP_LD64] = cstr("LD64 "), | ||
105 | // Store ops. | ||
106 | [OP_ST8I] = cstr("ST8I "), | ||
107 | [OP_ST16I] = cstr("ST16I "), | ||
108 | [OP_ST32I] = cstr("ST32I "), | ||
109 | [OP_ST64I] = cstr("ST64I "), | ||
110 | [OP_ST8] = cstr("ST8 "), | ||
111 | [OP_ST16] = cstr("ST16 "), | ||
112 | [OP_ST32] = cstr("ST32 "), | ||
113 | [OP_ST64] = cstr("ST64 "), | ||
114 | // Arithmetic. | ||
115 | [OP_ADDI] = cstr("ADDI "), | ||
116 | [OP_SUBI] = cstr("SUBI "), | ||
117 | [OP_MULI] = cstr("MULI "), | ||
118 | [OP_DIVI] = cstr("DIVI "), | ||
119 | [OP_MODI] = cstr("MODI "), | ||
120 | [OP_ADD] = cstr("ADD "), | ||
121 | [OP_SUB] = cstr("SUB "), | ||
122 | [OP_MUL] = cstr("MUL "), | ||
123 | [OP_DIV] = cstr("DIV "), | ||
124 | [OP_MOD] = cstr("MOD "), | ||
125 | [OP_ADDFI] = cstr("ADDFI "), | ||
126 | [OP_SUBFI] = cstr("SUBFI "), | ||
127 | [OP_MULFI] = cstr("MULFI "), | ||
128 | [OP_DIVFI] = cstr("DIVFI "), | ||
129 | [OP_MODFI] = cstr("MODFI "), | ||
130 | [OP_ADDF] = cstr("ADDF "), | ||
131 | [OP_SUBF] = cstr("SUBF "), | ||
132 | [OP_MULF] = cstr("MULF "), | ||
133 | [OP_DIVF] = cstr("DIVF "), | ||
134 | // Reg copy/move. | ||
135 | [OP_MODF] = cstr("MODF "), | ||
136 | [OP_MOV8] = cstr("MOV8 "), | ||
137 | [OP_MOV16] = cstr("MOV16 "), | ||
138 | [OP_MOV32] = cstr("MOV32 "), | ||
139 | [OP_MOV64] = cstr("MOV64 "), | ||
140 | }; | ||
141 | 6 | ||
142 | void | 7 | void |
143 | disassemble_instruction(Instruction instruction) { | 8 | disassemble_instruction(Instruction instruction) { |
@@ -308,112 +173,4 @@ vm_run(VM *vm) { | |||
308 | } | 173 | } |
309 | } | 174 | } |
310 | 175 | ||
311 | typedef enum { | 176 | #endif // VM_C |
312 | COMP_CONST, | ||
313 | COMP_STRING, | ||
314 | COMP_REG, | ||
315 | COMP_ERR, | ||
316 | } CompResultType; | ||
317 | |||
318 | typedef struct CompResult { | ||
319 | sz idx; | ||
320 | CompResultType type; | ||
321 | } CompResult; | ||
322 | |||
323 | CompResult compile_expr(Chunk *chunk, Node *node); | ||
324 | |||
325 | #define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ | ||
326 | do { \ | ||
327 | Instruction inst = (Instruction){ \ | ||
328 | .op = (OP), \ | ||
329 | .dst = (DST), \ | ||
330 | .a = (A), \ | ||
331 | .b = (B), \ | ||
332 | }; \ | ||
333 | array_push((CHUNK)->code, inst, (CHUNK)->storage); \ | ||
334 | } while (0) | ||
335 | |||
336 | CompResult | ||
337 | compile_binary(OpCode op, Chunk *chunk, Node *node) { | ||
338 | CompResult comp_a = compile_expr(chunk, node->left); | ||
339 | CompResult comp_b = compile_expr(chunk, node->right); | ||
340 | sz reg_a; | ||
341 | sz reg_b; | ||
342 | switch (comp_a.type) { | ||
343 | case COMP_CONST: { | ||
344 | reg_a = chunk->reg_idx++; | ||
345 | EMIT_OP(OP_LD64K, reg_a, comp_a.idx, 0, node, chunk); | ||
346 | } break; | ||
347 | case COMP_REG: { | ||
348 | reg_a = comp_a.idx; | ||
349 | } break; | ||
350 | default: { | ||
351 | return (CompResult){.type = COMP_ERR}; | ||
352 | } break; | ||
353 | } | ||
354 | switch (comp_b.type) { | ||
355 | case COMP_CONST: { | ||
356 | reg_b = chunk->reg_idx++; | ||
357 | EMIT_OP(OP_LD64K, reg_b, comp_b.idx, 0, node, chunk); | ||
358 | } break; | ||
359 | case COMP_REG: { | ||
360 | reg_b = comp_b.idx; | ||
361 | } break; | ||
362 | default: { | ||
363 | return (CompResult){.type = COMP_ERR}; | ||
364 | } break; | ||
365 | } | ||
366 | sz reg_dst = comp_a.idx; // Less registers | ||
367 | // sz reg_dst = chunk->reg_idx++; // Better for optimization | ||
368 | EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); | ||
369 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
370 | } | ||
371 | |||
372 | CompResult | ||
373 | compile_expr(Chunk *chunk, Node *node) { | ||
374 | switch (node->kind) { | ||
375 | case NODE_ADD: return compile_binary(OP_ADD, chunk, node); break; | ||
376 | case NODE_SUB: return compile_binary(OP_SUB, chunk, node); break; | ||
377 | case NODE_MUL: return compile_binary(OP_MUL, chunk, node); break; | ||
378 | case NODE_DIV: return compile_binary(OP_DIV, chunk, node); break; | ||
379 | case NODE_MOD: return compile_binary(OP_MOD, chunk, node); break; | ||
380 | case NODE_TRUE: | ||
381 | case NODE_FALSE: | ||
382 | case NODE_NUM_FLOAT: | ||
383 | case NODE_NUM_INT: { | ||
384 | sz value = node->value.i; | ||
385 | // Make sure we don't have duplicated constants. | ||
386 | IntIntMap *map = intintmap_lookup(&chunk->intmap, value); | ||
387 | if (!map) { | ||
388 | map = intintmap_insert(&chunk->intmap, value, | ||
389 | chunk->const_idx++, chunk->storage); | ||
390 | Constant c = (Constant){.i = node->value.i}; | ||
391 | array_push(chunk->constants, c, chunk->storage); | ||
392 | } | ||
393 | return (CompResult){ | ||
394 | .type = COMP_CONST, | ||
395 | .idx = map->val, | ||
396 | }; | ||
397 | } break; | ||
398 | case NODE_STRING: { | ||
399 | Str string = node->value.str; | ||
400 | // Make sure we don't have duplicated strings. | ||
401 | StrIntMap *map = strintmap_lookup(&chunk->strmap, string); | ||
402 | if (!map) { | ||
403 | map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++, | ||
404 | chunk->storage); | ||
405 | array_push(chunk->strings, string, chunk->storage); | ||
406 | } | ||
407 | return (CompResult){ | ||
408 | .type = COMP_STRING, | ||
409 | .idx = map->val, | ||
410 | }; | ||
411 | } break; | ||
412 | default: { | ||
413 | eprintln("error: compilation not implemented for node %s", | ||
414 | node_str[node->kind]); | ||
415 | exit(EXIT_FAILURE); | ||
416 | } break; | ||
417 | } | ||
418 | return (CompResult){.type = COMP_ERR}; | ||
419 | } | ||