Skip to content
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

Merged
merged 29 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a9646c1
Add GT_SWIFT_ERROR_RET
amanasifkhalid Apr 5, 2024
b328337
Cleanup
amanasifkhalid Apr 5, 2024
63eb15c
Style
amanasifkhalid Apr 5, 2024
674d8f1
Style; comments
amanasifkhalid Apr 5, 2024
7d2e8fa
Binop implementation
amanasifkhalid Apr 8, 2024
a342e00
Update comment
amanasifkhalid Apr 8, 2024
6e50ea7
Merge from main
amanasifkhalid Apr 8, 2024
aa8c83c
Comments
amanasifkhalid Apr 8, 2024
9e310ec
Style
amanasifkhalid Apr 8, 2024
15d39bf
Add GetReturnValue helper
amanasifkhalid Apr 8, 2024
873e15a
Handle GT_SWIFT_ERROR_RET in LSRA
amanasifkhalid Apr 8, 2024
5d96892
Overzealous opt
amanasifkhalid Apr 9, 2024
24e8d0d
Feedback
amanasifkhalid Apr 9, 2024
bf186b7
Store error to local during return merging
amanasifkhalid Apr 10, 2024
c381c48
Handle GT_SWIFT_ERROR_RET in morph
amanasifkhalid Apr 10, 2024
70a69d7
Move GT_SWIFT_ERROR_RET creation to phase
amanasifkhalid Apr 10, 2024
de4457b
Handle remaining GT_RETURN-specific code
amanasifkhalid Apr 10, 2024
7096e23
Style
amanasifkhalid Apr 10, 2024
927a55e
Add comment
amanasifkhalid Apr 10, 2024
848704b
Remove ifdef
amanasifkhalid Apr 10, 2024
502f471
Fix store ordering
amanasifkhalid Apr 10, 2024
e8b1dbc
Style
amanasifkhalid Apr 10, 2024
2dce428
Do SwiftError local conversion in phase
amanasifkhalid Apr 10, 2024
38ad8a7
Delete assert
amanasifkhalid Apr 10, 2024
18df9c7
Fix build
amanasifkhalid Apr 10, 2024
86a0825
Fix codegen on arm64
amanasifkhalid Apr 11, 2024
41ec8f7
Feedback
amanasifkhalid Apr 11, 2024
6d9d360
Update BADCODE message
amanasifkhalid Apr 11, 2024
0cd339d
Feedback
amanasifkhalid Apr 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4109,7 +4109,7 @@ GenTree* Compiler::optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeO
}

//------------------------------------------------------------------------
// optAssertionProp_Return: Try and optimize a GT_RETURN via assertions.
// optAssertionProp_Return: Try and optimize a GT_RETURN/GT_SWIFT_ERROR_RET via assertions.
//
// Propagates ZEROOBJ for the return value.
//
Expand All @@ -4124,9 +4124,9 @@ GenTree* Compiler::optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeO
// Notes:
// stmt may be nullptr during local assertion prop
//
GenTree* Compiler::optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeUnOp* ret, Statement* stmt)
GenTree* Compiler::optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeOp* ret, Statement* stmt)
{
GenTree* retValue = ret->gtGetOp1();
GenTree* retValue = ret->GetReturnValue();

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

case GT_RETURN:
return optAssertionProp_Return(assertions, tree->AsUnOp(), stmt);
case GT_SWIFT_ERROR_RET:
return optAssertionProp_Return(assertions, tree->AsOp(), stmt);

case GT_MOD:
case GT_DIV:
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,10 @@ class CodeGen final : public CodeGenInterface

void genReturn(GenTree* treeNode);

#ifdef SWIFT_SUPPORT
void genSwiftErrorReturn(GenTree* treeNode);
#endif // SWIFT_SUPPORT

#ifdef TARGET_XARCH
void genStackPointerConstantAdjustment(ssize_t spDelta, bool trackSpAdjustments);
void genStackPointerConstantAdjustmentWithProbe(ssize_t spDelta, bool trackSpAdjustments);
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2990,15 +2990,15 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
// Note: treeNode's and op1's registers are already consumed.
//
// Arguments:
// treeNode - The GT_RETURN or GT_RETFILT tree node with non-struct and non-void type
// treeNode - The GT_RETURN/GT_RETFILT/GT_SWIFT_ERROR_RET tree node with non-struct and non-void type
//
// Return Value:
// None
//
void CodeGen::genSimpleReturn(GenTree* treeNode)
{
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
GenTree* op1 = treeNode->gtGetOp1();
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));
GenTree* op1 = treeNode->AsOp()->GetReturnValue();
var_types targetType = treeNode->TypeGet();

