diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-05 08:23:14 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-05 08:56:15 -0500 |
| commit | aeaf92127d1c090f9281616e49ad10dda414bd45 (patch) | |
| tree | f85127c08b0caa13b95b3fb80e2996d3b5186434 /compiler/codegen.cup | |
| parent | Remove old test which disallowed initializing globals (diff) | |
| download | cup-aeaf92127d1c090f9281616e49ad10dda414bd45.tar.xz cup-aeaf92127d1c090f9281616e49ad10dda414bd45.zip | |
Add implementation of self-hosted compiler so far
There's also a `run.sh2` script which does the following:
- Compiles the C compiler `build/cupcc`
- Compiles the self-hosted compiler `build/cup.out` (with `cupcc`)
- Compiles the specified file on CLI with `build/cup.out`
- Runs this exectuable and shows the output
Diffstat (limited to 'compiler/codegen.cup')
| -rw-r--r-- | compiler/codegen.cup | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/compiler/codegen.cup b/compiler/codegen.cup new file mode 100644 index 0000000..41eea33 --- /dev/null +++ b/compiler/codegen.cup @@ -0,0 +1,151 @@ +import "compiler/ast.cup" +import "std/file.cup" + +let gen_out_file: File*; + +fn emit_asm4(msg1: char*, msg2: char*, msg3: char*, msg4: char*) { + fwrite(gen_out_file, msg1, strlen(msg1)); + fwrite(gen_out_file, msg2, strlen(msg2)); + fwrite(gen_out_file, msg3, strlen(msg3)); + fwrite(gen_out_file, msg4, strlen(msg4)); +} + +fn emit_asm3(msg1: char*, msg2: char*, msg3: char*) { + fwrite(gen_out_file, msg1, strlen(msg1)); + fwrite(gen_out_file, msg2, strlen(msg2)); + fwrite(gen_out_file, msg3, strlen(msg3)); +} + +fn emit_asm2(msg1: char*, msg2: char*) { + fwrite(gen_out_file, msg1, strlen(msg1)); + fwrite(gen_out_file, msg2, strlen(msg2)); +} + +fn emit_asm(msg: char*) { + fwrite(gen_out_file, msg, strlen(msg)); +} + +fn emit_num(num: int) { + fputu(gen_out_file, num); +} + +fn generate_syscall(num: int) { + emit_asm(" mov rax, "); emit_num(num); emit_asm("\n"); + emit_asm(" syscall\n"); +} + +fn generate_expr_into_rax(node: Node*) { + if (node.typ == AST_LITERAL) { + if (node.etyp.typ == TYPE_INT) { + emit_asm(" mov rax, "); emit_num(node.d.literal.as_int); emit_asm("\n"); + } else { + die("Unsupported literal type in generate_expr_into_rax"); + } + } else if (node.typ == AST_PLUS) { + generate_expr_into_rax(node.d.binary.rhs); + emit_asm(" push rax\n"); + generate_expr_into_rax(node.d.binary.lhs); + emit_asm(" pop rbx\n"); + emit_asm(" add rax, rbx\n"); + } else if (node.typ == AST_MINUS) { + generate_expr_into_rax(node.d.binary.rhs); + emit_asm(" push rax\n"); + generate_expr_into_rax(node.d.binary.lhs); + emit_asm(" pop rbx\n"); + emit_asm(" sub rax, rbx\n"); + } else if (node.typ == AST_DIV) { + generate_expr_into_rax(node.d.binary.rhs); + emit_asm(" push rax\n"); + generate_expr_into_rax(node.d.binary.lhs); + emit_asm(" pop rbx\n"); + emit_asm(" cqo\n"); + emit_asm(" idiv rbx\n"); + + } else if (node.typ == AST_MOD) { + generate_expr_into_rax(node.d.binary.rhs); + emit_asm(" push rax\n"); + generate_expr_into_rax(node.d.binary.lhs); + emit_asm(" pop rbx\n"); + emit_asm(" cqo\n"); + emit_asm(" idiv rbx\n"); + emit_asm(" mov rax, rdx\n"); + + } else if (node.typ == AST_MUL) { + generate_expr_into_rax(node.d.binary.rhs); + emit_asm(" push rax\n"); + generate_expr_into_rax(node.d.binary.lhs); + emit_asm(" pop rbx\n"); + emit_asm(" imul rbx\n"); + } +} + +fn generate_statement(node: Node*) { + if (node.typ == AST_RETURN) { + generate_expr_into_rax(node.d.unary); + emit_asm(" mov rsp, rbp\n"); + emit_asm(" pop rbp\n"); + emit_asm(" ret\n"); + } +} + +fn generate_block(node: Node*) { + let n = node.d.block.children.size; + for (let i = 0; i < n; ++i) { + generate_statement(node.d.block.children.data[i]); + } +} + +fn generate_function(node: Node*) { + emit_asm3("global func_", node.d.func.name, "\n"); + emit_asm3("func_", node.d.func.name, ":\n"); + emit_asm(" push rbp\n"); + emit_asm(" mov rbp, rsp\n"); + emit_asm(" sub rsp, "); emit_num(node.d.func.max_locals_size); emit_asm("\n"); + + generate_block(node.d.func.body); + + emit_asm(" mov rsp, rbp\n"); + emit_asm(" pop rbp\n"); + emit_asm(" ret\n"); +} + +fn generate_program(ast: Node*, file: File*) { + gen_out_file = file; + + let n = ast.d.block.children.size; + for (let i = 0; i < n; ++i) { + let node: Node* = ast.d.block.children.data[i]; + if (node.typ == AST_FUNC) { + generate_function(node); + } else { + die("Unknown node type in generate_program"); + } + } + + if (OS_IS_MACOS) { + emit_asm("global _main\n"); + emit_asm("_main:\n"); + // Push argv + emit_asm(" mov rax, rsi\n"); + emit_asm(" push rax\n"); + // Push argc + emit_asm(" mov rax, rdi\n"); + emit_asm(" push rax\n"); + } else { + emit_asm("global _start\n"); + emit_asm("_start:\n"); + + emit_asm(" mov rbp, rsp\n"); + // // Push argv + emit_asm(" mov rax, rbp\n"); + emit_asm(" add rax, 8\n"); + emit_asm(" push rax\n"); + // Push argc + emit_asm(" mov rax, [rbp]\n"); + emit_asm(" push rax\n"); + } + + emit_asm(" call func_main\n"); + emit_asm(" mov rdi, rax\n"); + generate_syscall(SYS_exit); +}
\ No newline at end of file |