Skip to content

Commit

Permalink
JIT: Add support for struct returns from Swift reverse pinvokes (#100091
Browse files Browse the repository at this point in the history
)

Update the 10 tests to have some struct returns as well.

We also have to change the prestub to save `rax` since it is used as a register for the ret buffer in Swift calls.
  • Loading branch information
jakobbotsch authored Mar 23, 2024
1 parent 839bc58 commit d981ed9
Show file tree
Hide file tree
Showing 19 changed files with 650 additions and 379 deletions.
3 changes: 2 additions & 1 deletion src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_PINVOKE_PROLOG:
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) &
~fullIntArgRegMask(compiler->info.compCallConv)) == 0);

#ifdef PSEUDORANDOM_NOP_INSERTION
// the runtime side requires the codegen here to be consistent
Expand Down
69 changes: 47 additions & 22 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2895,9 +2895,9 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
else // we are doing the integer registers
{
noway_assert(argMax <= MAX_REG_ARG);
if (hasFixedRetBuffReg())
if (hasFixedRetBuffReg(compiler->info.compCallConv))
{
fixedRetBufIndex = theFixedRetBuffArgNum();
fixedRetBufIndex = theFixedRetBuffArgNum(compiler->info.compCallConv);
// We have an additional integer register argument when hasFixedRetBuffReg() is true
argMax = fixedRetBufIndex + 1;
assert(argMax == (MAX_REG_ARG + 1));
Expand Down Expand Up @@ -3105,7 +3105,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
slotRegType = compiler->GetEightByteType(structDesc, slotCounter);
}

regArgNum = genMapRegNumToRegArgNum(regNum, slotRegType);
regArgNum = genMapRegNumToRegArgNum(regNum, slotRegType, compiler->info.compCallConv);

if ((!doingFloat && (structDesc.IsIntegralSlot(slotCounter))) ||
(doingFloat && (structDesc.IsSseSlot(slotCounter))))
Expand Down Expand Up @@ -3139,7 +3139,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
#endif // defined(UNIX_AMD64_ABI)
{
// Bingo - add it to our table
regArgNum = genMapRegNumToRegArgNum(varDsc->GetArgReg(), regType);
regArgNum = genMapRegNumToRegArgNum(varDsc->GetArgReg(), regType, compiler->info.compCallConv);
slots = 1;

if (TargetArchitecture::IsArm32 ||
Expand Down Expand Up @@ -3202,7 +3202,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
for (int i = 0; i < slots; i++)
{
regType = regArgTab[regArgNum + i].type;
regNumber regNum = genMapRegArgNumToRegNum(regArgNum + i, regType);
regNumber regNum = genMapRegArgNumToRegNum(regArgNum + i, regType, compiler->info.compCallConv);

#if !defined(UNIX_AMD64_ABI)
assert((i > 0) || (regNum == varDsc->GetArgReg()));
Expand Down Expand Up @@ -3343,7 +3343,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
noway_assert(!regArgTab[argNum].stackArg);

var_types regType = regArgTab[argNum].type;
regNumber regNum = genMapRegArgNumToRegNum(argNum, regType);
regNumber regNum = genMapRegArgNumToRegNum(argNum, regType, compiler->info.compCallConv);

regNumber destRegNum = REG_NA;
if (varTypeIsPromotable(varDsc) &&
Expand Down Expand Up @@ -3423,7 +3423,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
if (genRegMask(destRegNum) & regArgMaskLive)
{
/* we are trashing a live argument register - record it */
unsigned destRegArgNum = genMapRegNumToRegArgNum(destRegNum, regType);
unsigned destRegArgNum = genMapRegNumToRegArgNum(destRegNum, regType, compiler->info.compCallConv);
noway_assert(destRegArgNum < argMax);
regArgTab[destRegArgNum].trashBy = argNum;
}
Expand Down Expand Up @@ -3570,7 +3570,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
noway_assert(genTypeSize(storeType) == TARGET_POINTER_SIZE);
#endif // TARGET_X86

regNumber srcRegNum = genMapRegArgNumToRegNum(argNum, storeType);
regNumber srcRegNum = genMapRegArgNumToRegNum(argNum, storeType, compiler->info.compCallConv);

// Stack argument - if the ref count is 0 don't care about it

Expand Down Expand Up @@ -3789,7 +3789,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere

assert(xtraReg != REG_NA);

regNumber begRegNum = genMapRegArgNumToRegNum(begReg, destMemType);
regNumber begRegNum = genMapRegArgNumToRegNum(begReg, destMemType, compiler->info.compCallConv);
GetEmitter()->emitIns_Mov(insCopy, size, xtraReg, begRegNum, /* canSkip */ false);
assert(!genIsValidIntReg(xtraReg) || !genIsValidFloatReg(begRegNum));

Expand All @@ -3802,8 +3802,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
{
/* mov dest, src */

regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType);
regNumber srcRegNum = genMapRegArgNumToRegNum(srcReg, destMemType);
regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType, compiler->info.compCallConv);
regNumber srcRegNum = genMapRegArgNumToRegNum(srcReg, destMemType, compiler->info.compCallConv);

GetEmitter()->emitIns_Mov(insCopy, size, destRegNum, srcRegNum, /* canSkip */ false);
assert(!genIsValidIntReg(destRegNum) || !genIsValidFloatReg(srcRegNum));
Expand Down Expand Up @@ -3855,7 +3855,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere

/* move the dest reg (begReg) in the extra reg */

regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType);
regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType, compiler->info.compCallConv);

GetEmitter()->emitIns_Mov(insCopy, size, destRegNum, xtraReg, /* canSkip */ false);
assert(!genIsValidIntReg(destRegNum) || !genIsValidFloatReg(xtraReg));
Expand Down Expand Up @@ -3913,16 +3913,17 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere

assert(varDsc->lvIsHfa());
assert((argNum >= firstArgNum) && (argNum <= lastArgNum));
assert(destRegNum == genMapRegArgNumToRegNum(argNum, regType));
assert(destRegNum == genMapRegArgNumToRegNum(argNum, regType, compiler->info.compCallConv));

// Pass 0: move the conflicting part; Pass1: insert everything else
//
for (int pass = 0; pass <= 1; pass++)
{
for (unsigned currentArgNum = firstArgNum; currentArgNum <= lastArgNum; currentArgNum++)
{
const regNumber regNum = genMapRegArgNumToRegNum(currentArgNum, regType);
bool insertArg =
const regNumber regNum =
genMapRegArgNumToRegNum(currentArgNum, regType, compiler->info.compCallConv);
bool insertArg =
((pass == 0) && (currentArgNum == argNum)) || ((pass == 1) && (currentArgNum != argNum));

if (insertArg)
Expand Down Expand Up @@ -3964,7 +3965,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
varNum = regArgTab[argNum].varNum;
varDsc = compiler->lvaGetDesc(varNum);
const var_types regType = regArgTab[argNum].type;
const regNumber regNum = genMapRegArgNumToRegNum(argNum, regType);
const regNumber regNum = genMapRegArgNumToRegNum(argNum, regType, compiler->info.compCallConv);
const var_types varRegType = varDsc->GetRegisterType();

#if defined(UNIX_AMD64_ABI)
Expand Down Expand Up @@ -4128,7 +4129,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
{
argRegCount = 2;
int nextArgNum = argNum + 1;
regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
regNumber nextRegNum =
genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type, compiler->info.compCallConv);
noway_assert(regArgTab[nextArgNum].varNum == varNum);
// Emit a shufpd with a 0 immediate, which preserves the 0th element of the dest reg
// and moves the 0th element of the src reg into the 1st element of the dest reg.
Expand All @@ -4155,8 +4157,9 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
{
int nextArgNum = argNum + i;
LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varDsc->lvFieldLclStart + i);
regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
destRegNum = fieldVarDsc->GetRegNum();
regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type,
compiler->info.compCallConv);
destRegNum = fieldVarDsc->GetRegNum();
noway_assert(regArgTab[nextArgNum].varNum == varNum);
noway_assert(genIsValidFloatReg(nextRegNum));
noway_assert(genIsValidFloatReg(destRegNum));
Expand All @@ -4177,7 +4180,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
int nextArgNum = argNum + i;
regArgElem* nextArgElem = &regArgTab[nextArgNum];
var_types nextArgType = nextArgElem->type;
regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, nextArgType);
regNumber nextRegNum =
genMapRegArgNumToRegNum(nextArgNum, nextArgType, compiler->info.compCallConv);
noway_assert(nextArgElem->varNum == varNum);
noway_assert(genIsValidFloatReg(nextRegNum));
noway_assert(genIsValidFloatReg(destRegNum));
Expand All @@ -4197,7 +4201,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
int nextArgNum = argNum + regSlot;
assert(!regArgTab[nextArgNum].processed);
regArgTab[nextArgNum].processed = true;
regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
regNumber nextRegNum =
genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type, compiler->info.compCallConv);
regArgMaskLive &= ~genRegMask(nextRegNum);
}
#endif // FEATURE_MULTIREG_ARGS
Expand Down Expand Up @@ -7926,12 +7931,32 @@ void CodeGen::genStructReturn(GenTree* treeNode)
toReg = retTypeDesc.GetABIReturnReg(1, compiler->info.compCallConv);
GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset);
}
#else // !TARGET_LOONGARCH64 && !TARGET_RISCV64
#else // !TARGET_LOONGARCH64 && !TARGET_RISCV64

