Skip to content

Commit e2acd3d

Browse files
amanasifkhalidmatouskozak
authored andcommitted
JIT: Add GT_SWIFT_ERROR_RET to represent loading error register upon return (dotnet#100692)
Follow-up to dotnet#100429. If a method has a `SwiftError*` out parameter, a new phase -- `fgAddSwiftErrorReturns` -- converts all `GT_RETURN` nodes into `GT_SWIFT_ERROR_RET` nodes; this new node type is a binop that takes the error value as its first operand, and the normal return value (if there is one) as its second operand. The error value is loaded into the Swift error register upon returning.
1 parent ae442e5 commit e2acd3d

33 files changed

+437
-161
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,7 +4109,7 @@ GenTree* Compiler::optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeO
41094109
}
41104110

41114111
//------------------------------------------------------------------------
4112-
// optAssertionProp_Return: Try and optimize a GT_RETURN via assertions.
4112+
// optAssertionProp_Return: Try and optimize a GT_RETURN/GT_SWIFT_ERROR_RET via assertions.
41134113
//
41144114
// Propagates ZEROOBJ for the return value.
41154115
//
@@ -4124,9 +4124,9 @@ GenTree* Compiler::optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeO
41244124
// Notes:
41254125
// stmt may be nullptr during local assertion prop
41264126
//
4127-
GenTree* Compiler::optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeUnOp* ret, Statement* stmt)
4127+
GenTree* Compiler::optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeOp* ret, Statement* stmt)
41284128
{
4129-
GenTree* retValue = ret->gtGetOp1();
4129+
GenTree* retValue = ret->GetReturnValue();
41304130

41314131
// Only propagate zeroes that lowering can deal with.
41324132
if (!ret->TypeIs(TYP_VOID) && varTypeIsStruct(retValue) && !varTypeIsStruct(info.compRetNativeType))
@@ -5512,7 +5512,8 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
55125512
return optAssertionProp_BlockStore(assertions, tree->AsBlk(), stmt);
55135513

55145514
case GT_RETURN:
5515-
return optAssertionProp_Return(assertions, tree->AsUnOp(), stmt);
5515+
case GT_SWIFT_ERROR_RET:
5516+
return optAssertionProp_Return(assertions, tree->AsOp(), stmt);
55165517

55175518
case GT_MOD:
55185519
case GT_DIV:

src/coreclr/jit/codegen.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,10 @@ class CodeGen final : public CodeGenInterface
13091309

13101310
void genReturn(GenTree* treeNode);
13111311

1312+
#ifdef SWIFT_SUPPORT
1313+
void genSwiftErrorReturn(GenTree* treeNode);
1314+
#endif // SWIFT_SUPPORT
1315+
13121316
#ifdef TARGET_XARCH
13131317
void genStackPointerConstantAdjustment(ssize_t spDelta, bool trackSpAdjustments);
13141318
void genStackPointerConstantAdjustmentWithProbe(ssize_t spDelta, bool trackSpAdjustments);

src/coreclr/jit/codegenarm64.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2990,15 +2990,15 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
29902990
// Note: treeNode's and op1's registers are already consumed.
29912991
//
29922992
// Arguments:
2993-
// treeNode - The GT_RETURN or GT_RETFILT tree node with non-struct and non-void type
2993+
// treeNode - The GT_RETURN/GT_RETFILT/GT_SWIFT_ERROR_RET tree node with non-struct and non-void type
29942994
//
29952995
// Return Value:
29962996
// None
29972997
//
29982998
void CodeGen::genSimpleReturn(GenTree* treeNode)
29992999
{
3000-
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
3001-
GenTree* op1 = treeNode->gtGetOp1();
3000+
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));
3001+
GenTree* op1 = treeNode->AsOp()->GetReturnValue();
30023002
var_types targetType = treeNode->TypeGet();
30033003

30043004
assert(targetType != TYP_STRUCT);

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
282282
genReturn(treeNode);
283283
break;
284284

285+
#ifdef SWIFT_SUPPORT
286+
case GT_SWIFT_ERROR_RET:
287+
genSwiftErrorReturn(treeNode);
288+
break;
289+
#endif // SWIFT_SUPPORT
290+
285291
case GT_LEA:
286292
// If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction.
287293
genLeaInstruction(treeNode->AsAddrMode());

