Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3229,7 +3229,7 @@ void CodeGen::genSpillOrAddRegisterParam(
}

LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum);
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->IsLiveInOutOfHandler()))
{
LclVarDsc* paramVarDsc = m_compiler->lvaGetDesc(paramLclNum);

Expand Down Expand Up @@ -3291,7 +3291,7 @@ void CodeGen::genSpillOrAddRegisterParam(
void CodeGen::genSpillOrAddNonStandardRegisterParam(unsigned lclNum, regNumber sourceReg, RegGraph* graph)
{
LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum);
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->IsLiveInOutOfHandler()))
{
GetEmitter()->emitIns_S_R(ins_Store(varDsc->TypeGet()), emitActualTypeSize(varDsc), sourceReg, lclNum, 0);
}
Expand Down Expand Up @@ -3779,7 +3779,7 @@ void CodeGen::genCheckUseBlockInit()
{
if (!varDsc->lvRegister)
{
if (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr)
if (!varDsc->lvIsInReg() || varDsc->IsLiveInOutOfHandler())
{
// Var is on the stack at entry.
initStkLclCnt +=
Expand Down Expand Up @@ -4075,7 +4075,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg,
// Locals that are (only) in registers to begin with do not need
// their stack home zeroed. Their register will be zeroed later in
// the prolog.
if (varDsc->lvIsInReg() && !varDsc->lvLiveInOutOfHndlr)
if (varDsc->lvIsInReg() && !varDsc->IsLiveInOutOfHandler())
{
continue;
}
Expand Down Expand Up @@ -5176,7 +5176,7 @@ void CodeGen::genFnProlog()
}

bool isInReg = varDsc->lvIsInReg();
bool isInMemory = !isInReg || varDsc->lvLiveInOutOfHndlr;
bool isInMemory = !isInReg || varDsc->IsLiveInOutOfHandler();

// Note that 'lvIsInReg()' will only be accurate for variables that are actually live-in to
// the first block. This will include all possibly-uninitialized locals, whose liveness
Expand All @@ -5186,7 +5186,7 @@ void CodeGen::genFnProlog()
// occupying it on entry.
if (isInReg)
{
if (m_compiler->lvaEnregEHVars && varDsc->lvLiveInOutOfHndlr)
if (m_compiler->lvaEnregEHVars && varDsc->IsLiveInOutOfHandler())
{
isInReg = VarSetOps::IsMember(m_compiler, m_compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex);
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ void CodeGen::genHomeRegisterParamsOutsideProlog()
return;
}

if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->IsLiveInOutOfHandler()))
{
LclVarDsc* paramVarDsc = m_compiler->lvaGetDesc(paramLclNum);
var_types storeType = genParamStackType(paramVarDsc, segment);
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10707,11 +10707,9 @@ void Compiler::EnregisterStats::RecordLocal(const LclVarDsc* varDsc)
m_longParamField++;
break;
#endif
#ifdef JIT32_GCENCODER
case DoNotEnregisterReason::PinningRef:
m_PinningRef++;
break;
Comment on lines 10710 to 10712
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JIT32 GC encoder does not support enregistering pinned locals, while the other GC encoder does. However, we never track pinned locals and hence they are never register candidates anyway. To simplify things I removed the ifdef and started always marking these DNER.

Comment on lines 10707 to 10712
#endif
case DoNotEnregisterReason::LclAddrNode:
m_lclAddrNode++;
break;
Expand Down Expand Up @@ -10867,9 +10865,7 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const
#if !defined(TARGET_64BIT)
PRINT_STATS(m_longParamField, notEnreg);
#endif // !TARGET_64BIT
#ifdef JIT32_GCENCODER
PRINT_STATS(m_PinningRef, notEnreg);
#endif // JIT32_GCENCODER
PRINT_STATS(m_lclAddrNode, notEnreg);
PRINT_STATS(m_castTakesAddr, notEnreg);
PRINT_STATS(m_storeBlkSrc, notEnreg);
Expand Down
22 changes: 14 additions & 8 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,7 @@ enum class DoNotEnregisterReason
#if !defined(TARGET_64BIT)
LongParamField, // It is a decomposed field of a long parameter.
#endif
#ifdef JIT32_GCENCODER
PinningRef,
#endif
LclAddrNode, // the local is accessed with LCL_ADDR_VAR/FLD.
CastTakesAddr,
StoreBlkSrc, // the local is used as STORE_BLK source.
Expand Down Expand Up @@ -513,6 +511,9 @@ enum class AddressExposedReason

class LclVarDsc
{
template <typename TLiveness>
friend class Liveness;

public:
// note this only packs because var_types is a typedef of unsigned char
var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
Expand Down Expand Up @@ -542,12 +543,11 @@ class LclVarDsc
bool m_addrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
// global location, etc.
// We cannot reason reliably about the value of the variable.
unsigned char lvLiveInOutOfHandler : 1; // The variable is live in or out of an exception handler.
public:
unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
// struct promotion.
unsigned char lvLiveInOutOfHndlr : 1; // The variable is live in or out of an exception handler, and therefore must
// be on the stack (at least at those boundaries.)

unsigned char lvInSsa : 1; // The variable is in SSA form (set by SsaBuilder)
unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
Expand Down Expand Up @@ -1157,14 +1157,20 @@ class LclVarDsc
return IsEnregisterableType();
}

bool IsLiveInOutOfHandler() const
{
assert(lvTracked);
return lvLiveInOutOfHandler != 0;
}

//-----------------------------------------------------------------------------
// IsAlwaysAliveInMemory: Determines if this variable's value is always
// up-to-date on stack. This is possible if this is an EH-var or
// we decided to spill after single-def.
//
bool IsAlwaysAliveInMemory() const
{
return lvLiveInOutOfHndlr || lvSpillAtSingleDef;
return IsLiveInOutOfHandler() || lvSpillAtSingleDef;
}

bool CanBeReplacedWithItsField(Compiler* comp) const;
Expand Down Expand Up @@ -3870,6 +3876,8 @@ class Compiler
bool gtGetIndNodeCost(GenTreeIndir* node, int* pCostEx, int* pCostSz);
bool gtGetAddrNodeCost(GenTree* addr, var_types type, bool isVolatile, int* pCostEx, int* pCostSz);

bool IsEHVarARegCandidate(LclVarDsc* varDsc);

// Returns true iff the secondNode can be swapped with firstNode.
bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);

Expand Down Expand Up @@ -4183,10 +4191,10 @@ class Compiler
bool lvaVarAddrExposed(unsigned varNum) const;
void lvaSetVarAddrExposed(unsigned varNum DEBUGARG(AddressExposedReason reason));
void lvaSetHiddenBufferStructArg(unsigned varNum);
void lvaSetVarLiveInOutOfHandler(unsigned varNum);
bool lvaVarDoNotEnregister(unsigned varNum);

void lvSetMinOptsDoNotEnreg();
void lvSetEHVarsDoNotEnreg();

bool lvaEnregEHVars;
bool lvaEnregMultiRegVars;
Expand Down Expand Up @@ -11978,9 +11986,7 @@ class Compiler
unsigned m_depField;
unsigned m_noRegVars;
unsigned m_wasmGcVisibility;
#ifdef JIT32_GCENCODER
unsigned m_PinningRef;
#endif // JIT32_GCENCODER
#if !defined(TARGET_64BIT)
unsigned m_longParamField;
#endif // !TARGET_64BIT
Expand Down
8 changes: 5 additions & 3 deletions src/coreclr/jit/copyprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,12 @@ bool Compiler::optCopyProp(
continue;
}

// It may not be profitable to propagate a 'doNotEnregister' lclVar to an existing use of an
// enregisterable lclVar.
// It may not be profitable to propagate a local if that changes its expected enregister status.
LclVarDsc* const newLclVarDsc = lvaGetDesc(newLclNum);
if (varDsc->lvDoNotEnregister != newLclVarDsc->lvDoNotEnregister)
bool enregOld = !varDsc->lvDoNotEnregister && (!varDsc->IsLiveInOutOfHandler() || IsEHVarARegCandidate(varDsc));
bool enregNew = !newLclVarDsc->lvDoNotEnregister &&
(!newLclVarDsc->IsLiveInOutOfHandler() || IsEHVarARegCandidate(newLclVarDsc));
if (enregOld != enregNew)
{
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/earlyprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ bool Compiler::optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry, bool
if (tree->OperIs(GT_STORE_LCL_VAR))
{
LclVarDsc* varDsc = lvaGetDesc(tree->AsLclVar());
result = varDsc->lvTracked && !varDsc->lvLiveInOutOfHndlr;
result = varDsc->lvTracked && !varDsc->IsLiveInOutOfHandler();
}
}
else
Expand Down
18 changes: 17 additions & 1 deletion src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5000,7 +5000,7 @@ bool Compiler::gtIsLikelyRegVar(GenTree* tree)

// If this is an EH-live var, return false if it is a def,
// as it will have to go to memory.
if (varDsc->lvTracked && varDsc->lvLiveInOutOfHndlr && ((tree->gtFlags & GTF_VAR_DEF) != 0))
if (varDsc->lvTracked && varDsc->IsLiveInOutOfHandler() && ((tree->gtFlags & GTF_VAR_DEF) != 0))
{
return false;
}
Expand Down Expand Up @@ -5029,6 +5029,22 @@ bool Compiler::gtIsLikelyRegVar(GenTree* tree)
return true;
}

