Skip to content

Commit 81c1d87

Browse files
authored
[RISC-V] Use common CodeGen::genHomeRegisterParams (#101288)
* Code review from #101114 * Use common genHomeRegisterParams on RISC-V * Make passSlot integer-only because we know hardware floating-point calling convention passes in registers only * Make a RISC-V specific routine for homing stack parts of split parameters. * Move genHomeStackPartOfSplitParameter out of genHomeSwiftStructParameters, share stack segment homing with Swift code
1 parent e1928e4 commit 81c1d87

File tree

6 files changed

+141
-538
lines changed

6 files changed

+141
-538
lines changed

src/coreclr/jit/abi.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,16 @@ bool ABIPassingInformation::HasExactlyOneStackSegment() const
258258
//
259259
bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
260260
{
261-
bool anyReg = false;
262-
bool anyStack = false;
263-
for (unsigned i = 0; i < NumSegments; i++)
261+
if (NumSegments < 2)
262+
return false;
263+
264+
bool isFirstInReg = Segments[0].IsPassedInRegister();
265+
for (unsigned i = 1; i < NumSegments; i++)
264266
{
265-
anyReg |= Segments[i].IsPassedInRegister();
266-
anyStack |= Segments[i].IsPassedOnStack();
267+
if (isFirstInReg != Segments[i].IsPassedInRegister())
268+
return true;
267269
}
268-
return anyReg && anyStack;
270+
return false;
269271
}
270272

271273
//-----------------------------------------------------------------------------

src/coreclr/jit/abi.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ struct ABIPassingInformation
5151
// - On loongarch64/riscv64, structs can be passed in two registers or
5252
// can be split out over register and stack, giving
5353
// multiple register segments and a struct segment.
54-
unsigned NumSegments = 0;
55-
ABIPassingSegment* Segments = nullptr;
54+
unsigned NumSegments;
55+
ABIPassingSegment* Segments;
5656

5757
ABIPassingInformation(unsigned numSegments = 0, ABIPassingSegment* segments = nullptr)
5858
: NumSegments(numSegments)

src/coreclr/jit/codegen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ class CodeGen final : public CodeGenInterface
284284
void genEnregisterOSRArgsAndLocals();
285285
#endif
286286

287+
void genHomeStackSegment(unsigned lclNum, const ABIPassingSegment& seg, regNumber initReg, bool* pInitRegZeroed);
287288
void genHomeSwiftStructParameters(bool handleStack);
289+
void genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegStillZeroed);
288290

289291
void genCheckUseBlockInit();
290292
#if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)

src/coreclr/jit/codegencommon.cpp

Lines changed: 101 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,7 +2802,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
28022802
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
28032803
*/
28042804

2805-
#if !defined(TARGET_RISCV64)
28062805
struct RegNode;
28072806

28082807
struct RegNodeEdge
@@ -3346,8 +3345,6 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
33463345
}
33473346
}
33483347

3349-
#endif
3350-
33513348
// -----------------------------------------------------------------------------
33523349
// genGetParameterHomingTempRegisterCandidates: Get the registers that are
33533350
// usable during register homing.
@@ -4122,15 +4119,69 @@ void CodeGen::genEnregisterOSRArgsAndLocals()
41224119
}
41234120
}
41244121

4122+
#if defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64)
4123+
//-----------------------------------------------------------------------------
4124+
// genHomeSwiftStructParameters: Move the incoming segment to the local stack frame.
4125+
//
4126+
// Arguments:
4127+
// lclNum - Number of local variable to home
4128+
// seg - Stack segment of the local variable to home
4129+
// initReg - Scratch register to use if needed
4130+
// initRegStillZeroed - Set to false if the scratch register was needed
4131+
//
4132+
void CodeGen::genHomeStackSegment(unsigned lclNum,
4133+
const ABIPassingSegment& seg,
4134+
regNumber initReg,
4135+
bool* initRegStillZeroed)
4136+
{
4137+
var_types loadType = TYP_UNDEF;
4138+
switch (seg.Size)
4139+
{
4140+
case 1:
4141+
loadType = TYP_UBYTE;
4142+
break;
4143+
case 2:
4144+
loadType = TYP_USHORT;
4145+
break;
4146+
case 3:
4147+
case 4:
4148+
loadType = TYP_INT;
4149+
break;
4150+
case 5:
4151+
case 6:
4152+
case 7:
4153+
case 8:
4154+
loadType = TYP_LONG;
4155+
break;
4156+
default:
4157+
assert(!"Unexpected segment size for struct parameter not passed implicitly by ref");
4158+
return;
4159+
}
4160+
emitAttr size = emitTypeSize(loadType);
4161+
4162+
int loadOffset =
4163+
-(isFramePointerUsed() ? genCallerSPtoFPdelta() : genCallerSPtoInitialSPdelta()) + (int)seg.GetStackOffset();
4164+
#ifdef TARGET_XARCH
4165+
GetEmitter()->emitIns_R_AR(ins_Load(loadType), size, initReg, genFramePointerReg(), loadOffset);
4166+
#else
4167+
genInstrWithConstant(ins_Load(loadType), size, initReg, genFramePointerReg(), loadOffset, initReg);
4168+
#endif
4169+
GetEmitter()->emitIns_S_R(ins_Store(loadType), size, initReg, lclNum, seg.Offset);
4170+
4171+
if (initRegStillZeroed)
4172+
*initRegStillZeroed = false;
4173+
}
4174+
#endif // defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64)
4175+
41254176
#ifdef SWIFT_SUPPORT
41264177

