Skip to content

Commit

Permalink
JIT: Support storing Swift error register value to SwiftError struct (#…
Browse files Browse the repository at this point in the history
…98586)

Adds JIT support for storing the error result of a Swift call to the provided SwiftError struct, assuming the caller passed a SwiftError* argument. The LSRA changes assume the presence of a SwiftError* argument in a Swift call indicates the error register may be trashed, and thus should be killed until consumed by GT_SWIFT_ERROR, a new GenTree node for representing the value of the error register post-Swift call. Similarly, these changes also assume the lack of a SwiftError* argument indicates the Swift call cannot throw, and thus will not trash the error register; thus, the Swift call should not block the register's usage.
  • Loading branch information
amanasifkhalid committed Feb 26, 2024
1 parent 5323f83 commit 597d647
Show file tree
Hide file tree
Showing 24 changed files with 367 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
void genCodeForPhysReg(GenTreePhysReg* tree);
#ifdef SWIFT_SUPPORT
void genCodeForSwiftErrorReg(GenTree* tree);
#endif // SWIFT_SUPPORT
void genCodeForNullCheck(GenTreeIndir* tree);
void genCodeForCmpXchg(GenTreeCmpXchg* tree);
void genCodeForReuseVal(GenTree* treeNode);
Expand Down
17 changes: 17 additions & 0 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
break;
#endif // TARGET_ARM64

#ifdef SWIFT_SUPPORT
case GT_SWIFT_ERROR:
genCodeForSwiftErrorReg(treeNode);
break;
#endif // SWIFT_SUPPORT

case GT_RELOAD:
// do nothing - reload is just a marker.
// The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
Expand Down Expand Up @@ -3369,6 +3375,17 @@ void CodeGen::genCall(GenTreeCall* call)
genDefineTempLabel(genCreateTempLabel());
}

#ifdef SWIFT_SUPPORT
// Clear the Swift error register before calling a Swift method,
// so we can check if it set the error register after returning.
// (Flag is only set if we know we need to check the error register)
if ((call->gtCallMoreFlags & GTF_CALL_M_SWIFT_ERROR_HANDLING) != 0)
{
assert(call->unmgdCallConv == CorInfoCallConvExtension::Swift);
instGen_Set_Reg_To_Zero(EA_PTRSIZE, REG_SWIFT_ERROR);
}
#endif // SWIFT_SUPPORT

genCallInstruction(call);

genDefinePendingCallLabel(call);
Expand Down
28 changes: 28 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8569,3 +8569,31 @@ void CodeGen::genCodeForReuseVal(GenTree* treeNode)
genDefineTempLabel(genCreateTempLabel());
}
}

#ifdef SWIFT_SUPPORT
//---------------------------------------------------------------------
// genCodeForSwiftErrorReg - generate code for a GT_SWIFT_ERROR node
//
// Arguments
// tree - the GT_SWIFT_ERROR node
//
// Return value:
// None
//
void CodeGen::genCodeForSwiftErrorReg(GenTree* tree)
{
assert(tree->OperIs(GT_SWIFT_ERROR));

var_types targetType = tree->TypeGet();
regNumber targetReg = tree->GetRegNum();

// LSRA should have picked REG_SWIFT_ERROR as the destination register, too
// (see LinearScan::BuildNode for an explanation of why we want this)
assert(targetReg == REG_SWIFT_ERROR);

inst_Mov(targetType, targetReg, REG_SWIFT_ERROR, /* canSkip */ true);
genTransferRegGCState(targetReg, REG_SWIFT_ERROR);

genProduceReg(tree);
}
#endif // SWIFT_SUPPORT
17 changes: 17 additions & 0 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
case GT_NOP:
break;

#ifdef SWIFT_SUPPORT
case GT_SWIFT_ERROR:
genCodeForSwiftErrorReg(treeNode);
break;
#endif // SWIFT_SUPPORT

case GT_KEEPALIVE:
genConsumeRegs(treeNode->AsOp()->gtOp1);
break;
Expand Down Expand Up @@ -6035,6 +6041,17 @@ void CodeGen::genCall(GenTreeCall* call)
instGen(INS_vzeroupper);
}

