aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-07-01 16:45:07 +0200
committerBad Diode <bd@badd10de.dev>2024-07-01 16:45:07 +0200
commitce659ff12aab4931901386281d1c4c007e1f0b40 (patch)
treebb1f225e1d1341b1270a16b31c41512113024ca3 /src
parent593bb7d44082872e56b762fed374ad414245f4c2 (diff)
downloadbdl-ce659ff12aab4931901386281d1c4c007e1f0b40.tar.gz
bdl-ce659ff12aab4931901386281d1c4c007e1f0b40.zip
Change jumps to be label based from backpatching
Diffstat (limited to 'src')
-rw-r--r--src/compiler.c151
-rw-r--r--src/main.c5
-rw-r--r--src/vm.c46
3 files changed, 117 insertions, 85 deletions
diff --git a/src/compiler.c b/src/compiler.c
index ea9234a..4c6a946 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -25,7 +25,7 @@ typedef struct Instruction {
25typedef union Constant { 25typedef union Constant {
26 s64 i; 26 s64 i;
27 u64 u; 27 u64 u;
28 double f; 28 f64 f;
29 ptrsize ptr; 29 ptrsize ptr;
30} Constant; 30} Constant;
31 31
@@ -37,6 +37,9 @@ typedef struct LineCol {
37typedef struct Chunk { 37typedef struct Chunk {
38 sz id; 38 sz id;
39 Instruction *code; 39 Instruction *code;
40 IntIntMap *labels; // label -> chunk_index
41 IntIntMap *labels_rev; // chunk_index -> label
42 sz labels_idx;
40 43
41 // Constant values that fit in 64 bits. 44 // Constant values that fit in 64 bits.
42 Constant *constants; 45 Constant *constants;
@@ -149,12 +152,11 @@ typedef enum OpCode {
149 OP_BITOR, // bor rx, ra, rb 152 OP_BITOR, // bor rx, ra, rb
150 OP_BITNOT, // bnot rx, ra 153 OP_BITNOT, // bnot rx, ra
151 // Jump instructions. 154 // Jump instructions.
152 OP_JMPI, // jmp cx ; cx := signed offset 155 OP_JMP, // jmp lx ; jmp to label lx
153 OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset 156 OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false
154 OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset 157 OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true
155 OP_JMP, // jmp rx ; rx := signed offset 158 OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false
156 OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset 159 OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true
157 OP_JMPT, // jmpt rx, ca ; rx := condition, ca := offset
158} OpCode; 160} OpCode;
159 161
160Str op_str[] = { 162Str op_str[] = {
@@ -241,12 +243,11 @@ Str op_str[] = {
241 [OP_BITOR] = cstr("BOR "), 243 [OP_BITOR] = cstr("BOR "),
242 [OP_BITNOT] = cstr("BNOT "), 244 [OP_BITNOT] = cstr("BNOT "),
243 // Jump instructions. 245 // Jump instructions.
244 [OP_JMPI] = cstr("JMPI "),
245 [OP_JMPFI] = cstr("JMPFI "),
246 [OP_JMPTI] = cstr("JMPTI "),
247 [OP_JMP] = cstr("JMP "), 246 [OP_JMP] = cstr("JMP "),
248 [OP_JMPF] = cstr("JMPF "), 247 [OP_JMPF] = cstr("JMPF "),
249 [OP_JMPT] = cstr("JMPT "), 248 [OP_JMPT] = cstr("JMPT "),
249 [OP_JMPFI] = cstr("JMPFI "),
250 [OP_JMPTI] = cstr("JMPTI "),
250}; 251};
251 252
252typedef enum { 253typedef enum {
@@ -264,17 +265,21 @@ typedef struct CompResult {
264 265
265CompResult compile_expr(Chunk *chunk, Node *node); 266CompResult compile_expr(Chunk *chunk, Node *node);
266 267
267#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 268#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \
268 do { \ 269 do { \
269 Instruction inst = (Instruction){ \ 270 Instruction inst = (Instruction){ \
270 .op = (OP), \ 271 .op = (OP), \
271 .dst = (DST), \ 272 .dst = (DST), \
272 .a = (A), \ 273 .a = (A), \
273 .b = (B), \ 274 .b = (B), \
274 }; \ 275 }; \
275 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 276 array_push((CHUNK)->code, inst, (CHUNK)->storage); \
276 LineCol linecol = (LineCol){.line = (NODE)->line, .col = (NODE)->col}; \ 277 LineCol linecol = (LineCol){0}; \
277 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ 278 if (NODE) { \
279 Node *_node = (NODE); \
280 linecol = (LineCol){.line = _node->line, .col = _node->col}; \
281 } \
282 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \
278 } while (0) 283 } while (0)
279 284
280CompResult 285CompResult
@@ -476,7 +481,6 @@ compile_if(Chunk *chunk, Node *node) {
476 return (CompResult){.type = COMP_ERR}; 481 return (CompResult){.type = COMP_ERR};
477 } break; 482 } break;
478 } 483 }
479 sz jump_a = array_size(chunk->code);
480 sz reg_dst = 255; 484 sz reg_dst = 255;
481 bool has_value = !str_eq(node->type, cstr("nil")); 485 bool has_value = !str_eq(node->type, cstr("nil"));
482 if (has_value) { 486 if (has_value) {
@@ -484,7 +488,8 @@ compile_if(Chunk *chunk, Node *node) {
484 } 488 }
485 489
486 // Jump to the `false` branch. 490 // Jump to the `false` branch.
487 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk); 491 sz lab0 = chunk->labels_idx++;
492 EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk);
488 493
489 // Condition is true. 494 // Condition is true.
490 CompResult then_expr = compile_expr(chunk, node->cond_expr); 495 CompResult then_expr = compile_expr(chunk, node->cond_expr);
@@ -506,8 +511,9 @@ compile_if(Chunk *chunk, Node *node) {
506 511
507 if (node->cond_else) { 512 if (node->cond_else) {
508 // Jump to the end of the expression. 513 // Jump to the end of the expression.
509 sz jump_b = array_size(chunk->code); 514 sz pos0 = array_size(chunk->code);
510 EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_else, chunk); 515 sz lab1 = chunk->labels_idx++;
516 EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk);
511 517
512 // Else expression. 518 // Else expression.
513 CompResult else_expr = compile_expr(chunk, node->cond_else); 519 CompResult else_expr = compile_expr(chunk, node->cond_else);
@@ -526,25 +532,33 @@ compile_if(Chunk *chunk, Node *node) {
526 } break; 532 } break;
527 } 533 }
528 } 534 }
529 sz end_expr = array_size(chunk->code); 535 sz pos1 = array_size(chunk->code);
530 536
531 // Backpatch jumps. 537 // Update labels.
532 sz const_a = add_constant(chunk, jump_b + 1 - jump_a); 538 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
533 sz const_b = add_constant(chunk, end_expr - jump_b); 539 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
534 chunk->code[jump_a].a = const_a; 540 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage);
535 chunk->code[jump_b].dst = const_b; 541 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
536 } else { 542 } else {
537 sz end_expr = array_size(chunk->code);
538 if (has_value) { 543 if (has_value) {
539 sz const_a = add_constant(chunk, end_expr + 1 - jump_a);
540 chunk->code[jump_a].a = const_a;
541 sz zero = add_constant(chunk, 0); 544 sz zero = add_constant(chunk, 0);
542 sz end = add_constant(chunk, 2); 545 sz lab1 = chunk->labels_idx++;
543 EMIT_OP(OP_JMPI, end, 0, 0, node, chunk); 546 EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk);
547 sz pos0 = array_size(chunk->code);
544 EMIT_OP(OP_LD64K, reg_dst, zero, 0, node, chunk); 548 EMIT_OP(OP_LD64K, reg_dst, zero, 0, node, chunk);
549 sz pos1 = array_size(chunk->code);
550
551 // Update labels.
552 intintmap_insert(&chunk->labels, lab0, pos0, chunk->storage);
553 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
554 intintmap_insert(&chunk->labels_rev, pos0, lab0, chunk->storage);
555 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
545 } else { 556 } else {
546 sz const_a = add_constant(chunk, end_expr - jump_a); 557 sz pos0 = array_size(chunk->code);
547 chunk->code[jump_a].a = const_a; 558
559 // Update labels.
560 intintmap_insert(&chunk->labels, lab0, pos0, chunk->storage);
561 intintmap_insert(&chunk->labels_rev, pos0, lab0, chunk->storage);
548 } 562 }
549 } 563 }
550 // TODO: does it has an else or not? Moreover, should we enforce on the 564 // TODO: does it has an else or not? Moreover, should we enforce on the
@@ -560,7 +574,7 @@ compile_if(Chunk *chunk, Node *node) {
560 574
561CompResult 575CompResult
562compile_while(Chunk *chunk, Node *node) { 576compile_while(Chunk *chunk, Node *node) {
563 sz start = array_size(chunk->code); 577 sz pos1 = array_size(chunk->code);
564 CompResult cond = compile_expr(chunk, node->while_cond); 578 CompResult cond = compile_expr(chunk, node->while_cond);
565 OpCode jmpop; 579 OpCode jmpop;
566 switch (cond.type) { 580 switch (cond.type) {
@@ -574,18 +588,22 @@ compile_while(Chunk *chunk, Node *node) {
574 return (CompResult){.type = COMP_ERR}; 588 return (CompResult){.type = COMP_ERR};
575 } break; 589 } break;
576 } 590 }
577 sz jump_a = array_size(chunk->code);
578 591
579 // Jump to the `end of the loop` branch. 592 // Jump to the `end of the loop` branch.
580 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->while_cond, chunk); 593 sz lab0 = chunk->labels_idx++;
594 EMIT_OP(jmpop, lab0, cond.idx, 0, node->while_cond, chunk);
581 595
582 // Condition is true. 596 // Condition is true.
583 CompResult then_expr = compile_expr(chunk, node->while_expr); 597 compile_expr(chunk, node->while_expr);
584 sz end_expr = array_size(chunk->code); 598 sz pos0 = array_size(chunk->code);
585 sz loopback = add_constant(chunk, (start - end_expr)); 599 sz lab1 = chunk->labels_idx++;
586 EMIT_OP(OP_JMPI, loopback, 0, 0, node, chunk); 600 EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk);
587 sz const_a = add_constant(chunk, end_expr - jump_a + 1); 601
588 chunk->code[jump_a].a = const_a; 602 // Update labels.
603 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
604 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
605 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage);
606 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
589 607
590 // Return. 608 // Return.
591 return (CompResult){.type = COMP_NIL}; 609 return (CompResult){.type = COMP_NIL};
@@ -747,12 +765,15 @@ disassemble_instruction(Instruction instruction) {
747 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 765 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
748 instruction.a, instruction.b); 766 instruction.a, instruction.b);
749 break; 767 break;
768 case OP_JMPF:
769 case OP_JMPT:
770 println("%s l%d, r%d", op_str[instruction.op], instruction.dst,
771 instruction.a, instruction.b);
772 break;
750 case OP_LD8K: 773 case OP_LD8K:
751 case OP_LD16K: 774 case OP_LD16K:
752 case OP_LD32K: 775 case OP_LD32K:
753 case OP_LD64K: 776 case OP_LD64K:
754 case OP_JMPF:
755 case OP_JMPT:
756 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 777 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
757 instruction.a, instruction.b); 778 instruction.a, instruction.b);
758 break; 779 break;
@@ -844,17 +865,13 @@ disassemble_instruction(Instruction instruction) {
844 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 865 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
845 instruction.a, instruction.b); 866 instruction.a, instruction.b);
846 break; 867 break;
847 case OP_JMPI:
848 println("%s c%d", op_str[instruction.op], instruction.dst,
849 instruction.a, instruction.b);
850 break;
851 case OP_JMP: 868 case OP_JMP:
852 println("%s r%d", op_str[instruction.op], instruction.dst, 869 println("%s l%d", op_str[instruction.op], instruction.dst,
853 instruction.a, instruction.b); 870 instruction.a, instruction.b);
854 break; 871 break;
855 case OP_JMPFI: 872 case OP_JMPFI:
856 case OP_JMPTI: 873 case OP_JMPTI:
857 println("%s c%d, c%d", op_str[instruction.op], instruction.dst, 874 println("%s l%d, c%d", op_str[instruction.op], instruction.dst,
858 instruction.a, instruction.b); 875 instruction.a, instruction.b);
859 break; 876 break;
860 case OP_HALT: println("%s", op_str[instruction.op]); break; 877 case OP_HALT: println("%s", op_str[instruction.op]); break;
@@ -864,26 +881,39 @@ disassemble_instruction(Instruction instruction) {
864 881
865void 882void
866disassemble_chunk(Chunk chunk) { 883disassemble_chunk(Chunk chunk) {
867 println("%s: ============== code ==============", chunk.file_name); 884 println("%s: ================== code ==================", chunk.file_name);
885 println("%s: LINE:COL INUM LABELS OP OPERANDS ", chunk.file_name);
886 println("%s: ------------------------------------------", chunk.file_name);
868 for (sz i = 0; i < array_size(chunk.code); i++) { 887 for (sz i = 0; i < array_size(chunk.code); i++) {
869 print("%s: %x{4}: ", chunk.file_name, i); 888 print("%s:", chunk.file_name);
889 printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line,
890 chunk.linecol[i].col, i);
891 IntIntMap *label = intintmap_lookup(&chunk.labels_rev, i);
892 if (label) {
893 printf(".L%.2ld ", label->val);
894 } else {
895 printf(" %2s ", "");
896 }
870 disassemble_instruction(chunk.code[i]); 897 disassemble_instruction(chunk.code[i]);
871 } 898 }
872 if (array_size(chunk.constants) > 0) { 899 if (array_size(chunk.constants) > 0) {
873 println("%s: ============ constants ===========", chunk.file_name); 900 println("%s: ================ constants ===============",
901 chunk.file_name);
874 for (sz i = 0; i < array_size(chunk.constants); i++) { 902 for (sz i = 0; i < array_size(chunk.constants); i++) {
875 println("%s: %x{2}: %x{8}", chunk.file_name, i, 903 println("%s: %x{2}: %x{8}", chunk.file_name, i,
876 chunk.constants[i]); 904 chunk.constants[i]);
877 } 905 }
878 } 906 }
879 if (array_size(chunk.strings) > 0) { 907 if (array_size(chunk.strings) > 0) {
880 println("%s: ============= strings ============", chunk.file_name); 908 println("%s: ================= strings ================",
909 chunk.file_name);
881 for (sz i = 0; i < array_size(chunk.strings); i++) { 910 for (sz i = 0; i < array_size(chunk.strings); i++) {
882 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 911 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]);
883 } 912 }
884 } 913 }
885 if (array_size(chunk.vars) > 0) { 914 if (array_size(chunk.vars) > 0) {
886 println("%s: ============ variables ===========", chunk.file_name); 915 println("%s: ================ variables ===============",
916 chunk.file_name);
887 for (sz i = 0; i < array_size(chunk.vars); i++) { 917 for (sz i = 0; i < array_size(chunk.vars); i++) {
888 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, 918 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i,
889 chunk.vars[i].offset, 919 chunk.vars[i].offset,
@@ -891,6 +921,7 @@ disassemble_chunk(Chunk chunk) {
891 chunk.vars[i].name, chunk.vars[i].type); 921 chunk.vars[i].name, chunk.vars[i].type);
892 } 922 }
893 } 923 }
924 println("%s: ==========================================", chunk.file_name);
894 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 925 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d",
895 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 926 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx,
896 chunk.const_idx); 927 chunk.const_idx);
diff --git a/src/main.c b/src/main.c
index 0e453c6..5e5775e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -181,6 +181,7 @@ process_file(Str path) {
181 exit(EXIT_FAILURE); 181 exit(EXIT_FAILURE);
182 } 182 }
183 } 183 }
184 // Make sure the last result is on r0.
184 sz res_reg = 0; 185 sz res_reg = 0;
185 switch (res.type) { 186 switch (res.type) {
186 case COMP_CONST: { 187 case COMP_CONST: {
@@ -194,9 +195,7 @@ process_file(Str path) {
194 } break; 195 } break;
195 default: break; 196 default: break;
196 } 197 }
197 // After we are done move the last result to r0 for printing. 198 EMIT_OP(OP_HALT, res_reg, 0, 0, NULL, &chunk);
198 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg};
199 array_push(chunk.code, halt, &bytecode_arena);
200 199
201 if (chunk.const_idx >= 256) { 200 if (chunk.const_idx >= 256) {
202 eprintln("too many constants on chunk %s", chunk.id); 201 eprintln("too many constants on chunk %s", chunk.id);
diff --git a/src/vm.c b/src/vm.c
index 205c15a..52f5476 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -155,40 +155,41 @@ vm_run(VM *vm) {
155 s64 *stack = (s64 *)&vm->stack[var.offset]; 155 s64 *stack = (s64 *)&vm->stack[var.offset];
156 *stack = vm->chunk->constants[src].i; 156 *stack = vm->chunk->constants[src].i;
157 } break; 157 } break;
158 case OP_JMPI: { 158 case OP_JMP: {
159 sz offset = vm->chunk->constants[instruction.dst].i; 159 u8 dst = instruction.dst;
160 vm->ip += offset - 1; 160 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
161 vm->ip = vm->chunk->code + pos;
161 } break; 162 } break;
162 case OP_JMPFI: { 163 case OP_JMPFI: {
163 bool cond = vm->chunk->constants[instruction.dst].i; 164 u8 dst = instruction.dst;
164 sz offset = vm->chunk->constants[instruction.a].i; 165 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
166 bool cond = vm->chunk->constants[instruction.a].i;
165 if (!cond) { 167 if (!cond) {
166 vm->ip += offset - 1; 168 vm->ip = vm->chunk->code + pos;
167 } 169 }
168 } break; 170 } break;
169 case OP_JMPTI: { 171 case OP_JMPTI: {
170 bool cond = vm->chunk->constants[instruction.dst].i; 172 u8 dst = instruction.dst;
171 sz offset = vm->chunk->constants[instruction.a].i; 173 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
174 bool cond = vm->chunk->constants[instruction.a].i;
172 if (cond) { 175 if (cond) {
173 vm->ip += offset - 1; 176 vm->ip = vm->chunk->code + pos;
174 } 177 }
175 } break; 178 } break;
176 case OP_JMP: {
177 sz offset = vm->chunk->constants[instruction.dst].i;
178 vm->ip += offset - 1;
179 } break;
180 case OP_JMPF: { 179 case OP_JMPF: {
181 bool cond = vm->regs[instruction.dst].i; 180 u8 dst = instruction.dst;
182 sz offset = vm->chunk->constants[instruction.a].i; 181 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
182 bool cond = vm->regs[instruction.a].i;
183 if (!cond) { 183 if (!cond) {
184 vm->ip += offset - 1; 184 vm->ip = vm->chunk->code + pos;
185 } 185 }
186 } break; 186 } break;
187 case OP_JMPT: { 187 case OP_JMPT: {
188 bool cond = vm->regs[instruction.dst].i; 188 u8 dst = instruction.dst;
189 sz offset = vm->chunk->constants[instruction.a].i; 189 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
190 bool cond = vm->regs[instruction.a].i;
190 if (cond) { 191 if (cond) {
191 vm->ip += offset - 1; 192 vm->ip = vm->chunk->code + pos;
192 } 193 }
193 } break; 194 } break;
194 case OP_MOV64: { 195 case OP_MOV64: {
@@ -212,9 +213,10 @@ vm_run(VM *vm) {
212 vm->regs[dst].i = vm->regs[src].i & 0xFF; 213 vm->regs[dst].i = vm->regs[src].i & 0xFF;
213 } break; 214 } break;
214 case OP_HALT: { 215 case OP_HALT: {
215 println("VM HALT (int) -> %d", vm->regs[instruction.dst]); 216 Constant result = vm->regs[instruction.dst];
216 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 217 printf("VM HALT (int) -> %lld\n", result.i);
217 println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); 218 printf("VM HALT (float) -> %.10e\n", result.f);
219 printf("VM HALT (hex) -> %llx\n", (u64)result.i);
218 return; 220 return;
219 } 221 }
220 default: { 222 default: {