aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/stdarg.h4
-rw-r--r--src/codegen.c37
-rw-r--r--tests/066.sh2
3 files changed, 23 insertions, 20 deletions
diff --git a/include/stdarg.h b/include/stdarg.h
index 95c068c..609e6af 100644
--- a/include/stdarg.h
+++ b/include/stdarg.h
@@ -12,9 +12,7 @@ struct __ducc_va_list {
void* overflow_arg_area;
void* reg_save_area;
};
-// ducc currently does not support array type.
-// typedef struct __ducc_va_list va_list[1];
-typedef struct __ducc_va_list* va_list;
+typedef struct __ducc_va_list va_list[1];
#define va_start(args, start) __ducc_va_start(args, start)
#define va_end(args)
diff --git a/src/codegen.c b/src/codegen.c
index a16ae73..000126b 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -307,24 +307,29 @@ static void codegen_func_call(CodeGen* g, AstNode* ast) {
const char* func_name = ast->name;
if (strcmp(func_name, "__ducc_va_start") == 0) {
- int stack_size = g->current_func->node_stack_size;
fprintf(g->out, " # __ducc_va_start BEGIN\n");
- for (int i = 0; i < 6; ++i) {
- fprintf(g->out, " mov rax, %s\n", param_reg(i));
- fprintf(g->out, " mov [rbp-%d], rax\n", 8 + (stack_size - 4 - i) * 8);
- }
- AstNode* va_list_args = ast->node_args->node_items;
- codegen_expr(g, va_list_args, GenMode_lval);
+ AstNode* va_list_args = &ast->node_args->node_items[0];
+ codegen_expr(g, va_list_args, GenMode_rval);
fprintf(g->out, " pop rdi\n");
- fprintf(g->out, " mov rax, rbp\n");
- fprintf(g->out, " sub rax, %d\n", 8 + (stack_size - 1) * 8);
- fprintf(g->out, " mov [rdi], rax\n");
- fprintf(g->out, " mov DWORD PTR [rax], 8\n");
- fprintf(g->out, " mov DWORD PTR [rax+4], 0\n");
- fprintf(g->out, " mov QWORD PTR [rax+8], 0\n");
- fprintf(g->out, " mov rdi, rbp\n");
- fprintf(g->out, " sub rdi, %d\n", 8 + (stack_size - 4) * 8);
- fprintf(g->out, " mov QWORD PTR [rax+16], rdi\n");
+
+ // Allocate save area.
+ fprintf(g->out, " sub rsp, 48\n");
+
+ fprintf(g->out, " mov [rsp+ 0], rdi\n");
+ fprintf(g->out, " mov [rsp+ 8], rsi\n");
+ fprintf(g->out, " mov [rsp+16], rdx\n");
+ fprintf(g->out, " mov [rsp+24], rcx\n");
+ fprintf(g->out, " mov [rsp+32], r8\n");
+ fprintf(g->out, " mov [rsp+40], r9\n");
+
+ // Initialize va_list.
+ fprintf(g->out, " mov DWORD PTR [rdi], 8\n"); // gp_offset
+ fprintf(g->out, " mov DWORD PTR [rdi+4], 0\n"); // fp_offset
+ fprintf(g->out, " lea rax, [rbp+16]\n"); // overflow_arg_area
+ fprintf(g->out, " mov QWORD PTR [rdi+8], rax\n");
+ fprintf(g->out, " mov QWORD PTR [rdi+16], rsp\n"); // reg_save_area
+
+ fprintf(g->out, " push 0\n"); // dummy return value
fprintf(g->out, " # __ducc_va_start END\n");
return;
}
diff --git a/tests/066.sh b/tests/066.sh
index 21ef9c6..0a5e570 100644
--- a/tests/066.sh
+++ b/tests/066.sh
@@ -1,5 +1,5 @@
cat <<'EOF' > expected
-8
+24
EOF
test_diff <<'EOF'