From a9d83c22663c3ef2d705d5e215e7e74b38498f6f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 19 Dec 2023 10:12:20 +0900 Subject: [PATCH] Save FP register on function prologue * Callee/Caller Save --- src/cc/arch/riscv64/emit_code.c | 36 +++++------ src/cc/arch/riscv64/ir_riscv64.c | 100 +++++++++++++++---------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/cc/arch/riscv64/emit_code.c b/src/cc/arch/riscv64/emit_code.c index 32e3d369d..021a3ceec 100644 --- a/src/cc/arch/riscv64/emit_code.c +++ b/src/cc/arch/riscv64/emit_code.c @@ -363,13 +363,13 @@ static bool is_asm(Stmt *stmt) { static void move_params_to_assigned(Function *func) { extern const char *kReg64s[]; extern const int ArchRegParamMapping[]; - // extern const char *kFReg32s[], *kFReg64s[]; + 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[] = {D0, D1, D2, D3, D4, D5, D6, D7}; + const char *kFRegParam64s[] = {FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7}; static const int kPow2Table[] = {-1, 0, 1, -1, 2, -1, -1, -1, 3}; #define kPow2TableSize ((int)(sizeof(kPow2Table) / sizeof(*kPow2Table))) @@ -410,22 +410,22 @@ static void move_params_to_assigned(Function *func) { MV(dst, src); } } - // for (int i = 0; i < fparam_count; ++i) { - // RegParamInfo *p = &fparams[i]; - // VReg *vreg = p->vreg; - // const char *src = (p->type->flonum.kind >= FL_DOUBLE ? kFRegParam64s : kFRegParam32s)[p->index]; - // if (vreg->flag & VRF_SPILLED) { - // int offset = vreg->frame.offset; - // assert(offset != 0); - // assert(offset != 0); - // SD(src, IMMEDIATE_OFFSET(offset, FP)); - // } else { - // if (p->index != vreg->phys) { - // const char *dst = (p->type->flonum.kind >= FL_DOUBLE ? kFReg64s : kFReg32s)[vreg->phys]; - // FMOV(dst, src); - // } - // } - // } + for (int i = 0; i < fparam_count; ++i) { + RegParamInfo *p = &fparams[i]; + VReg *vreg = p->vreg; + const char *src = kFRegParam64s[p->index]; + if (vreg->flag & VRF_SPILLED) { + int offset = vreg->frame.offset; + assert(offset != 0); + assert(offset != 0); + SD(src, IMMEDIATE_OFFSET(offset, FP)); + } else { + if (p->index != vreg->phys) { + const char *dst = kFReg64s[vreg->phys]; + FMV_D(dst, src); + } + } + } #if VAARG_ON_STACK bool vaargs = false; diff --git a/src/cc/arch/riscv64/ir_riscv64.c b/src/cc/arch/riscv64/ir_riscv64.c index 9b8aa46ea..0464f5d35 100644 --- a/src/cc/arch/riscv64/ir_riscv64.c +++ b/src/cc/arch/riscv64/ir_riscv64.c @@ -65,11 +65,11 @@ const char *kFReg64s[PHYSICAL_FREG_MAX] = { #define GET_FA0_INDEX() 0 -// #define CALLEE_SAVE_FREG_COUNT ((int)(sizeof(kCalleeSaveFRegs) / sizeof(*kCalleeSaveFRegs))) -// static const int kCalleeSaveFRegs[] = {8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19}; +#define CALLEE_SAVE_FREG_COUNT ((int)(sizeof(kCalleeSaveFRegs) / sizeof(*kCalleeSaveFRegs))) +static const int kCalleeSaveFRegs[] = {8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19}; -// #define CALLER_SAVE_FREG_COUNT ((int)(sizeof(kCallerSaveFRegs) / sizeof(*kCallerSaveFRegs))) -// static const int kCallerSaveFRegs[] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; +#define CALLER_SAVE_FREG_COUNT ((int)(sizeof(kCallerSaveFRegs) / sizeof(*kCallerSaveFRegs))) +static const int kCallerSaveFRegs[] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; static unsigned long detect_extra_occupied(RegAlloc *ra, IR *ir) { UNUSED(ir); @@ -799,49 +799,42 @@ static int enum_callee_save_regs(unsigned long bit, int n, const int *indices, c return count; } -#define N CALLEE_SAVE_REG_COUNT +#define N (CALLEE_SAVE_REG_COUNT + CALLEE_SAVE_FREG_COUNT) int push_callee_save_regs(unsigned long used, unsigned long fused) { - UNUSED(fused); - const char *saves[(N + 1) & ~1]; + const char *saves[ALIGN(N, 2)]; int count = enum_callee_save_regs(used, CALLEE_SAVE_REG_COUNT, kCalleeSaveRegs, kReg64s, saves); - if (count > 0) - ADDI(SP, SP, IM(-POINTER_SIZE * ALIGN(count, 2))); + int fcount = enum_callee_save_regs(fused, CALLEE_SAVE_FREG_COUNT, kCalleeSaveFRegs, kFReg64s, + &saves[count]); + int total = count + fcount; + int total_aligned = ALIGN(total, 2); + if (total_aligned > 0) + ADDI(SP, SP, IM(-POINTER_SIZE * total_aligned)); for (int i = 0; i < count; ++i) { - SD(saves[i], IMMEDIATE_OFFSET((count - 1 - i) * POINTER_SIZE, SP)); + SD(saves[i], IMMEDIATE_OFFSET((total - 1 - i) * POINTER_SIZE, SP)); } - // int fcount = enum_callee_save_regs(fused, CALLEE_SAVE_FREG_COUNT, kCalleeSaveFRegs, kFReg64s, - // saves); - // for (int i = 0; i < fcount; i += 2) { - // if (i + 1 < fcount) - // STP(saves[i], saves[i + 1], PRE_INDEX(SP, -16)); - // else - // STR(saves[i], PRE_INDEX(SP, -16)); - // } - // return ALIGN(count, 2) + ALIGN(fcount, 2); - return ALIGN(count, 2); + for (int i = 0; i < fcount; ++i) { + FSD(saves[i + count], IMMEDIATE_OFFSET((total - 1 - count - i) * POINTER_SIZE, SP)); + } + return total_aligned; } void pop_callee_save_regs(unsigned long used, unsigned long fused) { - UNUSED(fused); - const char *saves[(N + 1) & ~1]; - // int fcount = enum_callee_save_regs(fused, CALLEE_SAVE_FREG_COUNT, kCalleeSaveFRegs, kFReg64s, - // saves); - // if ((fcount & 1) != 0) - // LDR(saves[--fcount], POST_INDEX(SP, 16)); - // for (int i = fcount; i > 0; ) { - // i -= 2; - // LDP(saves[i], saves[i + 1], POST_INDEX(SP, 16)); - // } + const char *saves[ALIGN(N, 2)]; int count = enum_callee_save_regs(used, CALLEE_SAVE_REG_COUNT, kCalleeSaveRegs, kReg64s, saves); - if (count == 0) + int fcount = enum_callee_save_regs(fused, CALLEE_SAVE_FREG_COUNT, kCalleeSaveFRegs, kFReg64s, + &saves[count]); + int total = count + fcount; + if (total == 0) return; - for (int i = count; i > 0; ) { - --i; + for (int i = fcount; i-- > 0; ) { + FLD(saves[i + count], IMMEDIATE_OFFSET((total - 1 - count - i) * POINTER_SIZE, SP)); + } + for (int i = count; i-- > 0; ) { LD(saves[i], IMMEDIATE_OFFSET((count - 1 - i) * POINTER_SIZE, SP)); } - ADDI(SP, SP, IM(POINTER_SIZE * ALIGN(count, 2))); + ADDI(SP, SP, IM(POINTER_SIZE * ALIGN(total, 2))); } int calculate_func_param_bottom(Function *func) { @@ -858,6 +851,10 @@ int calculate_func_param_bottom(Function *func) { } #undef N +inline bool is_freg(const char *reg) { + return reg[0] == 'f' && reg[1] != 'p'; +} + static Vector *push_caller_save_regs(unsigned long living) { Vector *saves = new_vector(); @@ -868,29 +865,32 @@ static Vector *push_caller_save_regs(unsigned long living) { } } - // { - // for (int i = 0; i < CALLER_SAVE_FREG_COUNT; ++i) { - // int ireg = kCallerSaveFRegs[i]; - // if (living & (1UL << (ireg + PHYSICAL_REG_MAX))) { - // // TODO: Detect register size. - // vec_push(saves, kFReg64s[ireg]); - // } - // } - // } + for (int i = 0; i < CALLER_SAVE_FREG_COUNT; ++i) { + int freg = kCallerSaveFRegs[i]; + if (living & (1UL << (freg + PHYSICAL_REG_MAX))) { + // TODO: Detect register size. + vec_push(saves, kFReg64s[freg]); + } + } - int n = saves->len; - for (int i = 0; i < n; ++i) { - SD(saves->data[i], IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); + for (int i = 0, n = saves->len; i < n; ++i) { + const char *reg = saves->data[i]; + if (is_freg(reg)) + FSD(reg, IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); + else + SD(reg, IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); } return saves; } static void pop_caller_save_regs(Vector *saves) { - int n = saves->len; - for (int i = n; i > 0; ) { - --i; - LD(saves->data[i], IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); + for (int n = saves->len, i = n; i-- > 0; ) { + const char *reg = saves->data[i]; + if (is_freg(reg)) + FLD(saves->data[i], IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); + else + LD(saves->data[i], IMMEDIATE_OFFSET((n - 1 - i) * POINTER_SIZE, SP)); } }