Skip to content

Commit

Permalink
JIT: Support Swift error handling for reverse P/Invokes (dotnet#100429)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanasifkhalid authored Apr 4, 2024
1 parent 48aa85f commit 16492b9
Show file tree
Hide file tree
Showing 20 changed files with 321 additions and 76 deletions.
11 changes: 11 additions & 0 deletions src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,17 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
TARGET_POINTER_SIZE));
}

if (wellKnownParam == WellKnownArg::SwiftError)
{
// We aren't actually going to pass the SwiftError* parameter in REG_SWIFT_ERROR.
// We won't be using this parameter at all, and shouldn't allocate registers/stack space for it,
// as that will mess with other args.
// Quirk: To work around the JIT for now, "pass" it in REG_SWIFT_ERROR,
// and let CodeGen::genFnProlog handle the rest.
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_SWIFT_ERROR, 0,
TARGET_POINTER_SIZE));
}

return m_classifier.Classify(comp, type, structLayout, wellKnownParam);
}
#endif
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2149,7 +2149,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog)
{
assert(compiler->compGeneratingEpilog);

regMaskTP maskPopRegs = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP maskPopRegs = regSet.rsGetModifiedCalleeSavedRegsMask();
regMaskTP maskPopRegsFloat = maskPopRegs & RBM_ALLFLOAT;
regMaskTP maskPopRegsInt = maskPopRegs & ~maskPopRegsFloat;

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
{
assert(compiler->compGeneratingEpilog);

regMaskTP rsRestoreRegs = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP rsRestoreRegs = regSet.rsGetModifiedCalleeSavedRegsMask();

if (isFramePointerUsed())
{
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4893,7 +4893,7 @@ void CodeGen::genPushCalleeSavedRegisters()
intRegState.rsCalleeRegArgMaskLiveIn);
#endif

regMaskTP rsPushRegs = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP rsPushRegs = regSet.rsGetModifiedCalleeSavedRegsMask();

#if ETW_EBP_FRAMED
if (!isFramePointerUsed() && regSet.rsRegsModified(RBM_FPBASE))
Expand Down Expand Up @@ -5540,8 +5540,8 @@ void CodeGen::genFnEpilog(BasicBlock* block)
compiler->unwindSetFrameReg(REG_SAVED_LOCALLOC_SP, 0);
}

if (jmpEpilog || genStackAllocRegisterMask(compiler->compLclFrameSize,
regSet.rsGetModifiedRegsMask() & RBM_FLT_CALLEE_SAVED) == RBM_NONE)
if (jmpEpilog ||
genStackAllocRegisterMask(compiler->compLclFrameSize, regSet.rsGetModifiedFltCalleeSavedRegsMask()) == RBM_NONE)
{
genFreeLclFrame(compiler->compLclFrameSize, &unwindStarted);
}
Expand Down
30 changes: 28 additions & 2 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2980,6 +2980,17 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
{
continue;
}

// On a similar note, the SwiftError* parameter is not a real argument,
// and should not be allocated any registers/stack space.
// We mark it as being passed in REG_SWIFT_ERROR so it won't interfere with other args.
// In genFnProlog, we should have removed this callee-save register from intRegState.rsCalleeRegArgMaskLiveIn.
// TODO-CQ: Fix this.
if (varNum == compiler->lvaSwiftErrorArg)
{
assert((intRegState.rsCalleeRegArgMaskLiveIn & RBM_SWIFT_ERROR) == 0);
continue;
}
#endif

var_types regType = compiler->mangleVarArgsType(varDsc->TypeGet());
Expand Down Expand Up @@ -5382,7 +5393,7 @@ void CodeGen::genFinalizeFrame()
noway_assert(!regSet.rsRegsModified(RBM_FPBASE));
#endif

regMaskTP maskCalleeRegsPushed = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP maskCalleeRegsPushed = regSet.rsGetModifiedCalleeSavedRegsMask();

#ifdef TARGET_ARMARCH
if (isFramePointerUsed())
Expand Down Expand Up @@ -6062,7 +6073,7 @@ void CodeGen::genFnProlog()

#ifdef TARGET_ARM
maskStackAlloc = genStackAllocRegisterMask(compiler->compLclFrameSize + extraFrameSize,
regSet.rsGetModifiedRegsMask() & RBM_FLT_CALLEE_SAVED);
regSet.rsGetModifiedFltCalleeSavedRegsMask());
#endif // TARGET_ARM

