diff --git a/src/cc/arch/riscv64/ir_riscv64.c b/src/cc/arch/riscv64/ir_riscv64.c index 0464f5d35..6b3aa3b36 100644 --- a/src/cc/arch/riscv64/ir_riscv64.c +++ b/src/cc/arch/riscv64/ir_riscv64.c @@ -664,6 +664,16 @@ static void ei_precall(IR *ir) { static void ei_pusharg(IR *ir) { assert(!(ir->opr1->flag & VRF_CONST)); if (ir->opr1->flag & VRF_FLONUM) { +#if VAARG_FP_AS_GP + if (ir->pusharg.fp_as_gp) { + switch (ir->opr1->vsize) { + case SZ_FLOAT: FMV_X_W(kReg64s[ir->pusharg.index], kFReg32s[ir->opr1->phys]); break; + case SZ_DOUBLE: FMV_X_D(kReg64s[ir->pusharg.index], kFReg64s[ir->opr1->phys]); break; + default: assert(false); break; + } + return; + } +#endif // Assume parameter registers are arranged from index 0. if (ir->pusharg.index != ir->opr1->phys) { switch (ir->opr1->vsize) { diff --git a/src/cc/arch/riscv64/riscv64.h b/src/cc/arch/riscv64/riscv64.h index 8d560a737..b693669e2 100644 --- a/src/cc/arch/riscv64/riscv64.h +++ b/src/cc/arch/riscv64/riscv64.h @@ -212,6 +212,9 @@ #define FCVT_D_S(o1, o2) EMIT_ASM("fcvt.d.s", o1, o2) // double <- float #define FCVT_S_D(o1, o2) EMIT_ASM("fcvt.s.d", o1, o2) // float <- double +#define FMV_X_W(o1, o2) EMIT_ASM("fmv.x.w", o1, o2) // int <- float(hex) +#define FMV_X_D(o1, o2) EMIT_ASM("fmv.x.d", o1, o2) // int <- double(hex) + #define FEQ_D(o1, o2, o3) EMIT_ASM("feq.d", o1, o2, o3) #define FEQ_S(o1, o2, o3) EMIT_ASM("feq.s", o1, o2, o3) #define FLT_D(o1, o2, o3) EMIT_ASM("flt.d", o1, o2, o3) diff --git a/src/cc/backend/codegen_expr.c b/src/cc/backend/codegen_expr.c index f2f5c77b6..1f5340c3e 100644 --- a/src/cc/backend/codegen_expr.c +++ b/src/cc/backend/codegen_expr.c @@ -447,6 +447,9 @@ static VReg *gen_funcall(Expr *expr) { int size; bool stack_arg; bool is_flo; +#if VAARG_FP_AS_GP + bool fp_as_gp; +#endif } ArgInfo; ArgInfo *arg_infos = NULL; @@ -468,6 +471,13 @@ static VReg *gen_funcall(Expr *expr) { assert(arg->type->kind != TY_ARRAY); p->size = type_size(arg->type); p->is_flo = is_flonum(arg->type); +#if VAARG_FP_AS_GP + p->fp_as_gp = false; + if (functype->func.vaargs && functype->func.params != NULL && i >= functype->func.params->len) { + p->is_flo = false; + p->fp_as_gp = true; + } +#endif p->stack_arg = is_stack_param(arg->type); #if VAARG_ON_STACK if (functype->func.vaargs && functype->func.params != NULL && i >= functype->func.params->len) @@ -517,7 +527,13 @@ static VReg *gen_funcall(Expr *expr) { ++iregarg; int index = reg_arg_count - iregarg + arg_start; assert(index < MAX_REG_ARGS); - new_ir_pusharg(vreg, index); + IR *ir = new_ir_pusharg(vreg, index); +#if !VAARG_FP_AS_GP + UNUSED(ir); +#else + if (p->fp_as_gp) + ir->pusharg.fp_as_gp = true; +#endif } } else { enum VRegSize offset_type = 2; //{.size = 4, .align = 4}; // TODO: diff --git a/src/cc/backend/ir.c b/src/cc/backend/ir.c index 65995daf9..424119114 100644 --- a/src/cc/backend/ir.c +++ b/src/cc/backend/ir.c @@ -252,11 +252,15 @@ void new_ir_tjmp(VReg *val, BB **bbs, size_t len) { ir->tjmp.len = len; } -void new_ir_pusharg(VReg *vreg, int index) { +IR *new_ir_pusharg(VReg *vreg, int index) { assert(index >= 0); IR *ir = new_ir(IR_PUSHARG); ir->opr1 = vreg; ir->pusharg.index = index; +#if VAARG_FP_AS_GP + ir->pusharg.fp_as_gp = false; +#endif + return ir; } IR *new_ir_precall(int arg_count, int stack_args_size) { diff --git a/src/cc/backend/ir.h b/src/cc/backend/ir.h index c35c22841..5ffa152ac 100644 --- a/src/cc/backend/ir.h +++ b/src/cc/backend/ir.h @@ -152,6 +152,9 @@ typedef struct IR { } precall; struct { int index; +#if VAARG_FP_AS_GP + bool fp_as_gp; +#endif } pusharg; struct { const Name *label; @@ -183,7 +186,7 @@ void new_ir_jmp(BB *bb); // Non-conditional jump void new_ir_cjmp(VReg *opr1, VReg *opr2, enum ConditionKind cond, BB *bb); // Conditional jump void new_ir_tjmp(VReg *val, BB **bbs, size_t len); IR *new_ir_precall(int arg_count, int stack_args_size); -void new_ir_pusharg(VReg *vreg, int index); +IR *new_ir_pusharg(VReg *vreg, int index); VReg *new_ir_call(const Name *label, bool global, VReg *freg, int total_arg_count, int reg_arg_count, enum VRegSize result_size, int result_flag, IR *precall, VReg **args, int vaarg_start); diff --git a/src/config.h b/src/config.h index 9d16f321e..2bb90e875 100644 --- a/src/config.h +++ b/src/config.h @@ -61,6 +61,11 @@ #define VAARG_ON_STACK 1 #endif +#if !defined(VAARG_FP_AS_GP) && XCC_TARGET_ARCH == XCC_ARCH_RISCV64 +// Pass floating-point arguments in general-purpose registers for variadic arguments. +#define VAARG_FP_AS_GP 1 +#endif + #if !defined(MANGLE_PREFIX) && XCC_TARGET_PLATFORM == XCC_PLATFORM_APPLE #define MANGLE_PREFIX "_" #endif