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: Pick some low-hanging fruit in LSRA throughput #81916

Merged
merged 10 commits into from
Feb 10, 2023
Merged
73 changes: 40 additions & 33 deletions src/coreclr/jit/lsra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11078,13 +11078,10 @@ void LinearScan::RegisterSelection::reset(Interval* interval, RefPosition* refPo
{
currentInterval = interval;
refPosition = refPos;
score = 0;

regType = linearScan->getRegisterType(currentInterval, refPosition);
currentLocation = refPosition->nodeLocation;
nextRefPos = refPosition->nextRefPosition;
candidates = refPosition->registerAssignment;
preferences = currentInterval->registerPreferences;
regType = linearScan->getRegisterType(currentInterval, refPosition);
candidates = refPosition->registerAssignment;
preferences = currentInterval->registerPreferences;

// This is not actually a preference, it's merely to track the lclVar that this
// "specialPutArg" is using.
Expand All @@ -11094,25 +11091,21 @@ void LinearScan::RegisterSelection::reset(Interval* interval, RefPosition* refPo
rangeEndLocation = refPosition->getRangeEndLocation();
relatedLastLocation = rangeEndLocation;
preferCalleeSave = currentInterval->preferCalleeSave;
rangeEndRefPosition = nullptr;
lastRefPosition = currentInterval->lastRefPosition;
lastLocation = MinLocation;
prevRegRec = currentInterval->assignedReg;

// These are used in the post-selection updates, and must be set for any selection.
freeCandidates = RBM_NONE;
matchingConstants = RBM_NONE;
unassignedSet = RBM_NONE;

coversSet = RBM_NONE;
preferenceSet = RBM_NONE;
coversRelatedSet = RBM_NONE;
coversFullSet = RBM_NONE;

foundRegBit = REG_NA;
found = false;
skipAllocation = false;
coversSetsCalculated = false;
freeCandidates = RBM_NONE;
matchingConstants = RBM_NONE;
unassignedSet = RBM_NONE;
coversSet = RBM_NONE;
preferenceSet = RBM_NONE;
coversRelatedSet = RBM_NONE;
coversFullSet = RBM_NONE;
coversSetsCalculated = false;
found = false;
skipAllocation = false;
coversFullApplied = false;
constAvailableApplied = false;
}

// ----------------------------------------------------------
Expand All @@ -11130,7 +11123,6 @@ bool LinearScan::RegisterSelection::applySelection(int selectionScore, regMaskTP
regMaskTP newCandidates = candidates & selectionCandidates;
if (newCandidates != RBM_NONE)
{
score += selectionScore;
candidates = newCandidates;
return LinearScan::isSingleRegister(candidates);
}
Expand Down Expand Up @@ -11188,7 +11180,13 @@ void LinearScan::RegisterSelection::try_CONST_AVAILABLE()

if (currentInterval->isConstant && RefTypeIsDef(refPosition->refType))
{
found = applySelection(CONST_AVAILABLE, matchingConstants);
regMaskTP newCandidates = candidates & matchingConstants;
if (newCandidates != RBM_NONE)
{
candidates = newCandidates;
constAvailableApplied = true;
found = isSingleRegister(newCandidates);
}
}
}

Expand All @@ -11203,7 +11201,7 @@ void LinearScan::RegisterSelection::try_THIS_ASSIGNED()
return;
}

if (prevRegRec != nullptr)
if (currentInterval->assignedReg != nullptr)
{
found = applySelection(THIS_ASSIGNED, freeCandidates & preferences & prevRegBit);
}
Expand Down Expand Up @@ -11296,7 +11294,13 @@ void LinearScan::RegisterSelection::try_COVERS_FULL()
calculateCoversSets();
#endif

found = applySelection(COVERS_FULL, (coversFullSet & freeCandidates));
regMaskTP newCandidates = candidates & coversFullSet & freeCandidates;
if (newCandidates != RBM_NONE)
{
candidates = newCandidates;
found = isSingleRegister(candidates);
coversFullApplied = true;
}
}

