- `LinearScan::identifyCandidates`
- This mostly duplicates what is done in
- `Compiler::lvaMarkLocalVars(). There are differences in what
+ `Compiler::lvaMarkLocalVars()`. There are differences in what
constitutes a register candidate vs. what is tracked, but we
should probably handle them in `Compiler::lvaMarkLocalVars()`
when it is called after `Lowering`.
- First, we create `RefPosition`s to define any internal registers that are required.
As we create new `Interval`s for these, we add the definition `RefPosition` to an array,
- `InternalDefs`. This allows us to create the corresponding uses of these internal
+ `internalDefs`. This allows us to create the corresponding uses of these internal
registers later.
- Then we create `RefPosition`s for each use in the instruction.
we need to ensure that the other source isn't given the same register as the
target. For this, we annotate the use `RefPosition` with `delayRegFree`.
-- Next we create the uses of the internal registers, using the `InternalDefs` array.
+- Next we create the uses of the internal registers, using the `internalDefs` array.
This is cleared before the next instruction is handled.
- Next, any registers in the kill set for the instruction are killed. This is performed
- When `COMPlus_EnableEHWriteThru == 0`, any variable that's
live in to an exception region is always referenced on the stack.
- - See [Enable EHWriteThru by default](#enable-EHWriteThru-by-default).
+ - See [Enable EHWriteThru by default](#enable-ehwritethru-by-default).
- Code generation (genGenerateCode)
// If, in minopts/debug, we really want to allow locals to become
// unreferenced later, we'll have to explicitly clear this bit.
varDsc->setLvRefCnt(0);
- varDsc->setLvRefCntWtd(0);
+ varDsc->setLvRefCntWtd(BB_ZERO_WEIGHT);
// Special case for some varargs params ... these must
// remain unreferenced.
}
//------------------------------------------------------------------------
-// spill: Spill this Interval between "fromRefPosition" and "toRefPosition"
+// spill: Spill the "interval" starting from "fromRefPosition" (upto "toRefPosition")
//
// Arguments:
+// interval - The interval that contains the RefPosition to be spilled
// fromRefPosition - The RefPosition at which the Interval is to be spilled
// toRefPosition - The RefPosition at which it must be reloaded (debug only arg)
//
{
Interval* assignedInterval = regRec->assignedInterval;
assert(assignedInterval != nullptr);
+ assert(spillRefPosition == nullptr || spillRefPosition->getInterval() == assignedInterval);
regNumber thisRegNum = regRec->regNum;
// Is assignedInterval actually still assigned to this register?
public:
RefInfoListNodePool(Compiler* compiler, unsigned preallocate = defaultPreallocation);
- RefInfoListNode* GetNode(RefPosition* r, GenTree* t, unsigned regIdx = 0);
+ RefInfoListNode* GetNode(RefPosition* r, GenTree* t);
void ReturnNode(RefInfoListNode* listNode);
};
// interval to which this register is currently allocated.
// If the interval is inactive (isActive == false) then it is not currently live,
- // and the register call be unassigned (i.e. setting assignedInterval to nullptr)
+ // and the register can be unassigned (i.e. setting assignedInterval to nullptr)
// without spilling the register.
Interval* assignedInterval;
// Interval to which this register was previously allocated, and which was unassigned
// i.e. whose consuming node has not yet been handled.
RefInfoListNodePool listNodePool;
- // The defList is used for the transient RefInfo that is computed by
- // the Build methods, and used in building RefPositions.
- // When Def RefPositions are built for a node, their NodeInfo is placed
- // in the defList. As the consuming node is handled, it moves the NodeInfo
- // into an ordered useList corresponding to the uses for that node.
+ // When Def RefPositions are built for a node, their RefInfoListNode
+ // (GenTree* to RefPosition* mapping) is placed in the defList.
+ // As the consuming node is handled, it removes the RefInfoListNode from the
+ // defList, use the interval associated with the corresponding Def RefPosition and
+ // use it to build the Use RefPosition.
RefInfoList defList;
// As we build uses, we may want to preference the next definition (i.e. the register produced
GenTree* treeNode;
unsigned int bbNum;
+ LsraLocation nodeLocation;
+
// Prior to the allocation pass, registerAssignment captures the valid registers
- // for this RefPosition. An empty set means that any register is valid. A non-empty
- // set means that it must be one of the given registers (may be the full set if the
- // only constraint is that it must reside in SOME register)
+ // for this RefPosition.
// After the allocation pass, this contains the actual assignment
- LsraLocation nodeLocation;
- regMaskTP registerAssignment;
+ regMaskTP registerAssignment;
RefType refType;
// pool.
//
// Arguments:
-// l - - The `LsraLocation` for the `RefInfo` value.
-// i - The interval for the `RefInfo` value.
-// t - The IR node for the `RefInfo` value
-// regIdx - The register index for the `RefInfo` value.
+// r - The `RefPosition` for the `RefInfo` value.
+// t - The IR node for the `RefInfo` value
//
// Returns:
// A pooled or newly-allocated `RefInfoListNode`, depending on the
// contents of the pool.
-RefInfoListNode* RefInfoListNodePool::GetNode(RefPosition* r, GenTree* t, unsigned regIdx)
+RefInfoListNode* RefInfoListNodePool::GetNode(RefPosition* r, GenTree* t)
{
RefInfoListNode* head = m_freeList;
if (head == nullptr)
#ifdef DEBUG
int newDefListCount = defList.Count();
- int produce = newDefListCount - oldDefListCount;
+ // Currently produce is unused, but need to strengthen an assert to check if produce is
+ // as expected. See https://github.com/dotnet/runtime/issues/8678
+ int produce = newDefListCount - oldDefListCount;
assert((consume == 0) || (ComputeAvailableSrcCount(tree) == consume));
-#endif // DEBUG
-#ifdef DEBUG
// If we are constraining registers, modify all the RefPositions we've just built to specify the
// minimum reg count required.
if ((getStressLimitRegs() != LSRA_LIMIT_NONE) || (getSelectionHeuristics() != LSRA_SELECT_DEFAULT))
{
setBlockSequence();
}
- curBBNum = blockSequence[bbSeqCount - 1]->bbNum;
// Next, create ParamDef RefPositions for all the tracked parameters, in order of their varIndex.
// Assign these RefPositions to the (nonexistent) BB0.
{
JITDUMP(" Marking RP #%d of V%02u as spillAfter\n", interval->recentRefPosition->rpNum,
interval->varNum);
- interval->recentRefPosition->spillAfter;
+ interval->recentRefPosition->spillAfter = true;
}
}
}