assert(targetType != TYP_STRUCT);
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
genReturn(treeNode);
break;

#ifdef SWIFT_SUPPORT
case GT_SWIFT_ERROR_RET:
genSwiftErrorReturn(treeNode);
break;
#endif // SWIFT_SUPPORT

case GT_LEA:
// If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction.
genLeaInstruction(treeNode->AsAddrMode());
Expand Down
56 changes: 33 additions & 23 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7733,8 +7733,8 @@ GenTreeIntCon CodeGen::intForm(var_types type, ssize_t value)
//
void CodeGen::genLongReturn(GenTree* treeNode)
{
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
assert(treeNode->TypeGet() == TYP_LONG);
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
assert(treeNode->TypeIs(TYP_LONG));
GenTree* op1 = treeNode->gtGetOp1();
var_types targetType = treeNode->TypeGet();

Expand All @@ -7758,16 +7758,16 @@ void CodeGen::genLongReturn(GenTree* treeNode)
// In case of LONG return on 32-bit, delegates to the genLongReturn method.
//
// Arguments:
// treeNode - The GT_RETURN or GT_RETFILT tree node.
// treeNode - The GT_RETURN/GT_RETFILT/GT_SWIFT_ERROR_RET tree node.
//
// Return Value:
// None
//
void CodeGen::genReturn(GenTree* treeNode)
{
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));

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