#ifdef SWIFT_SUPPORT
const uint32_t* offsets = nullptr;
if (compiler->info.compCallConv == CorInfoCallConvExtension::Swift)
{
CORINFO_CLASS_HANDLE retTypeHnd = compiler->info.compMethodInfo->args.retTypeClass;
const CORINFO_SWIFT_LOWERING* lowering = compiler->GetSwiftLowering(retTypeHnd);
assert(!lowering->byReference && (regCount == lowering->numLoweredElements));
offsets = lowering->offsets;
}
#endif

int offset = 0;
for (unsigned i = 0; i < regCount; ++i)
{
var_types type = retTypeDesc.GetReturnRegType(i);
regNumber toReg = retTypeDesc.GetABIReturnReg(i, compiler->info.compCallConv);

#ifdef SWIFT_SUPPORT
if (offsets != nullptr)
{
offset = offsets[i];
}
#endif

GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset);
offset += genTypeSize(type);
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4941,7 +4941,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_PINVOKE_PROLOG:
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) &
~fullIntArgRegMask(compiler->info.compCallConv)) == 0);

// the runtime side requires the codegen here to be consistent
#ifdef PSEUDORANDOM_NOP_INSERTION
Expand Down
15 changes: 9 additions & 6 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5054,7 +5054,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;