if (maskStackAlloc == RBM_NONE)
Expand Down Expand Up @@ -6137,6 +6148,10 @@ void CodeGen::genFnProlog()
GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SWIFT_SELF, compiler->lvaSwiftSelfArg, 0);
intRegState.rsCalleeRegArgMaskLiveIn &= ~RBM_SWIFT_SELF;
}
else if (compiler->lvaSwiftErrorArg != BAD_VAR_NUM)
{
intRegState.rsCalleeRegArgMaskLiveIn &= ~RBM_SWIFT_ERROR;
}
#endif

//
Expand Down Expand Up @@ -7820,6 +7835,17 @@ void CodeGen::genReturn(GenTree* treeNode)

genStackPointerCheck(doStackPointerCheck, compiler->lvaReturnSpCheck);
#endif // defined(DEBUG) && defined(TARGET_XARCH)

#ifdef SWIFT_SUPPORT
// If this method has a SwiftError* out parameter, load the SwiftError pseudolocal value into the error register.
// TODO-CQ: Introduce GenTree node that models returning a normal and Swift error value.
if (compiler->lvaSwiftErrorArg != BAD_VAR_NUM)
{
assert(compiler->info.compCallConv == CorInfoCallConvExtension::Swift);
assert(compiler->lvaSwiftErrorLocal != BAD_VAR_NUM);
GetEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_SWIFT_ERROR, compiler->lvaSwiftErrorLocal, 0);
}
#endif // SWIFT_SUPPORT
}

//------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7714,7 +7714,7 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe
{
assert(compiler->compGeneratingProlog);

regMaskTP rsPushRegs = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP rsPushRegs = regSet.rsGetModifiedCalleeSavedRegsMask();

#if ETW_EBP_FRAMED
if (!isFramePointerUsed() && regSet.rsRegsModified(RBM_FPBASE))
Expand Down Expand Up @@ -7879,7 +7879,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog)
{
assert(compiler->compGeneratingEpilog);

regMaskTP regsToRestoreMask = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP regsToRestoreMask = regSet.rsGetModifiedCalleeSavedRegsMask();

assert(isFramePointerUsed());

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7792,7 +7792,7 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe
// beforehand. We don't care if REG_SCRATCH will be overwritten, so we'll skip 'RegZeroed check'.
//
// Unlike on x86/x64, we can also push float registers to stack
regMaskTP rsPushRegs = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP rsPushRegs = regSet.rsGetModifiedCalleeSavedRegsMask();

#if ETW_EBP_FRAMED
if (!isFramePointerUsed() && regSet.rsRegsModified(RBM_FPBASE))
Expand Down Expand Up @@ -7955,7 +7955,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog)
{
assert(compiler->compGeneratingEpilog);

regMaskTP regsToRestoreMask = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP regsToRestoreMask = regSet.rsGetModifiedCalleeSavedRegsMask();

// On RV64 we always use the FP (frame-pointer)
assert(isFramePointerUsed());
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9756,7 +9756,7 @@ void CodeGen::genOSRSaveRemainingCalleeSavedRegisters()
// x86/x64 doesn't support push of xmm/ymm regs, therefore consider only integer registers for pushing onto stack
// here. Space for float registers to be preserved is stack allocated and saved as part of prolog sequence and not
// here.
regMaskTP rsPushRegs = regSet.rsGetModifiedRegsMask() & RBM_OSR_INT_CALLEE_SAVED;
regMaskTP rsPushRegs = regSet.rsGetModifiedOsrIntCalleeSavedRegsMask();

#if ETW_EBP_FRAMED
if (!isFramePointerUsed() && regSet.rsRegsModified(RBM_FPBASE))
Expand Down Expand Up @@ -9837,7 +9837,7 @@ void CodeGen::genPushCalleeSavedRegisters()
// x86/x64 doesn't support push of xmm/ymm regs, therefore consider only integer registers for pushing onto stack
// here. Space for float registers to be preserved is stack allocated and saved as part of prolog sequence and not
// here.
regMaskTP rsPushRegs = regSet.rsGetModifiedRegsMask() & RBM_INT_CALLEE_SAVED;
regMaskTP rsPushRegs = regSet.rsGetModifiedIntCalleeSavedRegsMask();

#if ETW_EBP_FRAMED
if (!isFramePointerUsed() && regSet.rsRegsModified(RBM_FPBASE))
Expand Down Expand Up @@ -9895,7 +9895,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog)
//
if (doesSupersetOfNormalPops)
{
regMaskTP rsPopRegs = regSet.rsGetModifiedRegsMask() & RBM_OSR_INT_CALLEE_SAVED;
regMaskTP rsPopRegs = regSet.rsGetModifiedOsrIntCalleeSavedRegsMask();
regMaskTP tier0CalleeSaves =
((regMaskTP)compiler->info.compPatchpointInfo->CalleeSaveRegisters()) & RBM_OSR_INT_CALLEE_SAVED;
regMaskTP additionalCalleeSaves = rsPopRegs & ~tier0CalleeSaves;
Expand All @@ -9915,7 +9915,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog)