// A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
Expand Down Expand Up @@ -7869,7 +7869,7 @@ void CodeGen::genReturn(GenTree* treeNode)
//
// There should be a single GT_RETURN while generating profiler ELT callbacks.
//
if (treeNode->OperIs(GT_RETURN) && compiler->compIsProfilerHookNeeded())
if (treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET) && compiler->compIsProfilerHookNeeded())
{
// !! NOTE !!
// Since we are invalidating the assumption that we would slip into the epilog
Expand Down Expand Up @@ -7939,18 +7939,28 @@ 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
//------------------------------------------------------------------------
// genSwiftErrorReturn: Generates code for returning the normal return value,
// and loading the SwiftError pseudolocal value in the error register.
//
// Arguments:
// treeNode - The GT_SWIFT_ERROR_RET tree node.
//
// Return Value:
// None
//
void CodeGen::genSwiftErrorReturn(GenTree* treeNode)
{
assert(treeNode->OperIs(GT_SWIFT_ERROR_RET));
GenTree* swiftErrorNode = treeNode->gtGetOp1();
const regNumber errorSrcReg = genConsumeReg(swiftErrorNode);
inst_Mov(swiftErrorNode->TypeGet(), REG_SWIFT_ERROR, errorSrcReg, true, EA_PTRSIZE);
genReturn(treeNode);
}
#endif // SWIFT_SUPPORT

//------------------------------------------------------------------------
// isStructReturn: Returns whether the 'treeNode' is returning a struct.
Expand All @@ -7959,15 +7969,15 @@ void CodeGen::genReturn(GenTree* treeNode)
// treeNode - The tree node to evaluate whether is a struct return.
//
// Return Value:
// Returns true if the 'treeNode" is a GT_RETURN node of type struct.
// Returns true if the 'treeNode' is a GT_RETURN/GT_SWIFT_ERROR_RET node of type struct.
// Otherwise returns false.
//
bool CodeGen::isStructReturn(GenTree* treeNode)
{
// This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN.
// This method could be called for 'treeNode' of GT_RET_FILT/GT_RETURN/GT_SWIFT_ERROR_RET.
// For the GT_RET_FILT, the return is always a bool or a void, for the end of a finally block.
noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
if (treeNode->OperGet() != GT_RETURN)
noway_assert(treeNode->OperIs(GT_RETURN, GT_RETFILT, GT_SWIFT_ERROR_RET));
if (!treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET))
{
return false;
}
Expand All @@ -7994,13 +8004,13 @@ bool CodeGen::isStructReturn(GenTree* treeNode)
//
void CodeGen::genStructReturn(GenTree* treeNode)
{
assert(treeNode->OperGet() == GT_RETURN);

genConsumeRegs(treeNode->gtGetOp1());
assert(treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET));

GenTree* op1 = treeNode->gtGetOp1();
GenTree* op1 = treeNode->AsOp()->GetReturnValue();
GenTree* actualOp1 = op1->gtSkipReloadOrCopy();

genConsumeRegs(op1);

ReturnTypeDesc retTypeDesc = compiler->compRetTypeDesc;
const unsigned regCount = retTypeDesc.GetReturnRegCount();
assert(regCount <= MAX_RET_REG_COUNT);
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,10 @@ void CodeGen::genCodeForBBlist()
// as the determiner because something we are tracking as a byref
// might be used as a return value of a int function (which is legal)
GenTree* blockLastNode = block->lastNode();
if ((blockLastNode != nullptr) && (blockLastNode->gtOper == GT_RETURN) &&
if ((blockLastNode != nullptr) && (blockLastNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)) &&
(varTypeIsGC(compiler->info.compRetType) ||
(blockLastNode->AsOp()->gtOp1 != nullptr && varTypeIsGC(blockLastNode->AsOp()->gtOp1->TypeGet()))))
(blockLastNode->AsOp()->GetReturnValue() != nullptr &&
varTypeIsGC(blockLastNode->AsOp()->GetReturnValue()->TypeGet()))))
{
nonVarPtrRegs &= ~RBM_INTRET;
}
Expand Down
10 changes: 9 additions & 1 deletion src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1402,13 +1402,15 @@ void CodeGen::genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc)
//
// Arguments:
// treeNode - The GT_RETURN or GT_RETFILT tree node with float type.
// (We don't expect treeNode to be a GT_SWIFT_ERROR_RET node,
// as Swift interop isn't supported on x86.)
//
// Return Value:
// None
//
void CodeGen::genFloatReturn(GenTree* treeNode)
{
assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
assert(treeNode->OperIs(GT_RETURN, GT_RETFILT));
assert(varTypeIsFloating(treeNode));

GenTree* op1 = treeNode->gtGetOp1();
Expand Down Expand Up @@ -1966,6 +1968,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
genReturn(treeNode);
break;

#ifdef SWIFT_SUPPORT
case GT_SWIFT_ERROR_RET:
genSwiftErrorReturn(treeNode);
break;
#endif // SWIFT_SUPPORT

case GT_LEA:
// If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction.
genLeaInstruction(treeNode->AsAddrMode());
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4717,6 +4717,12 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
//
DoPhase(this, PHASE_MORPH_ADD_INTERNAL, &Compiler::fgAddInternal);

#ifdef SWIFT_SUPPORT
// Transform GT_RETURN nodes into GT_SWIFT_ERROR_RET nodes if this method has Swift error handling
//
DoPhase(this, PHASE_SWIFT_ERROR_RET, &Compiler::fgAddSwiftErrorReturns);
#endif // SWIFT_SUPPORT

// Remove empty try regions
//
DoPhase(this, PHASE_EMPTY_TRY, &Compiler::fgRemoveEmptyTry);
Expand Down
12 changes: 10 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5279,6 +5279,10 @@ class Compiler

PhaseStatus fgAddInternal();

#ifdef SWIFT_SUPPORT
PhaseStatus fgAddSwiftErrorReturns();
#endif // SWIFT_SUPPORT

enum class FoldResult
{
FOLD_DID_NOTHING,
Expand Down Expand Up @@ -6523,7 +6527,7 @@ class Compiler
GenTree* fgOptimizeBitwiseAnd(GenTreeOp* andOp);
GenTree* fgOptimizeBitwiseXor(GenTreeOp* xorOp);
GenTree* fgPropagateCommaThrow(GenTree* parent, GenTreeOp* commaThrow, GenTreeFlags precedingSideEffects);
GenTree* fgMorphRetInd(GenTreeUnOp* tree);
GenTree* fgMorphRetInd(GenTreeOp* tree);
GenTree* fgMorphModToZero(GenTreeOp* tree);
GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
GenTree* fgMorphUModToAndSub(GenTreeOp* tree);
Expand Down Expand Up @@ -7878,7 +7882,7 @@ class Compiler
GenTree* optAssertionProp_LocalStore(ASSERT_VALARG_TP assertions, GenTreeLclVarCommon* store, Statement* stmt);
GenTree* optAssertionProp_BlockStore(ASSERT_VALARG_TP assertions, GenTreeBlk* store, Statement* stmt);
GenTree* optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions, GenTreeOp* tree, Statement* stmt);
GenTree* optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeUnOp* ret, Statement* stmt);
GenTree* optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeOp* ret, Statement* stmt);
GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt);
GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTreeCast* cast, Statement* stmt);
GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, Statement* stmt);
Expand Down Expand Up @@ -8406,6 +8410,10 @@ class Compiler
unsigned genReturnLocal; // Local number for the return value when applicable.
BasicBlock* genReturnBB; // jumped to when not optimizing for speed.