src/coreclr/jit/codegencommon.cpp

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6869,8 +6869,8 @@ GenTreeIntCon CodeGen::intForm(var_types type, ssize_t value)
68696869
//
68706870
void CodeGen::genLongReturn(GenTree* treeNode)
68716871
{
6872-
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
6873-
assert(treeNode->TypeGet() == TYP_LONG);
6872+
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
6873+
assert(treeNode->TypeIs(TYP_LONG));
68746874
GenTree* op1 = treeNode->gtGetOp1();
68756875
var_types targetType = treeNode->TypeGet();
68766876

@@ -6894,16 +6894,16 @@ void CodeGen::genLongReturn(GenTree* treeNode)
68946894
// In case of LONG return on 32-bit, delegates to the genLongReturn method.
68956895
//
68966896
// Arguments:
6897-
// treeNode - The GT_RETURN or GT_RETFILT tree node.
6897+
// treeNode - The GT_RETURN/GT_RETFILT/GT_SWIFT_ERROR_RET tree node.
68986898
//
68996899
// Return Value:
69006900
// None
69016901
//
69026902
void CodeGen::genReturn(GenTree* treeNode)
69036903
{
6904-
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
6904+
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));
69056905

6906-
GenTree* op1 = treeNode->gtGetOp1();
6906+
GenTree* op1 = treeNode->AsOp()->GetReturnValue();
69076907
var_types targetType = treeNode->TypeGet();
69086908

69096909
// A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
@@ -7005,7 +7005,7 @@ void CodeGen::genReturn(GenTree* treeNode)
70057005
//
70067006
// There should be a single GT_RETURN while generating profiler ELT callbacks.
70077007
//
7008-
if (treeNode->OperIs(GT_RETURN) && compiler->compIsProfilerHookNeeded())
7008+
if (treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET) && compiler->compIsProfilerHookNeeded())
70097009
{
70107010
// !! NOTE !!
70117011
// Since we are invalidating the assumption that we would slip into the epilog
@@ -7075,18 +7075,28 @@ void CodeGen::genReturn(GenTree* treeNode)
70757075

70767076
genStackPointerCheck(doStackPointerCheck, compiler->lvaReturnSpCheck);
70777077
#endif // defined(DEBUG) && defined(TARGET_XARCH)
7078+
}
70787079

70797080
#ifdef SWIFT_SUPPORT
7080-
// If this method has a SwiftError* out parameter, load the SwiftError pseudolocal value into the error register.
7081-
// TODO-CQ: Introduce GenTree node that models returning a normal and Swift error value.
7082-
if (compiler->lvaSwiftErrorArg != BAD_VAR_NUM)
7083-
{
7084-
assert(compiler->info.compCallConv == CorInfoCallConvExtension::Swift);
7085-
assert(compiler->lvaSwiftErrorLocal != BAD_VAR_NUM);
7086-
GetEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_SWIFT_ERROR, compiler->lvaSwiftErrorLocal, 0);
7087-
}
7088-
#endif // SWIFT_SUPPORT
7081+
//------------------------------------------------------------------------
7082+
// genSwiftErrorReturn: Generates code for returning the normal return value,
7083+
// and loading the SwiftError pseudolocal value in the error register.
7084+
//
7085+
// Arguments:
7086+
// treeNode - The GT_SWIFT_ERROR_RET tree node.
7087+
//
7088+
// Return Value:
7089+
// None
7090+
//
7091+
void CodeGen::genSwiftErrorReturn(GenTree* treeNode)
7092+
{
7093+
assert(treeNode->OperIs(GT_SWIFT_ERROR_RET));
7094+
GenTree* swiftErrorNode = treeNode->gtGetOp1();
7095+
const regNumber errorSrcReg = genConsumeReg(swiftErrorNode);
7096+
inst_Mov(swiftErrorNode->TypeGet(), REG_SWIFT_ERROR, errorSrcReg, true, EA_PTRSIZE);
7097+
genReturn(treeNode);
70897098
}
7099+
#endif // SWIFT_SUPPORT
70907100

