Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Clean up liveness #103809

Merged
merged 8 commits into from
Jun 25, 2024
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
4 changes: 0 additions & 4 deletions src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,6 @@ void BasicBlock::CloneBlockState(Compiler* compiler, BasicBlock* to, const Basic
to->bbStkDepth = from->bbStkDepth;
to->bbCodeOffs = from->bbCodeOffs;
to->bbCodeOffsEnd = from->bbCodeOffsEnd;
VarSetOps::AssignAllowUninitRhs(compiler, to->bbScope, from->bbScope);
#ifdef DEBUG
to->bbTgtStkDepth = from->bbTgtStkDepth;
#endif // DEBUG
Expand Down Expand Up @@ -1470,7 +1469,6 @@ void BasicBlock::InitVarSets(Compiler* comp)
VarSetOps::AssignNoCopy(comp, bbVarDef, VarSetOps::MakeEmpty(comp));
VarSetOps::AssignNoCopy(comp, bbLiveIn, VarSetOps::MakeEmpty(comp));
VarSetOps::AssignNoCopy(comp, bbLiveOut, VarSetOps::MakeEmpty(comp));
VarSetOps::AssignNoCopy(comp, bbScope, VarSetOps::MakeEmpty(comp));

bbMemoryUse = emptyMemoryKindSet;
bbMemoryDef = emptyMemoryKindSet;
Expand Down Expand Up @@ -1672,15 +1670,13 @@ BasicBlock* BasicBlock::New(Compiler* compiler)
VarSetOps::AssignNoCopy(compiler, block->bbVarDef, VarSetOps::MakeEmpty(compiler));
VarSetOps::AssignNoCopy(compiler, block->bbLiveIn, VarSetOps::MakeEmpty(compiler));
VarSetOps::AssignNoCopy(compiler, block->bbLiveOut, VarSetOps::MakeEmpty(compiler));
VarSetOps::AssignNoCopy(compiler, block->bbScope, VarSetOps::MakeEmpty(compiler));
}
else
{
VarSetOps::AssignNoCopy(compiler, block->bbVarUse, VarSetOps::UninitVal());
VarSetOps::AssignNoCopy(compiler, block->bbVarDef, VarSetOps::UninitVal());
VarSetOps::AssignNoCopy(compiler, block->bbLiveIn, VarSetOps::UninitVal());
VarSetOps::AssignNoCopy(compiler, block->bbLiveOut, VarSetOps::UninitVal());
VarSetOps::AssignNoCopy(compiler, block->bbScope, VarSetOps::UninitVal());
}

block->bbMemoryUse = emptyMemoryKindSet;
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -1611,8 +1611,6 @@ struct BasicBlock : private LIR::Range
unsigned bbMemorySsaNumIn[MemoryKindCount]; // The SSA # of memory on entry to the block.
unsigned bbMemorySsaNumOut[MemoryKindCount]; // The SSA # of memory on exit from the block.

VARSET_TP bbScope; // variables in scope over the block

void InitVarSets(class Compiler* comp);

