diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/builtins.c | 134 | ||||
| -rw-r--r-- | src/builtins.h | 5 | ||||
| -rw-r--r-- | src/generator.c | 58 | ||||
| -rw-r--r-- | src/generator.h | 1 | ||||
| -rw-r--r-- | src/types.c | 1 |
5 files changed, 125 insertions, 74 deletions
diff --git a/src/builtins.c b/src/builtins.c index 3922d54..2883c1d 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1,19 +1,54 @@ #include "builtins.h" #include "ast.h" #include "utils.h" +#include "generator.h" #include <string.h> #include <stdlib.h> #include <assert.h> +#include <stdarg.h> +#include <sys/syscall.h> +#define MAX_CUSTOM_BUILTIN_COUNT 128 +static Node *custom_builtins[MAX_CUSTOM_BUILTIN_COUNT]; +static i64 custom_builtins_count = 0; -#define MAX_BUILTINS_COUNT 128 -static Node *all_builtins[MAX_BUILTINS_COUNT]; -static i64 builtins_count = 0; +#define MAX_SYSCALL_BUILTIN_COUNT 256 +static Node *syscall_builtins[MAX_SYSCALL_BUILTIN_COUNT]; +static i64 syscall_builtins_count = 0; static void push_builtin(Node *node) { - assert(builtins_count < MAX_BUILTINS_COUNT); - all_builtins[builtins_count++] = node; + assert(custom_builtins_count < MAX_CUSTOM_BUILTIN_COUNT); + custom_builtins[custom_builtins_count++] = node; +} + +static void make_syscall(int num_args, i64 syscall_num, char *name, Type *return_type, ...) +{ + Node *node = Node_new(AST_BUILTIN); + node->func.name = name; + node->func.return_type = return_type; + node->func.num_args = num_args; + node->func.args = calloc(sizeof(Variable), num_args); + + // This is a hack to get around the fact that we can't pass a variable + // Luckily, we don't actually use this field for the builtins anyway. + node->func.max_locals_size = syscall_num; + + va_list ap; + va_start(ap, return_type); + for (i64 i = 0; i < num_args; i++) + { + Type *typ = va_arg(ap, Type *); + if (!typ) { + fprintf(stderr, "Error: Builtin %s has no type for argument %lld\n", name, i); + exit(1); + } + node->func.args[i] = (Variable){"arg", typ, 0}; + } + va_end(ap); + + assert(syscall_builtins_count < MAX_SYSCALL_BUILTIN_COUNT); + syscall_builtins[syscall_builtins_count++] = node; } void initialize_builtins() @@ -28,22 +63,87 @@ void initialize_builtins() node->func.args[0] = (Variable){"val", type_new(TYPE_ANY), 0}; push_builtin(node); - node = Node_new(AST_BUILTIN); - node->func.name = "write"; - node->func.return_type = type_new(TYPE_INT); - node->func.num_args = 3; - node->func.args = (Variable *)calloc(sizeof(Variable), 3); - node->func.args[0] = (Variable){"fd", type_new(TYPE_INT), 0}; - node->func.args[1] = (Variable){"buf", type_new_ptr(TYPE_CHAR), 0}; - node->func.args[2] = (Variable){"size", type_new(TYPE_INT), 0}; - push_builtin(node); + make_syscall(3, SYS_write, "write", type_new(TYPE_INT), + type_new(TYPE_INT), type_new_ptr(TYPE_CHAR), type_new(TYPE_INT) // Args + ); + make_syscall(3, SYS_read, "read", type_new(TYPE_INT), + type_new(TYPE_INT), type_new_ptr(TYPE_CHAR), type_new(TYPE_INT) // Args + ); } Node *find_builtin_function(Token *token) { - for (i64 i = 0; i < builtins_count; i++) { - if (strcmp(all_builtins[i]->func.name, token->value.as_string) == 0) - return all_builtins[i]; + for (i64 i = 0; i < custom_builtins_count; i++) { + if (strcmp(custom_builtins[i]->func.name, token->value.as_string) == 0) + return custom_builtins[i]; + } + for (i64 i = 0; i < syscall_builtins_count; i++) { + if (strcmp(syscall_builtins[i]->func.name, token->value.as_string) == 0) + return syscall_builtins[i]; } return NULL; +} + +char *x86_64_syscall_regs[10] = { + "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13" +}; + +static void generate_syscall_builtins(FILE *out) +{ + for (i64 i = 0; i < syscall_builtins_count; i++) { + Node *node = syscall_builtins[i]; + fprintf(out, "func_%s:\n", node->func.name); + for (i64 i = 0; i < node->func.num_args; i++) + fprintf(out, " mov %s, [rsp+%lld]\n", x86_64_syscall_regs[i], (i+1) * 8); + generate_syscall(node->func.max_locals_size, out); + fprintf(out, " ret\n"); + } +} + +static void generate_custom_builtins(FILE *out) +{ + // Stolen shamelessly from tsoding/porth: + // https://gitlab.com/tsoding/porth + fprintf(out, + "func_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" + ".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" + " 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" + ); + generate_syscall(SYS_write, out); + fprintf(out, " add rsp, 40\n"); + fprintf(out, " ret\n"); +} + +void generate_builtins(FILE *out) +{ + generate_custom_builtins(out); + generate_syscall_builtins(out); }
\ No newline at end of file diff --git a/src/builtins.h b/src/builtins.h index 38c1cb4..b81d8d4 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -3,4 +3,7 @@ #include "ast.h" void initialize_builtins(); -Node *find_builtin_function(Token *token);
\ No newline at end of file +Node *find_builtin_function(Token *token); + +// Codegen +void generate_builtins(FILE *out); diff --git a/src/generator.c b/src/generator.c index aace3bc..829bf73 100644 --- a/src/generator.c +++ b/src/generator.c @@ -16,7 +16,7 @@ static Node *current_function = NULL; static Node *defer_stack[DEFER_STACK_SIZE]; static i64 defer_stack_count = 0; -void make_syscall(i64 syscall_no, FILE *out) { +void generate_syscall(i64 syscall_no, FILE *out) { #if __APPLE__ syscall_no += 0x2000000; #endif @@ -457,7 +457,7 @@ void generate_asm(Node *root, FILE *out) fprintf(out, " call func_main\n"); fprintf(out, " mov rdi, rax\n"); - make_syscall(SYS_exit, out); + generate_syscall(SYS_exit, out); // TODO: Don't generate code for functions that cannot get called. // TODO: Add implementations of some primitives? @@ -471,58 +471,4 @@ void generate_asm(Node *root, FILE *out) for (i64 i = 0; i < num_string_literals; i++) { fprintf(out, " global_string_%lld: db `%s`, 0\n", i, all_string_literals[i]); } -} - -void generate_builtins(FILE *out) -{ - // Stolen shamelessly from tsoding/porth: - // https://gitlab.com/tsoding/porth - fprintf(out, - "func_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" - ".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" - " 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"); - - ///////////////////////////////////////////////////////////////// - - // Write syscall - fprintf(out, - "func_write:\n" - " mov rdi, [rsp+8]\n" // stdout - " mov rsi, [rsp+16]\n" - " mov rdx, [rsp+24]\n" // 1 byte - ); - make_syscall(SYS_write, out); - fprintf(out, " ret\n"); }
\ No newline at end of file diff --git a/src/generator.h b/src/generator.h index 602cf3a..a03b9d4 100644 --- a/src/generator.h +++ b/src/generator.h @@ -3,4 +3,5 @@ #include "ast.h" #include <stdio.h> +void generate_syscall(i64 syscall_no, FILE *out); void generate_asm(Node *root, FILE *out);
\ No newline at end of file diff --git a/src/types.c b/src/types.c index 7a055fe..6c7c0e5 100644 --- a/src/types.c +++ b/src/types.c @@ -95,6 +95,7 @@ static char *data_type_to_str(DataType type) case TYPE_PTR: return "*"; case TYPE_ARRAY: return "array"; case TYPE_CHAR: return "char"; + case TYPE_ANY: return "<@>"; default: assert(false && "Unreachable"); } } |