70917101
//------------------------------------------------------------------------
70927102
// isStructReturn: Returns whether the 'treeNode' is returning a struct.
@@ -7095,15 +7105,15 @@ void CodeGen::genReturn(GenTree* treeNode)
70957105
// treeNode - The tree node to evaluate whether is a struct return.
70967106
//
70977107
// Return Value:
7098-
// Returns true if the 'treeNode" is a GT_RETURN node of type struct.
7108+
// Returns true if the 'treeNode' is a GT_RETURN/GT_SWIFT_ERROR_RET node of type struct.
70997109
// Otherwise returns false.
71007110
//
71017111
bool CodeGen::isStructReturn(GenTree* treeNode)
71027112
{
7103-
// This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN.
7113+
// This method could be called for 'treeNode' of GT_RET_FILT/GT_RETURN/GT_SWIFT_ERROR_RET.
71047114
// For the GT_RET_FILT, the return is always a bool or a void, for the end of a finally block.
7105-
noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
7106-
if (treeNode->OperGet() != GT_RETURN)
7115+
noway_assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));
7116+
if (!treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET))
71077117
{
71087118
return false;
71097119
}
@@ -7130,13 +7140,13 @@ bool CodeGen::isStructReturn(GenTree* treeNode)
71307140
//
71317141
void CodeGen::genStructReturn(GenTree* treeNode)
71327142
{
7133-
assert(treeNode->OperGet() == GT_RETURN);
7134-
7135-
genConsumeRegs(treeNode->gtGetOp1());
7143+
assert(treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET));
71367144

7137-
GenTree* op1 = treeNode->gtGetOp1();
7145+
GenTree* op1 = treeNode->AsOp()->GetReturnValue();
71387146
GenTree* actualOp1 = op1->gtSkipReloadOrCopy();
71397147

7148+
genConsumeRegs(op1);
7149+
71407150
ReturnTypeDesc retTypeDesc = compiler->compRetTypeDesc;
71417151
const unsigned regCount = retTypeDesc.GetReturnRegCount();
71427152
assert(regCount <= MAX_RET_REG_COUNT);

src/coreclr/jit/codegenlinear.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,10 @@ void CodeGen::genCodeForBBlist()
498498
// as the determiner because something we are tracking as a byref
499499
// might be used as a return value of a int function (which is legal)
500500
GenTree* blockLastNode = block->lastNode();
501-
if ((blockLastNode != nullptr) && (blockLastNode->gtOper == GT_RETURN) &&
501+
if ((blockLastNode != nullptr) && (blockLastNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)) &&
502502
(varTypeIsGC(compiler->info.compRetType) ||
503-
(blockLastNode->AsOp()->gtOp1 != nullptr && varTypeIsGC(blockLastNode->AsOp()->gtOp1->TypeGet()))))
503+
(blockLastNode->AsOp()->GetReturnValue() != nullptr &&
504+
varTypeIsGC(blockLastNode->AsOp()->GetReturnValue()->TypeGet()))))
504505
{
505506
nonVarPtrRegs &= ~RBM_INTRET;
506507
}

