-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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 GT_SWIFT_ERROR_RET to represent loading error register upon return #100692
Changes from 12 commits
a9646c1
b328337
63eb15c
674d8f1
7d2e8fa
a342e00
6e50ea7
aa8c83c
9e310ec
15d39bf
873e15a
5d96892
24e8d0d
bf186b7
c381c48
70a69d7
de4457b
7096e23
927a55e
848704b
502f471
e8b1dbc
2dce428
38ad8a7
18df9c7
86a0825
41ec8f7
6d9d360
0cd339d
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 |
---|---|---|
|
@@ -10883,6 +10883,22 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) | |
} | ||
} | ||
|
||
#ifdef SWIFT_SUPPORT | ||
// If this method has a SwiftError* out parameter, we need to set the error register upon returning. | ||
// By placing the GT_SWIFT_ERROR_RET node before the GT_RETURN node, | ||
// we don't have to teach the JIT that GT_SWIFT_ERROR_RET is a valid terminator for BBJ_RETURN blocks. | ||
// During lowering, we will move the GT_SWIFT_ERROR_RET to the end of the block | ||
// so the error register won't get trashed when returning the normal value. | ||
if (lvaSwiftErrorArg != BAD_VAR_NUM) | ||
{ | ||
assert(info.compCallConv == CorInfoCallConvExtension::Swift); | ||
assert(lvaSwiftErrorLocal != BAD_VAR_NUM); | ||
GenTree* const swiftErrorNode = gtNewLclFldNode(lvaSwiftErrorLocal, TYP_I_IMPL, 0); | ||
op1 = new (this, GT_SWIFT_ERROR_RET) | ||
GenTreeOp(GT_SWIFT_ERROR_RET, op1->TypeGet(), swiftErrorNode, op1->gtGetOp1()); | ||
} | ||
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 comment is outdated now, right? 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. You can use |
||
#endif // SWIFT_SUPPORT | ||
|
||
impAppendTree(op1, CHECK_SPILL_NONE, impCurStmtDI); | ||
#ifdef DEBUG | ||
// Remember at which BC offset the tree was finished | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -521,6 +521,7 @@ GenTree* Lowering::LowerNode(GenTree* node) | |
break; | ||
|
||
case GT_RETURN: | ||
case GT_SWIFT_ERROR_RET: | ||
LowerRet(node->AsUnOp()); | ||
break; | ||
|
||
|
@@ -4544,19 +4545,19 @@ void Lowering::LowerJmpMethod(GenTree* jmp) | |
// Lower GT_RETURN node to insert PInvoke method epilog if required. | ||
void Lowering::LowerRet(GenTreeUnOp* ret) | ||
{ | ||
assert(ret->OperGet() == GT_RETURN); | ||
assert(ret->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)); | ||
|
||
JITDUMP("lowering GT_RETURN\n"); | ||
DISPNODE(ret); | ||
JITDUMP("============\n"); | ||
|
||
GenTree* retVal = ret->gtGetOp1(); | ||
GenTree* retVal = ret->AsOp()->GetReturnValue(); | ||
// There are two kinds of retyping: | ||
// - A simple bitcast can be inserted when: | ||
// - We're returning a floating type as an integral type or vice-versa, or | ||
// - If we're returning a struct as a primitive type, we change the type of | ||
// 'retval' in 'LowerRetStructLclVar()' | ||
bool needBitcast = (ret->TypeGet() != TYP_VOID) && !varTypeUsesSameRegType(ret, ret->gtGetOp1()); | ||
bool needBitcast = (ret->TypeGet() != TYP_VOID) && !varTypeUsesSameRegType(ret, retVal); | ||
bool doPrimitiveBitcast = false; | ||
if (needBitcast) | ||
{ | ||
|
@@ -4625,6 +4626,27 @@ void Lowering::LowerRet(GenTreeUnOp* ret) | |
ContainCheckRet(ret); | ||
} | ||
|
||
//---------------------------------------------------------------------------------------------- | ||
// LowerSwiftErrorRet: Lower swift error return node by moving it to the end of its BBJ_RETURN block. | ||
// We wait to do this late in the JIT's phases, | ||
// as we typically expect BBJ_RETURN blocks to end with a GT_RETURN/GT_RETFILT node. | ||
// | ||
// Arguments: | ||
// swiftErrorRet - The GT_SWIFT_ERROR_RET node. | ||
// | ||
// Return Value: | ||
// The next node to be lowered. | ||
// | ||
GenTree* Lowering::LowerSwiftErrorRet(GenTree* swiftErrorRet) | ||
{ | ||
assert(swiftErrorRet->OperIs(GT_SWIFT_ERROR_RET)); | ||
GenTree* const nextNode = swiftErrorRet->gtNext; | ||
LIR::Range& blockRange = BlockRange(); | ||
blockRange.Remove(swiftErrorRet); | ||
blockRange.InsertAtEnd(swiftErrorRet); | ||
return nextNode; | ||
} | ||
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 assume this isn't needed anymore? |
||
|
||
//---------------------------------------------------------------------------------------------- | ||
// LowerStoreLocCommon: platform independent part of local var or field store lowering. | ||
// | ||
|
@@ -4871,7 +4893,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) | |
return; | ||
} | ||
|
||
assert(ret->OperIs(GT_RETURN)); | ||
assert(ret->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)); | ||
assert(varTypeIsStruct(ret)); | ||
|
||
GenTree* retVal = ret->gtGetOp1(); | ||
|
@@ -4963,7 +4985,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) | |
void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) | ||
{ | ||
assert(!comp->compMethodReturnsMultiRegRetType()); | ||
assert(ret->OperIs(GT_RETURN)); | ||
assert(ret->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)); | ||
GenTreeLclVarCommon* lclVar = ret->gtGetOp1()->AsLclVar(); | ||
assert(lclVar->OperIs(GT_LCL_VAR)); | ||
unsigned lclNum = lclVar->GetLclNum(); | ||
|
@@ -8147,7 +8169,7 @@ void Lowering::ContainCheckLclHeap(GenTreeOp* node) | |
// | ||
void Lowering::ContainCheckRet(GenTreeUnOp* ret) | ||
{ | ||
assert(ret->OperIs(GT_RETURN)); | ||
assert(ret->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)); | ||
|
||
#if !defined(TARGET_64BIT) | ||
if (ret->TypeGet() == TYP_LONG) | ||
|
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.
Would be nice with a comment that
op1
has the error andop2
has the normal return value (or null if method returns void)