From cc067c65f93e959eeda02591d8b0a9859067843a Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 19 Dec 2023 09:13:39 +0900 Subject: [PATCH] Fix handling variadic parameters * `typedef void **va_list` * Must layout saved registers to the bottom of stack frame --- include/stdarg.h | 8 +++++ src/cc/arch/riscv64/emit_code.c | 53 ++++++++++++++++++++++----------- src/cc/backend/codegen.c | 7 ++++- src/cc/builtin.c | 42 +++++++++++++++++++++++++- 4 files changed, 91 insertions(+), 19 deletions(-) diff --git a/include/stdarg.h b/include/stdarg.h index 963e97b80..8941176ac 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -22,6 +22,14 @@ typedef void **va_list; #define va_arg(ap, type) (*(type*)(ap)++) // Assume little endian #define va_copy(dst,src) (dst = src) +#elif defined(__riscv) +typedef void **va_list; + +#define va_start(ap,p) __builtin_va_start(ap,&(p)) +#define va_end(ap) /*(void)*/(ap = 0) +#define va_arg(ap, type) ((ap) += 1, *(type*)((ap) - 1)) // Assume little endian +#define va_copy(dst,src) (dst = src) + #else // not __APPLE__ nor __aarch64__ #include diff --git a/src/cc/arch/riscv64/emit_code.c b/src/cc/arch/riscv64/emit_code.c index 021a3ceec..decb2bf77 100644 --- a/src/cc/arch/riscv64/emit_code.c +++ b/src/cc/arch/riscv64/emit_code.c @@ -356,17 +356,42 @@ static void emit_varinfo(const VarInfo *varinfo, const Initializer *init) { //////////////////////////////////////////////// +static const char *kRegParam64s[] = {A0, A1, A2, A3, A4, A5, A6, A7}; + static bool is_asm(Stmt *stmt) { return stmt->kind == ST_ASM; } +static int put_vaarg_params(Function *func) { + assert(func->type->func.vaargs); +#if VAARG_ON_STACK + return; +#else + RegParamInfo iparams[MAX_REG_ARGS]; + RegParamInfo fparams[MAX_FREG_ARGS]; + int iparam_count = 0; + int fparam_count = 0; + enumerate_register_params(func, iparams, MAX_REG_ARGS, fparams, MAX_FREG_ARGS, + &iparam_count, &fparam_count); + + int size = 0; + int n = MAX_REG_ARGS - iparam_count; + if (n > 0) { + size = n * POINTER_SIZE; + ADDI(SP, SP, IM(-size)); + for (int i = iparam_count, offset = 0; i < MAX_REG_ARGS; ++i, offset += POINTER_SIZE) + SD(kRegParam64s[i], IMMEDIATE_OFFSET(offset, SP)); + } + return size; +#endif +} + static void move_params_to_assigned(Function *func) { extern const char *kReg64s[]; extern const int ArchRegParamMapping[]; extern const char *kFReg64s[]; // static const char *kRegParam32s[] = {W0, W1, W2, W3, W4, W5, W6, W7}; - static const char *kRegParam64s[] = {A0, A1, A2, A3, A4, A5, A6, A7}; // static const char **kRegParamTable[] = {kRegParam32s, kRegParam32s, kRegParam32s, kRegParam64s}; // const char *kFRegParam32s[] = {S0, S1, S2, S3, S4, S5, S6, S7}; const char *kFRegParam64s[] = {FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7}; @@ -426,22 +451,6 @@ static void move_params_to_assigned(Function *func) { } } } - -#if VAARG_ON_STACK - bool vaargs = false; -#else - bool vaargs = func->type->func.vaargs; -#endif - if (vaargs) { - for (int i = iparam_count; i < MAX_REG_ARGS; ++i) { - int offset = (i - MAX_REG_ARGS - MAX_FREG_ARGS) * POINTER_SIZE; - SD(kRegParam64s[i], IMMEDIATE_OFFSET(offset, FP)); - } - // for (int i = fparam_count; i < MAX_FREG_ARGS; ++i) { - // int offset = (i - MAX_FREG_ARGS) * POINTER_SIZE; - // SD(kFRegParam64s[i], IMMEDIATE_OFFSET(offset, FP)); - // } - } } static void emit_defun(Function *func) { @@ -491,7 +500,15 @@ static void emit_defun(Function *func) { bool fp_saved = false; // Frame pointer saved? bool ra_saved = false; // Return Address register saved? unsigned long used_reg_bits = fnbe->ra->used_reg_bits; + int vaarg_params_saved = 0; if (!no_stmt) { + if (func->type->func.vaargs) { + vaarg_params_saved = put_vaarg_params(func); + + // Re-align frame size. + frame_size = ALIGN(fnbe->frame_size + vaarg_params_saved, 16) - vaarg_params_saved; + } + fp_saved = frame_size > 0 || fnbe->ra->flag & RAF_STACK_FRAME; ra_saved = (func->flag & FUNCF_HAS_FUNCALL) != 0; @@ -542,6 +559,8 @@ static void emit_defun(Function *func) { ADD(SP, SP, IM(16)); } } + if (vaarg_params_saved > 0) + ADD(SP, SP, IM(vaarg_params_saved)); RET(); } diff --git a/src/cc/backend/codegen.c b/src/cc/backend/codegen.c index 733d5ae41..abd09c47d 100644 --- a/src/cc/backend/codegen.c +++ b/src/cc/backend/codegen.c @@ -777,8 +777,13 @@ void alloc_stack_variables_onto_stack_frame(Function *func) { int param_offset = calculate_func_param_bottom(func); fnbe->vaarg_frame_info.offset = param_offset; - if (func->type->func.vaargs) + if (func->type->func.vaargs) { +#if VAARG_FP_AS_GP + // Register parameters are put below stack frame, so not added to frame_size. +#else frame_size = (MAX_REG_ARGS + MAX_FREG_ARGS) * POINTER_SIZE; +#endif + } bool require_stack_frame = false; diff --git a/src/cc/builtin.c b/src/cc/builtin.c index 811dc7f57..4e4dcd7e2 100644 --- a/src/cc/builtin.c +++ b/src/cc/builtin.c @@ -48,6 +48,46 @@ static VReg *gen_builtin_va_start(Expr *expr) { new_ir_mov(varinfo->local.vreg, ptr, IRF_UNSIGNED); return NULL; } +#elif XCC_TARGET_ARCH == XCC_ARCH_RISCV64 +static VReg *gen_builtin_va_start(Expr *expr) { + assert(expr->kind == EX_FUNCALL); + Vector *args = expr->funcall.args; + assert(args->len == 2); + assert(curfunc != NULL); + Expr *var = strip_cast(args->data[1]); + if (var->kind == EX_REF) + var = var->unary.sub; + int gn = -1; + if (var->kind == EX_VAR) { + const Vector *params = curfunc->params; + int g = 0; + for (int i = 0; i < params->len; ++i) { + VarInfo *info = params->data[i]; + const Type *t = info->type; + if (t->kind != TY_STRUCT) { + ++g; + } + + if (info->name != NULL && equal_name(info->name, var->var.name)) { + gn = g; + break; + } + } + } + if (gn < 0) { + parse_error(PE_FATAL, var->token, "Must be function argument"); + return NULL; + } + + FuncBackend *fnbe = curfunc->extra; + FrameInfo *fi = &fnbe->vaarg_frame_info; + VReg *p = new_ir_bofs(fi); + + // (void)(ap = fp + ) + VReg *ap = gen_expr(args->data[0]); + new_ir_mov(ap, p, IRF_UNSIGNED); + return NULL; +} #else static VReg *gen_builtin_va_start(Expr *expr) { assert(expr->kind == EX_FUNCALL); @@ -146,7 +186,7 @@ void install_builtins(void) { add_builtin_expr_ident("__builtin_type_kind", &p_reg_class); { -#if VAARG_ON_STACK +#if VAARG_ON_STACK || XCC_TARGET_ARCH == XCC_ARCH_RISCV64 Type *tyVaList = ptrof(&tyVoidPtr); #else Type *tyVaElem = create_struct_type(NULL, alloc_name("__va_elem", NULL, false), 0);