Skip to content

Commit 2b69aa4

Browse files
jakobbotschRuihan-Yin
authored andcommitted
JIT: Mark swift error as busy before call definition RefPosition (dotnet#101792)
The RefPosition we were inserting here was inserted too late to actually protect the call definition from being allocated into the error register. Instead, we can just mark the existing `RefTypeFixedReg` created for the argument use as delay freed, which will have the intended effect of keeping the error register busy until after the call definition.
1 parent f4f3575 commit 2b69aa4

File tree

4 files changed

+36
-34
lines changed

4 files changed

+36
-34
lines changed

src/coreclr/jit/lsra.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,7 @@ class LinearScan : public LinearScanInterface
20622062
#endif
20632063
int BuildPutArgReg(GenTreeUnOp* node);
20642064
int BuildCall(GenTreeCall* call);
2065+
void MarkSwiftErrorBusyForCall(GenTreeCall* call);
20652066
int BuildCmp(GenTree* tree);
20662067
int BuildCmpOperands(GenTree* tree);
20672068
int BuildBlockStore(GenTreeBlk* blkNode);

src/coreclr/jit/lsraarmarch.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -404,23 +404,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
404404
#ifdef SWIFT_SUPPORT
405405
if (call->HasSwiftErrorHandling())
406406
{
407-
// Tree is a Swift call with error handling; error register should have been killed
408-
assert((killMask & RBM_SWIFT_ERROR) != 0);
409-
410-
// After a Swift call that might throw returns, we expect the error register to be consumed
411-
// by a GT_SWIFT_ERROR node. However, we want to ensure the error register won't be trashed
412-
// before GT_SWIFT_ERROR can consume it.
413-
// (For example, the PInvoke epilog comes before the error register store.)
414-
// To do so, delay the freeing of the error register until the next node.
415-
// This only works if the next node after the call is the GT_SWIFT_ERROR node.
416-
// (InsertPInvokeCallEpilog should have moved the GT_SWIFT_ERROR node during lowering.)
417-
assert(call->gtNext != nullptr);
418-
assert(call->gtNext->OperIs(GT_SWIFT_ERROR));
419-
420-
// We could use RefTypeKill, but RefTypeFixedReg is used less commonly, so the check for delayRegFree
421-
// during register allocation should be cheaper in terms of TP.
422-
RefPosition* pos = newRefPosition(REG_SWIFT_ERROR, currentLoc + 1, RefTypeFixedReg, call, RBM_SWIFT_ERROR);
423-
setDelayFree(pos);
407+
MarkSwiftErrorBusyForCall(call);
424408
}
425409
#endif // SWIFT_SUPPORT
426410

src/coreclr/jit/lsrabuild.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4479,3 +4479,36 @@ int LinearScan::BuildCmpOperands(GenTree* tree)
44794479
srcCount += BuildOperandUses(op2, op2Candidates);
44804480
return srcCount;
44814481
}
4482+
4483+
#ifdef SWIFT_SUPPORT
4484+
//------------------------------------------------------------------------
4485+
// MarkSwiftErrorBusyForCall: Given a call set the appropriate RefTypeFixedReg
4486+
// RefPosition for the Swift error register as delay free to ensure the error
4487+
// register does not get allocated by LSRA before it has been consumed.
4488+
//
4489+
// Arguments:
4490+
// call - The call node
4491+
//
4492+
void LinearScan::MarkSwiftErrorBusyForCall(GenTreeCall* call)
4493+
{
4494+
assert(call->HasSwiftErrorHandling());
4495+
// After a Swift call that might throw returns, we expect the error register to be consumed
4496+
// by a GT_SWIFT_ERROR node. However, we want to ensure the error register won't be trashed
4497+
// before GT_SWIFT_ERROR can consume it.
4498+
// (For example, by LSRA allocating the call's result to the same register.)
4499+
// To do so, delay the freeing of the error register until the next node.
4500+
// This only works if the next node after the call is the GT_SWIFT_ERROR node.
4501+
// (LowerNonvirtPinvokeCall should have moved the GT_SWIFT_ERROR node.)
4502+
assert(call->gtNext != nullptr);
4503+
assert(call->gtNext->OperIs(GT_SWIFT_ERROR));
4504+
4505+
// Conveniently we model the zeroing of the register as a non-standard constant zero argument,
4506+
// which will have created a RefPosition corresponding to the use of the error at the location
4507+
// of the uses. Marking this RefPosition as delay freed has the effect of keeping the register
4508+
// busy at the location of the definition of the call.
4509+
RegRecord* swiftErrorRegRecord = getRegisterRecord(REG_SWIFT_ERROR);
4510+
assert((swiftErrorRegRecord != nullptr) && (swiftErrorRegRecord->lastRefPosition != nullptr) &&
4511+
(swiftErrorRegRecord->lastRefPosition->nodeLocation == currentLoc));
4512+
setDelayFree(swiftErrorRegRecord->lastRefPosition);
4513+
}
4514+
#endif

src/coreclr/jit/lsraxarch.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,23 +1380,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
13801380
#ifdef SWIFT_SUPPORT
13811381
if (call->HasSwiftErrorHandling())
13821382
{
1383-
// Tree is a Swift call with error handling; error register should have been killed
1384-
assert((killMask & RBM_SWIFT_ERROR) != 0);
1385-
1386-
// After a Swift call that might throw returns, we expect the error register to be consumed
1387-
// by a GT_SWIFT_ERROR node. However, we want to ensure the error register won't be trashed
1388-
// before GT_SWIFT_ERROR can consume it.
1389-
// (For example, the PInvoke epilog comes before the error register store.)
1390-
// To do so, delay the freeing of the error register until the next node.
1391-
// This only works if the next node after the call is the GT_SWIFT_ERROR node.
1392-
// (InsertPInvokeCallEpilog should have moved the GT_SWIFT_ERROR node during lowering.)
1393-
assert(call->gtNext != nullptr);
1394-
assert(call->gtNext->OperIs(GT_SWIFT_ERROR));
1395-
1396-
// We could use RefTypeKill, but RefTypeFixedReg is used less commonly, so the check for delayRegFree
1397-
// during register allocation should be cheaper in terms of TP.
1398-
RefPosition* pos = newRefPosition(REG_SWIFT_ERROR, currentLoc + 1, RefTypeFixedReg, call, RBM_SWIFT_ERROR);
1399-
setDelayFree(pos);
1383+
MarkSwiftErrorBusyForCall(call);
14001384
}
14011385
#endif // SWIFT_SUPPORT
14021386

0 commit comments

Comments
 (0)