diff options
| author | Mustafa Quraish <[email protected]> | 2022-01-31 01:26:07 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-01-31 01:26:07 -0500 |
| commit | cb0d77c3dc83d6c7cb39642e8708b12a29b7b8c7 (patch) | |
| tree | 904a6c70509da3f9274bb2df8e214f2b9e6fd9ac /src/generator.c | |
| parent | Put tokens in their own macro to allow looping over them (diff) | |
| download | cup-cb0d77c3dc83d6c7cb39642e8708b12a29b7b8c7.tar.xz cup-cb0d77c3dc83d6c7cb39642e8708b12a29b7b8c7.zip | |
Add basic builtin-function support
This isn't really super extendible for now, but it's a start and gives
us the `print` builtin which allows us to finally actually print out
values to the screen, so we can move away from testing with exit codes
eventually.
Diffstat (limited to 'src/generator.c')
| -rw-r--r-- | src/generator.c | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/src/generator.c b/src/generator.c index 6a95d0c..5b1f630 100644 --- a/src/generator.c +++ b/src/generator.c @@ -12,6 +12,14 @@ static int label_counter = 0; static Node *current_function = NULL; +void make_syscall(i64 syscall_no, FILE *out) { +#if __APPLE__ + syscall_no += 0x2000000; +#endif + fprintf(out, " mov rax, %lld\n", syscall_no); + fprintf(out, " syscall\n"); +} + void generate_expr_into_rax(Node *expr, FILE *out); void generate_func_call(Node *node, FILE *out) @@ -319,8 +327,17 @@ void generate_function(Node *func, FILE *out) current_function = func; generate_function_header(func, out); generate_block(func->func.body, out); + // TODO: This is a hack, we should make sure a function contains a return statement + // if it says it's going to return something + fprintf(out, " mov rsp, rbp\n"); + fprintf(out, " pop rbp\n"); + // Return 0 by default if we don't have a return statement + fprintf(out, " mov qword rax, 0\n"); + fprintf(out, " ret\n"); } +void generate_builtins(FILE *out); + void generate_asm(Node *root, FILE *out) { assert(root->type == AST_PROGRAM); @@ -343,13 +360,85 @@ void generate_asm(Node *root, FILE *out) #endif fprintf(out, " call main\n"); -#if __APPLE__ - fprintf(out, " ret\n"); -#else fprintf(out, " mov rdi, rax\n"); - fprintf(out, " mov rax, %d\n", SYS_exit); - fprintf(out, " syscall\n"); -#endif + make_syscall(SYS_exit, out); // TODO: Add implementations of some primitives? + generate_builtins(out); +} + +void generate_builtins(FILE *out) +{ + // Stolen shamelessly from tsoding/porth: + // https://gitlab.com/tsoding/porth + fprintf(out, + "print:\n" + " mov rdi, [rsp+8]\n" + " mov r9, -3689348814741910323\n" + " sub rsp, 40\n" + " mov BYTE [rsp+31], 10\n" + " lea rcx, [rsp+30]\n" + " mov qword rbx, 0\n" + + // Check if < 0, and set rbx=0, negate value + // " cmp rdi, 0\n" + // " jge .L2\n" + // " mov qword rbx, 1\n" + // " neg rdi\n" + // " sub rcx, 1\n" + + ".L2:\n" + " mov rax, rdi\n" + " lea r8, [rsp+32]\n" + " mul r9\n" + " mov rax, rdi\n" + " sub r8, rcx\n" + " shr rdx, 3\n" + " lea rsi, [rdx+rdx*4]\n" + " add rsi, rsi\n" + " sub rax, rsi\n" + " add eax, 48\n" + " mov BYTE [rcx], al\n" + " mov rax, rdi\n" + " mov rdi, rdx\n" + " mov rdx, rcx\n" + " sub rcx, 1\n" + " cmp rax, 9\n" + " ja .L2\n" + + // If rbx=1, then we need to add a minus sign, not sure how + // the above code works so there's probably a nicer way. + // " cmp rbx, 0\n" + // " je .end_neg_sign\n" + // " add eax, 48\n" + // " mov BYTE [rcx], 45\n" + // " mov rax, rdi\n" + // " mov rdi, rdx\n" + // " mov rdx, rcx\n" + // " sub rcx, 1\n" + // ".end_neg_sign:\n" + + " lea rax, [rsp+32]\n" + " mov edi, 1\n" + " sub rdx, rax\n" + " xor eax, eax\n" + " lea rsi, [rsp+32+rdx]\n" + " mov rdx, r8\n" + ); + make_syscall(SYS_write, out); + fprintf(out, " add rsp, 40\n"); + fprintf(out, " ret\n"); + + ///////////////////////////////////////////////////////////////// + + // Print out a single character + fprintf(out, + "putc:\n" + " mov rdi, 1\n" // stdout + " mov rsi, rsp\n" + " add rsi, 8\n" + " mov rdx, 1\n" // 1 byte + ); + make_syscall(SYS_write, out); + fprintf(out, " ret\n"); }
\ No newline at end of file |