// Registers saved by a normal prolog
//
regMaskTP rsPopRegs = regSet.rsGetModifiedRegsMask() & RBM_INT_CALLEE_SAVED;
regMaskTP rsPopRegs = regSet.rsGetModifiedIntCalleeSavedRegsMask();
const unsigned popCount = genPopCalleeSavedRegistersFromMask(rsPopRegs);
noway_assert(compiler->compCalleeRegsPushed == popCount);
}
Expand Down Expand Up @@ -10102,7 +10102,7 @@ void CodeGen::genFnEpilog(BasicBlock* block)

regMaskTP const tier0CalleeSaves = (regMaskTP)patchpointInfo->CalleeSaveRegisters();
regMaskTP const tier0IntCalleeSaves = tier0CalleeSaves & RBM_OSR_INT_CALLEE_SAVED;
regMaskTP const osrIntCalleeSaves = regSet.rsGetModifiedRegsMask() & RBM_OSR_INT_CALLEE_SAVED;
regMaskTP const osrIntCalleeSaves = regSet.rsGetModifiedOsrIntCalleeSavedRegsMask();
regMaskTP const allIntCalleeSaves = osrIntCalleeSaves | tier0IntCalleeSaves;
unsigned const tier0FrameSize = patchpointInfo->TotalFrameSize() + REGSIZE_BYTES;
unsigned const tier0IntCalleeSaveUsedSize = genCountBits(allIntCalleeSaves) * REGSIZE_BYTES;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5925,7 +5925,7 @@ void Compiler::generatePatchpointInfo()
// Record callee save registers.
// Currently only needed for x64.
//
regMaskTP rsPushRegs = codeGen->regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
regMaskTP rsPushRegs = codeGen->regSet.rsGetModifiedCalleeSavedRegsMask();
rsPushRegs |= RBM_FPBASE;
patchpointInfo->SetCalleeSaveRegisters((uint64_t)rsPushRegs);
JITDUMP("--OSR-- Tier0 callee saves: ");
Expand Down
10 changes: 6 additions & 4 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3876,6 +3876,8 @@ class Compiler

#ifdef SWIFT_SUPPORT
unsigned lvaSwiftSelfArg;
unsigned lvaSwiftErrorArg;
unsigned lvaSwiftErrorLocal;
#endif

#if defined(DEBUG) && defined(TARGET_XARCH)
Expand Down Expand Up @@ -4005,7 +4007,7 @@ class Compiler