//------------------------------------------------------------------------
// IsEHVarARegCandidate:
// Check if a local is a candidate to go in a register even though it is live
// into EH.
//
// Arguments:
// varDsc - Info about the local
//
// Returns:
// True if so.
//
bool Compiler::IsEHVarARegCandidate(LclVarDsc* varDsc)
{
return lvaEnregEHVars && varDsc->lvSingleDefRegCandidate && varDsc->lvRefCnt() > 1;
}

//------------------------------------------------------------------------
// gtGetLclVarNodeCost: Calculate the cost for a local variable node.
//
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/gschecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,6 @@ bool Compiler::gsCreateShadowingLocals()
shadowVarDsc->SetAddressExposed(varDsc->IsAddressExposed() DEBUGARG(varDsc->GetAddrExposedReason()));
shadowVarDsc->lvDoNotEnregister = varDsc->lvDoNotEnregister;
shadowVarDsc->lvSingleDefRegCandidate = varDsc->lvSingleDefRegCandidate;
// The old variable will not be used in handlers anymore, allow it to stay enregistered
varDsc->lvLiveInOutOfHndlr = false;
#ifdef DEBUG
Comment thread
jakobbotsch marked this conversation as resolved.
shadowVarDsc->SetDoNotEnregReason(varDsc->GetDoNotEnregReason());
shadowVarDsc->SetDefinedViaAddress(varDsc->IsDefinedViaAddress());
Expand Down
16 changes: 7 additions & 9 deletions src/coreclr/jit/inductionvariableopts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,10 +470,9 @@ bool Compiler::optCanSinkWidenedIV(unsigned lclNum, FlowGraphNaturalLoop* loop)

