aboutsummaryrefslogtreecommitdiff
path: root/compiler/codegen.cup
diff options
context:
space:
mode:
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