aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-20 14:20:07 +0200
committerBad Diode <bd@badd10de.dev>2024-06-20 14:20:07 +0200
commit972c453a085bedb3de8d598cc4ae4486e24f0144 (patch)
tree02503240867fc8e77fbca4f7c900192e9a7873be /src/main.c
parentc0faac681a32ffc2e323917f8b54f33558b391a5 (diff)
downloadbdl-972c453a085bedb3de8d598cc4ae4486e24f0144.tar.gz
bdl-972c453a085bedb3de8d598cc4ae4486e24f0144.zip
Move vm/chunk compiler to separate file
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c444
1 files changed, 40 insertions, 404 deletions
diff --git a/src/main.c b/src/main.c
index 598a93f..909caa4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,6 +5,7 @@
5#include "badlib.h" 5#include "badlib.h"
6#include "lexer.c" 6#include "lexer.c"
7#include "parser.c" 7#include "parser.c"
8#include "vm.c"
8 9
9typedef enum ExecMode { 10typedef enum ExecMode {
10 RUN_NORMAL, 11 RUN_NORMAL,
@@ -21,379 +22,13 @@ init(void) {
21 log_init_default(); 22 log_init_default();
22} 23}
23 24
24typedef struct Instruction {
25 u8 dst;
26 u8 a;
27 u8 b;
28 u8 op;
29} Instruction;
30
31typedef union Constant {
32 s64 i;
33 u64 u;
34 double f;
35 ptrsize ptr;
36} Constant;
37
38typedef struct Chunk {
39 Instruction *code;
40 Constant *constants;
41 Str file_name;
42 sz reg_idx;
43 sz const_idx;
44 Arena *storage;
45 // TODO: line/col info for debugging.
46} Chunk;
47
48typedef enum OpCode {
49 // OP DST A B
50 // ---------------------------------------------------------------
51 OP_HALT, // halt
52 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
53 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
54 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
55 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
56 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb]
57 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb]
58 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb]
59 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb]
60 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb]
61 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb]
62 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb]
63 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb]
64 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx
65 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx
66 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx
67 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx
68 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx
69 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx
70 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx
71 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx
72 OP_ADDI, // addk rx, ra, cb
73 OP_SUBI, // subk rx, ra, cb
74 OP_MULI, // mulk rx, ra, cb
75 OP_DIVI, // divk rx, ra, cb
76 OP_MODI, // modk rx, ra, cb
77 OP_ADD, // add rx, ra, rb
78 OP_SUB, // sub rx, ra, rb
79 OP_MUL, // mul rx, ra, rb
80 OP_DIV, // div rx, ra, rb
81 OP_MOD, // mod rx, ra, rb
82 OP_ADDFI, // addk rx, ra, cb
83 OP_SUBFI, // subk rx, ra, cb
84 OP_MULFI, // mulk rx, ra, cb
85 OP_DIVFI, // divk rx, ra, cb
86 OP_MODFI, // modk rx, ra, cb
87 OP_ADDF, // add rx, ra, rb
88 OP_SUBF, // sub rx, ra, rb
89 OP_MULF, // mul rx, ra, rb
90 OP_DIVF, // div rx, ra, rb
91 OP_MODF, // mod rx, ra, rb
92 OP_MOV8, // mov8 rx, ra -> rx = ra & 0xFF
93 OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF
94 OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF
95 OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF
96} OpCode;
97
98Str op_str[] = {
99 [OP_HALT] = cstr("HALT "),
100 // Load ops.
101 [OP_LD8K] = cstr("LD8K "),
102 [OP_LD16K] = cstr("LD16K "),
103 [OP_LD32K] = cstr("LD32K "),
104 [OP_LD64K] = cstr("LD64K "),
105 [OP_LD8I] = cstr("LD8I "),
106 [OP_LD16I] = cstr("LD16I "),
107 [OP_LD32I] = cstr("LD32I "),
108 [OP_LD64I] = cstr("LD64I "),
109 [OP_LD8] = cstr("LD8 "),
110 [OP_LD16] = cstr("LD16 "),
111 [OP_LD32] = cstr("LD32 "),
112 [OP_LD64] = cstr("LD64 "),
113 // Store ops.
114 [OP_ST8I] = cstr("ST8I "),
115 [OP_ST16I] = cstr("ST16I "),
116 [OP_ST32I] = cstr("ST32I "),
117 [OP_ST64I] = cstr("ST64I "),
118 [OP_ST8] = cstr("ST8 "),
119 [OP_ST16] = cstr("ST16 "),
120 [OP_ST32] = cstr("ST32 "),
121 [OP_ST64] = cstr("ST64 "),
122 // Arithmetic.
123 [OP_ADDI] = cstr("ADDI "),
124 [OP_SUBI] = cstr("SUBI "),
125 [OP_MULI] = cstr("MULI "),
126 [OP_DIVI] = cstr("DIVI "),
127 [OP_MODI] = cstr("MODI "),
128 [OP_ADD] = cstr("ADD "),
129 [OP_SUB] = cstr("SUB "),
130 [OP_MUL] = cstr("MUL "),
131 [OP_DIV] = cstr("DIV "),
132 [OP_MOD] = cstr("MOD "),
133 [OP_ADDFI] = cstr("ADDFI "),
134 [OP_SUBFI] = cstr("SUBFI "),
135 [OP_MULFI] = cstr("MULFI "),
136 [OP_DIVFI] = cstr("DIVFI "),
137 [OP_MODFI] = cstr("MODFI "),
138 [OP_ADDF] = cstr("ADDF "),
139 [OP_SUBF] = cstr("SUBF "),
140 [OP_MULF] = cstr("MULF "),
141 [OP_DIVF] = cstr("DIVF "),
142 // Reg copy/move.
143 [OP_MODF] = cstr("MODF "),
144 [OP_MOV8] = cstr("MOV8 "),
145 [OP_MOV16] = cstr("MOV16 "),
146 [OP_MOV32] = cstr("MOV32 "),
147 [OP_MOV64] = cstr("MOV64 "),
148};
149
150void
151disassemble_instruction(Instruction instruction) {
152 switch (instruction.op) {
153 case OP_MOV8:
154 case OP_MOV16:
155 case OP_MOV32:
156 case OP_MOV64:
157 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
158 instruction.a, instruction.b);
159 break;
160 case OP_LD8K:
161 case OP_LD16K:
162 case OP_LD32K:
163 case OP_LD64K:
164 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
165 instruction.a, instruction.b);
166 break;
167 case OP_LD8I:
168 case OP_LD16I:
169 case OP_LD32I:
170 case OP_LD64I:
171 case OP_ST8I:
172 case OP_ST16I:
173 case OP_ST32I:
174 case OP_ST64I:
175 case OP_ADDI:
176 case OP_SUBI:
177 case OP_MULI:
178 case OP_DIVI:
179 case OP_MODI:
180 case OP_ADDFI:
181 case OP_SUBFI:
182 case OP_MULFI:
183 case OP_DIVFI:
184 case OP_MODFI:
185 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst,
186 instruction.a, instruction.b);
187 break;
188 case OP_LD8:
189 case OP_LD16:
190 case OP_LD32:
191 case OP_LD64:
192 case OP_ST8:
193 case OP_ST16:
194 case OP_ST32:
195 case OP_ST64:
196 case OP_ADD:
197 case OP_SUB:
198 case OP_MUL:
199 case OP_DIV:
200 case OP_MOD:
201 case OP_ADDF:
202 case OP_SUBF:
203 case OP_MULF:
204 case OP_DIVF:
205 case OP_MODF:
206 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst,
207 instruction.a, instruction.b);
208 break;
209 case OP_HALT: println("%s", op_str[instruction.op]); break;
210 default: println("Unknown opcode %d", instruction.op); break;
211 }
212}
213
214void
215disassemble_chunk(Chunk chunk) {
216 println("%s: ========= code =========", chunk.file_name);
217 for (sz i = 0; i < array_size(chunk.code); i++) {
218 print("%s: %x{4}: ", chunk.file_name, i);
219 disassemble_instruction(chunk.code[i]);
220 }
221 if (array_size(chunk.constants) > 0) {
222 println("%s: ======= constants ======", chunk.file_name);
223 for (sz i = 0; i < array_size(chunk.constants); i++) {
224 println("%s: %x{2}: %x{8}", chunk.file_name, i, chunk.constants[i]);
225 }
226 }
227}
228
229#define N_CONST 256
230typedef struct VM {
231 Chunk *chunk;
232 Constant regs[N_CONST];
233 Instruction *ip;
234} VM;
235
236void
237vm_init(VM *vm, Chunk *chunk) {
238 assert(vm);
239 assert(chunk);
240 assert(chunk->code);
241 vm->chunk = chunk;
242 vm->ip = vm->chunk->code;
243}
244
245#define OP_ARITHMETIC(OP, TYPE) \
246 do { \
247 u8 dst = instruction.dst; \
248 u8 src_a = instruction.a; \
249 u8 src_b = instruction.b; \
250 vm->regs[dst].TYPE = vm->regs[src_a].TYPE OP vm->regs[src_b].TYPE; \
251 } while (0);
252
253#define OP_ARITHMETIC_CONST(OP, TYPE) \
254 do { \
255 u8 dst = instruction.dst; \
256 u8 src_a = instruction.a; \
257 u8 src_b = instruction.b; \
258 vm->regs[dst].TYPE = \
259 vm->regs[src_a].TYPE OP vm->chunk->constants[src_b].TYPE; \
260 } while (0);
261
262#include <math.h>
263
264void
265vm_run(VM *vm) {
266 assert(vm);
267 assert(vm->chunk);
268 assert(vm->ip);
269 println("VM running...");
270 while (true) {
271 Instruction instruction = *vm->ip++;
272#if DEBUG == 1
273 print("IP: %d -> ", vm->ip - vm->chunk->code - 1);
274 disassemble_instruction(instruction);
275#endif
276
277 switch (instruction.op) {
278 case OP_LD64K: {
279 u8 dst = instruction.dst;
280 u8 src_a = instruction.a;
281 vm->regs[dst].i = vm->chunk->constants[src_a].i;
282 } break;
283 case OP_ADD: OP_ARITHMETIC(+, i) break;
284 case OP_SUB: OP_ARITHMETIC(-, i) break;
285 case OP_MUL: OP_ARITHMETIC(*, i) break;
286 case OP_DIV: OP_ARITHMETIC(/, i) break;
287 case OP_MOD: OP_ARITHMETIC(%, i) break;
288 case OP_ADDF: OP_ARITHMETIC(+, f) break;
289 case OP_SUBF: OP_ARITHMETIC(-, f) break;
290 case OP_MULF: OP_ARITHMETIC(*, f) break;
291 case OP_DIVF: OP_ARITHMETIC(/, f) break;
292 case OP_MODF: {
293 u8 dst = instruction.dst;
294 u8 src_a = instruction.a;
295 u8 src_b = instruction.b;
296 vm->regs[dst].f =
297 fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f);
298 } break;
299 case OP_HALT: {
300 println("VM HALT -> %d", vm->regs[instruction.dst]);
301 return;
302 }
303
304 default: {
305 eprintln("unimplemented OP code: %d", instruction.op);
306 return;
307 }
308 }
309 }
310}
311
312typedef enum {
313 COMP_CONST,
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, CHUNK, ARENA)
326
327CompResult
328compile_binary(OpCode op, Chunk *chunk, Node *node) {
329 sz reg_dst = chunk->reg_idx++;
330 CompResult comp_a = compile_expr(chunk, node->left);
331 CompResult comp_b = compile_expr(chunk, node->right);
332 sz reg_a;
333 sz reg_b;
334 switch (comp_a.type) {
335 case COMP_CONST: {
336 reg_a = chunk->reg_idx++;
337 Instruction inst =
338 (Instruction){.op = OP_LD64K, .dst = reg_a, .a = comp_a.idx};
339 array_push(chunk->code, inst, chunk->storage);
340 } break;
341 case COMP_REG: {
342 reg_a = comp_a.idx;
343 } break;
344 default: {
345 return (CompResult){.type = COMP_ERR};
346 } break;
347 }
348 switch (comp_b.type) {
349 case COMP_CONST: {
350 reg_b = chunk->reg_idx++;
351 Instruction inst =
352 (Instruction){.op = OP_LD64K, .dst = reg_b, .a = comp_b.idx};
353 array_push(chunk->code, inst, chunk->storage);
354 } break;
355 case COMP_REG: {
356 reg_b = comp_b.idx;
357 } break;
358 default: {
359 return (CompResult){.type = COMP_ERR};
360 } break;
361 }
362 Instruction inst =
363 (Instruction){.op = op, .dst = reg_dst, .a = reg_a, .b = reg_b};
364 array_push(chunk->code, inst, chunk->storage);
365 return (CompResult){.type = COMP_REG, .idx = reg_dst};
366}
367
368CompResult
369compile_expr(Chunk *chunk, Node *node) {
370 switch (node->kind) {
371 case NODE_ADD: return compile_binary(OP_ADD, chunk, node); break;
372 case NODE_SUB: return compile_binary(OP_SUB, chunk, node); break;
373 case NODE_MUL: return compile_binary(OP_MUL, chunk, node); break;
374 case NODE_DIV: return compile_binary(OP_DIV, chunk, node); break;
375 case NODE_MOD: return compile_binary(OP_MOD, chunk, node); break;
376 case NODE_NUM_FLOAT:
377 case NODE_NUM_INT: {
378 Constant c = (Constant){.i = node->value.i};
379 array_push(chunk->constants, c, chunk->storage);
380 return (CompResult){
381 .type = COMP_CONST,
382 .idx = chunk->const_idx++,
383 };
384 } break;
385 default: break;
386 }
387 return (CompResult){.type = COMP_ERR};
388}
389
390void 25void
391process_file(Str path) { 26process_file(Str path) {
392 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator); 27 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator);
393 28
394 FileContents file = platform_read_file(path, &lexer_arena); 29 FileContents file = platform_read_file(path, &lexer_arena);
395 if (file.err) { 30 if (file.err) {
396 eprintln("%s: error: %s", path, cstr("WOT")); 31 eprintln("%s: error: %s", path, cstr("couldn't read the file"));
397 exit(EXIT_FAILURE); 32 exit(EXIT_FAILURE);
398 } 33 }
399 sz errors = 0; 34 sz errors = 0;
@@ -432,7 +67,7 @@ process_file(Str path) {
432 while (parser.current.kind != TOK_EOF) { 67 while (parser.current.kind != TOK_EOF) {
433#if DEBUG == 1 68#if DEBUG == 1
434 static sz ctr = 0; 69 static sz ctr = 0;
435 println("parsing root: %d", ctr++); 70 println("ROOT: %d", ctr++);
436#endif 71#endif
437 parse_expr(&parser, PREC_LOW); 72 parse_expr(&parser, PREC_LOW);
438 if (parser.panic) { 73 if (parser.panic) {
@@ -451,44 +86,45 @@ process_file(Str path) {
451 // TODO: Type checking. 86 // TODO: Type checking.
452 87
453 // Compile roots. 88 // Compile roots.
454 Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); 89 // Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator);
455 Chunk chunk = {.file_name = path, .storage = &bytecode_arena}; 90 // Chunk chunk = {.file_name = path, .storage = &bytecode_arena};
456 array_zero(chunk.constants, 256, &bytecode_arena); 91 // array_zero(chunk.constants, 256, &bytecode_arena);
457 array_zero(chunk.code, 0xffff, &bytecode_arena); 92 // array_zero(chunk.code, 0xffff, &bytecode_arena);
458 sz n_roots = array_size(parser.nodes); 93 // sz n_roots = array_size(parser.nodes);
459 CompResult res; 94 // CompResult res;
460 for (sz i = 0; i < n_roots; i++) { 95 // for (sz i = 0; i < n_roots; i++) {
461 // The parser stores the root nodes as a stack. 96 // // The parser stores the root nodes as a stack.
462 Node *root = parser.nodes[i]; 97 // Node *root = parser.nodes[i];
463 res = compile_expr(&chunk, root); 98 // res = compile_expr(&chunk, root);
464 } 99 // }
465 sz res_reg = 0; 100 // sz res_reg = 0;
466 switch (res.type) { 101 // switch (res.type) {
467 case COMP_CONST: { 102 // case COMP_CONST: {
468 res_reg = chunk.reg_idx++; 103 // res_reg = chunk.reg_idx++;
469 Instruction inst = 104 // Instruction inst =
470 (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx}; 105 // (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx};
471 array_push(chunk.code, inst, chunk.storage); 106 // array_push(chunk.code, inst, chunk.storage);
472 } break; 107 // } break;
473 case COMP_REG: { 108 // case COMP_REG: {
474 res_reg = res.idx; 109 // res_reg = res.idx;
475 } break; 110 // } break;
476 default: break; 111 // default: break;
477 } 112 // }
478 // After we are done move the last result to r0 for printing. 113 // // After we are done move the last result to r0 for printing.
479 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg}; 114 // Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg};
480 array_push(chunk.code, halt, &bytecode_arena); 115 // array_push(chunk.code, halt, &bytecode_arena);
481 116
482 // Run bytecode on VM. 117 // // Run bytecode on VM.
483 VM vm = {0}; 118 // VM vm = {0};
484 vm_init(&vm, &chunk); 119 // vm_init(&vm, &chunk);
485 // println("VM REGISTERS BEFORE:\n%{Mem}", 120 // // println("VM REGISTERS BEFORE:\n%{Mem}",
121 // // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)});
122 // vm_run(&vm);
123 // println("VM REGISTERS AFTER:\n%{Mem}",
486 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); 124 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)});
487 vm_run(&vm); 125 // disassemble_chunk(chunk);
488 println("VM REGISTERS AFTER:\n%{Mem}",
489 &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)});
490 disassemble_chunk(chunk);
491 126
127 // arena_destroy(&bytecode_arena, os_allocator);
492stop: 128stop:
493 // Free up resources. 129 // Free up resources.
494 arena_destroy(&lexer_arena, os_allocator); 130 arena_destroy(&lexer_arena, os_allocator);