From 8f0fa8d70ce08ee0347a5880d44faab8307b72f6 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 10 Jan 2026 00:33:08 +0900 Subject: feat: implement va_arg() --- src/codegen.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/parse.c | 10 +++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) (limited to 'src') 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; diff --git a/src/parse.c b/src/parse.c index b201aaf..c602073 100644 --- a/src/parse.c +++ b/src/parse.c @@ -165,8 +165,11 @@ static Parser* parser_new(TokenArray* tokens) { Func* va_start_func = funcs_push_new(&p->funcs); va_start_func->name = "__ducc_va_start"; - va_start_func->ty = calloc(1, sizeof(Type)); - va_start_func->ty->kind = TypeKind_void; + va_start_func->ty = type_new_func(type_new(TypeKind_void), NULL); + + Func* va_arg_func = funcs_push_new(&p->funcs); + va_arg_func->name = "__ducc_va_arg"; + va_arg_func->ty = type_new_func(type_new_ptr(type_new(TypeKind_void)), NULL); return p; } @@ -524,6 +527,7 @@ static bool is_type_token(Parser* p, Token* tok) { } static Type* parse_type_name(Parser* p); +static AstNode* parse_cast_expr(Parser* p); static AstNode* parse_prefix_expr(Parser* p) { TokenKind op = peek_token(p)->kind; @@ -540,7 +544,7 @@ static AstNode* parse_prefix_expr(Parser* p) { AstNode* operand = parse_prefix_expr(p); return ast_new_ref_expr(operand); } else if (consume_token_if(p, TokenKind_star)) { - AstNode* operand = parse_prefix_expr(p); + AstNode* operand = parse_cast_expr(p); return ast_new_deref_expr(operand); } else if (consume_token_if(p, TokenKind_plusplus)) { AstNode* operand = parse_prefix_expr(p); -- cgit v1.2.3-70-g09d2