summaryrefslogtreecommitdiff
path: root/src/jit/compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/compiler.cpp')
-rw-r--r--src/jit/compiler.cpp760
1 files changed, 760 insertions, 0 deletions
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index c70e90da6a..e08a89aa12 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -10970,3 +10970,763 @@ bool Compiler::killGCRefs(GenTree* tree)
return false;
}
+
+#ifdef USING_VARIABLE_LIVE_RANGE
+#ifdef DEBUG
+//------------------------------------------------------------------------
+// VariableLiveRanges dumpers
+//------------------------------------------------------------------------
+
+// Dump "VariableLiveRange" when code has not been generated and we don't have so the assembly native offset
+// but at least "emitLocation"s and "siVarLoc"
+void VariableLiveKeeper::VariableLiveRange::dumpVariableLiveRange(const CodeGenInterface* codeGen) const
+{
+ codeGen->dumpSiVarLoc(&m_VarLocation);
+ printf(" [ ");
+ m_StartEmitLocation.Print();
+ printf(", ");
+ if (m_EndEmitLocation.Valid())
+ {
+ m_EndEmitLocation.Print();
+ }
+ else
+ {
+ printf("NON_CLOSED_RANGE");
+ }
+ printf(" ]; ");
+}
+
+// Dump "VariableLiveRange" when code has been generated and we have the assembly native offset of each "emitLocation"
+void VariableLiveKeeper::VariableLiveRange::dumpVariableLiveRange(emitter* emit, const CodeGenInterface* codeGen) const
+{
+ assert(emit != nullptr);
+
+ // "VariableLiveRanges" are created setting its location ("m_VarLocation") and the initial native offset
+ // ("m_StartEmitLocation")
+ codeGen->dumpSiVarLoc(&m_VarLocation);
+
+ // If this is an open "VariableLiveRange", "m_EndEmitLocation" is non-valid and print -1
+ UNATIVE_OFFSET endAssemblyOffset = m_EndEmitLocation.Valid() ? m_EndEmitLocation.CodeOffset(emit) : -1;
+
+ printf(" [%X , %X )", m_StartEmitLocation.CodeOffset(emit), m_EndEmitLocation.CodeOffset(emit));
+}
+
+//------------------------------------------------------------------------
+// LiveRangeDumper
+//------------------------------------------------------------------------
+//------------------------------------------------------------------------
+// resetDumper: If the the "liveRange" has its last "VariableLiveRange" closed, it makes
+// the "LiveRangeDumper" points to end of "liveRange" (nullptr). In other case,
+// it makes the "LiveRangeDumper" points to the last "VariableLiveRange" of
+// "liveRange", which is opened.
+//
+// Arguments:
+// liveRanges - the "LiveRangeList" of the "VariableLiveDescriptor" we want to
+// udpate its "LiveRangeDumper".
+//
+// Notes:
+// This method is expected to be called once a the code for a BasicBlock has been
+// generated and all the new "VariableLiveRange"s of the variable during this block
+// has been dumped.
+void VariableLiveKeeper::LiveRangeDumper::resetDumper(const LiveRangeList* liveRanges)
+{
+ // There must have reported something in order to reset
+ assert(m_hasLiveRangestoDump);
+
+ if (liveRanges->back().m_EndEmitLocation.Valid())
+ {
+ // the last "VariableLiveRange" is closed and the variable
+ // is no longer alive
+ m_hasLiveRangestoDump = false;
+ }
+ else
+ {
+ // the last "VariableLiveRange" remains opened because it is
+ // live at "BasicBlock"s "bbLiveOut".
+ m_StartingLiveRange = liveRanges->backPosition();
+ }
+}
+
+//------------------------------------------------------------------------
+// setDumperStartAt: Make "LiveRangeDumper" instance points the last "VariableLiveRange"
+// added so we can starts dumping from there after the actual "BasicBlock"s code is generated.
+//
+// Arguments:
+// liveRangeIt - an iterator to a position in "VariableLiveDescriptor::m_VariableLiveRanges"
+//
+// Return Value:
+// A const pointer to the "LiveRangeList" containing all the "VariableLiveRange"s
+// of the variable with index "varNum".
+//
+// Notes:
+// "varNum" should be always a valid inde ("varnum" < "m_LiveDscCount")
+void VariableLiveKeeper::LiveRangeDumper::setDumperStartAt(const LiveRangeListIterator liveRangeIt)
+{
+ m_hasLiveRangestoDump = true;
+ m_StartingLiveRange = liveRangeIt;
+}
+
+//------------------------------------------------------------------------
+// getStartForDump: Return an iterator to the first "VariableLiveRange" edited/added
+// during the current "BasicBlock"
+//
+// Return Value:
+// A LiveRangeListIterator to the first "VariableLiveRange" in "LiveRangeList" which
+// was used during last "BasicBlock".
+//
+VariableLiveKeeper::LiveRangeListIterator VariableLiveKeeper::LiveRangeDumper::getStartForDump() const
+{
+ return m_StartingLiveRange;
+}
+
+//------------------------------------------------------------------------
+// hasLiveRangesToDump: Retutn wheter at least a "VariableLiveRange" was alive during
+// the current "BasicBlock"'s code generation
+//
+// Return Value:
+// A boolean indicating indicating if there is at least a "VariableLiveRange"
+// that has been used for the variable during last "BasicBlock".
+//
+bool VariableLiveKeeper::LiveRangeDumper::hasLiveRangesToDump() const
+{
+ return m_hasLiveRangestoDump;
+}
+#endif // DEBUG
+
+//------------------------------------------------------------------------
+// VariableLiveDescriptor
+//------------------------------------------------------------------------
+
+VariableLiveKeeper::VariableLiveDescriptor::VariableLiveDescriptor(CompAllocator allocator)
+{
+ // Initialize an empty list
+ m_VariableLiveRanges = new (allocator) LiveRangeList(allocator);
+
+ INDEBUG(m_VariableLifeBarrier = new (allocator) LiveRangeDumper(m_VariableLiveRanges));
+}
+
+//------------------------------------------------------------------------
+// hasVariableLiveRangeOpen: Return true if the variable is still alive,
+// false in other case.
+//
+bool VariableLiveKeeper::VariableLiveDescriptor::hasVariableLiveRangeOpen() const
+{
+ return !m_VariableLiveRanges->empty() && !m_VariableLiveRanges->back().m_EndEmitLocation.Valid();
+}
+
+//------------------------------------------------------------------------
+// getLiveRanges: Return the list of variable locations for this variable.
+//
+// Return Value:
+// A const LiveRangeList* pointing to the first variable location if it has
+// any or the end of the list in other case.
+//
+VariableLiveKeeper::LiveRangeList* VariableLiveKeeper::VariableLiveDescriptor::getLiveRanges() const
+{
+ return m_VariableLiveRanges;
+}
+
+//------------------------------------------------------------------------
+// startLiveRangeFromEmitter: Report this variable as being born in "varLocation"
+// since the instruction where "emit" is located.
+//
+// Arguments:
+// varLocation - the home of the variable.
+// emit - an emitter* instance located at the first instruction from
+// where "varLocation" becomes valid.
+//
+// Assumptions:
+// This variable is being born so it should be dead.
+//
+// Notes:
+// The position of "emit" matters to ensure intervals inclusive of the
+// beginning and exclusive of the end.
+//
+void VariableLiveKeeper::VariableLiveDescriptor::startLiveRangeFromEmitter(CodeGenInterface::siVarLoc varLocation,
+ emitter* emit) const
+{
+ noway_assert(emit != nullptr);
+
+ // Is the first "VariableLiveRange" or the previous one has been closed so its "m_EndEmitLocation" is valid
+ noway_assert(m_VariableLiveRanges->empty() || m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
+
+ // Creates new live range with invalid end
+ m_VariableLiveRanges->emplace_back(varLocation, emitLocation(), emitLocation());
+ m_VariableLiveRanges->back().m_StartEmitLocation.CaptureLocation(emit);
+
+#ifdef DEBUG
+ if (!m_VariableLifeBarrier->hasLiveRangesToDump())
+ {
+ m_VariableLifeBarrier->setDumperStartAt(m_VariableLiveRanges->backPosition());
+ }
+#endif // DEBUG
+
+ // startEmitLocationendEmitLocation has to be Valid and endEmitLocationendEmitLocation not
+ noway_assert(m_VariableLiveRanges->back().m_StartEmitLocation.Valid());
+ noway_assert(!m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
+}
+
+//------------------------------------------------------------------------
+// endLiveRangeAtEmitter: Report this variable as becoming dead since the
+// instruction where "emit" is located.
+//
+// Arguments:
+// emit - an emitter* instance located at the first instruction from
+// this variable becomes dead.
+//
+// Assumptions:
+// This variable is becoming dead so it should be alive.
+//
+// Notes:
+// The position of "emit" matters to ensure intervals inclusive of the
+// beginning and exclusive of the end.
+//
+void VariableLiveKeeper::VariableLiveDescriptor::endLiveRangeAtEmitter(emitter* emit) const
+{
+ noway_assert(emit != nullptr);
+ noway_assert(hasVariableLiveRangeOpen());
+
+ // Using [close, open) ranges so as to not compute the size of the last instruction
+ m_VariableLiveRanges->back().m_EndEmitLocation.CaptureLocation(emit);
+
+ // No m_EndEmitLocation has to be Valid
+ noway_assert(m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
+}
+
+//------------------------------------------------------------------------
+// UpdateLiveRangeAtEmitter: Report this variable as changing its variable
+// home to "varLocation" since the instruction where "emit" is located.
+//
+// Arguments:
+// varLocation - the new variable location.
+// emit - an emitter* instance located at the first instruction from
+// where "varLocation" becomes valid.
+//
+// Assumptions:
+// This variable is being born so it should be dead.
+//
+// Notes:
+// The position of "emit" matters to ensure intervals inclusive of the
+// beginning and exclusive of the end.
+//
+void VariableLiveKeeper::VariableLiveDescriptor::updateLiveRangeAtEmitter(CodeGenInterface::siVarLoc varLocation,
+ emitter* emit) const
+{
+ // This variable is changing home so it has been started before during this block
+ noway_assert(m_VariableLiveRanges != nullptr && !m_VariableLiveRanges->empty());
+
+ // And its last m_EndEmitLocation has to be invalid
+ noway_assert(!m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
+
+ // If we are reporting again the same home, that means we are doing something twice?
+ // noway_assert(! CodeGenInterface::siVarLoc::Equals(&m_VariableLiveRanges->back().m_VarLocation, varLocation));
+
+ // Close previous live range
+ endLiveRangeAtEmitter(emit);
+
+ startLiveRangeFromEmitter(varLocation, emit);
+}
+
+#ifdef DEBUG
+void VariableLiveKeeper::VariableLiveDescriptor::dumpAllRegisterLiveRangesForBlock(
+ emitter* emit, const CodeGenInterface* codeGen) const
+{
+ printf("[");
+ for (LiveRangeListIterator it = m_VariableLiveRanges->begin(); it != m_VariableLiveRanges->end(); it++)
+ {
+ it->dumpVariableLiveRange(emit, codeGen);
+ }
+ printf("]\n");
+}
+
+void VariableLiveKeeper::VariableLiveDescriptor::dumpRegisterLiveRangesForBlockBeforeCodeGenerated(
+ const CodeGenInterface* codeGen) const
+{
+ noway_assert(codeGen != nullptr);
+
+ printf("[");
+ for (LiveRangeListIterator it = m_VariableLifeBarrier->getStartForDump(); it != m_VariableLiveRanges->end(); it++)
+ {
+ it->dumpVariableLiveRange(codeGen);
+ }
+ printf("]\n");
+}
+
+// Returns true if a live range for this variable has been recorded
+bool VariableLiveKeeper::VariableLiveDescriptor::hasVarLiveRangesToDump() const
+{
+ return !m_VariableLiveRanges->empty();
+}
+
+// Returns true if a live range for this variable has been recorded from last call to EndBlock
+bool VariableLiveKeeper::VariableLiveDescriptor::hasVarLiverRangesFromLastBlockToDump() const
+{
+ return m_VariableLifeBarrier->hasLiveRangesToDump();
+}
+
+// Reset the barrier so as to dump only next block changes on next block
+void VariableLiveKeeper::VariableLiveDescriptor::endBlockLiveRanges()
+{
+ // make "m_VariableLifeBarrier->m_StartingLiveRange" now points to nullptr for printing purposes
+ m_VariableLifeBarrier->resetDumper(m_VariableLiveRanges);
+}
+#endif // DEBUG
+
+//------------------------------------------------------------------------
+// VariableLiveKeeper
+//------------------------------------------------------------------------
+// Initialize structures for VariableLiveRanges
+void Compiler::initializeVariableLiveKeeper()
+{
+ CompAllocator allocator = getAllocator(CMK_VariableLiveRanges);
+
+ int amountTrackedVariables = opts.compDbgInfo ? info.compLocalsCount : 0;
+ int amountTrackedArgs = opts.compDbgInfo ? info.compArgsCount : 0;
+
+ varLiveKeeper = new (allocator) VariableLiveKeeper(amountTrackedVariables, amountTrackedArgs, this, allocator);
+}
+
+VariableLiveKeeper* Compiler::getVariableLiveKeeper() const
+{
+ return varLiveKeeper;
+};
+
+//------------------------------------------------------------------------
+// VariableLiveKeeper: Create an instance of the object in charge of managing
+// VariableLiveRanges and intialize the array "m_vlrLiveDsc".
+//
+// Arguments:
+// totalLocalCount - the count of args, special args and IL Local
+// variables in the method.
+// argsCount - the count of args and special args in the method.
+// compiler - a compiler instance
+//
+VariableLiveKeeper::VariableLiveKeeper(unsigned int totalLocalCount,
+ unsigned int argsCount,
+ Compiler* comp,
+ CompAllocator allocator)
+ : m_LiveDscCount(totalLocalCount)
+ , m_LiveArgsCount(argsCount)
+ , m_Compiler(comp)
+ , m_LastBasicBlockHasBeenEmited(false)
+{
+ if (m_LiveDscCount > 0)
+ {
+ // Allocate memory for "m_vlrLiveDsc" and initialize each "VariableLiveDescriptor"
+ m_vlrLiveDsc = allocator.allocate<VariableLiveDescriptor>(m_LiveDscCount);
+
+ for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
+ {
+ new (m_vlrLiveDsc + varNum, jitstd::placement_t()) VariableLiveDescriptor(allocator);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// siStartOrCloseVariableLiveRange: Reports the given variable as beign born
+// or becoming dead.
+//
+// Arguments:
+// varDsc - the variable for which a location changed will be reported
+// varNum - the index of the variable in the "compiler->lvaTable"
+// isBorn - whether the variable is being born from where the emitter is located.
+// isDying - whether the variable is dying from where the emitter is located.
+//
+// Assumptions:
+// The emitter should be located on the first instruction from where is true that
+// the variable becoming valid (when isBorn is true) or invalid (when isDying is true).
+//
+// Notes:
+// This method is being called from treeLifeUpdater when the variable is being born,
+// becoming dead, or both.
+//
+void VariableLiveKeeper::siStartOrCloseVariableLiveRange(const LclVarDsc* varDsc,
+ unsigned int varNum,
+ bool isBorn,
+ bool isDying)
+{
+ noway_assert(varDsc != nullptr);
+
+ // Only the variables that exists in the IL, "this", and special arguments
+ // are reported.
+ if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount)
+ {
+ if (isBorn && !isDying)
+ {
+ // "varDsc" is valid from this point
+ siStartVariableLiveRange(varDsc, varNum);
+ }
+ if (isDying && !isBorn)
+ {
+ // this variable live range is no longer valid from this point
+ siEndVariableLiveRange(varNum);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// siStartOrCloseVariableLiveRanges: Iterates the given set of variables
+// calling "siStartOrCloseVariableLiveRange" with each one.
+//
+// Arguments:
+// varsIndexSet - the set of variables to report start/end "VariableLiveRange"
+// isBorn - whether the set is being born from where the emitter is located.
+// isDying - whether the set is dying from where the emitter is located.
+//
+// Assumptions:
+// The emitter should be located on the first instruction from where is true that
+// the variable becoming valid (when isBorn is true) or invalid (when isDying is true).
+//
+// Notes:
+// This method is being called from treeLifeUpdater when a set of variables
+// is being born, becoming dead, or both.
+//
+void VariableLiveKeeper::siStartOrCloseVariableLiveRanges(VARSET_VALARG_TP varsIndexSet, bool isBorn, bool isDying)
+{
+ if (m_Compiler->opts.compDbgInfo)
+ {
+ VarSetOps::Iter iter(m_Compiler, varsIndexSet);
+ unsigned varIndex = 0;
+ while (iter.NextElem(&varIndex))
+ {
+ unsigned int varNum = m_Compiler->lvaTrackedToVarNum[varIndex];
+ const LclVarDsc* varDsc = m_Compiler->lvaGetDesc(varNum);
+ siStartOrCloseVariableLiveRange(varDsc, varNum, isBorn, isDying);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// siStartVariableLiveRange: Reports the given variable as being born.
+//
+// Arguments:
+// varDsc - the variable for which a location changed will be reported
+// varNum - the index of the variable to report home in lvLiveDsc
+//
+// Assumptions:
+// The emitter should be pointing to the first instruction from where the VariableLiveRange is
+// becoming valid.
+// The given "varDsc" should have its VariableRangeLists initialized.
+//
+// Notes:
+// This method should be called on every place a Variable is becoming alive.
+void VariableLiveKeeper::siStartVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum)
+{
+ noway_assert(varDsc != nullptr);
+
+ // Only the variables that exists in the IL, "this", and special arguments
+ // are reported.
+ if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount)
+ {
+ // Build siVarLoc for this born "varDsc"
+ CodeGenInterface::siVarLoc varLocation =
+ m_Compiler->codeGen->getSiVarLoc(varDsc, m_Compiler->codeGen->getCurrentStackLevel());
+
+ VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum];
+ // this variable live range is valid from this point
+ varLiveDsc->startLiveRangeFromEmitter(varLocation, m_Compiler->getEmitter());
+ }
+}
+
+//------------------------------------------------------------------------
+// siEndVariableLiveRange: Reports the variable as becoming dead.
+//
+// Arguments:
+// varNum - the index of the variable at m_vlrLiveDsc or lvaTable in that
+// is becoming dead.
+//
+// Assumptions:
+// The given variable should be alive.
+// The emitter should be pointing to the first instruction from where the VariableLiveRange is
+// becoming invalid.
+//
+// Notes:
+// This method should be called on every place a Variable is becoming dead.
+void VariableLiveKeeper::siEndVariableLiveRange(unsigned int varNum)
+{
+ // Only the variables that exists in the IL, "this", and special arguments
+ // will be reported.
+
+ // This method is being called from genUpdateLife, and that one is called after
+ // code for BasicBlock have been generated, but the emitter has no longer
+ // a valid IG so we don't report the close of a "VariableLiveRange" after code is
+ // emitted.
+
+ if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount && !m_LastBasicBlockHasBeenEmited)
+ {
+ // this variable live range is no longer valid from this point
+ m_vlrLiveDsc[varNum].endLiveRangeAtEmitter(m_Compiler->getEmitter());
+ }
+}
+
+//------------------------------------------------------------------------
+// siUpdateVariableLiveRange: Reports the change of variable location for the
+// given variable.
+//
+// Arguments:
+// varDsc - the variable for which tis home has changed.
+// varNum - the index of the variable to report home in lvLiveDsc
+//
+// Assumptions:
+// The given variable should be alive.
+// The emitter should be pointing to the first instruction from where
+// the new variable location is becoming valid.
+//
+void VariableLiveKeeper::siUpdateVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum)
+{
+ noway_assert(varDsc != nullptr);
+
+ // Only the variables that exists in the IL, "this", and special arguments
+ // will be reported. This are locals and arguments, and are counted in
+ // "info.compLocalsCount".
+
+ // This method is being called when the prolog is being generated, and
+ // the emitter has no longer a valid IG so we don't report the close of
+ // a "VariableLiveRange" after code is emitted.
+ if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount && !m_LastBasicBlockHasBeenEmited)
+ {
+ // Build the location of the variable
+ CodeGenInterface::siVarLoc siVarLoc =
+ m_Compiler->codeGen->getSiVarLoc(varDsc, m_Compiler->codeGen->getCurrentStackLevel());
+
+ // Report the home change for this variable
+ VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum];
+ varLiveDsc->updateLiveRangeAtEmitter(siVarLoc, m_Compiler->getEmitter());
+ }
+}
+
+//------------------------------------------------------------------------
+// siEndAllVariableLiveRange: Reports the set of variables as becoming dead.
+//
+// Arguments:
+// newLife - the set of variables that are becoming dead.
+//
+// Assumptions:
+// All the variables in the set are alive.
+//
+// Notes:
+// This method is called when the last block being generated to killed all
+// the live variables and set a flag to avoid reporting variable locations for
+// on next calls to method that update variable liveness.
+void VariableLiveKeeper::siEndAllVariableLiveRange(VARSET_VALARG_TP varsToClose)
+{
+ if (m_Compiler->opts.compDbgInfo)
+ {
+ if (m_Compiler->lvaTrackedCount > 0 || !m_Compiler->opts.OptimizationDisabled())
+ {
+ VarSetOps::Iter iter(m_Compiler, varsToClose);
+ unsigned varIndex = 0;
+ while (iter.NextElem(&varIndex))
+ {
+ unsigned int varNum = m_Compiler->lvaTrackedToVarNum[varIndex];
+ siEndVariableLiveRange(varNum);
+ }
+ }
+ else
+ {
+ // It seems we are jitting debug code, so we don't have variable
+ // liveness info
+ siEndAllVariableLiveRange();
+ }
+ }
+
+ m_LastBasicBlockHasBeenEmited = true;
+}
+
+//------------------------------------------------------------------------
+// siEndAllVariableLiveRange: Reports all live variables as dead.
+//
+// Notes:
+// This overload exists for the case we are jitting code compiled in
+// debug mode. When that happen we don't have variable liveness info
+// as "BaiscBlock::bbLiveIn" or "BaiscBlock::bbLiveOut" and there is no
+// tracked variable.
+//
+void VariableLiveKeeper::siEndAllVariableLiveRange()
+{
+ // TODO: we can improve this keeping a set for the variables with
+ // open VariableLiveRanges
+
+ for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
+ {
+ const VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
+ if (varLiveDsc->hasVariableLiveRangeOpen())
+ {
+ siEndVariableLiveRange(varNum);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// getLiveRangesForVar: Return the "VariableLiveRange" that correspond to
+// the given "varNum".
+//
+// Arguments:
+// varNum - the index of the variable in m_vlrLiveDsc, which is the same as
+// in lvaTable.
+//
+// Return Value:
+// A const pointer to the list of variable locations reported for the variable.
+//
+// Assumtions:
+// This variable should be an argument, a special argument or an IL local
+// variable.
+VariableLiveKeeper::LiveRangeList* VariableLiveKeeper::getLiveRangesForVar(unsigned int varNum) const
+{
+ // There should be at least one variable for which its liveness is tracked
+ noway_assert(varNum < m_LiveDscCount);
+
+ return m_vlrLiveDsc[varNum].getLiveRanges();
+}
+
+//------------------------------------------------------------------------
+// getLiveRangesCount: Returns the count of variable locations reported for the tracked
+// variables, which are arguments, special arguments, and local IL variables.
+//
+// Return Value:
+// size_t - the count of variable locations
+//
+// Notes:
+// This method is being called from "genSetScopeInfo" to know the count of
+// "varResultInfo" that should be created on eeSetLVcount.
+//
+size_t VariableLiveKeeper::getLiveRangesCount() const
+{
+ size_t liveRangesCount = 0;
+
+ if (m_Compiler->opts.compDbgInfo)
+ {
+ for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
+ {
+ VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
+
+ if (m_Compiler->compMap2ILvarNum(varNum) != (unsigned int)ICorDebugInfo::UNKNOWN_ILNUM)
+ {
+ liveRangesCount += varLiveDsc->getLiveRanges()->size();
+ }
+ }
+ }
+ return liveRangesCount;
+}
+
+//------------------------------------------------------------------------
+// psiStartVariableLiveRange: Reports the given variable as being born.
+//
+// Arguments:
+// varLcation - the variable location
+// varNum - the index of the variable in "compiler->lvaTable" or
+// "VariableLivekeeper->m_vlrLiveDsc"
+//
+// Notes:
+// This function is expected to be called from "psiBegProlog" during
+// prolog code generation.
+//
+void VariableLiveKeeper::psiStartVariableLiveRange(CodeGenInterface::siVarLoc varLocation, unsigned int varNum)
+{
+ // This descriptor has to correspond to a parameter. The first slots in lvaTable
+ // are arguments and special arguments.
+ noway_assert(varNum < m_LiveArgsCount);
+
+ VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum];
+ varLiveDsc->startLiveRangeFromEmitter(varLocation, m_Compiler->getEmitter());
+}
+
+//------------------------------------------------------------------------
+// psiClosePrologVariableRanges: Report all the parameters as becoming dead.
+//
+// Notes:
+// This function is expected to be called from preffix "psiEndProlog" after
+// code for prolog has been generated.
+//
+void VariableLiveKeeper::psiClosePrologVariableRanges()
+{
+ noway_assert(m_LiveArgsCount <= m_LiveDscCount);
+
+ for (unsigned int varNum = 0; varNum < m_LiveArgsCount; varNum++)
+ {
+ VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
+
+ if (varLiveDsc->hasVariableLiveRangeOpen())
+ {
+ varLiveDsc->endLiveRangeAtEmitter(m_Compiler->getEmitter());
+ }
+ }
+}
+
+#ifdef DEBUG
+void VariableLiveKeeper::dumpBlockVariableLiveRanges(const BasicBlock* block)
+{
+ // "block" will be dereferenced
+ noway_assert(block != nullptr);
+
+ bool hasDumpedHistory = false;
+
+ if (m_Compiler->verbose)
+ {
+ printf("////////////////////////////////////////\n");
+ printf("////////////////////////////////////////\n");
+ printf("Variable Live Range History Dump for Block %d \n", block->bbNum);
+
+ if (m_Compiler->opts.compDbgInfo)
+ {
+ for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
+ {
+ VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
+
+ if (varLiveDsc->hasVarLiverRangesFromLastBlockToDump())
+ {
+ hasDumpedHistory = true;
+ printf("IL Var Num %d:\n", m_Compiler->compMap2ILvarNum(varNum));
+ varLiveDsc->dumpRegisterLiveRangesForBlockBeforeCodeGenerated(m_Compiler->codeGen);
+ varLiveDsc->endBlockLiveRanges();
+ }
+ }
+ }
+
+ if (!hasDumpedHistory)
+ {
+ printf("..None..\n");
+ }
+
+ printf("////////////////////////////////////////\n");
+ printf("////////////////////////////////////////\n");
+ printf("End Generating code for Block %d \n", block->bbNum);
+ }
+}
+
+void VariableLiveKeeper::dumpLvaVariableLiveRanges() const
+{
+ bool hasDumpedHistory = false;
+
+ if (m_Compiler->verbose)
+ {
+ printf("////////////////////////////////////////\n");
+ printf("////////////////////////////////////////\n");
+ printf("PRINTING VARIABLE LIVE RANGES:\n");
+
+ if (m_Compiler->opts.compDbgInfo)
+ {
+ for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
+ {
+ VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
+
+ if (varLiveDsc->hasVarLiveRangesToDump())
+ {
+ hasDumpedHistory = true;
+ printf("IL Var Num %d:\n", m_Compiler->compMap2ILvarNum(varNum));
+ varLiveDsc->dumpAllRegisterLiveRangesForBlock(m_Compiler->getEmitter(), m_Compiler->codeGen);
+ }
+ }
+ }
+
+ if (!hasDumpedHistory)
+ {
+ printf("..None..\n");
+ }
+
+ printf("////////////////////////////////////////\n");
+ printf("////////////////////////////////////////\n");
+ }
+}
+#endif // DEBUG
+#endif // USING_VARIABLE_LIVE_RANGE