-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JIT: Add basic support for Swift reverse pinvokes #100018
Changes from all commits
9a9a052
bfd4e28
53d00a6
ea5c172
4fd5964
ea32187
e01d190
40d998a
4c64049
7d43f3c
49826a8
d65c4c3
3e76803
21d1c52
b4b73d7
cb44f0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -456,13 +456,14 @@ enum class DoNotEnregisterReason | |
#endif | ||
LclAddrNode, // the local is accessed with LCL_ADDR_VAR/FLD. | ||
CastTakesAddr, | ||
StoreBlkSrc, // the local is used as STORE_BLK source. | ||
SwizzleArg, // the local is passed using LCL_FLD as another type. | ||
BlockOpRet, // the struct is returned and it promoted or there is a cast. | ||
ReturnSpCheck, // the local is used to do SP check on return from function | ||
CallSpCheck, // the local is used to do SP check on every call | ||
SimdUserForcesDep, // a promoted struct was used by a SIMD/HWI node; it must be dependently promoted | ||
HiddenBufferStructArg // the argument is a hidden return buffer passed to a method. | ||
StoreBlkSrc, // the local is used as STORE_BLK source. | ||
SwizzleArg, // the local is passed using LCL_FLD as another type. | ||
BlockOpRet, // the struct is returned and it promoted or there is a cast. | ||
ReturnSpCheck, // the local is used to do SP check on return from function | ||
CallSpCheck, // the local is used to do SP check on every call | ||
SimdUserForcesDep, // a promoted struct was used by a SIMD/HWI node; it must be dependently promoted | ||
HiddenBufferStructArg, // the argument is a hidden return buffer passed to a method. | ||
NonStandardParameter, // local is a parameter that is passed in a register unhandled by genFnPrologCalleeRegArgs | ||
}; | ||
|
||
enum class AddressExposedReason | ||
|
@@ -489,7 +490,6 @@ class LclVarDsc | |
// The constructor. Most things can just be zero'ed. | ||
// | ||
// Initialize the ArgRegs to REG_STK. | ||
// Morph will update if this local is passed in a register. | ||
LclVarDsc() | ||
: _lvArgReg(REG_STK) | ||
#if FEATURE_MULTIREG_ARGS | ||
|
@@ -3860,6 +3860,10 @@ class Compiler | |
// where it is used to detect tail-call chains. | ||
unsigned lvaRetAddrVar; | ||
|
||
#ifdef SWIFT_SUPPORT | ||
unsigned lvaSwiftSelfArg; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since all the places where we check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'll do that. |
||
#endif | ||
|
||
#if defined(DEBUG) && defined(TARGET_XARCH) | ||
|
||
unsigned lvaReturnSpCheck; // Stores SP to confirm it is not corrupted on return. | ||
|
@@ -3982,6 +3986,8 @@ class Compiler | |
CORINFO_ARG_LIST_HANDLE varList, | ||
CORINFO_SIG_INFO* varSig); | ||
|
||
bool lvaInitSpecialSwiftParam(InitVarDscInfo* varDscInfo, CorInfoType type, CORINFO_CLASS_HANDLE typeHnd); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on the naming of this method, I guess we'll be using this to do the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I was thinking that same logic could live here. |
||
|
||
var_types lvaGetActualType(unsigned lclNum); | ||
var_types lvaGetRealType(unsigned lclNum); | ||
|
||
|
@@ -7984,6 +7990,7 @@ class Compiler | |
|
||
public: | ||
regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc); | ||
void raCheckValidIntParamReg(LclVarDsc* dsc, regNumber inArgReg); | ||
|
||
void raMarkStkVars(); | ||
|
||
|
@@ -10636,6 +10643,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
unsigned m_returnSpCheck; | ||
unsigned m_callSpCheck; | ||
unsigned m_simdUserForcesDep; | ||
unsigned m_nonStandardParameter; | ||
unsigned m_liveInOutHndlr; | ||
unsigned m_depField; | ||
unsigned m_noRegVars; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,10 @@ void Compiler::lvaInit() | |
lvaMonAcquired = BAD_VAR_NUM; | ||
lvaRetAddrVar = BAD_VAR_NUM; | ||
|
||
#ifdef SWIFT_SUPPORT | ||
lvaSwiftSelfArg = BAD_VAR_NUM; | ||
#endif | ||
|
||
lvaInlineeReturnSpillTemp = BAD_VAR_NUM; | ||
|
||
gsShadowVarInfo = nullptr; | ||
|
@@ -622,6 +626,17 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un | |
lvaSetClass(varDscInfo->varNum, clsHnd); | ||
} | ||
|
||
// The final home for this incoming parameter might be our local stack frame. | ||
varDsc->lvOnFrame = true; | ||
|
||
#ifdef SWIFT_SUPPORT | ||
if ((info.compCallConv == CorInfoCallConvExtension::Swift) && | ||
lvaInitSpecialSwiftParam(varDscInfo, strip(corInfoType), typeHnd)) | ||
{ | ||
continue; | ||
} | ||
#endif | ||
|
||
// For ARM, ARM64, LOONGARCH64, RISCV64 and AMD64 varargs, all arguments go in integer registers | ||
var_types argType = mangleVarArgsType(varDsc->TypeGet()); | ||
|
||
|
@@ -821,10 +836,6 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un | |
} | ||
#endif // UNIX_AMD64_ABI | ||
|
||
// The final home for this incoming register might be our local stack frame. | ||
// For System V platforms the final home will always be on the local stack frame. | ||
varDsc->lvOnFrame = true; | ||
|
||
bool canPassArgInRegisters = false; | ||
|
||
#if defined(UNIX_AMD64_ABI) | ||
|
@@ -1301,6 +1312,48 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un | |
#endif // TARGET_ARM | ||
} | ||
|
||
#ifdef SWIFT_SUPPORT | ||
//----------------------------------------------------------------------------- | ||
// lvaInitSpecialSwiftParam: | ||
// If the parameter is a special Swift parameter then initialize it and return true. | ||
// | ||
// Parameters: | ||
// varDsc - LclVarDsc* for the parameter | ||
// type - Type of the parameter | ||
// typeHnd - Class handle for the type of the parameter | ||
// | ||
// Remarks: | ||
// Handles SwiftSelf. | ||
// | ||
bool Compiler::lvaInitSpecialSwiftParam(InitVarDscInfo* varDscInfo, CorInfoType type, CORINFO_CLASS_HANDLE typeHnd) | ||
{ | ||
if (type != CORINFO_TYPE_VALUECLASS) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!info.compCompHnd->isIntrinsicType(typeHnd)) | ||
{ | ||
return false; | ||
} | ||
|
||
const char* namespaceName; | ||
const char* className = info.compCompHnd->getClassNameFromMetadata(typeHnd, &namespaceName); | ||
if ((strcmp(className, "SwiftSelf") == 0) && (strcmp(namespaceName, "System.Runtime.InteropServices.Swift") == 0)) | ||
{ | ||
LclVarDsc* varDsc = varDscInfo->varDsc; | ||
varDsc->SetArgReg(REG_SWIFT_SELF); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean that the reg value is loaded into the SwiftSelf argument? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The JIT can directly reference and use IL locals in its internal IR, and each of the parameter locals are marked with information about how they're passed (in a register or on stack). That's what the code here is doing. It's ultimately up to the register allocator to decide what register every local is allocated into. For parameter locals LSRA will prefer to keep it in the same register that it was passed in, but it might also be allocated to another register (in which case a move from the initial register is needed in the prolog) or to stack (in which case a store to the stack frame is needed). The PR here doesn't allow enregistering There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, thanks for info. |
||
varDsc->SetOtherArgReg(REG_NA); | ||
varDsc->lvIsRegArg = true; | ||
lvaSwiftSelfArg = varDscInfo->varNum; | ||
lvaSetVarDoNotEnregister(lvaSwiftSelfArg DEBUGARG(DoNotEnregisterReason::NonStandardParameter)); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
#endif | ||
|
||
/*****************************************************************************/ | ||
void Compiler::lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo) | ||
{ | ||
|
@@ -2752,6 +2805,10 @@ void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregister | |
JITDUMP("Promoted struct used by a SIMD/HWI node\n"); | ||
break; | ||
|
||
case DoNotEnregisterReason::NonStandardParameter: | ||
JITDUMP("Non-standard parameter\n"); | ||
break; | ||
|
||
default: | ||
unreached(); | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1721,8 +1721,6 @@ void CodeGen::psiBegProlog() | |
regNumber otherRegNum = REG_NA; | ||
for (unsigned nCnt = 0; nCnt < structDesc.eightByteCount; nCnt++) | ||
{ | ||
var_types regType = TYP_UNDEF; | ||
|
||
if (nCnt == 0) | ||
{ | ||
regNum = lclVarDsc->GetArgReg(); | ||
|
@@ -1735,12 +1733,6 @@ void CodeGen::psiBegProlog() | |
{ | ||
assert(false && "Invalid eightbyte number."); | ||
} | ||
|
||
regType = compiler->GetEightByteType(structDesc, nCnt); | ||
#ifdef DEBUG | ||
regType = compiler->mangleVarArgsType(regType); | ||
assert(genMapRegNumToRegArgNum((nCnt == 0 ? regNum : otherRegNum), regType) != (unsigned)-1); | ||
#endif // DEBUG | ||
Comment on lines
-1738
to
-1743
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed this assert in a couple of places because I don't think it is asserting anything meaningful. The existence and mapping of |
||
} | ||
|
||
varLocation.storeVariableInRegisters(regNum, otherRegNum); | ||
|
@@ -1789,7 +1781,6 @@ void CodeGen::psiBegProlog() | |
regType = lclVarDsc->GetHfaType(); | ||
} | ||
#endif // defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) | ||
assert(genMapRegNumToRegArgNum(lclVarDsc->GetArgReg(), regType) != (unsigned)-1); | ||
#endif // DEBUG | ||
varLocation.storeVariableInRegisters(lclVarDsc->GetArgReg(), REG_NA); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there situations where
lvaSwiftSelfArg
is valid, but the reg mask doesn't include the Swift self reg? If not, maybe we should assert that the reg mask includes it iflvaSwiftSelfArg
is set.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if
lvaSwiftSelfArg
is dead on entry then it shouldn't be in the live-in set.