aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.c')
-rw-r--r--src/codegen.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/src/codegen.c b/src/codegen.c
index 97a9209..0b586be 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -56,7 +56,7 @@ static const char* param_reg(int n) {
static void codegen_func_prologue(CodeGen* g, AstNode* ast) {
fprintf(g->out, " push rbp\n");
fprintf(g->out, " mov rbp, rsp\n");
- for (int i = 0; i < ast->node_params->node_len; ++i) {
+ for (int i = 0; i < ast->node_params->node_len && i < 6; ++i) {
fprintf(g->out, " push %s\n", param_reg(i));
}
// Note: rsp must be aligned to 8.
@@ -363,6 +363,17 @@ static void codegen_assign_expr(CodeGen* g, AstNode* ast) {
}
}
+static void codegen_args(CodeGen* g, AstNode* args) {
+ // Evaluate arguments in the reverse order (right to left).
+ for (int i = args->node_len - 1; i >= 0; --i) {
+ AstNode* arg = &args->node_items[i];
+ codegen_expr(g, arg, GenMode_rval);
+ }
+ for (int i = 0; i < args->node_len && i < 6; ++i) {
+ fprintf(g->out, " pop %s\n", param_reg(i));
+ }
+}
+
static void codegen_func_call(CodeGen* g, AstNode* ast) {
const char* func_name = ast->name;
@@ -395,41 +406,41 @@ static void codegen_func_call(CodeGen* g, AstNode* ast) {
}
AstNode* args = ast->node_args;
- // Evaluate arguments in the reverse order (right to left).
- for (int i = args->node_len - 1; i >= 0; --i) {
- AstNode* arg = &args->node_items[i];
- codegen_expr(g, arg, GenMode_rval);
- }
- for (int i = 0; i < args->node_len && i < 6; ++i) {
- fprintf(g->out, " pop %s\n", param_reg(i));
- }
+ int overflow_args_count = args->node_len <= 6 ? 0 : args->node_len - 6;
int label = codegen_new_label(g);
fprintf(g->out, " mov rax, rsp\n");
+ if (overflow_args_count % 2 == 1) {
+ fprintf(g->out, " add rax, 8\n");
+ }
fprintf(g->out, " and rax, 15\n");
fprintf(g->out, " cmp rax, 0\n");
fprintf(g->out, " je .Laligned%d\n", label);
- fprintf(g->out, " mov rax, 0\n");
fprintf(g->out, " sub rsp, 8\n");
+ codegen_args(g, args);
+ fprintf(g->out, " mov rax, 0\n");
fprintf(g->out, " call %s\n", func_name);
fprintf(g->out, " add rsp, 8\n");
- fprintf(g->out, " push rax\n");
fprintf(g->out, " jmp .Lend%d\n", label);
fprintf(g->out, ".Laligned%d:\n", label);
+ codegen_args(g, args);
fprintf(g->out, " mov rax, 0\n");
fprintf(g->out, " call %s\n", func_name);
- fprintf(g->out, " push rax\n");
fprintf(g->out, ".Lend%d:\n", label);
+ // Pop pass-by-stack arguments.
+ for (int i = 0; i < overflow_args_count; i++) {
+ fprintf(g->out, " add rsp, 8\n");
+ }
+ fprintf(g->out, " push rax\n");
}
static void codegen_lvar(CodeGen* g, AstNode* ast, GenMode gen_mode) {
- fprintf(g->out, " mov rax, rbp\n");
- fprintf(g->out, " sub rax, %d\n", ast->node_stack_offset);
+ fprintf(g->out, " lea rax, %d[rbp]\n", -ast->node_stack_offset);
fprintf(g->out, " push rax\n");
if (gen_mode == GenMode_rval) {
codegen_lval2rval(g, ast->ty);