Skip to content
Merged
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
3 changes: 3 additions & 0 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,9 @@ struct BasicBlock : private LIR::Range
template <typename TFunc>
BasicBlockVisit VisitAllSuccs(Compiler* comp, TFunc func);

template <typename TFunc>
BasicBlockVisit VisitRegularSuccs(Compiler* comp, TFunc func);

bool HasPotentialEHSuccs(Compiler* comp);

// BBSuccList: adapter class for forward iteration of block successors, using range-based `for`,
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4908,7 +4908,7 @@ class Compiler
void fgPerNodeLocalVarLiveness(GenTreeHWIntrinsic* hwintrinsic);
#endif // FEATURE_HW_INTRINSICS

void fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveVars);
void fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveVars, MemoryKindSet& memoryLiveness);

void fgLiveVarAnalysis(bool updateInternalOnly = false);

Expand Down
89 changes: 89 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,95 @@ BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func)
return BasicBlockVisit::Continue;
}

//------------------------------------------------------------------------------
// VisitRegularSuccs: Visit regular successors of this block.
//
// Arguments:
// comp - Compiler instance
// func - Callback
//
// Returns:
// Whether or not the visiting was aborted.
//
template <typename TFunc>
BasicBlockVisit BasicBlock::VisitRegularSuccs(Compiler* comp, TFunc func)
{
switch (bbJumpKind)
{
case BBJ_EHFILTERRET:
RETURN_ON_ABORT(func(bbJumpDest));
break;

case BBJ_EHFINALLYRET:
{
EHblkDsc* ehDsc = comp->ehGetDsc(getHndIndex());
assert(ehDsc->HasFinallyHandler());

BasicBlock* begBlk;
BasicBlock* endBlk;
comp->ehGetCallFinallyBlockRange(getHndIndex(), &begBlk, &endBlk);

BasicBlock* finBeg = ehDsc->ebdHndBeg;

for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
{
if ((bcall->bbJumpKind != BBJ_CALLFINALLY) || (bcall->bbJumpDest != finBeg))
{
continue;
}

assert(bcall->isBBCallAlwaysPair());

RETURN_ON_ABORT(func(bcall->bbNext));
}

break;
}

case BBJ_CALLFINALLY:
case BBJ_EHCATCHRET:
case BBJ_LEAVE:
case BBJ_ALWAYS:
RETURN_ON_ABORT(func(bbJumpDest));
break;

case BBJ_NONE:
RETURN_ON_ABORT(func(bbNext));
break;

case BBJ_COND:
RETURN_ON_ABORT(func(bbNext));

if (bbJumpDest != bbNext)
{
RETURN_ON_ABORT(func(bbJumpDest));
}

break;

case BBJ_SWITCH:
{
Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
for (unsigned i = 0; i < sd.numDistinctSuccs; i++)
{
RETURN_ON_ABORT(func(sd.nonDuplicates[i]));
}

break;
}

case BBJ_THROW:
case BBJ_RETURN:
case BBJ_EHFAULTRET:
break;

default:
unreached();
}

return BasicBlockVisit::Continue;
}

#undef RETURN_ON_ABORT

