diff options
Diffstat (limited to 'src/jit/compiler.cpp')
-rw-r--r-- | src/jit/compiler.cpp | 760 |
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 |