aboutsummaryrefslogtreecommitdiffstats
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c253
1 files changed, 5 insertions, 248 deletions
diff --git a/src/vm.c b/src/vm.c
index cb1b6cd..8d4e67e 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1,143 +1,8 @@
1#include "badlib.h" 1#ifndef VM_C
2#include "parser.c" 2#define VM_C
3
4typedef struct Instruction {
5 u8 dst;
6 u8 a;
7 u8 b;
8 u8 op;
9} Instruction;
10
11typedef union Constant {
12 s64 i;
13 u64 u;
14 double f;
15 ptrsize ptr;
16} Constant;
17
18typedef 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
40typedef 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
90Str 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
142void 7void
143disassemble_instruction(Instruction instruction) { 8disassemble_instruction(Instruction instruction) {
@@ -308,112 +173,4 @@ vm_run(VM *vm) {
308 } 173 }
309} 174}
310 175
311typedef enum { 176#endif // VM_C
312 COMP_CONST,
313 COMP_STRING,
314 COMP_REG,
315 COMP_ERR,
316} CompResultType;
317
318typedef struct CompResult {
319 sz idx;
320 CompResultType type;
321} CompResult;
322
323CompResult 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
336CompResult
337compile_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
372CompResult
373compile_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}