//------------------------------------------------------------------------------
Expand Down
31 changes: 20 additions & 11 deletions src/coreclr/jit/liveness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ void Compiler::fgExtendDbgLifetimes()
// block - the block in question
// ehHandlerLiveVars - On entry, contains an allocated VARSET_TP that the
// function will add handler live vars into.
// memoryLiveness - Set of memory liveness that will be added to.
//
// Notes:
// Assumes caller has screened candidate blocks to only those with
Expand Down Expand Up @@ -1073,7 +1074,7 @@ void Compiler::fgExtendDbgLifetimes()
// Console.WriteLine("In catch 1");
// }
//
void Compiler::fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveVars)
void Compiler::fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveVars, MemoryKindSet& memoryLiveness)
{
assert(block->HasPotentialEHSuccs(this));

Expand All @@ -1087,6 +1088,7 @@ void Compiler::fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveV
if (HBtab->HasFilter())
{
VarSetOps::UnionD(this, ehHandlerLiveVars, HBtab->ebdFilter->bbLiveIn);
memoryLiveness |= HBtab->ebdFilter->bbMemoryLiveIn;
#if defined(FEATURE_EH_FUNCLETS)
// The EH subsystem can trigger a stack walk after the filter
// has returned, but before invoking the handler, and the only
Expand All @@ -1095,11 +1097,13 @@ void Compiler::fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveV
// must report as live any variables live-out of the filter
// (which is the same as those live-in to the handler)
VarSetOps::UnionD(this, ehHandlerLiveVars, HBtab->ebdHndBeg->bbLiveIn);
memoryLiveness |= HBtab->ebdHndBeg->bbMemoryLiveIn;
#endif // FEATURE_EH_FUNCLETS
}
else
{
VarSetOps::UnionD(this, ehHandlerLiveVars, HBtab->ebdHndBeg->bbLiveIn);
memoryLiveness |= HBtab->ebdHndBeg->bbMemoryLiveIn;
}

/* If we have nested try's edbEnclosing will provide them */
Expand All @@ -1118,8 +1122,9 @@ void Compiler::fgAddHandlerLiveVars(BasicBlock* block, VARSET_TP& ehHandlerLiveV

if (bbInFilterBBRange(block))
{
block->VisitEHSecondPassSuccs(this, [this, &ehHandlerLiveVars](BasicBlock* succ) {
block->VisitEHSecondPassSuccs(this, [this, &ehHandlerLiveVars, &memoryLiveness](BasicBlock* succ) {
VarSetOps::UnionD(this, ehHandlerLiveVars, succ->bbLiveIn);
memoryLiveness |= succ->bbMemoryLiveIn;
return BasicBlockVisit::Continue;
});
}
Expand Down Expand Up @@ -1190,8 +1195,11 @@ class LiveVarAnalysis
}
}

// Additionally, union in all the live-in tracked vars of successors.
block->VisitAllSuccs(m_compiler, [=](BasicBlock* succ) {
// Additionally, union in all the live-in tracked vars of regular
// successors. EH successors need to be handled more conservatively
// (their live-in state is live in this entire basic block). Those are
// handled below.
block->VisitRegularSuccs(m_compiler, [=](BasicBlock* succ) {
VarSetOps::UnionD(m_compiler, m_liveOut, succ->bbLiveIn);
m_memoryLiveOut |= succ->bbMemoryLiveIn;
if (succ->bbNum <= block->bbNum)
Expand All @@ -1214,16 +1222,12 @@ class LiveVarAnalysis
/* Compute the 'm_liveIn' set */
VarSetOps::LivenessD(m_compiler, m_liveIn, block->bbVarDef, block->bbVarUse, m_liveOut);

// Even if block->bbMemoryDef is set, we must assume that it doesn't kill memory liveness from m_memoryLiveOut,
// since (without proof otherwise) the use and def may touch different memory at run-time.
m_memoryLiveIn = m_memoryLiveOut | block->bbMemoryUse;

// Does this block have implicit exception flow to a filter or handler?
// If so, include the effects of that flow.
if (block->HasPotentialEHSuccs(m_compiler))
{
VarSetOps::ClearD(m_compiler, m_ehHandlerLiveVars);
m_compiler->fgAddHandlerLiveVars(block, m_ehHandlerLiveVars);
m_compiler->fgAddHandlerLiveVars(block, m_ehHandlerLiveVars, m_memoryLiveOut);
VarSetOps::UnionD(m_compiler, m_liveIn, m_ehHandlerLiveVars);
VarSetOps::UnionD(m_compiler, m_liveOut, m_ehHandlerLiveVars);

Expand All @@ -1232,7 +1236,11 @@ class LiveVarAnalysis
m_hasPossibleBackEdge = true;
}

/* Has there been any change in either live set? */
// Even if block->bbMemoryDef is set, we must assume that it doesn't kill memory liveness from m_memoryLiveOut,
// since (without proof otherwise) the use and def may touch different memory at run-time.
m_memoryLiveIn = m_memoryLiveOut | block->bbMemoryUse;

// Has there been any change in either live set?

bool liveInChanged = !VarSetOps::Equal(m_compiler, block->bbLiveIn, m_liveIn);
if (liveInChanged || !VarSetOps::Equal(m_compiler, block->bbLiveOut, m_liveOut))
Expand Down Expand Up @@ -2525,7 +2533,8 @@ void Compiler::fgInterBlockLocalVarLiveness()

if (block->HasPotentialEHSuccs(this))
{
fgAddHandlerLiveVars(block, volatileVars);
MemoryKindSet memoryLiveness = 0;
fgAddHandlerLiveVars(block, volatileVars, memoryLiveness);

// volatileVars is a subset of exceptVars
noway_assert(VarSetOps::IsSubset(this, volatileVars, exceptVars));
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/jit/lsra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2400,8 +2400,9 @@ void LinearScan::checkLastUses(BasicBlock* block)
// We may have exception vars in the liveIn set of exception blocks that are not computed live.
if (block->HasPotentialEHSuccs(compiler))
{
VARSET_TP ehHandlerLiveVars(VarSetOps::MakeEmpty(compiler));
compiler->fgAddHandlerLiveVars(block, ehHandlerLiveVars);
VARSET_TP ehHandlerLiveVars(VarSetOps::MakeEmpty(compiler));
MemoryKindSet memoryLiveness = emptyMemoryKindSet;
compiler->fgAddHandlerLiveVars(block, ehHandlerLiveVars, memoryLiveness);
VarSetOps::DiffD(compiler, liveInNotComputedLive, ehHandlerLiveVars);
}
VarSetOps::Iter liveInNotComputedLiveIter(compiler, liveInNotComputedLive);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/promotionliveness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ bool PromotionLiveness::PerBlockLiveness(BasicBlock* block)

BasicBlockLiveness& bbInfo = m_bbInfo[block->bbNum];
BitVecOps::ClearD(m_bvTraits, bbInfo.LiveOut);
block->VisitAllSuccs(m_compiler, [=, &bbInfo](BasicBlock* succ) {
block->VisitRegularSuccs(m_compiler, [=, &bbInfo](BasicBlock* succ) {
BitVecOps::UnionD(m_bvTraits, bbInfo.LiveOut, m_bbInfo[succ->bbNum].LiveIn);
m_hasPossibleBackEdge |= succ->bbNum <= block->bbNum;
return BasicBlockVisit::Continue;
Expand Down