// ----------------------------------------------------------
Expand All @@ -11314,7 +11318,7 @@ void LinearScan::RegisterSelection::try_BEST_FIT()
regMaskTP bestFitSet = RBM_NONE;
// If the best score includes COVERS_FULL, pick the one that's killed soonest.
// If none cover the full range, the BEST_FIT is the one that's killed later.
bool earliestIsBest = ((score & COVERS_FULL) != 0);
bool earliestIsBest = coversFullApplied;
LsraLocation bestFitLocation = earliestIsBest ? MaxLocation : MinLocation;
for (regMaskTP bestFitCandidates = candidates; bestFitCandidates != RBM_NONE;)
{
Expand Down Expand Up @@ -11382,7 +11386,7 @@ void LinearScan::RegisterSelection::try_BEST_FIT()
void LinearScan::RegisterSelection::try_IS_PREV_REG()
{
// TODO: We do not check found here.
if ((prevRegRec != nullptr) && ((score & COVERS_FULL) != 0))
if ((currentInterval->assignedReg != nullptr) && coversFullApplied)
{
found = applySingleRegSelection(IS_PREV_REG, prevRegBit);
}
Expand Down Expand Up @@ -11449,7 +11453,7 @@ void LinearScan::RegisterSelection::try_SPILL_COST()

// Can and should the interval in this register be spilled for this one,
// if we don't find a better alternative?
if ((linearScan->getNextIntervalRef(spillCandidateRegNum, regType) == currentLocation) &&
if ((linearScan->getNextIntervalRef(spillCandidateRegNum, regType) == refPosition->nodeLocation) &&
!assignedInterval->getNextRefPosition()->RegOptional())
{
continue;
Expand Down Expand Up @@ -11740,6 +11744,7 @@ regMaskTP LinearScan::RegisterSelection::select(Interval* currentInterval,
// process data-structures
if (RefTypeIsDef(refPosition->refType))
{
RefPosition* nextRefPos = refPosition->nextRefPosition;
if (currentInterval->hasConflictingDefUse)
{
linearScan->resolveConflictingDefAndUse(currentInterval, refPosition);
Expand Down Expand Up @@ -11949,8 +11954,8 @@ regMaskTP LinearScan::RegisterSelection::select(Interval* currentInterval,
regNumber checkConflictReg = genRegNumFromMask(checkConflictBit);
LsraLocation checkConflictLocation = linearScan->nextFixedRef[checkConflictReg];

if ((checkConflictLocation == currentLocation) ||
(refPosition->delayRegFree && (checkConflictLocation == (currentLocation + 1))))
if ((checkConflictLocation == refPosition->nodeLocation) ||
(refPosition->delayRegFree && (checkConflictLocation == (refPosition->nodeLocation + 1))))
{
candidates &= ~checkConflictBit;
}
Expand All @@ -11963,9 +11968,10 @@ regMaskTP LinearScan::RegisterSelection::select(Interval* currentInterval,
// been restored as inactive after a kill?
// NOTE: this is not currently considered one of the selection criteria - it always wins
// if it is the assignedInterval of 'prevRegRec'.
if (!found && (prevRegRec != nullptr))
if (!found && (currentInterval->assignedReg != nullptr))
{
prevRegBit = genRegMask(prevRegRec->regNum);
RegRecord* prevRegRec = currentInterval->assignedReg;
prevRegBit = genRegMask(prevRegRec->regNum);
if ((prevRegRec->assignedInterval == currentInterval) && ((candidates & prevRegBit) != RBM_NONE))
{
candidates = prevRegBit;
Expand Down Expand Up @@ -12059,6 +12065,7 @@ regMaskTP LinearScan::RegisterSelection::select(Interval* currentInterval,
Selection_Done:
if (skipAllocation)
{
foundRegBit = RBM_NONE;
return RBM_NONE;
}

Expand Down
20 changes: 9 additions & 11 deletions src/coreclr/jit/lsra.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ class LinearScan : public LinearScanInterface
// Did we apply CONST_AVAILABLE heuristics
FORCEINLINE bool isConstAvailable()
{
return (score & CONST_AVAILABLE) != 0;
return constAvailableApplied;
}

private:
Expand All @@ -1251,13 +1251,10 @@ class LinearScan : public LinearScanInterface
ScoreMappingTable* mappingTable = nullptr;
#endif
LinearScan* linearScan = nullptr;
int score = 0;
Interval* currentInterval = nullptr;
RefPosition* refPosition = nullptr;

RegisterType regType = RegisterType::TYP_UNKNOWN;
LsraLocation currentLocation = MinLocation;
RefPosition* nextRefPos = nullptr;
RegisterType regType = RegisterType::TYP_UNKNOWN;

regMaskTP candidates;
regMaskTP preferences = RBM_NONE;
Expand All @@ -1271,26 +1268,27 @@ class LinearScan : public LinearScanInterface
RefPosition* lastRefPosition;
regMaskTP callerCalleePrefs = RBM_NONE;
LsraLocation lastLocation;
RegRecord* prevRegRec = nullptr;

regMaskTP foundRegBit;

regMaskTP prevRegBit = RBM_NONE;

// These are used in the post-selection updates, and must be set for any selection.
regMaskTP freeCandidates;
regMaskTP matchingConstants;
regMaskTP unassignedSet;
regMaskTP foundRegBit;

// Compute the sets for COVERS, OWN_PREFERENCE, COVERS_RELATED, COVERS_FULL and UNASSIGNED together,
// as they all require similar computation.
regMaskTP coversSet;
regMaskTP preferenceSet;
regMaskTP coversRelatedSet;
regMaskTP coversFullSet;
bool coversSetsCalculated = false;
bool found = false;
bool skipAllocation = false;
regNumber foundReg = REG_NA;
bool coversSetsCalculated = false;
bool found = false;
bool skipAllocation = false;
bool coversFullApplied = false;
bool constAvailableApplied = false;

// If the selected register is already assigned to the current internal
FORCEINLINE bool isAlreadyAssigned()
Expand Down