void lvaClassifyParameterABI();

bool lvaInitSpecialSwiftParam(InitVarDscInfo* varDscInfo, CorInfoType type, CORINFO_CLASS_HANDLE typeHnd);
bool lvaInitSpecialSwiftParam(CORINFO_ARG_LIST_HANDLE argHnd, InitVarDscInfo* varDscInfo, CorInfoType type, CORINFO_CLASS_HANDLE typeHnd);

var_types lvaGetActualType(unsigned lclNum);
var_types lvaGetRealType(unsigned lclNum);
Expand Down Expand Up @@ -4420,12 +4422,12 @@ class Compiler
void impCheckForPInvokeCall(
GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, const DebugInfo& di = DebugInfo());
void impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, CallArg** swiftErrorArg);
void impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, CallArg** swiftErrorArg);
void impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, GenTree** swiftErrorNode);
void impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, GenTree** swiftErrorNode);
void impRetypeUnmanagedCallArgs(GenTreeCall* call);

#ifdef SWIFT_SUPPORT
void impAppendSwiftErrorStore(GenTreeCall* call, CallArg* const swiftErrorArg);
void impAppendSwiftErrorStore(GenTree* const swiftErrorNode);
#endif // SWIFT_SUPPORT

void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/jit/gtlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ GTNODE(LABEL , GenTree ,0,0,GTK_LEAF) // Jump-
GTNODE(JMP , GenTreeVal ,0,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function
GTNODE(FTN_ADDR , GenTreeFptrVal ,0,0,GTK_LEAF) // Address of a function
GTNODE(RET_EXPR , GenTreeRetExpr ,0,0,GTK_LEAF|DBK_NOTLIR) // Place holder for the return expression from an inline candidate
GTNODE(SWIFT_ERROR , GenTree ,0,0,GTK_LEAF) // Error register value post-Swift call

//-----------------------------------------------------------------------------
// Constant nodes:
Expand Down Expand Up @@ -287,6 +286,12 @@ GTNODE(RETFILT , GenTreeOp ,0,1,GTK_UNOP|GTK_NOVALUE) // End f
GTNODE(END_LFIN , GenTreeVal ,0,0,GTK_LEAF|GTK_NOVALUE) // End locally-invoked finally.
#endif // !FEATURE_EH_FUNCLETS

//-----------------------------------------------------------------------------
// Swift interop-specific nodes:
//-----------------------------------------------------------------------------

GTNODE(SWIFT_ERROR , GenTree ,0,0,GTK_LEAF) // Error register value post-Swift call

//-----------------------------------------------------------------------------
// Nodes used by Lower to generate a closer CPU representation of other nodes
//-----------------------------------------------------------------------------
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10462,6 +10462,21 @@ void Compiler::impLoadArg(unsigned ilArgNum, IL_OFFSET offset)
{
lclNum = lvaArg0Var;
}
#ifdef SWIFT_SUPPORT
else if (lclNum == lvaSwiftErrorArg)
{
// Convert any usages of the SwiftError pointer/ref parameter to pointers/refs to the SwiftError pseudolocal
// (set side effect flags so usages of references to pseudolocal aren't removed)
assert(info.compCallConv == CorInfoCallConvExtension::Swift);
assert(lvaSwiftErrorArg != BAD_VAR_NUM);
assert(lvaSwiftErrorLocal != BAD_VAR_NUM);
const var_types type = lvaGetDesc(lvaSwiftErrorArg)->TypeGet();
GenTree* const swiftErrorLocalRef = gtNewLclVarAddrNode(lvaSwiftErrorLocal, type);
impPushOnStack(swiftErrorLocalRef, typeInfo(type));
JITDUMP("\nCreated GT_LCL_ADDR of SwiftError pseudolocal\n");
return;
}
#endif // SWIFT_SUPPORT

impLoadVar(lclNum, offset);
}
Expand Down
Loading

0 comments on commit 16492b9

Please sign in to comment.