#ifdef SWIFT_SUPPORT
// Clear the Swift error register before calling a Swift method,
// so we can check if it set the error register after returning.
// (Flag is only set if we know we need to check the error register)
if ((call->gtCallMoreFlags & GTF_CALL_M_SWIFT_ERROR_HANDLING) != 0)
{
assert(call->unmgdCallConv == CorInfoCallConvExtension::Swift);
instGen_Set_Reg_To_Zero(EA_PTRSIZE, REG_SWIFT_ERROR);
}
#endif // SWIFT_SUPPORT

genCallInstruction(call X86_ARG(stackArgBytes));

genDefinePendingCallLabel(call);
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4368,7 +4368,11 @@ 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);
void impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, /* OUT */ CallArg** swiftErrorArg, /* OUT */ CallArg** swiftSelfArg);

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

void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
Expand Down Expand Up @@ -11315,6 +11319,7 @@ class GenTreeVisitor
case GT_PINVOKE_EPILOG:
case GT_IL_OFFSET:
case GT_NOP:
case GT_SWIFT_ERROR:
break;

// Lclvar unary operators
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4246,6 +4246,7 @@ void GenTree::VisitOperands(TVisitor visitor)
case GT_PINVOKE_EPILOG:
case GT_IL_OFFSET:
case GT_NOP:
case GT_SWIFT_ERROR:
return;

// Unary operators with an optional operand
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7066,6 +7066,9 @@ bool GenTree::OperRequiresCallFlag(Compiler* comp) const
case GT_KEEPALIVE:
return true;

case GT_SWIFT_ERROR:
return true;

case GT_INTRINSIC:
return comp->IsIntrinsicImplementedByUserCall(this->AsIntrinsic()->gtIntrinsicName);

Expand Down Expand Up @@ -7362,6 +7365,7 @@ bool GenTree::OperRequiresGlobRefFlag(Compiler* comp) const
case GT_CMPXCHG:
case GT_MEMORYBARRIER:
case GT_KEEPALIVE:
case GT_SWIFT_ERROR:
return true;

case GT_CALL:
Expand Down Expand Up @@ -7420,6 +7424,7 @@ bool GenTree::OperSupportsOrderingSideEffect() const
case GT_CMPXCHG:
case GT_MEMORYBARRIER:
case GT_CATCH_ARG:
case GT_SWIFT_ERROR:
return true;
default:
return false;
Expand Down Expand Up @@ -8778,7 +8783,7 @@ GenTreeStoreDynBlk* Compiler::gtNewStoreDynBlkNode(GenTree* addr,
//
// Arguments:
// type - Type of the store
// addr - Destionation address
// addr - Destination address
// data - Value to store
// indirFlags - Indirection flags
//
Expand Down Expand Up @@ -10324,6 +10329,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
case GT_PINVOKE_EPILOG:
case GT_IL_OFFSET:
case GT_NOP:
case GT_SWIFT_ERROR:
m_state = -1;
return;

Expand Down Expand Up @@ -12451,6 +12457,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
case GT_MEMORYBARRIER:
case GT_PINVOKE_PROLOG:
case GT_JMPTABLE:
case GT_SWIFT_ERROR:
break;

case GT_RET_EXPR:
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4113,6 +4113,10 @@ enum GenTreeCallFlags : unsigned int
GTF_CALL_M_CAST_CAN_BE_EXPANDED = 0x04000000, // this cast (helper call) can be expanded if it's profitable. To be removed.
GTF_CALL_M_CAST_OBJ_NONNULL = 0x08000000, // if we expand this specific cast we don't need to check the input object for null
// NOTE: if needed, this flag can be removed, and we can introduce new _NONNUL cast helpers

#ifdef SWIFT_SUPPORT
GTF_CALL_M_SWIFT_ERROR_HANDLING = 0x10000000, // call uses the Swift calling convention, and error register will be checked after it returns.
#endif // SWIFT_SUPPORT
};

inline constexpr GenTreeCallFlags operator ~(GenTreeCallFlags a)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/gtlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ 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
Loading

0 comments on commit 597d647

Please sign in to comment.