#ifdef TARGET_ARM64
nextConsecutiveRefPositionMap = nullptr;
#endif
- buildIntervals();
+
+ if (enregisterLocalVars)
+ {
+ buildIntervals<true>();
+ }
+ else
+ {
+ buildIntervals<false>();
+ }
+
DBEXEC(VERBOSE, TupleStyleDump(LSRA_DUMP_REFPOS));
compiler->EndPhase(PHASE_LINEAR_SCAN_BUILD);
allocationPassComplete = true;
compiler->EndPhase(PHASE_LINEAR_SCAN_ALLOC);
- resolveRegisters();
+ if (enregisterLocalVars)
+ {
+ resolveRegisters<true>();
+ }
+ else
+ {
+ resolveRegisters<false>();
+ }
compiler->EndPhase(PHASE_LINEAR_SCAN_RESOLVE);
assert(blockSequencingDone); // Should do at least one traversal.
return true;
}
+template void LinearScan::identifyCandidates<true>();
+template void LinearScan::identifyCandidates<false>();
+
// Identify locals & compiler temps that are register candidates
// TODO-Cleanup: This was cloned from Compiler::lvaSortByRefCount() in lclvars.cpp in order
// to avoid perturbation, but should be merged.
-
-void LinearScan::identifyCandidates()
+template <bool localVarsEnregistered>
+void LinearScan::identifyCandidates()
{
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
// Initialize the set of lclVars that are candidates for register allocation.
VarSetOps::AssignNoCopy(compiler, registerCandidateVars, VarSetOps::MakeEmpty(compiler));
unsigned int largeVectorVarCount = 0;
weight_t thresholdLargeVectorRefCntWtd = 4 * BB_UNITY_WEIGHT;
#endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
VarSetOps::AssignNoCopy(compiler, fpCalleeSaveCandidateVars, VarSetOps::MakeEmpty(compiler));
VarSetOps::AssignNoCopy(compiler, fpMaybeCandidateVars, VarSetOps::MakeEmpty(compiler));
#endif // DOUBLE_ALIGN
// Check whether register variables are permitted.
- if (!enregisterLocalVars)
+ if (!localVarsEnregistered)
{
localVarIntervals = nullptr;
}
varDsc->SetOtherReg(REG_STK);
#endif // TARGET_64BIT
- if (!enregisterLocalVars)
+ if (!localVarsEnregistered)
{
varDsc->lvLRACandidate = false;
continue;
// the same register assignment throughout
varDsc->lvRegister = false;
- if (!isRegCandidate(varDsc))
+ if (!localVarsEnregistered || !isRegCandidate(varDsc))
{
varDsc->lvLRACandidate = 0;
if (varDsc->lvTracked)
}
else
{
+ // Added code just to check if we ever reach here. If not delete this if-else.
+ assert(false);
localVarIntervals[varDsc->lvVarIndex] = nullptr;
}
}
#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
// Create Intervals to use for the save & restore of the upper halves of large vector lclVars.
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
VarSetOps::Iter largeVectorVarsIter(compiler, largeVectorVars);
unsigned largeVectorVarIndex = 0;
if (VERBOSE)
{
printf("\nFP callee save candidate vars: ");
- if (enregisterLocalVars && !VarSetOps::IsEmpty(compiler, fpCalleeSaveCandidateVars))
+ if (localVarsEnregistered && !VarSetOps::IsEmpty(compiler, fpCalleeSaveCandidateVars))
{
dumpConvertedVarSet(compiler, fpCalleeSaveCandidateVars);
printf("\n");
if (floatVarCount > 6 && compiler->fgHasLoops &&
(compiler->fgReturnBlocks == nullptr || compiler->fgReturnBlocks->next == nullptr))
{
- assert(enregisterLocalVars);
+ assert(localVarsEnregistered);
#ifdef DEBUG
if (VERBOSE)
{
}
// From here on, we're only interested in the exceptVars that are candidates.
- if (enregisterLocalVars && (compiler->compHndBBtabCount > 0))
+ if (localVarsEnregistered && (compiler->compHndBBtabCount > 0))
{
VarSetOps::IntersectionD(compiler, exceptVars, registerCandidateVars);
}
void LinearScan::processBlockEndAllocation(BasicBlock* currentBlock)
{
assert(currentBlock != nullptr);
+ markBlockVisited(currentBlock);
+
if (enregisterLocalVars)
{
processBlockEndLocations(currentBlock);
- }
- markBlockVisited(currentBlock);
- // Get the next block to allocate.
- // When the last block in the method has successors, there will be a final "RefTypeBB" to
- // ensure that we get the varToRegMap set appropriately, but in that case we don't need
- // to worry about "nextBlock".
- BasicBlock* nextBlock = getNextBlock();
- if (nextBlock != nullptr)
+ // Get the next block to allocate.
+ // When the last block in the method has successors, there will be a final "RefTypeBB" to
+ // ensure that we get the varToRegMap set appropriately, but in that case we don't need
+ // to worry about "nextBlock".
+ BasicBlock* nextBlock = getNextBlock();
+ if (nextBlock != nullptr)
+ {
+ processBlockStartLocations(nextBlock);
+ }
+ }
+ else
{
- processBlockStartLocations(nextBlock);
+ resetAllRegistersState();
}
}
}
}
+//------------------------------------------------------------------------
+// resetAllRegistersState: Resets the next interval ref, spill cost and clears
+// the constant registers.
+//
+void LinearScan::resetAllRegistersState()
+{
+ assert(!enregisterLocalVars);
+ // Just clear any constant registers and return.
+ resetAvailableRegs();
+ for (regNumber reg = REG_FIRST; reg < AVAILABLE_REG_COUNT; reg = REG_NEXT(reg))
+ {
+ RegRecord* physRegRecord = getRegisterRecord(reg);
+ Interval* assignedInterval = physRegRecord->assignedInterval;
+ clearNextIntervalRef(reg, physRegRecord->registerType);
+ clearSpillCost(reg, physRegRecord->registerType);
+ if (assignedInterval != nullptr)
+ {
+ assert(assignedInterval->isConstant);
+ physRegRecord->assignedInterval = nullptr;
+ }
+ }
+}
+
//------------------------------------------------------------------------
// processBlockStartLocations: Update var locations on entry to 'currentBlock' and clear constant
// registers.
assert(enregisterLocalVars || !allocationPassComplete);
- if (!enregisterLocalVars)
- {
- // Just clear any constant registers and return.
- resetAvailableRegs();
- for (regNumber reg = REG_FIRST; reg < AVAILABLE_REG_COUNT; reg = REG_NEXT(reg))
- {
- RegRecord* physRegRecord = getRegisterRecord(reg);
- Interval* assignedInterval = physRegRecord->assignedInterval;
- clearNextIntervalRef(reg, physRegRecord->registerType);
- clearSpillCost(reg, physRegRecord->registerType);
- if (assignedInterval != nullptr)
- {
- assert(assignedInterval->isConstant);
- physRegRecord->assignedInterval = nullptr;
- }
- }
- return;
- }
-
unsigned predBBNum = blockInfo[currentBlock->bbNum].predBBNum;
VarToRegMap predVarToRegMap = getOutVarToRegMap(predBBNum);
VarToRegMap inVarToRegMap = getInVarToRegMap(currentBlock->bbNum);
// This is the final phase of register allocation. It writes the register assignments to
// the tree, and performs resolution across joins and backedges.
//
-void LinearScan::resolveRegisters()
+template <bool localVarsEnregistered>
+void LinearScan::resolveRegisters()
{
// Iterate over the tree and the RefPositions in lockstep
// - annotate the tree with register assignments by setting GetRegNum() or gtRegPair (for longs)
// Clear register assignments - these will be reestablished as lclVar defs (including RefTypeParamDefs)
// are encountered.
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
for (regNumber reg = REG_FIRST; reg < AVAILABLE_REG_COUNT; reg = REG_NEXT(reg))
{
// handle incoming arguments and special temps
RefPositionIterator currentRefPosition = refPositions.begin();
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
VarToRegMap entryVarToRegMap = inVarToRegMaps[compiler->fgFirstBB->bbNum];
for (; currentRefPosition != refPositions.end(); ++currentRefPosition)
{
assert(curBBNum == block->bbNum);
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
// Record the var locations at the start of this block.
// (If it's fgFirstBB, we've already done that above, see entryVarToRegMap)
}
}
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
processBlockEndLocations(block);
}
}
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
#ifdef DEBUG
if (VERBOSE)
}
}
+template void LinearScan::buildIntervals<true>();
+template void LinearScan::buildIntervals<false>();
+
//------------------------------------------------------------------------
// buildIntervals: The main entry point for building the data structures over
// which we will do register allocation.
//
-void LinearScan::buildIntervals()
+template <bool localVarsEnregistered>
+void LinearScan::buildIntervals()
{
BasicBlock* block;
doDoubleAlign = false;
#endif
- identifyCandidates();
+ identifyCandidates<localVarsEnregistered>();
// Figure out if we're going to use a frame pointer. We need to do this before building
// the ref positions, because those objects will embed the frame register in various register masks
blockInfo[block->bbNum].predBBNum = predBlock->bbNum;
}
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
VarSetOps::AssignNoCopy(compiler, currentLiveVars,
VarSetOps::Intersection(compiler, registerCandidateVars, block->bbLiveIn));
currentLoc += 2;
}
-#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- // At the end of each block, create upperVectorRestores for any largeVectorVars that may be
- // partiallySpilled (during the build phase all intervals will be marked isPartiallySpilled if
- // they *may) be partially spilled at any point.
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
+#if FEATURE_PARTIAL_SIMD_CALLEE_SAVE
+ // At the end of each block, create upperVectorRestores for any largeVectorVars that may be
+ // partiallySpilled (during the build phase all intervals will be marked isPartiallySpilled if
+ // they *may) be partially spilled at any point.
VarSetOps::Iter largeVectorVarsIter(compiler, largeVectorVars);
unsigned largeVectorVarIndex = 0;
while (largeVectorVarsIter.NextElem(&largeVectorVarIndex))
Interval* lclVarInterval = getIntervalForLocalVar(largeVectorVarIndex);
buildUpperVectorRestoreRefPosition(lclVarInterval, currentLoc, nullptr, false);
}
- }
#endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE
- // Note: the visited set is cleared in LinearScan::doLinearScan()
- markBlockVisited(block);
- if (!defList.IsEmpty())
- {
- INDEBUG(dumpDefList());
- assert(!"Expected empty defList at end of block");
- }
+ // Note: the visited set is cleared in LinearScan::doLinearScan()
+ markBlockVisited(block);
+ if (!defList.IsEmpty())
+ {
+ INDEBUG(dumpDefList());
+ assert(!"Expected empty defList at end of block");
+ }
- if (enregisterLocalVars)
- {
// Insert exposed uses for a lclVar that is live-out of 'block' but not live-in to the
// next block, or any unvisited successors.
// This will address lclVars that are live on a backedge, as well as those that are kept
LclVarDsc* const varDsc = compiler->lvaGetDesc(varNum);
assert(isCandidateVar(varDsc));
RefPosition* const lastRP = getIntervalForLocalVar(varIndex)->lastRefPosition;
- // We should be able to assert that lastRP is non-null if it is live-out, but sometimes liveness lies.
+ // We should be able to assert that lastRP is non-null if it is live-out, but sometimes liveness
+ // lies.
if ((lastRP != nullptr) && (lastRP->bbNum == block->bbNum))
{
lastRP->lastUse = false;
}
#endif // DEBUG
}
+ else
+ {
+ // Note: the visited set is cleared in LinearScan::doLinearScan()
+ markBlockVisited(block);
+ if (!defList.IsEmpty())
+ {
+ INDEBUG(dumpDefList());
+ assert(!"Expected empty defList at end of block");
+ }
+ }
prevBlock = block;
}
- if (enregisterLocalVars)
+ if (localVarsEnregistered)
{
if (compiler->lvaKeepAliveAndReportThis())
{