diff options
author | Bad Diode <bd@badd10de.dev> | 2021-12-30 16:07:41 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-12-30 16:07:41 +0100 |
commit | 082764ad89c1b9613b6894d6593dee66041a5e54 (patch) | |
tree | 60700473f43e9b932d17e6be34973f331434f2d9 | |
parent | e8a30ba744982f1f00db6a962bd849ef53514bff (diff) | |
download | bdl-082764ad89c1b9613b6894d6593dee66041a5e54.tar.gz bdl-082764ad89c1b9613b6894d6593dee66041a5e54.zip |
Add WIP compilation of lambdas
-rw-r--r-- | src/ir.h | 173 |
1 files changed, 116 insertions, 57 deletions
@@ -124,15 +124,13 @@ typedef struct Procedure { | |||
124 | // Procedure name. | 124 | // Procedure name. |
125 | char *name; | 125 | char *name; |
126 | 126 | ||
127 | struct Procedure *parent; | ||
128 | |||
127 | // Program code. | 129 | // Program code. |
128 | Instruction *instructions; | 130 | Instruction *instructions; |
129 | 131 | ||
130 | // Locals code. | 132 | // Locals code. |
131 | Object **locals; | 133 | Object **locals; |
132 | |||
133 | // Number of locals and parameters. | ||
134 | size_t n_params; | ||
135 | size_t n_locals; | ||
136 | } Procedure; | 134 | } Procedure; |
137 | 135 | ||
138 | typedef struct ProgramIr { | 136 | typedef struct ProgramIr { |
@@ -205,12 +203,13 @@ print_procedure(Procedure *proc) { | |||
205 | } | 203 | } |
206 | 204 | ||
207 | Procedure * | 205 | Procedure * |
208 | proc_alloc(ProgramIr *program, StringView name) { | 206 | proc_alloc(ProgramIr *program, StringView name, Procedure *parent) { |
209 | Procedure *proc = calloc(1, sizeof(Procedure)); | 207 | Procedure *proc = calloc(1, sizeof(Procedure)); |
210 | array_init(proc->name, name.n); | 208 | array_init(proc->name, name.n); |
211 | array_insert(proc->name, name.start, name.n); | 209 | array_insert(proc->name, name.start, name.n); |
212 | array_init(proc->instructions, 0); | 210 | array_init(proc->instructions, 0); |
213 | array_init(proc->locals, 0); | 211 | array_init(proc->locals, 0); |
212 | proc->parent = parent; | ||
214 | array_push(program->procedures, proc); | 213 | array_push(program->procedures, proc); |
215 | return proc; | 214 | return proc; |
216 | } | 215 | } |
@@ -304,58 +303,63 @@ compile_or(ProgramIr *program, Procedure *proc, | |||
304 | } | 303 | } |
305 | 304 | ||
306 | void | 305 | void |
307 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { | 306 | compile_builtin(ProgramIr *program, Procedure *proc, Object *obj) { |
308 | size_t line = obj->line; | 307 | size_t line = obj->line; |
309 | size_t col = obj->col; | 308 | size_t col = obj->col; |
310 | if (obj->head->type == OBJ_TYPE_BUILTIN) { | 309 | switch (obj->head->builtin) { |
311 | switch (obj->head->builtin) { | 310 | case BUILTIN_ADD: { |
312 | case BUILTIN_ADD: { | 311 | compile_arithmetic(program, proc, OP_ADD, line, col, obj->tail); |
313 | compile_arithmetic(program, proc, OP_ADD, line, col, obj->tail); | 312 | } break; |
314 | } break; | 313 | case BUILTIN_SUB: { |
315 | case BUILTIN_SUB: { | 314 | compile_arithmetic(program, proc, OP_SUB, line, col, obj->tail); |
316 | compile_arithmetic(program, proc, OP_SUB, line, col, obj->tail); | 315 | } break; |
317 | } break; | 316 | case BUILTIN_MUL: { |
318 | case BUILTIN_MUL: { | 317 | compile_arithmetic(program, proc, OP_MUL, line, col, obj->tail); |
319 | compile_arithmetic(program, proc, OP_MUL, line, col, obj->tail); | 318 | } break; |
320 | } break; | 319 | case BUILTIN_DIV: { |
321 | case BUILTIN_DIV: { | 320 | compile_arithmetic(program, proc, OP_DIV, line, col, obj->tail); |
322 | compile_arithmetic(program, proc, OP_DIV, line, col, obj->tail); | 321 | } break; |
323 | } break; | 322 | case BUILTIN_MOD: { |
324 | case BUILTIN_MOD: { | 323 | compile_arithmetic(program, proc, OP_MOD, line, col, obj->tail); |
325 | compile_arithmetic(program, proc, OP_MOD, line, col, obj->tail); | 324 | } break; |
326 | } break; | 325 | case BUILTIN_PRINT: { |
327 | case BUILTIN_PRINT: { | 326 | compile_print(program, proc, line, col, obj->tail); |
328 | compile_print(program, proc, line, col, obj->tail); | 327 | } break; |
329 | } break; | 328 | case BUILTIN_NOT: { |
330 | case BUILTIN_NOT: { | 329 | compile_not(program, proc, line, col, obj->tail); |
331 | compile_not(program, proc, line, col, obj->tail); | 330 | } break; |
332 | } break; | 331 | case BUILTIN_AND: { |
333 | case BUILTIN_AND: { | 332 | compile_and(program, proc, line, col, obj->tail); |
334 | compile_and(program, proc, line, col, obj->tail); | 333 | } break; |
335 | } break; | 334 | case BUILTIN_OR: { |
336 | case BUILTIN_OR: { | 335 | compile_or(program, proc, line, col, obj->tail); |
337 | compile_or(program, proc, line, col, obj->tail); | 336 | } break; |
338 | } break; | 337 | case BUILTIN_EQ: { |
339 | case BUILTIN_EQ: { | 338 | compile_numeric_cmp(program, proc, OP_JUMP_IF_NEQ, line, col, obj->tail); |
340 | compile_numeric_cmp(program, proc, OP_JUMP_IF_NEQ, line, col, obj->tail); | 339 | } break; |
341 | } break; | 340 | case BUILTIN_GT: { |
342 | case BUILTIN_GT: { | 341 | compile_numeric_cmp(program, proc, OP_JUMP_IF_LE, line, col, obj->tail); |
343 | compile_numeric_cmp(program, proc, OP_JUMP_IF_LE, line, col, obj->tail); | 342 | } break; |
344 | } break; | 343 | case BUILTIN_LT: { |
345 | case BUILTIN_LT: { | 344 | compile_numeric_cmp(program, proc, OP_JUMP_IF_GE, line, col, obj->tail); |
346 | compile_numeric_cmp(program, proc, OP_JUMP_IF_GE, line, col, obj->tail); | 345 | } break; |
347 | } break; | 346 | case BUILTIN_GE: { |
348 | case BUILTIN_GE: { | 347 | compile_numeric_cmp(program, proc, OP_JUMP_IF_LT, line, col, obj->tail); |
349 | compile_numeric_cmp(program, proc, OP_JUMP_IF_LT, line, col, obj->tail); | 348 | } break; |
350 | } break; | 349 | case BUILTIN_LE: { |
351 | case BUILTIN_LE: { | 350 | compile_numeric_cmp(program, proc, OP_JUMP_IF_GT, line, col, obj->tail); |
352 | compile_numeric_cmp(program, proc, OP_JUMP_IF_GT, line, col, obj->tail); | 351 | } break; |
353 | } break; | 352 | // TODO: cons, car, cdr, type checks (nil? zero? fixnum? bool? ...) |
354 | // TODO: cons, car, cdr, type checks (nil? zero? fixnum? bool? ...) | 353 | default: { |
355 | default: { | 354 | assert(false && "builtin not implemented"); |
356 | assert(false && "builtin not implemented"); | 355 | } break; |
357 | } break; | 356 | } |
358 | } | 357 | } |
358 | |||
359 | void | ||
360 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { | ||
361 | if (IS_BUILTIN(obj->head)) { | ||
362 | compile_builtin(program, proc, obj); | ||
359 | } else { | 363 | } else { |
360 | assert(false && "compile_proc_call: not implemented"); | 364 | assert(false && "compile_proc_call: not implemented"); |
361 | } | 365 | } |
@@ -390,6 +394,61 @@ compile_def(ProgramIr *program, Procedure *proc, Object *obj) { | |||
390 | } | 394 | } |
391 | 395 | ||
392 | void | 396 | void |
397 | compile_lambda(ProgramIr *program, Procedure *proc, Object *obj) { | ||
398 | Procedure *lambda = proc_alloc(program, STRING("lambda"), proc); | ||
399 | for (size_t i = 0; i < array_size(obj->body) - 1; i++) { | ||
400 | compile_object(program, lambda, obj->body[i]); | ||
401 | } | ||
402 | Object *last_expr = obj->body[array_size(obj->body) - 1]; | ||
403 | |||
404 | // Tail Call Optimization. | ||
405 | // TODO: also for if statements | ||
406 | if (IS_PAIR(last_expr)) { | ||
407 | if (IS_BUILTIN(last_expr->head)) { | ||
408 | compile_builtin(program, lambda, last_expr); | ||
409 | } else { | ||
410 | // Discard the previous stack frame. | ||
411 | // context_printf(" mov rsp, rbp\n"); | ||
412 | |||
413 | // size_t old_offset = n_locals + n_captured + n_params; | ||
414 | // size_t new_offset = compile_call_body(last_expr); | ||
415 | // context_printf(" mov rdi, [rbp - 8]\n"); | ||
416 | // for (size_t i = 0; i < new_offset + 1; i++) { | ||
417 | // context_printf(" mov rax, [rbp - 8 * %zu]\n", i + 1); | ||
418 | // context_printf(" mov [rbp + 8 * %zu], rax\n", old_offset - i); | ||
419 | // } | ||
420 | |||
421 | // // Set the stack pointer at the end of given parameters. | ||
422 | // context_printf(" mov rsp, rbp\n"); | ||
423 | // ssize_t offset_diff = old_offset - new_offset; | ||
424 | // if (offset_diff > 0) { | ||
425 | // context_printf(" add rsp, 8 * %zu\n", offset_diff); | ||
426 | // } else { | ||
427 | // context_printf(" sub rsp, 8 * %zu\n", offset_diff); | ||
428 | // } | ||
429 | |||
430 | // context_printf(" jmp rdi\n"); | ||
431 | } | ||
432 | } else { | ||
433 | // compile_nil(); | ||
434 | compile_object(program, lambda, last_expr); | ||
435 | |||
436 | // // Return is stored in the `rax`. | ||
437 | // context_printf(" pop rax\n"); | ||
438 | |||
439 | // // Restore the previous call frame. | ||
440 | // size_t rp_offset = (n_locals + n_params + n_captured + 1); | ||
441 | // context_printf(" mov rdi, [rbp + %zu]\n", 8 * rp_offset); | ||
442 | // context_printf(" mov rsp, rbp\n"); | ||
443 | // context_printf(" add rsp, %zu\n", 8 * n_locals); | ||
444 | // context_printf(" jmp rdi\n"); | ||
445 | } | ||
446 | INST_SIMPLE(lambda, OP_RETURN, obj->line, obj->col); | ||
447 | |||
448 | INST_ARG(proc, OP_PUSH, obj, obj->line, obj->col); | ||
449 | } | ||
450 | |||
451 | void | ||
393 | compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | 452 | compile_object(ProgramIr *program, Procedure *proc, Object *obj) { |
394 | switch (obj->type) { | 453 | switch (obj->type) { |
395 | case OBJ_TYPE_NIL: | 454 | case OBJ_TYPE_NIL: |
@@ -399,7 +458,7 @@ compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | |||
399 | case OBJ_TYPE_FIXNUM: { INST_ARG(proc, OP_PUSH, obj, obj->line, obj->col); } break; | 458 | case OBJ_TYPE_FIXNUM: { INST_ARG(proc, OP_PUSH, obj, obj->line, obj->col); } break; |
400 | case OBJ_TYPE_PAIR: { compile_proc_call(program, proc, obj); } break; | 459 | case OBJ_TYPE_PAIR: { compile_proc_call(program, proc, obj); } break; |
401 | case OBJ_TYPE_IF: { compile_if(program, proc, obj); } break; | 460 | case OBJ_TYPE_IF: { compile_if(program, proc, obj); } break; |
402 | // case OBJ_TYPE_LAMBDA: { compile_lambda(obj); } break; | 461 | case OBJ_TYPE_LAMBDA: { compile_lambda(program, proc, obj); } break; |
403 | case OBJ_TYPE_DEF: { compile_def(program, proc, obj); } break; | 462 | case OBJ_TYPE_DEF: { compile_def(program, proc, obj); } break; |
404 | // case OBJ_TYPE_SYMBOL: { compile_symbol(obj); } break; | 463 | // case OBJ_TYPE_SYMBOL: { compile_symbol(obj); } break; |
405 | default: { | 464 | default: { |
@@ -415,7 +474,7 @@ ProgramIr | |||
415 | compile(Program program) { | 474 | compile(Program program) { |
416 | ProgramIr program_ir = {0}; | 475 | ProgramIr program_ir = {0}; |
417 | array_init(program_ir.procedures, 0); | 476 | array_init(program_ir.procedures, 0); |
418 | Procedure *main = proc_alloc(&program_ir, STRING("main")); | 477 | Procedure *main = proc_alloc(&program_ir, STRING("main"), NULL); |
419 | 478 | ||
420 | for (size_t i = 0; i < array_size(program.roots); i++) { | 479 | for (size_t i = 0; i < array_size(program.roots); i++) { |
421 | Object *root = program.roots[i]; | 480 | Object *root = program.roots[i]; |