summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/lsra.cpp62
-rw-r--r--src/jit/lsra.h52
2 files changed, 65 insertions, 49 deletions
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 3298eb6986..3b98491303 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -4903,7 +4903,7 @@ LinearScan::tryAllocateFreeReg(Interval *currentInterval, RefPosition *refPositi
// Arguments:
// current The interval for the current allocation
// refPosition The RefPosition of the current Interval for which a register is being allocated
-// allocationOptional If true, a reg may not be allocated if all other ref positions currently
+// allocateIfProfitable If true, a reg may not be allocated if all other ref positions currently
// occupying registers are more important than the 'refPosition'.
//
// Return Value:
@@ -4911,20 +4911,20 @@ LinearScan::tryAllocateFreeReg(Interval *currentInterval, RefPosition *refPositi
//
// Note: Currently this routine uses weight and farthest distance of next reference
// to select a ref position for spilling.
-// a) if allocationOptional = false
+// a) if allocateIfProfitable = false
// The ref position chosen for spilling will be the lowest weight
// of all and if there is is more than one ref position with the
// same lowest weight, among them choses the one with farthest
// distance to its next reference.
//
-// b) if allocationOptional = true
+// b) if allocateIfProfitable = true
// The ref position chosen for spilling will not only be lowest weight
// of all but also has a weight lower than 'refPosition'. If there is
// no such ref position, reg will not be allocated.
regNumber
LinearScan::allocateBusyReg(Interval* current,
RefPosition* refPosition,
- bool allocationOptional)
+ bool allocateIfProfitable)
{
regNumber foundReg = REG_NA;
@@ -4951,7 +4951,7 @@ LinearScan::allocateBusyReg(Interval* current,
LsraLocation farthestLocation = MinLocation;
LsraLocation refLocation = refPosition->nodeLocation;
unsigned farthestRefPosWeight;
- if (allocationOptional)
+ if (allocateIfProfitable)
{
// If allocating a reg is optional, we will consider those ref positions
// whose weight is less than 'refPosition' for spilling.
@@ -5132,13 +5132,13 @@ LinearScan::allocateBusyReg(Interval* current,
// the farthest.
assert(recentAssignedRefWeight == farthestRefPosWeight);
- // If allocation is optional, the first spill candidate selected
+ // If allocateIfProfitable=true, the first spill candidate selected
// will be based on weight alone. After we have found a spill
// candidate whose weight is less than the 'refPosition', we will
// consider farthest distance when there is a tie in weights.
// This is to ensure that we don't spill a ref position whose
// weight is equal to weight of 'refPosition'.
- if (allocationOptional && farthestRefPhysRegRecord == nullptr)
+ if (allocateIfProfitable && farthestRefPhysRegRecord == nullptr)
{
isBetterLocation = false;
}
@@ -5157,7 +5157,7 @@ LinearScan::allocateBusyReg(Interval* current,
}
#if DEBUG
- if (allocationOptional)
+ if (allocateIfProfitable)
{
// There may not be a spill candidate or if one is found
// its weight must be less than the weight of 'refPosition'
@@ -5312,7 +5312,10 @@ LinearScan::spillInterval(Interval* interval, RefPosition* fromRefPosition, RefP
if (!fromRefPosition->lastUse)
{
- if (!fromRefPosition->IsActualRef())
+ // If not allocated a register, Lcl var def/use ref positions even if reg optional
+ // should be marked as spillAfter.
+ if (!fromRefPosition->RequiresRegister() &&
+ !(interval->isLocalVar && fromRefPosition->IsActualRef()))
{
fromRefPosition->registerAssignment = RBM_NONE;
}
@@ -6607,12 +6610,12 @@ LinearScan::allocateRegisters()
{
bool allocateReg = true;
- if (currentRefPosition->IsRegOptional())
+ if (currentRefPosition->AllocateIfProfitable())
{
- if (currentRefPosition->lastUse &&
+ // We can avoid allocating a register if it is a the last use requiring a reload.
+ if (currentRefPosition->lastUse &&
currentRefPosition->reload)
{
- // We can avoid allocating a register if it is a the last use requiring a reload
allocateReg = false;
}
@@ -6653,26 +6656,25 @@ LinearScan::allocateRegisters()
}
else
#endif // FEATURE_SIMD
- if (currentRefPosition->IsActualRef())
+ if (currentRefPosition->RequiresRegister() ||
+ currentRefPosition->AllocateIfProfitable())
{
if (allocateReg)
{
- // Though Lower/Codegen has indicated that it can generate code even if
- // no reg is allocated to this ref position, we will make an attempt
- // to get a busy reg if it is allocated to a lesser important ref position.
- // If all the refpositions currently occupying registers are more
- // important than currentRefPosition, no reg will be allocated.
- assignedRegister = allocateBusyReg(currentInterval, currentRefPosition, currentRefPosition->IsRegOptional());
+ assignedRegister = allocateBusyReg(currentInterval,
+ currentRefPosition,
+ currentRefPosition->AllocateIfProfitable());
}
if (assignedRegister != REG_NA)
{
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_ALLOC_SPILLED_REG, currentInterval, assignedRegister));
}
- else
+ else
{
- // This can happen only if ref position requires a reg optionally
- noway_assert(currentRefPosition->IsRegOptional());
+ // This can happen only for those ref positions that are to be allocated
+ // only if profitable.
+ noway_assert(currentRefPosition->AllocateIfProfitable());
currentRefPosition->registerAssignment = RBM_NONE;
currentRefPosition->reload = false;
@@ -6855,6 +6857,13 @@ LinearScan::allocateRegisters()
// NICE: Consider tracking whether an Interval is always in the same location (register/stack)
// in which case it will require no resolution.
//
+// TODO: If def of a lclVar is spilled, this routine will simply assign it to REG_STK
+// so that the result gets stored to stack. However, if a use of a lclVar is
+// marked both reload and spillAfter, this routine will mark it as 'spill after'
+// which results in lclVar reload and spill. If such a use of lclVar is flagged as
+// reg-optional by lower/codegen, we could simply assign it to REG_STK without
+// requring to reload and spill. This would avoid generation of unnecessary
+// reload and spill.
void
LinearScan::resolveLocalRef(GenTreePtr treeNode, RefPosition * currentRefPosition)
{
@@ -6867,9 +6876,7 @@ LinearScan::resolveLocalRef(GenTreePtr treeNode, RefPosition * currentRefPositio
if (currentRefPosition->registerAssignment == RBM_NONE)
{
- // Either requires no register or reg is optional.
- assert(!currentRefPosition->IsActualRef() ||
- currentRefPosition->IsRegOptional());
+ assert(!currentRefPosition->RequiresRegister());
interval->isSpilled = true;
varDsc->lvRegNum = REG_STK;
@@ -10761,14 +10768,15 @@ LinearScan::verifyFinalAllocation()
interval->physReg = REG_NA;
interval->assignedReg = nullptr;
- // regRegcord could be null if RefPosition requires a reg optionally
+ // regRegcord could be null if RefPosition is to be allocated a
+ // reg only if profitable.
if (regRecord != nullptr)
{
regRecord->assignedInterval = nullptr;
}
else
{
- assert(currentRefPosition->IsRegOptional());
+ assert(currentRefPosition->AllocateIfProfitable());
}
}
}
diff --git a/src/jit/lsra.h b/src/jit/lsra.h
index dc6d689d2e..11af9be3aa 100644
--- a/src/jit/lsra.h
+++ b/src/jit/lsra.h
@@ -538,8 +538,8 @@ private:
LsraSpill getLsraSpill() { return (LsraSpill) (lsraStressMask & LSRA_SPILL_MASK); }
bool spillAlways() { return getLsraSpill() == LSRA_SPILL_ALWAYS; }
- // This controls whether RefPositions that require a register optionally should
- // be allocated a reg at all.
+ // This controls whether RefPositions that lower/codegen indicated as reg optional be
+ // allocated a reg at all.
enum LsraRegOptionalControl { LSRA_REG_OPTIONAL_DEFAULT = 0,
LSRA_REG_OPTIONAL_NO_ALLOC = 0x1000,
LSRA_REG_OPTIONAL_MASK = 0x1000 };
@@ -768,7 +768,7 @@ private:
regNumber tryAllocateFreeReg(Interval *current, RefPosition *refPosition);
RegRecord* findBestPhysicalReg(RegisterType regType, LsraLocation endLocation,
regMaskTP candidates, regMaskTP preferences);
- regNumber allocateBusyReg(Interval* current, RefPosition* refPosition, bool allocationOptional);
+ regNumber allocateBusyReg(Interval* current, RefPosition* refPosition, bool allocateIfProfitable);
regNumber assignCopyReg(RefPosition * refPosition);
void checkAndAssignInterval(RegRecord * regRec, Interval * interval);
@@ -1355,15 +1355,39 @@ public:
RefType refType;
+ // Returns true if it is a reference on a gentree node.
bool IsActualRef()
{
return (refType == RefTypeDef ||
- refType == RefTypeUse
+ refType == RefTypeUse);
+ }
+
+ bool RequiresRegister()
+ {
+ return (IsActualRef()
#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- || refType == RefTypeUpperVectorSaveDef
+ || refType == RefTypeUpperVectorSaveDef
|| refType == RefTypeUpperVectorSaveUse
#endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- );
+ ) && !AllocateIfProfitable();
+ }
+
+ // Returns true whether this ref position is to be allocated
+ // a reg only if it is profitable. Currently these are the
+ // ref positions that lower/codegen has indicated as reg
+ // optional and is considered a contained memory operand if
+ // no reg is allocated.
+ bool AllocateIfProfitable()
+ {
+ // TODO-CQ: Right now if a ref position is marked as
+ // copyreg or movereg, then it is not treated as
+ // 'allocate if profitable'. This is an implementation
+ // limitation that needs to be addressed.
+ return (refType == RefTypeUse) &&
+ !copyReg &&
+ !moveReg &&
+ (treeNode != nullptr) &&
+ treeNode->IsRegOptional();
}
// Used by RefTypeDef/Use positions of a multi-reg call node.
@@ -1381,22 +1405,6 @@ public:
unsigned getMultiRegIdx() { return multiRegIdx; }
- // Returns true if codegen has indicated that the tree node
- // referred to by RefPosition can be treated as a contained
- // memory operand if no register was allocated.
- bool IsRegOptional()
- {
- // TODO-CQ: Right now if a ref position is marked as
- // copyreg or movereg, then it is always allocated a
- // register, though it is marked as reg optional.
- // This is an implementation limitation that needs to
- // be addressed.
- return (refType == RefTypeUse) &&
- !copyReg &&
- !moveReg &&
- (treeNode != nullptr) &&
- treeNode->IsRegOptional();
- }
// Last Use - this may be true for multiple RefPositions in the same Interval
bool lastUse : 1;