#ifdef DEBUG
// We currently do not expect to ever widen IVs that are live into
// exceptional exits. Such IVs are expected to have been marked DNER
// previously (EH write-thru is only for single def locals) which makes it
// unprofitable. If this ever changes we need some more expansive handling
// here.
// exceptional exits. Such IVs are not currently register candidates (EH
// write-thru is only for single def locals) which makes it unprofitable.
// If this ever changes we need some more expansive handling here.
loop->VisitLoopBlocks([=](BasicBlock* block) {
block->VisitAllSuccs(this, [=](BasicBlock* succ) {
if (!loop->ContainsBlock(succ) && bbIsHandlerBeg(succ))
Expand Down Expand Up @@ -895,12 +894,11 @@ bool Compiler::optWidenPrimaryIV(FlowGraphNaturalLoop* loop, unsigned lclNum, Sc
return false;
}

// If the IV is not enregisterable then uses/defs are going to go
// to stack regardless. This check also filters out IVs that may be
// live into exceptional exits since those are always marked DNER.
if (lclDsc->lvDoNotEnregister)
// If the IV is not enregisterable, or if it lives into a handler, then
// uses/defs are going to go to stack regardless.
if (lclDsc->lvDoNotEnregister || lclDsc->IsLiveInOutOfHandler())
{
JITDUMP(" V%02u is marked DNER\n", lclNum);
JITDUMP(" V%02u is marked DNER or lives into a handler\n", lclNum);
return false;
}

Expand Down
Loading
Loading