aboutsummaryrefslogtreecommitdiff
path: root/compiler/codegen.cup
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-05 08:23:14 -0500
committerMustafa Quraish <[email protected]>2022-02-05 08:56:15 -0500
commitaeaf92127d1c090f9281616e49ad10dda414bd45 (patch)
treef85127c08b0caa13b95b3fb80e2996d3b5186434 /compiler/codegen.cup
parentRemove old test which disallowed initializing globals (diff)
downloadcup-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.cup151
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