src/coreclr/jit/codegenxarch.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,13 +1402,15 @@ void CodeGen::genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc)
14021402
//
14031403
// Arguments:
14041404
// treeNode - The GT_RETURN or GT_RETFILT tree node with float type.
1405+
// (We don't expect treeNode to be a GT_SWIFT_ERROR_RET node,
1406+
// as Swift interop isn't supported on x86.)
14051407
//
14061408
// Return Value:
14071409
// None
14081410
//
14091411
void CodeGen::genFloatReturn(GenTree* treeNode)
14101412
{
1411-
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
1413+
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
14121414
assert(varTypeIsFloating(treeNode));
14131415

14141416
GenTree* op1 = treeNode->gtGetOp1();
@@ -1966,6 +1968,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
19661968
genReturn(treeNode);
19671969
break;
19681970

1971+
#ifdef SWIFT_SUPPORT
1972+
case GT_SWIFT_ERROR_RET:
1973+
genSwiftErrorReturn(treeNode);
1974+
break;
1975+
#endif // SWIFT_SUPPORT
1976+
19691977
case GT_LEA:
19701978
// If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction.
19711979
genLeaInstruction(treeNode->AsAddrMode());

src/coreclr/jit/compiler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4722,6 +4722,12 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
47224722
//
47234723
DoPhase(this, PHASE_MORPH_ADD_INTERNAL, &Compiler::fgAddInternal);
47244724

4725+
#ifdef SWIFT_SUPPORT
4726+
// Transform GT_RETURN nodes into GT_SWIFT_ERROR_RET nodes if this method has Swift error handling
4727+
//
4728+
DoPhase(this, PHASE_SWIFT_ERROR_RET, &Compiler::fgAddSwiftErrorReturns);
4729+
#endif // SWIFT_SUPPORT
4730+
47254731
// Remove empty try regions
47264732
//
47274733
DoPhase(this, PHASE_EMPTY_TRY, &Compiler::fgRemoveEmptyTry);

src/coreclr/jit/compiler.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5285,6 +5285,10 @@ class Compiler
52855285

52865286
PhaseStatus fgAddInternal();
52875287

5288+
#ifdef SWIFT_SUPPORT
5289+
PhaseStatus fgAddSwiftErrorReturns();
5290+
#endif // SWIFT_SUPPORT
5291+
52885292
enum class FoldResult
52895293
{
52905294
FOLD_DID_NOTHING,
@@ -6529,7 +6533,7 @@ class Compiler
65296533
GenTree* fgOptimizeBitwiseAnd(GenTreeOp* andOp);
65306534
GenTree* fgOptimizeBitwiseXor(GenTreeOp* xorOp);
65316535
GenTree* fgPropagateCommaThrow(GenTree* parent, GenTreeOp* commaThrow, GenTreeFlags precedingSideEffects);
6532-
GenTree* fgMorphRetInd(GenTreeUnOp* tree);
6536+
GenTree* fgMorphRetInd(GenTreeOp* tree);
65336537
GenTree* fgMorphModToZero(GenTreeOp* tree);
65346538
GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
65356539
GenTree* fgMorphUModToAndSub(GenTreeOp* tree);
@@ -7892,7 +7896,7 @@ class Compiler
78927896
GenTree* optAssertionProp_LocalStore(ASSERT_VALARG_TP assertions, GenTreeLclVarCommon* store, Statement* stmt);
78937897
GenTree* optAssertionProp_BlockStore(ASSERT_VALARG_TP assertions, GenTreeBlk* store, Statement* stmt);
78947898
GenTree* optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeOp* tree, Statement* stmt);
7895-
GenTree* optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeUnOp* ret, Statement* stmt);
7899+
GenTree* optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeOp* ret, Statement* stmt);
78967900
GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt);
78977901
GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTreeCast* cast, Statement* stmt);
78987902
GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, Statement* stmt);
@@ -8420,6 +8424,10 @@ class Compiler
84208424
unsigned genReturnLocal; // Local number for the return value when applicable.
84218425
BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
84228426

8427+
#ifdef SWIFT_SUPPORT
8428+
unsigned genReturnErrorLocal; // Local number for the Swift error value when applicable.
8429+
#endif // SWIFT_SUPPORT
8430+
84238431
// The following properties are part of CodeGenContext. Getters are provided here for
84248432
// convenience and backward compatibility, but the properties can only be set by invoking
84258433
// the setter on CodeGenContext directly.

src/coreclr/jit/compphases.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ CompPhaseNameMacro(PHASE_INCPROFILE, "Profile incorporation",
3434
CompPhaseNameMacro(PHASE_MORPH_INIT, "Morph - Init", false, -1, false)
3535
CompPhaseNameMacro(PHASE_MORPH_INLINE, "Morph - Inlining", false, -1, true)
3636
CompPhaseNameMacro(PHASE_MORPH_ADD_INTERNAL, "Morph - Add internal blocks", false, -1, true)
37+
CompPhaseNameMacro(PHASE_SWIFT_ERROR_RET, "Add Swift error returns", false, -1, true)
3738
CompPhaseNameMacro(PHASE_ALLOCATE_OBJECTS, "Allocate Objects", false, -1, false)
3839
CompPhaseNameMacro(PHASE_EMPTY_TRY, "Remove empty try", false, -1, false)
3940
CompPhaseNameMacro(PHASE_EMPTY_FINALLY, "Remove empty finally", false, -1, false)

0 commit comments

Comments
 (0)