diff options
author | Bad Diode <bd@badd10de.dev> | 2024-07-01 16:45:07 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-07-01 16:45:07 +0200 |
commit | ce659ff12aab4931901386281d1c4c007e1f0b40 (patch) | |
tree | bb1f225e1d1341b1270a16b31c41512113024ca3 | |
parent | 593bb7d44082872e56b762fed374ad414245f4c2 (diff) | |
download | bdl-ce659ff12aab4931901386281d1c4c007e1f0b40.tar.gz bdl-ce659ff12aab4931901386281d1c4c007e1f0b40.zip |
Change jumps to be label based from backpatching
-rw-r--r-- | src/compiler.c | 151 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/vm.c | 46 | ||||
-rw-r--r-- | tests/compilation.bad | 6 | ||||
-rw-r--r-- | tests/fib.bad | 6 |
5 files changed, 126 insertions, 88 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 { | |||
25 | typedef union Constant { | 25 | typedef 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 { | |||
37 | typedef struct Chunk { | 37 | typedef 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 | ||
160 | Str op_str[] = { | 162 | Str 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 | ||
252 | typedef enum { | 253 | typedef enum { |
@@ -264,17 +265,21 @@ typedef struct CompResult { | |||
264 | 265 | ||
265 | CompResult compile_expr(Chunk *chunk, Node *node); | 266 | CompResult 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 | ||
280 | CompResult | 285 | CompResult |
@@ -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 | ||
561 | CompResult | 575 | CompResult |
562 | compile_while(Chunk *chunk, Node *node) { | 576 | compile_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 | ||
865 | void | 882 | void |
866 | disassemble_chunk(Chunk chunk) { | 883 | disassemble_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); |
@@ -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); |
@@ -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: { |
diff --git a/tests/compilation.bad b/tests/compilation.bad index 187d4ae..0f3b2d7 100644 --- a/tests/compilation.bad +++ b/tests/compilation.bad | |||
@@ -7,6 +7,12 @@ | |||
7 | 7 | ||
8 | ; a + b + c | 8 | ; a + b + c |
9 | 9 | ||
10 | ; let a = 1 | ||
11 | ; if false { | ||
12 | ; set a = 2 | ||
13 | ; } | ||
14 | ; a | ||
15 | |||
10 | ; if true { | 16 | ; if true { |
11 | ; 2 | 17 | ; 2 |
12 | ; } | 18 | ; } |
diff --git a/tests/fib.bad b/tests/fib.bad index 8eec0b8..ae7c729 100644 --- a/tests/fib.bad +++ b/tests/fib.bad | |||
@@ -1,6 +1,6 @@ | |||
1 | let n = 90 | 1 | let n = 1000 |
2 | let a = 0 | 2 | let a = 0.0 |
3 | let b = 1 | 3 | let b = 1.0 |
4 | let i = 0 | 4 | let i = 0 |
5 | while i < n { | 5 | while i < n { |
6 | let tmp = a + b | 6 | let tmp = a + b |