/* The following are the standard bit sets for dataflow analysis.
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 @@ -10923,9 +10923,6 @@ void Compiler::EnregisterStats::RecordLocal(const LclVarDsc* varDsc)
case DoNotEnregisterReason::NoRegVars:
m_noRegVars++;
break;
case DoNotEnregisterReason::MinOptsGC:
m_minOptsGC++;
break;
#if !defined(TARGET_64BIT)
case DoNotEnregisterReason::LongParamField:
m_longParamField++;
Expand Down Expand Up @@ -11080,7 +11077,6 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const
PRINT_STATS(m_structArg, notEnreg);
PRINT_STATS(m_depField, notEnreg);
PRINT_STATS(m_noRegVars, notEnreg);
PRINT_STATS(m_minOptsGC, notEnreg);
#if !defined(TARGET_64BIT)
PRINT_STATS(m_longParamField, notEnreg);
#endif // !TARGET_64BIT
Expand Down
23 changes: 3 additions & 20 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,6 @@ enum class DoNotEnregisterReason
IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
DepField, // It is a field of a dependently promoted struct
NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
MinOptsGC, // It is a GC Ref and we are compiling MinOpts
#if !defined(TARGET_64BIT)
LongParamField, // It is a decomposed field of a long parameter.
#endif
Expand Down Expand Up @@ -5525,7 +5524,7 @@ class Compiler

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

void fgLiveVarAnalysis(bool updateInternalOnly = false);
void fgLiveVarAnalysis();

void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);

Expand All @@ -5545,10 +5544,10 @@ class Compiler
void fgComputeLife(VARSET_TP& life,
GenTree* startNode,
GenTree* endNode,
VARSET_VALARG_TP volatileVars,
VARSET_VALARG_TP keepAliveVars,
bool* pStmtInfoDirty DEBUGARG(bool* treeModf));

void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP keepAliveVars);

bool fgTryRemoveNonLocal(GenTree* node, LIR::Range* blockRange);

Expand Down Expand Up @@ -5916,8 +5915,6 @@ class Compiler

PhaseStatus fgComputeDominators(); // Compute dominators

bool fgRemoveDeadBlocks(); // Identify and remove dead blocks.

public:
enum GCPollType
{
Expand Down Expand Up @@ -6678,19 +6675,6 @@ class Compiler

void fgMarkUseDef(GenTreeLclVarCommon* tree);

void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);

void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);

void fgExtendDbgScopes();
void fgExtendDbgLifetimes();

#ifdef DEBUG
void fgDispDebugScopes();
#endif // DEBUG

//-------------------------------------------------------------------------
//
// The following keeps track of any code we've added for things like array
Expand Down Expand Up @@ -10887,7 +10871,6 @@ class Compiler
unsigned m_liveInOutHndlr;
unsigned m_depField;
unsigned m_noRegVars;
unsigned m_minOptsGC;
#ifdef JIT32_GCENCODER
unsigned m_PinningRef;
#endif // JIT32_GCENCODER
Expand Down
105 changes: 0 additions & 105 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,111 +162,6 @@ bool Compiler::fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock)
return changed;
}

//------------------------------------------------------------------------
// fgRemoveDeadBlocks: Identify all the unreachable blocks and remove them.
//
bool Compiler::fgRemoveDeadBlocks()
{
JITDUMP("\n*************** In fgRemoveDeadBlocks()");

unsigned prevFgCurBBEpoch = fgCurBBEpoch;
EnsureBasicBlockEpoch();

BlockSet visitedBlocks(BlockSetOps::MakeEmpty(this));

jitstd::list<BasicBlock*> worklist(jitstd::allocator<void>(getAllocator(CMK_Reachability)));
worklist.push_back(fgFirstBB);

// Visit all the reachable blocks, everything else can be removed
while (!worklist.empty())
{
BasicBlock* block = *(worklist.begin());
worklist.pop_front();

if (BlockSetOps::IsMember(this, visitedBlocks, block->bbNum))
{
continue;
}

BlockSetOps::AddElemD(this, visitedBlocks, block->bbNum);

for (BasicBlock* succ : block->Succs(this))
{
worklist.push_back(succ);
}

// Add all the "EH" successors. For every `try`, add its handler (including filter) to the worklist.
if (bbIsTryBeg(block))
{
// Due to EH normalization, a block can only be the start of a single `try` region, with the exception
// of mutually-protect regions.
assert(block->hasTryIndex());
unsigned tryIndex = block->getTryIndex();
EHblkDsc* ehDsc = ehGetDsc(tryIndex);
for (;;)
{
worklist.push_back(ehDsc->ebdHndBeg);
if (ehDsc->HasFilter())
{
worklist.push_back(ehDsc->ebdFilter);
}
tryIndex = ehDsc->ebdEnclosingTryIndex;
if (tryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
{
break;
}
ehDsc = ehGetDsc(tryIndex);
if (ehDsc->ebdTryBeg != block)
{
break;
}
}
}
}

// Track if there is any unreachable block. Even if it is marked with
// BBF_DONT_REMOVE, fgRemoveUnreachableBlocks() still removes the code
// inside the block. So this variable tracks if we ever found such blocks
// or not.
bool hasUnreachableBlock = false;

auto isBlockRemovable = [&](BasicBlock* block) -> bool {
const bool isVisited = BlockSetOps::IsMember(this, visitedBlocks, block->bbNum);
const bool isRemovable = !isVisited || (block->bbRefs == 0);

hasUnreachableBlock |= isRemovable;
return isRemovable;
};

bool changed = false;
unsigned iterationCount = 1;
do
{
JITDUMP("\nRemoving unreachable blocks for fgRemoveDeadBlocks iteration #%u\n", iterationCount);

// Just to be paranoid, avoid infinite loops; fall back to minopts.
if (iterationCount++ > 10)
{
noway_assert(!"Too many unreachable block removal loops");
}
changed = fgRemoveUnreachableBlocks(isBlockRemovable);
} while (changed);

#ifdef DEBUG
if (verbose && hasUnreachableBlock)
{
printf("\nAfter dead block removal:\n");
fgDispBasicBlocks(verboseTrees);
printf("\n");
}

fgVerifyHandlerTab();
fgDebugCheckBBlist(false);
#endif // DEBUG

return hasUnreachableBlock;
}

//-------------------------------------------------------------
// fgComputeDominators: Compute dominators
//
Expand Down
10 changes: 7 additions & 3 deletions src/coreclr/jit/gcencode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4053,9 +4053,13 @@ void GCInfo::gcMakeRegPtrTable(
{
GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);

const bool noTrackedGCSlots =
(compiler->opts.MinOpts() && !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) &&
!JitConfig.JitMinOptsTrackGCrefs());
// TODO: Decide on whether we should enable this optimization for all
// targets: https://github.com/dotnet/runtime/issues/103917
#ifdef TARGET_XARCH
const bool noTrackedGCSlots = compiler->opts.MinOpts() && !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT);
#else
const bool noTrackedGCSlots = false;
#endif

if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS)
{
Expand Down
8 changes: 0 additions & 8 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,14 +521,6 @@ RELEASE_CONFIG_INTEGER(JitEnableNoWayAssert, W("JitEnableNoWayAssert"), 0)
RELEASE_CONFIG_INTEGER(JitEnableNoWayAssert, W("JitEnableNoWayAssert"), 1)
#endif // !defined(DEBUG) && !defined(_DEBUG)

// Track GC roots
#if defined(TARGET_AMD64) || defined(TARGET_X86)
#define JitMinOptsTrackGCrefs_Default 0 // Not tracking GC refs in MinOpts is new behavior
#else
#define JitMinOptsTrackGCrefs_Default 1
#endif
RELEASE_CONFIG_INTEGER(JitMinOptsTrackGCrefs, W("JitMinOptsTrackGCrefs"), JitMinOptsTrackGCrefs_Default)

// The following should be wrapped inside "#if MEASURE_MEM_ALLOC / #endif", but
// some files include this one without bringing in the definitions from "jit.h"
// so we don't always know what the "true" value of that flag should be. For now
Expand Down
9 changes: 0 additions & 9 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3212,10 +3212,6 @@ void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregister
JITDUMP("opts.compFlags & CLFLG_REGVAR is not set\n");
assert(!compEnregLocals());
break;
case DoNotEnregisterReason::MinOptsGC:
JITDUMP("it is a GC Ref and we are compiling MinOpts\n");
assert(!JitConfig.JitMinOptsTrackGCrefs() && varTypeIsGC(varDsc->TypeGet()));
break;
#if !defined(TARGET_64BIT)
case DoNotEnregisterReason::LongParamField:
JITDUMP("it is a decomposed field of a long parameter\n");
Expand Down Expand Up @@ -4147,11 +4143,6 @@ void Compiler::lvaSortByRefCount()
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::PinningRef));
#endif
}
if (opts.MinOpts() && !JitConfig.JitMinOptsTrackGCrefs() && varTypeIsGC(varDsc->TypeGet()))
{
varDsc->lvTracked = 0;
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::MinOptsGC));
}
if (!compEnregLocals())
{
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::NoRegVars));
Expand Down
Loading
Loading