Skip to content

Commit

Permalink
Fix handling variadic parameters
Browse files Browse the repository at this point in the history
  * `typedef void **va_list`
  * Must layout saved registers to the bottom of stack frame
  • Loading branch information
tyfkda committed Dec 21, 2023
1 parent a6c1139 commit cc067c6
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 19 deletions.
8 changes: 8 additions & 0 deletions include/stdarg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stdint.h>
Expand Down
53 changes: 36 additions & 17 deletions src/cc/arch/riscv64/emit_code.c
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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();
}
Expand Down
7 changes: 6 additions & 1 deletion src/cc/backend/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
42 changes: 41 additions & 1 deletion src/cc/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 + <vaarg saved offset>)
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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit cc067c6

Please sign in to comment.