case GT_PINVOKE_PROLOG:
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) &
~fullIntArgRegMask(compiler->info.compCallConv)) == 0);

// the runtime side requires the codegen here to be consistent
#ifdef PSEUDORANDOM_NOP_INSERTION
Expand Down Expand Up @@ -8154,7 +8155,7 @@ void CodeGen::genFnPrologCalleeRegArgs()
{
if (genIsValidIntReg(varDsc->GetArgReg()))
{
assert(isValidIntArgReg(varDsc->GetArgReg()));
assert(isValidIntArgReg(varDsc->GetArgReg(), compiler->info.compCallConv));
regArg[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgReg();
regArgInit[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgInitReg();
regArgAttr[varDsc->GetArgReg() - REG_ARG_FIRST] =
Expand Down Expand Up @@ -8404,10 +8405,11 @@ void CodeGen::genFnPrologCalleeRegArgs()
{
for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= 0; i--)
{
if (regArg[i] != REG_NA && !isValidIntArgReg(regArgInit[i]) && !isValidFloatArgReg(regArgInit[i]))
if (regArg[i] != REG_NA && !isValidIntArgReg(regArgInit[i], compiler->info.compCallConv) &&
!isValidFloatArgReg(regArgInit[i]))
{
assert(regArg[i] != regArgInit[i]);
assert(isValidIntArgReg(regArg[i]) || isValidFloatArgReg(regArg[i]));
assert(isValidIntArgReg(regArg[i], compiler->info.compCallConv) || isValidFloatArgReg(regArg[i]));

GetEmitter()->emitIns_Mov(regArgAttr[i], regArgInit[i], regArg[i], false);

Expand Down Expand Up @@ -8447,9 +8449,10 @@ void CodeGen::genFnPrologCalleeRegArgs()
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]));
assert(isValidIntArgReg(regArg[cur], compiler->info.compCallConv) ||
isValidFloatArgReg(regArg[cur]));

if (isValidIntArgReg(regArgInit[cur]))
if (isValidIntArgReg(regArgInit[cur], compiler->info.compCallConv))
{
cur = regArgInit[cur] - REG_ARG_FIRST;
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2171,7 +2171,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
#endif // !FEATURE_EH_FUNCLETS

case GT_PINVOKE_PROLOG:
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) &
~fullIntArgRegMask(compiler->info.compCallConv)) == 0);

#ifdef PSEUDORANDOM_NOP_INSERTION
// the runtime side requires the codegen here to be consistent
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7993,7 +7993,6 @@ class Compiler

public:
regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
void raCheckValidIntParamReg(LclVarDsc* dsc, regNumber inArgReg);

void raMarkStkVars();

Expand Down
22 changes: 11 additions & 11 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3292,11 +3292,11 @@ inline int getJitStressLevel()
* we return the fixed return buffer register
*/

inline regNumber genMapIntRegArgNumToRegNum(unsigned argNum)
inline regNumber genMapIntRegArgNumToRegNum(unsigned argNum, CorInfoCallConvExtension callConv)
{
if (hasFixedRetBuffReg() && (argNum == theFixedRetBuffArgNum()))
if (hasFixedRetBuffReg(callConv) && (argNum == theFixedRetBuffArgNum(callConv)))
{
return theFixedRetBuffReg();
return theFixedRetBuffReg(callConv);
}

assert(argNum < ArrLen(intArgRegs));
Expand All @@ -3316,15 +3316,15 @@ inline regNumber genMapFloatRegArgNumToRegNum(unsigned argNum)
#endif
}

__forceinline regNumber genMapRegArgNumToRegNum(unsigned argNum, var_types type)
__forceinline regNumber genMapRegArgNumToRegNum(unsigned argNum, var_types type, CorInfoCallConvExtension callConv)
{
if (varTypeUsesFloatArgReg(type))
{
return genMapFloatRegArgNumToRegNum(argNum);
}
else
{
return genMapIntRegArgNumToRegNum(argNum);
return genMapIntRegArgNumToRegNum(argNum, callConv);
}
}

Expand Down Expand Up @@ -3379,9 +3379,9 @@ __forceinline regMaskTP genMapArgNumToRegMask(unsigned argNum, var_types type)
* If we have a fixed return buffer register we return theFixedRetBuffArgNum
*/

inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum)
inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum, CorInfoCallConvExtension callConv)
{
assert(genRegMask(regNum) & fullIntArgRegMask());
assert(genRegMask(regNum) & fullIntArgRegMask(callConv));

switch (regNum)
{
Expand Down Expand Up @@ -3417,9 +3417,9 @@ inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum)
#endif
default:
// Check for the Arm64 fixed return buffer argument register
if (hasFixedRetBuffReg() && (regNum == theFixedRetBuffReg()))
if (hasFixedRetBuffReg(callConv) && (regNum == theFixedRetBuffReg(callConv)))
{
return theFixedRetBuffArgNum();
return theFixedRetBuffArgNum(callConv);
}
else
{
Expand Down Expand Up @@ -3477,15 +3477,15 @@ inline unsigned genMapFloatRegNumToRegArgNum(regNumber regNum)
#endif // !arm
}

inline unsigned genMapRegNumToRegArgNum(regNumber regNum, var_types type)
inline unsigned genMapRegNumToRegArgNum(regNumber regNum, var_types type, CorInfoCallConvExtension callConv)
{
if (varTypeUsesFloatArgReg(type))
{
return genMapFloatRegNumToRegArgNum(regNum);
}
else
{
return genMapIntRegNumToRegArgNum(regNum);
return genMapIntRegNumToRegArgNum(regNum, callConv);
}
}

Expand Down
Loading

0 comments on commit d981ed9

Please sign in to comment.