From d7ff477159b2e45543f799be15103045b3974253 Mon Sep 17 00:00:00 2001 From: Timur Mustafin Date: Wed, 6 Sep 2023 01:44:38 +0300 Subject: [PATCH] [RISC-V] regArg dependcies unrolling in genFnPrologCalleeRegArgs() --- src/coreclr/jit/codegenriscv64.cpp | 265 ++++++++++------------------- src/coreclr/jit/emitriscv64.cpp | 28 +++ src/coreclr/jit/emitriscv64.h | 2 + 3 files changed, 124 insertions(+), 171 deletions(-) diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index d4bd4dcab9b6d..a0c8b9d7f3174 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -7578,11 +7578,22 @@ void CodeGen::genFnPrologCalleeRegArgs() noway_assert(regArgMaskLive != 0); unsigned varNum; - unsigned regArgMaskIsInt = 0; - unsigned regArgNum = 0; - // Process any circular dependencies - unsigned regArg[MAX_REG_ARG * 2] = {0}; - unsigned regArgInit[MAX_REG_ARG * 2] = {0}; + unsigned regArgNum = 0; + // Process any rearrangements including circular dependencies. + regNumber regArg[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; + regNumber regArgInit[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; + emitAttr regArgAttr[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; + + for (int i = 0; i < MAX_REG_ARG + MAX_FLOAT_REG_ARG; i++) + { + regArg[i] = REG_NA; + +#ifdef DEBUG + regArgInit[i] = REG_NA; + regArgAttr[i] = EA_UNKNOWN; +#endif + } + for (varNum = 0; varNum < compiler->lvaCount; ++varNum) { LclVarDsc* varDsc = compiler->lvaTable + varNum; @@ -7638,20 +7649,19 @@ void CodeGen::genFnPrologCalleeRegArgs() { if (genIsValidIntReg(varDsc->GetArgReg())) { - assert(varDsc->GetArgReg() >= REG_ARG_FIRST && varDsc->GetArgReg() <= REG_ARG_LAST); + assert(isValidIntArgReg(varDsc->GetArgReg())); regArg[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgReg(); regArgInit[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgInitReg(); - if (varDsc->TypeGet() == TYP_INT) - { - regArgMaskIsInt = 1 << (unsigned)varDsc->GetArgReg(); - } + regArgAttr[varDsc->GetArgReg() - REG_ARG_FIRST] = + varDsc->TypeGet() == TYP_INT ? EA_4BYTE : EA_PTRSIZE; } else { - assert(genIsValidFloatReg(varDsc->GetArgReg())); - assert(varDsc->GetArgReg() >= REG_ARG_FP_FIRST && varDsc->GetArgReg() <= REG_ARG_FP_LAST); - regArg[(varDsc->GetArgReg() - REG_ARG_FP_FIRST) | 0x8] = varDsc->GetArgReg(); - regArgInit[(varDsc->GetArgReg() - REG_ARG_FP_FIRST) | 0x8] = varDsc->GetArgInitReg(); + assert(isValidFloatArgReg(varDsc->GetArgReg())); + regArg[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgReg(); + regArgInit[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgInitReg(); + regArgAttr[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = + varDsc->TypeGet() == TYP_FLOAT ? EA_4BYTE : EA_PTRSIZE; } regArgNum++; } @@ -7673,9 +7683,11 @@ void CodeGen::genFnPrologCalleeRegArgs() } else { - assert(genIsValidFloatReg(varDsc->GetArgReg())); - regArg[(varDsc->GetArgReg() & 7) | 0x8] = varDsc->GetArgReg(); - regArgInit[(varDsc->GetArgReg() & 7) | 0x8] = varDsc->GetArgInitReg(); + assert(isValidFloatArgReg(varDsc->GetArgReg())); + regArg[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgReg(); + regArgInit[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgInitReg(); + regArgAttr[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = + varDsc->TypeGet() == TYP_FLOAT ? EA_4BYTE : EA_PTRSIZE; regArgNum++; } } @@ -7885,22 +7897,17 @@ void CodeGen::genFnPrologCalleeRegArgs() if (regArgNum > 0) { - for (int i = MAX_REG_ARG - 1; i >= 0; i--) + for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= 0; i--) { - if (regArg[i] > 0 && (regArgInit[i] <= REG_S1 || regArgInit[i] > REG_A7)) + if (regArg[i] != REG_NA && !isValidIntArgReg(regArgInit[i]) && !isValidFloatArgReg(regArgInit[i])) { - instruction ins; - if ((regArgMaskIsInt & (1 << regArg[i])) != 0) - { - ins = INS_slliw; - } - else - { - ins = INS_ori; - } - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], 0); - regArgMaskLive &= ~genRegMask((regNumber)regArg[i]); - regArg[i] = 0; + assert(regArg[i] != regArgInit[i]); + assert(isValidIntArgReg(regArg[i]) || isValidFloatArgReg(regArg[i])); + + GetEmitter()->emitIns_Mov(regArgAttr[i], regArgInit[i], regArg[i], false); + + regArgMaskLive &= ~genRegMask(regArg[i]); + regArg[i] = REG_NA; regArgNum -= 1; } } @@ -7908,170 +7915,86 @@ void CodeGen::genFnPrologCalleeRegArgs() if (regArgNum > 0) { - instruction ins; - for (int i = MAX_REG_ARG - 1; i >= 0; i--) + for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= 0; i--) { - if (regArg[i] > 0) + if (regArg[i] != REG_NA) { - assert(genIsValidIntReg((regNumber)regArg[i])); - assert(genIsValidIntReg((regNumber)regArgInit[i])); + assert(regArg[i] != regArgInit[i]); - regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[i]); - if ((regArgMaskIsInt & (1 << regArg[i])) != 0) - { - ins = INS_slliw; - } - else - { - ins = INS_ori; - } + // regArg indexes list + unsigned indexList[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; + int count = 0; // Number of nodes in list + bool loop = false; // List has a loop - if (regArgNum == 0) - { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], 0); - break; - } - else if (regArgInit[i] > regArg[i]) - { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], 0); - } - else + for (unsigned cur = i; regArg[cur] != REG_NA; count++) { - assert(i > 0); - assert(regArgNum > 0); + if (cur == i && count > 0) + { + loop = true; + break; + } + + indexList[count] = cur; + + for (int count2 = 0; count2 < count; count2++) + { + // The list could not have backlinks except last to first case which handled above. + assert(cur != indexList[count2] && "Attempt to move several values on same register."); + } + assert(cur < MAX_REG_ARG + MAX_FLOAT_REG_ARG); + assert(isValidIntArgReg(regArg[cur]) || isValidFloatArgReg(regArg[cur])); - int j = regArgInit[i] - REG_ARG_FIRST; - assert((j >= 0) && (j < MAX_REG_ARG)); - if (regArg[j] == 0) + if (isValidIntArgReg(regArgInit[cur])) { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], 0); + cur = regArgInit[cur] - REG_ARG_FIRST; + } + else if (isValidFloatArgReg(regArgInit[cur])) + { + cur = regArgInit[cur] - REG_ARG_FP_FIRST + MAX_REG_ARG; } else { - int k = regArgInit[j] - REG_ARG_FIRST; - // assert((k >= 0) && (k < MAX_REG_ARG)); - instruction ins2 = (regArgMaskIsInt & (1 << regArg[j])) != 0 ? INS_slliw : INS_ori; - if ((regArg[k] == 0) || (k > i) || k < 0) - { - GetEmitter()->emitIns_R_R_I(ins2, EA_PTRSIZE, (regNumber)regArgInit[j], - (regNumber)regArg[j], 0); - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], - 0); - regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[j]); - regArg[j] = 0; - } - else if (k == i) - { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, rsGetRsvdReg(), (regNumber)regArg[i], 0); - GetEmitter()->emitIns_R_R_I(ins2, EA_PTRSIZE, (regNumber)regArgInit[j], - (regNumber)regArg[j], 0); - GetEmitter()->emitIns_R_R_I(INS_ori, EA_PTRSIZE, (regNumber)regArgInit[i], rsGetRsvdReg(), - 0); - regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[j]); - regArg[j] = 0; - } - else - { - NYI_RISCV64("-----------CodeGen::genFnPrologCalleeRegArgs() error!--"); - } - - if (regArgNum == 0) - { - break; - } + assert(!"Argument register is neither valid float nor valid int argument register"); } } - } - } - if (regArgNum > 0) - { - for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= MAX_REG_ARG; i--) - { - if (regArg[i] > 0) + if (loop) + { + unsigned tmpArg = indexList[count - 1]; + + GetEmitter()->emitIns_Mov(regArgAttr[tmpArg], rsGetRsvdReg(), regArg[tmpArg], false); + count--; // Decrease count to not access last node which regArgInit points to start node i + assert(count > 0); + } + + for (int cur = count - 1; cur >= 0; cur--) { - assert(genIsValidFloatReg((regNumber)regArg[i])); + unsigned tmpArg = indexList[cur]; - instruction ins = genIsValidIntReg((regNumber)regArgInit[i]) ? INS_fmv_x_d : INS_fsgnj_d; + GetEmitter()->emitIns_Mov(regArgAttr[tmpArg], regArgInit[tmpArg], regArg[tmpArg], false); + regArgMaskLive &= ~genRegMask(regArg[tmpArg]); + regArg[tmpArg] = REG_NA; regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[i]); - if (regArgNum == 0) - { - GetEmitter()->emitIns_Mov(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], - true); - break; - } - else if (regArgInit[i] > regArg[i] || (regArgInit[i] <= REG_F9)) - { - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, (regNumber)regArgInit[i], - (regNumber)regArg[i], (regNumber)regArg[i]); - } - else - { - assert(i > MAX_REG_ARG); - assert(regArgNum > 0); + assert(regArgNum >= 0); + }; - int j = genIsValidIntReg((regNumber)regArgInit[i]) - ? (regArgInit[i] - REG_ARG_FIRST) - : ((((int)regArgInit[i]) - REG_ARG_FP_FIRST) + 0x8); - if (j < MAX_REG_ARG || regArg[j] == 0) - { - GetEmitter()->emitIns_Mov(ins, EA_PTRSIZE, (regNumber)regArgInit[i], (regNumber)regArg[i], - true); - } - else - { - // NOTE: Not support the int-register case. - assert(genIsValidFloatReg((regNumber)regArg[j])); - assert(genIsValidFloatReg((regNumber)regArgInit[j])); + if (loop) + { + unsigned tmpArg = indexList[count]; // count was decreased for loop case - int k = (((int)regArgInit[j]) - REG_ARG_FP_FIRST) + 0x8; - if ((regArg[k] == 0) || (k > i) || (k < MAX_REG_ARG)) - { - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, (regNumber)regArgInit[j], - (regNumber)regArg[j], (regNumber)regArg[j]); - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, (regNumber)regArgInit[i], - (regNumber)regArg[i], (regNumber)regArg[i]); - regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[j]); - regArg[j] = 0; - if (regArgNum == 0) - { - break; - } - } - else if (k == i) - { - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, REG_SCRATCH_FLT, - (regNumber)regArg[i], (regNumber)regArg[i]); - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, (regNumber)regArgInit[j], - (regNumber)regArg[j], (regNumber)regArg[j]); - GetEmitter()->emitIns_R_R_R(INS_fsgnj_d, EA_PTRSIZE, (regNumber)regArgInit[i], - REG_SCRATCH_FLT, REG_SCRATCH_FLT); - regArgNum--; - regArgMaskLive &= ~genRegMask((regNumber)regArg[j]); - regArg[j] = 0; - if (regArgNum == 0) - { - break; - } - } - else - { - NYI_RISCV64("-----------CodeGen::genFnPrologCalleeRegArgs() error!--"); - } - } - } + GetEmitter()->emitIns_Mov(regArgAttr[i], regArg[tmpArg], rsGetRsvdReg(), false); + + regArgMaskLive &= ~genRegMask(regArg[tmpArg]); + regArg[tmpArg] = REG_NA; + regArgNum--; } + assert(regArgNum >= 0); } } - assert(regArgNum == 0); } + assert(regArgNum == 0); assert(!regArgMaskLive); } diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index d33deb9fd4d6e..73a4536ddb48f 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -561,6 +561,34 @@ void emitter::emitIns_Mov( } } +void emitter::emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip) +{ + if (!canSkip || dstReg != srcReg) + { + assert(attr == EA_4BYTE || attr == EA_PTRSIZE); + if (isGeneralRegisterOrR0(dstReg) && isGeneralRegisterOrR0(srcReg)) + { + emitIns_R_R_I(attr == EA_4BYTE ? INS_addiw : INS_addi, attr, dstReg, srcReg, 0); + } + else if (isGeneralRegisterOrR0(dstReg) && genIsValidFloatReg(srcReg)) + { + emitIns_R_R(attr == EA_4BYTE ? INS_fmv_x_w : INS_fmv_x_d, attr, dstReg, srcReg); + } + else if (genIsValidFloatReg(dstReg) && isGeneralRegisterOrR0(srcReg)) + { + emitIns_R_R(attr == EA_4BYTE ? INS_fmv_w_x : INS_fmv_d_x, attr, dstReg, srcReg); + } + else if (genIsValidFloatReg(dstReg) && genIsValidFloatReg(srcReg)) + { + emitIns_R_R_R(attr == EA_4BYTE ? INS_fsgnj_s : INS_fsgnj_d, attr, dstReg, srcReg, srcReg); + } + else + { + assert(!"Invalid registers in emitIns_Mov()\n"); + } + } +} + /***************************************************************************** * * Add an instruction referencing two registers diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index a572ee9d2cf8c..ce207755efc4d 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -171,6 +171,8 @@ void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, ins void emitIns_Mov( instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE); +void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false); + void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE); void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)