41274178
//-----------------------------------------------------------------------------
41284179
// genHomeSwiftStructParameters:
4129-
// Reassemble Swift struct parameters if necessary.
4180+
// Reassemble Swift struct parameters if necessary.
41304181
//
4131-
// Parameters:
4132-
// handleStack - If true, reassemble the segments that were passed on the stack.
4133-
// If false, reassemble the segments that were passed in registers.
4182+
// Arguments:
4183+
// handleStack - If true, reassemble the segments that were passed on the stack.
4184+
// If false, reassemble the segments that were passed in registers.
41344185
//
41354186
void CodeGen::genHomeSwiftStructParameters(bool handleStack)
41364187
{
@@ -4176,59 +4227,54 @@ void CodeGen::genHomeSwiftStructParameters(bool handleStack)
41764227
}
41774228
else
41784229
{
4179-
var_types loadType = TYP_UNDEF;
4180-
switch (seg.Size)
4181-
{
4182-
case 1:
4183-
loadType = TYP_UBYTE;
4184-
break;
4185-
case 2:
4186-
loadType = TYP_USHORT;
4187-
break;
4188-
case 3:
4189-
case 4:
4190-
loadType = TYP_INT;
4191-
break;
4192-
case 5:
4193-
case 6:
4194-
case 7:
4195-
case 8:
4196-
loadType = TYP_LONG;
4197-
break;
4198-
default:
4199-
assert(!"Unexpected segment size for struct parameter not passed implicitly by ref");
4200-
continue;
4201-
}
4230+
// We can use REG_SCRATCH as a temporary register here as we ensured that during LSRA build.
4231+
genHomeStackSegment(lclNum, seg, REG_SCRATCH, nullptr);
4232+
}
4233+
}
4234+
}
4235+
}
4236+
#endif
42024237

4203-
int offset;
4204-
if (isFramePointerUsed())
4205-
{
4206-
offset = -genCallerSPtoFPdelta();
4207-
}
4208-
else
4209-
{
4210-
offset = -genCallerSPtoInitialSPdelta();
4211-
}
4238+
//-----------------------------------------------------------------------------
4239+
// genHomeStackPartOfSplitParameter: Home the tail (stack) portion of a split parameter next to where the head
4240+
// (register) portion is homed.
4241+
//
4242+
// Arguments:
4243+
// initReg - scratch register to use if needed
4244+
// initRegStillZeroed - set to false if scratch register was needed
4245+
//
4246+
// Notes:
4247+
// No-op on platforms where argument registers are already homed to form a contiguous space with incoming stack.
4248+
//
4249+
void CodeGen::genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegStillZeroed)
4250+
{
4251+
#ifdef TARGET_RISCV64
4252+
unsigned lclNum = 0;
4253+
for (; lclNum < compiler->info.compArgsCount; lclNum++)
4254+
{
4255+
LclVarDsc* var = compiler->lvaGetDesc(lclNum);
4256+
if (!var->lvIsSplit || !var->lvOnFrame)
4257+
continue;
42124258

4213-
offset += (int)seg.GetStackOffset();
4259+
JITDUMP("Homing stack part of split parameter V%02u\n", lclNum);
42144260

4215-
// Move the incoming segment to the local stack frame. We can
4216-
// use REG_SCRATCH as a temporary register here as we ensured
4217-
// that during LSRA build.
4218-
#ifdef TARGET_XARCH
4219-
GetEmitter()->emitIns_R_AR(ins_Load(loadType), emitTypeSize(loadType), REG_SCRATCH,
4220-
genFramePointerReg(), offset);
4221-
#else
4222-
genInstrWithConstant(ins_Load(loadType), emitTypeSize(loadType), REG_SCRATCH, genFramePointerReg(),
4223-
offset, REG_SCRATCH);
4224-
#endif
4261+
assert(varTypeIsStruct(var));
4262+
assert(!compiler->lvaIsImplicitByRefLocal(lclNum));
4263+
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum);
4264+
assert(abiInfo.NumSegments == 2);
4265+
assert(abiInfo.Segments[0].GetRegister() == REG_ARG_LAST);
4266+
const ABIPassingSegment& seg = abiInfo.Segments[1];
42254267

4226-
GetEmitter()->emitIns_S_R(ins_Store(loadType), emitTypeSize(loadType), REG_SCRATCH, lclNum, seg.Offset);
4227-
}
4268+
genHomeStackSegment(lclNum, seg, initReg, initRegStillZeroed);
4269+
4270+
for (lclNum += 1; lclNum < compiler->info.compArgsCount; lclNum++)
4271+
{
4272+
assert(!compiler->lvaGetDesc(lclNum)->lvIsSplit); // There should be only one split parameter
42284273
}
4274+
break;
42294275
}
4230-
}
42314276
#endif
4277+
}
42324278

42334279
/*-----------------------------------------------------------------------------
42344280
*
@@ -5547,6 +5593,8 @@ void CodeGen::genFnProlog()
55475593
{
55485594
compiler->lvaUpdateArgsWithInitialReg();
55495595

5596+
genHomeStackPartOfSplitParameter(initReg, &initRegZeroed);
5597+
55505598
if ((intRegState.rsCalleeRegArgMaskLiveIn | floatRegState.rsCalleeRegArgMaskLiveIn) != RBM_NONE)
55515599
{
55525600
genHomeRegisterParams(initReg, &initRegZeroed);

0 commit comments

Comments
 (0)