#ifdef SWIFT_SUPPORT
unsigned genReturnErrorLocal; // Local number for the Swift error value when applicable.
#endif // SWIFT_SUPPORT

// The following properties are part of CodeGenContext. Getters are provided here for
// convenience and backward compatibility, but the properties can only be set by invoking
// the setter on CodeGenContext directly.
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compphases.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ CompPhaseNameMacro(PHASE_INCPROFILE, "Profile incorporation",
CompPhaseNameMacro(PHASE_MORPH_INIT, "Morph - Init", false, -1, false)
CompPhaseNameMacro(PHASE_MORPH_INLINE, "Morph - Inlining", false, -1, true)
CompPhaseNameMacro(PHASE_MORPH_ADD_INTERNAL, "Morph - Add internal blocks", false, -1, true)
CompPhaseNameMacro(PHASE_SWIFT_ERROR_RET, "Add Swift error returns", false, -1, true)
CompPhaseNameMacro(PHASE_ALLOCATE_OBJECTS, "Allocate Objects", false, -1, false)
CompPhaseNameMacro(PHASE_EMPTY_TRY, "Remove empty try", false, -1, false)
CompPhaseNameMacro(PHASE_EMPTY_FINALLY, "Remove empty finally", false, -1, false)
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/decomposelongs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree)
break;

case GT_RETURN:
assert(tree->AsOp()->gtOp1->OperGet() == GT_LONG);
case GT_SWIFT_ERROR_RET:
assert(tree->AsOp()->GetReturnValue()->OperIs(GT_LONG));
break;

case GT_STOREIND:
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ void Compiler::fgInit()
genReturnBB = nullptr;
genReturnLocal = BAD_VAR_NUM;

#ifdef SWIFT_SUPPORT
genReturnErrorLocal = BAD_VAR_NUM;
#endif // SWIFT_SUPPORT

/* We haven't reached the global morphing phase */
fgGlobalMorph = false;
fgGlobalMorphDone = false;
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/fgstmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void Compiler::fgInsertStmtNearEnd(BasicBlock* block, Statement* stmt)
}
else if (block->KindIs(BBJ_RETURN))
{
assert((lastStmt->GetRootNode()->OperIs(GT_RETURN, GT_JMP)) ||
assert((lastStmt->GetRootNode()->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET, GT_JMP)) ||
// BBJ_RETURN blocks in functions returning void do not get a GT_RETURN node if they
// have a .tail prefix (even if canTailCall returns false for these calls)
// code:Compiler::impImportBlockCode (search for the RET: label)
Expand Down Expand Up @@ -538,6 +538,7 @@ inline bool OperIsControlFlow(genTreeOps oper)

case GT_RETURN:
case GT_RETFILT:
case GT_SWIFT_ERROR_RET:
#if defined(FEATURE_EH_WINDOWS_X86)
case GT_END_LFIN:
#endif // FEATURE_EH_WINDOWS_X86
Expand Down
Loading
Loading