aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-07-02 23:23:57 +0200
committerBad Diode <bd@badd10de.dev>2024-07-02 23:23:57 +0200
commit203e955a38fbb1321571444463eeac8ab2d31437 (patch)
tree4931f7586ea674a89ec8cd3353d7a20fcaef855c
parent3b37ecc2357251b99d8b99b3532cff343ece6971 (diff)
downloadbdl-203e955a38fbb1321571444463eeac8ab2d31437.tar.gz
bdl-203e955a38fbb1321571444463eeac8ab2d31437.zip
Change AR layout
-rw-r--r--src/compiler.c90
-rw-r--r--src/vm.c70
-rw-r--r--tests/compilation.bad18
3 files changed, 131 insertions, 47 deletions
diff --git a/src/compiler.c b/src/compiler.c
index d1c56b3..9b6a458 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -96,8 +96,11 @@ typedef enum OpCode {
96 OP_CALL, // call fx ; Bumps the stack pointer by cx 96 OP_CALL, // call fx ; Bumps the stack pointer by cx
97 OP_RET, // ret ; Returns from current function 97 OP_RET, // ret ; Returns from current function
98 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes 98 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes
99 OP_POP, // pop cx ; Decrements the stack pointer by cx bytes 99 OP_POP, // pop rx ; Pops the last value of the stack into rx.
100 OP_SPVAL, // val rx, cx ; u64 *stack; rx = stack[cx] 100 OP_PUSH, // push rx ; Push the rx value to the stack.
101 OP_PUSHI, // pushi cx ; Push the cx value to the stack.
102 OP_PUTRET, // putret rx ; Put rx into the return value memory.
103 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
101 // Printing values with builtin print/println functions. 104 // Printing values with builtin print/println functions.
102 OP_PRINTSTR, // p rx 105 OP_PRINTSTR, // p rx
103 OP_PRINTS64, // p rx 106 OP_PRINTS64, // p rx
@@ -202,12 +205,15 @@ Str op_str[] = {
202 [OP_PRINTF64] = cstr("PRNTF64 "), 205 [OP_PRINTF64] = cstr("PRNTF64 "),
203 [OP_PRINTS64I] = cstr("PRNTS64I"), 206 [OP_PRINTS64I] = cstr("PRNTS64I"),
204 [OP_PRINTF64I] = cstr("PRNTF64I"), 207 [OP_PRINTF64I] = cstr("PRNTF64I"),
208 [OP_PUTRET] = cstr("PUTRET "),
209 [OP_PUTRETI] = cstr("PUTRETI "),
205 // Functions. 210 // Functions.
206 [OP_CALL] = cstr("CALL "), 211 [OP_CALL] = cstr("CALL "),
207 [OP_RET] = cstr("RET "), 212 [OP_RET] = cstr("RET "),
208 [OP_RESERVE] = cstr("RESERVE "), 213 [OP_RESERVE] = cstr("RESERVE "),
209 [OP_POP] = cstr("POP "), 214 [OP_POP] = cstr("POP "),
210 [OP_SPVAL] = cstr("SPVAL "), 215 [OP_PUSH] = cstr("PUSH "),
216 [OP_PUSHI] = cstr("PUSHI "),
211 // Load ops. 217 // Load ops.
212 [OP_LD8K] = cstr("LD8K "), 218 [OP_LD8K] = cstr("LD8K "),
213 [OP_LD16K] = cstr("LD16K "), 219 [OP_LD16K] = cstr("LD16K "),
@@ -831,33 +837,57 @@ compile_funcall(Chunk *chunk, Node *node) {
831 } 837 }
832 Function fun = map->val; 838 Function fun = map->val;
833 839
834 // TODO: prologue (how much space do we actually need)? we need the symbol 840 // Reserve space for the return value if needed.
835 // table, arity and return parameters boy. 841 if (fun.return_arity > 0) {
836 // FIXME: assuming all values are 8 bytes for now... 842 // Put the return data into a register
837 sz alloc_size = (fun.param_arity + fun.return_arity) * 8; 843 sz ret_size = add_constant(chunk, 8);
838 sz alloc_const = add_constant(chunk, alloc_size); 844 EMIT_OP(OP_RESERVE, ret_size, 0, 0, node, chunk);
839 if (alloc_size > 0) { 845 }
840 EMIT_OP(OP_RESERVE, alloc_const, 0, 0, node, chunk); 846
847 // Send parameters to the stack.
848 for (sz i = 0; i < array_size(node->elements); i++) {
849 Node *expr = node->elements[i];
850 CompResult result = compile_expr(chunk, expr);
851 // TODO: Assuming all values are 8 bytes... again.
852 switch (result.type) {
853 case COMP_CONST: {
854 EMIT_OP(OP_PUSHI, result.idx, 0, 0, expr, chunk);
855 } break;
856 case COMP_REG: {
857 EMIT_OP(OP_PUSH, result.idx, 0, 0, expr, chunk);
858 } break;
859 default: {
860 return (CompResult){.type = COMP_ERR};
861 } break;
862 }
841 } 863 }
842 864
843 // println("FUNCALL: unique name: %s", node->unique_name); 865 // // TODO: prologue (how much space do we actually need)? we need the
844 // println("FUN: param_arity: %d", fun.param_arity); 866 // symbol
845 // println("FUN: return_arity: %d", fun.return_arity); 867 // // table, arity and return parameters boy.
868 // // FIXME: assuming all values are 8 bytes for now...
869 // sz alloc_size = (fun.param_arity + fun.return_arity) * 8;
870 // sz alloc_const = add_constant(chunk, alloc_size);
871 // if (alloc_size > 0) {
872 // // EMIT_OP(OP_RESERVE, alloc_const, 0, 0, node, chunk);
873 // }
874
875 // // println("FUNCALL: unique name: %s", node->unique_name);
876 // // println("FUN: param_arity: %d", fun.param_arity);
877 // // println("FUN: return_arity: %d", fun.return_arity);
846 EMIT_OP(OP_CALL, fun.index, 0, 0, node, chunk); 878 EMIT_OP(OP_CALL, fun.index, 0, 0, node, chunk);
847 879
848 // Only one return parameter for now. 880 // Only one return parameter for now.
849 if (fun.return_arity > 0) { 881 if (fun.return_arity > 0) {
850 // Put the return data into a register 882 // Put the return data into a register
851 sz reg_dst = chunk->reg_idx++; 883 sz reg_dst = chunk->reg_idx++;
852 sz ret_offset = add_constant(chunk, -fun.return_arity); 884 EMIT_OP(OP_POP, reg_dst, 0, 0, node, chunk);
853 EMIT_OP(OP_SPVAL, reg_dst, ret_offset, 0, node, chunk);
854 EMIT_OP(OP_POP, alloc_const, 0, 0, node, chunk);
855 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 885 return (CompResult){.type = COMP_REG, .idx = reg_dst};
856 } 886 }
857 887
858 if (alloc_size > 0) { 888 // if (alloc_size > 0) {
859 EMIT_OP(OP_POP, alloc_const, 0, 0, node, chunk); 889 // // EMIT_OP(OP_POP, alloc_const, 0, 0, node, chunk);
860 } 890 // }
861 // TODO: epilogue (how much space do we actually need)? we need to remove 891 // TODO: epilogue (how much space do we actually need)? we need to remove
862 // the AR data here after using it. If we only have one return parameter we 892 // the AR data here after using it. If we only have one return parameter we
863 // can put it in a register but what if that's not actually the case? 893 // can put it in a register but what if that's not actually the case?
@@ -887,8 +917,19 @@ compile_function(Chunk *chunk, Node *node) {
887 }; 917 };
888 funcmap_insert(&chunk->funmap, func->name, fun, chunk->storage); 918 funcmap_insert(&chunk->funmap, func->name, fun, chunk->storage);
889 array_push(chunk->functions, func, chunk->storage); 919 array_push(chunk->functions, func, chunk->storage);
890 // TODO: put return values into memory. 920
891 compile_expr(func, node->func_body); 921 // Put return values into memory.
922 CompResult res = compile_expr(func, node->func_body);
923 switch (res.type) {
924 case COMP_CONST: {
925 EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, func);
926 } break;
927 case COMP_REG: {
928 EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, func);
929 } break;
930 default: break;
931 }
932
892 // TODO: handle captured locals/globals? 933 // TODO: handle captured locals/globals?
893 EMIT_OP(OP_RET, 0, 0, 0, node, func); 934 EMIT_OP(OP_RET, 0, 0, 0, node, func);
894 return (CompResult){.type = COMP_NIL}; 935 return (CompResult){.type = COMP_NIL};
@@ -1159,7 +1200,6 @@ disassemble_instruction(Instruction instruction) {
1159 case OP_LD16K: 1200 case OP_LD16K:
1160 case OP_LD32K: 1201 case OP_LD32K:
1161 case OP_LD64K: 1202 case OP_LD64K:
1162 case OP_SPVAL:
1163 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 1203 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
1164 instruction.a, instruction.b); 1204 instruction.a, instruction.b);
1165 break; 1205 break;
@@ -1264,13 +1304,17 @@ disassemble_instruction(Instruction instruction) {
1264 case OP_PRINTS64: 1304 case OP_PRINTS64:
1265 case OP_PRINTF64: 1305 case OP_PRINTF64:
1266 case OP_PRINTSTR: 1306 case OP_PRINTSTR:
1307 case OP_PUSH:
1308 case OP_POP:
1309 case OP_PUTRET:
1267 println("%s r%d", op_str[instruction.op], instruction.dst, 1310 println("%s r%d", op_str[instruction.op], instruction.dst,
1268 instruction.a, instruction.b); 1311 instruction.a, instruction.b);
1269 break; 1312 break;
1270 case OP_PRINTS64I: 1313 case OP_PRINTS64I:
1271 case OP_PRINTF64I: 1314 case OP_PRINTF64I:
1272 case OP_RESERVE: 1315 case OP_RESERVE:
1273 case OP_POP: 1316 case OP_PUSHI:
1317 case OP_PUTRETI:
1274 println("%s c%d", op_str[instruction.op], instruction.dst, 1318 println("%s c%d", op_str[instruction.op], instruction.dst,
1275 instruction.a, instruction.b); 1319 instruction.a, instruction.b);
1276 break; 1320 break;
diff --git a/src/vm.c b/src/vm.c
index 72887ea..2992a18 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -11,6 +11,7 @@ typedef struct VM {
11 u8 stack[STACK_SIZE]; 11 u8 stack[STACK_SIZE];
12 Instruction *ip; 12 Instruction *ip;
13 u8 *sp; 13 u8 *sp;
14 u64 *fp;
14 Constant *regs; 15 Constant *regs;
15} VM; 16} VM;
16 17
@@ -21,6 +22,7 @@ vm_init(VM *vm, Chunk *chunk) {
21 assert(chunk->code); 22 assert(chunk->code);
22 vm->chunk = chunk; 23 vm->chunk = chunk;
23 vm->ip = vm->chunk->code; 24 vm->ip = vm->chunk->code;
25 vm->fp = (u64 *)vm->stack;
24 vm->sp = vm->stack + chunk->var_off; 26 vm->sp = vm->stack + chunk->var_off;
25 vm->regs = (Constant *)vm->sp; 27 vm->regs = (Constant *)vm->sp;
26 vm->sp += sizeof(Constant) * chunk->reg_idx; 28 vm->sp += sizeof(Constant) * chunk->reg_idx;
@@ -266,49 +268,81 @@ vm_run(VM *vm) {
266 Str string = vm->chunk->strings[idx]; 268 Str string = vm->chunk->strings[idx];
267 print("%s", string); 269 print("%s", string);
268 } break; 270 } break;
271 case OP_RESERVE: {
272 sz offset = vm->chunk->constants[instruction.dst].i;
273 vm->sp += offset;
274 } break;
275 case OP_PUSH: {
276 sz val = vm->regs[instruction.dst].i;
277 u64 *p = (u64 *)vm->sp;
278 *p = val;
279 vm->sp += sizeof(ptrsize);
280 } break;
281 case OP_PUSHI: {
282 sz val = vm->chunk->constants[instruction.dst].i;
283 u64 *p = (u64 *)vm->sp;
284 *p = val;
285 vm->sp += sizeof(ptrsize);
286 } break;
287 case OP_POP: {
288 vm->sp -= sizeof(ptrsize);
289 u64 *p = (u64 *)vm->sp;
290 vm->regs[instruction.dst].i = *p;
291 } break;
292 case OP_PUTRET: {
293 sz val = vm->regs[instruction.dst].i;
294 vm->fp[-1] = val;
295 } break;
296 case OP_PUTRETI: {
297 sz val = vm->chunk->constants[instruction.dst].i;
298 vm->fp[-1] = val;
299 } break;
269 case OP_CALL: { 300 case OP_CALL: {
270 u8 dst = instruction.dst; 301 u8 dst = instruction.dst;
271 Chunk *func = vm->chunk->functions[dst]; 302 Chunk *func = vm->chunk->functions[dst];
272 303
273 // Store memory addresses we need to return to this function.
274 ptrsize chunk_addr = (ptrsize)vm->chunk; 304 ptrsize chunk_addr = (ptrsize)vm->chunk;
275 ptrsize ip_addr = (ptrsize)vm->ip; 305 ptrsize ip_addr = (ptrsize)vm->ip;
276 ptrsize reg_addr = (ptrsize)vm->regs; 306 ptrsize reg_addr = (ptrsize)vm->regs;
277 u64 *p = (u64 *)vm->sp; 307 ptrsize old_fp = (ptrsize)vm->fp;
278 p[0] = chunk_addr;
279 p[1] = ip_addr;
280 p[2] = reg_addr;
281 vm->sp += sizeof(ptrsize);
282 vm->sp += sizeof(ptrsize);
283 vm->sp += sizeof(ptrsize);
284 308
285 // Allocate space for the locals. 309 // Allocate space for the locals.
286 vm->sp += func->var_off; 310 vm->fp = (u64 *)vm->sp;
311 vm->sp += func->var_off; // FIXME: - func->n_params!
287 vm->chunk = func; 312 vm->chunk = func;
288 vm->ip = func->code; 313 vm->ip = func->code;
289 vm->regs = (Constant *)vm->sp; 314 vm->regs = (Constant *)vm->sp;
290 315
291 // Allocate registers. 316 // Allocate registers.
292 vm->sp += sizeof(Constant) * func->reg_idx; 317 vm->sp += sizeof(Constant) * func->reg_idx;
318
319 // Store memory addresses we need to return to this function.
320 u64 *p = (u64 *)vm->sp;
321 p[0] = chunk_addr;
322 p[1] = ip_addr;
323 p[2] = reg_addr;
324 p[3] = old_fp;
325 vm->sp += sizeof(ptrsize) * 4;
293 } break; 326 } break;
294 case OP_RET: { 327 case OP_RET: {
295 // Deallocate locals. 328 u64 *p = (u64 *)vm->sp;
296 vm->sp -= vm->chunk->var_off; 329 ptrsize chunk_addr = p[-4];
330 ptrsize ip_addr = p[-3];
331 ptrsize reg_addr = p[-2];
332 ptrsize old_fp = p[-1];
333 vm->sp -= sizeof(ptrsize) * 4;
297 334
298 // Deallocate registers. 335 // Deallocate registers.
299 vm->sp -= sizeof(Constant) * vm->chunk->reg_idx; 336 vm->sp -= sizeof(Constant) * vm->chunk->reg_idx;
300 337
338 // Deallocate locals.
339 vm->sp -= vm->chunk->var_off;
340
301 // Restore previous activation record. 341 // Restore previous activation record.
302 u64 *p = (u64 *)vm->sp;
303 ptrsize chunk_addr = p[-3];
304 ptrsize ip_addr = p[-2];
305 ptrsize reg_addr = p[-1];
306 vm->sp -= sizeof(ptrsize);
307 vm->sp -= sizeof(ptrsize);
308 vm->sp -= sizeof(ptrsize);
309 vm->regs = (Constant *)reg_addr; 342 vm->regs = (Constant *)reg_addr;
310 vm->ip = (Instruction *)ip_addr; 343 vm->ip = (Instruction *)ip_addr;
311 vm->chunk = (Chunk *)chunk_addr; 344 vm->chunk = (Chunk *)chunk_addr;
345 vm->fp = (u64 *)old_fp;
312 } break; 346 } break;
313 case OP_HALT: { 347 case OP_HALT: {
314 println("VM halt..."); 348 println("VM halt...");
diff --git a/tests/compilation.bad b/tests/compilation.bad
index c0da031..ea467d2 100644
--- a/tests/compilation.bad
+++ b/tests/compilation.bad
@@ -1,15 +1,21 @@
1fun adder(a: int): int {
2 ; a + 1
3 4
4}
5adder(2)
1; let a = 1 6; let a = 1
2; let b = 8 7; let b = 8
3 8
4; a + b 9; a + b
5; 1 + 2 10; 1 + 2
6fun greet(): nil { 11; fun greet(name: str): nil {
7 println("hello world") 12; fun greet(name: str): nil {
8 ; 7 13; println("hello ")
9} 14; }
10 15
11greet() 16; greet("alex")
12greet() 17; greet("ding")
18; greet()
13; if true { 19; if true {
14; 1 20; 1
15; nil 21; nil