aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codegen.c
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-10 00:33:08 +0900
committernsfisis <nsfisis@gmail.com>2026-01-10 00:44:50 +0900
commit8f0fa8d70ce08ee0347a5880d44faab8307b72f6 (patch)
tree44f633c60ad6066772b66402a737096c4c21cbd4 /src/codegen.c
parent97980c1f3896a630e146fb12d475edbb6c52cbf7 (diff)
downloadducc-8f0fa8d70ce08ee0347a5880d44faab8307b72f6.tar.gz
ducc-8f0fa8d70ce08ee0347a5880d44faab8307b72f6.tar.zst
ducc-8f0fa8d70ce08ee0347a5880d44faab8307b72f6.zip
feat: implement va_arg()
Diffstat (limited to 'src/codegen.c')
-rw-r--r--src/codegen.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/codegen.c b/src/codegen.c
index 7adff5a..1c7abf7 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -447,6 +447,48 @@ static void codegen_func_call(CodeGen* g, AstNode* ast) {
return;
}
+ if (strcmp(func_name, "__ducc_va_arg") == 0) {
+ fprintf(g->out, " # __ducc_va_arg BEGIN\n");
+
+ // Evaluate va_list argument (first argument)
+ AstNode* va_list_arg = &ast->node_args->node_items[0];
+ codegen_expr(g, va_list_arg, GenMode_rval);
+ fprintf(g->out, " pop rdi\n"); // rdi = pointer to va_list
+
+ // Evaluate size argument (second argument)
+ AstNode* size_arg = &ast->node_args->node_items[1];
+ codegen_expr(g, size_arg, GenMode_rval);
+ fprintf(g->out, " pop rsi\n"); // rsi = size
+
+ int label = codegen_new_label(g);
+
+ // Check if gp_offset < 48 (6 registers * 8 bytes)
+ fprintf(g->out, " mov eax, DWORD PTR [rdi]\n"); // eax = gp_offset
+ fprintf(g->out, " cmp eax, 48\n");
+ fprintf(g->out, " jae .Lva_arg_overflow%d\n", label);
+
+ // Fetch from register save area
+ fprintf(g->out, " mov rcx, QWORD PTR [rdi+16]\n"); // rcx = reg_save_area
+ fprintf(g->out, " movsx rdx, eax\n"); // rdx = gp_offset (sign-extended)
+ fprintf(g->out, " add rcx, rdx\n"); // rcx = reg_save_area + gp_offset
+ fprintf(g->out, " add eax, 8\n"); // gp_offset += 8
+ fprintf(g->out, " mov DWORD PTR [rdi], eax\n"); // store updated gp_offset
+ fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument
+ fprintf(g->out, " jmp .Lva_arg_end%d\n", label);
+
+ // Fetch from overflow area (stack)
+ fprintf(g->out, ".Lva_arg_overflow%d:\n", label);
+ fprintf(g->out, " mov rcx, QWORD PTR [rdi+8]\n"); // rcx = overflow_arg_area
+ fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument
+ fprintf(g->out, " add rcx, 8\n"); // overflow_arg_area += 8
+ fprintf(g->out, " mov QWORD PTR [rdi+8], rcx\n"); // store updated overflow_arg_area
+
+ fprintf(g->out, ".Lva_arg_end%d:\n", label);
+ fprintf(g->out, " push rax\n");
+ fprintf(g->out, " # __ducc_va_arg END\n");
+ return;
+ }
+
AstNode* args = ast->node_args;
int gp_regs = 6;