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: Factor reachability sets and base them on new DFS #96892

Merged
merged 1 commit into from
Jan 12, 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
7 changes: 1 addition & 6 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,10 +398,7 @@ enum BasicBlockFlags : unsigned __int64
BBF_LOOP_ALIGN = MAKE_BBFLAG(16), // Block is lexically the first block in a loop we intend to align.
BBF_HAS_ALIGN = MAKE_BBFLAG(17), // BB ends with 'align' instruction
BBF_HAS_JMP = MAKE_BBFLAG(18), // BB executes a JMP instruction (instead of return)
BBF_GC_SAFE_POINT = MAKE_BBFLAG(19), // BB has a GC safe point (a call). More abstractly, BB does not require a
// (further) poll -- this may be because this BB has a call, or, in some
// cases, because the BB occurs in a loop, and we've determined that all
// paths in the loop body leading to BB include a call.
BBF_GC_SAFE_POINT = MAKE_BBFLAG(19), // BB has a GC safe point (e.g. a call)
BBF_HAS_IDX_LEN = MAKE_BBFLAG(20), // BB contains simple index or length expressions on an SD array local var.
BBF_HAS_MD_IDX_LEN = MAKE_BBFLAG(21), // BB contains simple index, length, or lower bound expressions on an MD array local var.
BBF_HAS_MDARRAYREF = MAKE_BBFLAG(22), // Block has a multi-dimensional array reference
Expand Down Expand Up @@ -1296,8 +1293,6 @@ struct BasicBlock : private LIR::Range
void ensurePredListOrder(Compiler* compiler);
void reorderPredList(Compiler* compiler);

BlockSet bbReach; // Set of all blocks that can reach this one

union {
BasicBlock* bbIDom; // Represent the closest dominator to this block (called the Immediate
// Dominator) used to compute the dominance tree.
Expand Down
19 changes: 9 additions & 10 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,6 @@ Histogram domsChangedIterationTable(domsChangedIterationBuckets);
unsigned computeReachabilitySetsIterationBuckets[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0};
Histogram computeReachabilitySetsIterationTable(computeReachabilitySetsIterationBuckets);

unsigned computeReachabilityIterationBuckets[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0};
Histogram computeReachabilityIterationTable(computeReachabilityIterationBuckets);

#endif // COUNT_BASIC_BLOCKS

/*****************************************************************************
Expand Down Expand Up @@ -1577,12 +1574,6 @@ void Compiler::compShutdown()
computeReachabilitySetsIterationTable.dump(jitstdout());
jitprintf("--------------------------------------------------\n");

jitprintf("--------------------------------------------------\n");
jitprintf("fgComputeReachability `while (change)` iterations:\n");
jitprintf("--------------------------------------------------\n");
computeReachabilityIterationTable.dump(jitstdout());
jitprintf("--------------------------------------------------\n");

#endif // COUNT_BASIC_BLOCKS

#if COUNT_LOOPS
Expand Down Expand Up @@ -5854,6 +5845,7 @@ void Compiler::RecomputeFlowGraphAnnotations()
optSetBlockWeights();
optFindLoops();

fgInvalidateDfsTree();
m_dfsTree = fgComputeDfs();
optFindNewLoops();

Expand Down Expand Up @@ -9650,7 +9642,14 @@ JITDBGAPI void __cdecl cReach(Compiler* comp)
{
static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
printf("===================================================================== *Reach %u\n", sequenceNumber++);
comp->fgDispReach();
if (comp->m_reachabilitySets != nullptr)
{
comp->m_reachabilitySets->Dump();
}
else
{
printf(" Not computed\n");
}
}

JITDBGAPI void __cdecl cDoms(Compiler* comp)
Expand Down
51 changes: 27 additions & 24 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -1570,10 +1570,8 @@ enum API_ICorJitInfo_Names

enum class FlowGraphUpdates
{
COMPUTE_BASICS = 0, // renumber blocks, reachability, etc
COMPUTE_DOMS = 1 << 0, // recompute dominators
COMPUTE_RETURNS = 1 << 1, // recompute return blocks
COMPUTE_LOOPS = 1 << 2, // recompute loop table
COMPUTE_BASICS = 0, // renumber blocks, reachability, etc
COMPUTE_DOMS = 1 << 0, // recompute dominators
};

inline constexpr FlowGraphUpdates operator|(FlowGraphUpdates a, FlowGraphUpdates b)
Expand Down Expand Up @@ -2392,6 +2390,30 @@ class BlockToNaturalLoopMap
static BlockToNaturalLoopMap* Build(FlowGraphNaturalLoops* loops);
};

// Represents a data structure that can answer A -> B reachability queries in
// O(1) time. Only takes regular flow into account; if A -> B requires
// exceptional flow, then CanReach returns false.
class BlockReachabilitySets
{
FlowGraphDfsTree* m_dfsTree;
BitVec* m_reachabilitySets;

BlockReachabilitySets(FlowGraphDfsTree* dfsTree, BitVec* reachabilitySets)
: m_dfsTree(dfsTree)
, m_reachabilitySets(reachabilitySets)
{
}

public:
bool CanReach(BasicBlock* from, BasicBlock* to);

#ifdef DEBUG
void Dump();
#endif

static BlockReachabilitySets* Build(FlowGraphDfsTree* dfsTree);
};

enum class FieldKindForVN
{
SimpleStatic,
Expand Down Expand Up @@ -4988,6 +5010,7 @@ class Compiler
// Dominator tree used by SSA construction and copy propagation (the two are expected to use the same tree
// in order to avoid the need for SSA reconstruction and an "out of SSA" phase).
FlowGraphDominatorTree* m_domTree;
BlockReachabilitySets* m_reachabilitySets;

// After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
// dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
Expand Down Expand Up @@ -5045,10 +5068,6 @@ class Compiler
roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);

#ifdef DEBUG
// All BlockSet objects are now invalid!
fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!

if (verbose)
{
unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this);
Expand Down Expand Up @@ -5128,14 +5147,6 @@ class Compiler

bool fgHasSwitch; // any BBJ_SWITCH jumps?

BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
// begin blocks.

#ifdef DEBUG
bool fgReachabilitySetsValid; // Are the bbReach sets valid?
bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
#endif // DEBUG

bool fgRemoveRestOfBlock; // true if we know that we will throw
bool fgStmtRemoved; // true if we remove statements -> need new DFA

Expand Down Expand Up @@ -5782,21 +5793,15 @@ class Compiler
// Dominator computation member functions
// Not exposed outside Compiler
protected:
bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2

// Compute immediate dominators, the dominator tree and and its pre/post-order travsersal numbers.
void fgComputeDoms();

BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
// Note: this is relatively slow compared to calling fgDominate(),
// especially if dealing with a single block versus block check.

void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)

void fgComputeReturnBlocks(); // Initialize fgReturnBlocks to a list of BBJ_RETURN blocks.

void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.

// Remove blocks determined to be unreachable by the 'canRemoveBlock'.
template <typename CanRemoveBlockBody>
bool fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock);
Expand Down Expand Up @@ -6120,7 +6125,6 @@ class Compiler
#ifdef DEBUG

void fgDispDoms();
void fgDispReach();
void fgDispBBLiveness(BasicBlock* block);
void fgDispBBLiveness();
void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
Expand Down Expand Up @@ -12302,7 +12306,6 @@ extern Histogram bbCntTable;
extern Histogram bbOneBBSizeTable;
extern Histogram domsChangedIterationTable;
extern Histogram computeReachabilitySetsIterationTable;
extern Histogram computeReachabilityIterationTable;
#endif

/*****************************************************************************
Expand Down
21 changes: 6 additions & 15 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ void Compiler::fgInit()
fgDomsComputed = false;
fgReturnBlocksComputed = false;

#ifdef DEBUG
fgReachabilitySetsValid = false;
#endif // DEBUG

/* Initialize the basic block list */

fgFirstBB = nullptr;
Expand Down Expand Up @@ -66,10 +62,12 @@ void Compiler::fgInit()
fgBBVarSetsInited = false;
fgReturnCount = 0;

m_dfsTree = nullptr;
m_loops = nullptr;
m_loopSideEffects = nullptr;
m_blockToLoop = nullptr;
m_dfsTree = nullptr;
m_loops = nullptr;
m_loopSideEffects = nullptr;
m_blockToLoop = nullptr;
m_domTree = nullptr;
m_reachabilitySets = nullptr;

// Initialize BlockSet data.
fgCurBBEpoch = 0;
Expand Down Expand Up @@ -118,15 +116,8 @@ void Compiler::fgInit()
/* We will record a list of all BBJ_RETURN blocks here */
fgReturnBlocks = nullptr;

/* This is set by fgComputeReachability */
fgEnterBlks = BlockSetOps::UninitVal();

fgUsedSharedTemps = nullptr;

#ifdef DEBUG
fgEnterBlksSetValid = false;
#endif // DEBUG

#if !defined(FEATURE_EH_FUNCLETS)
ehMaxHndNestingCount = 0;
#endif // !FEATURE_EH_FUNCLETS
Expand Down
19 changes: 0 additions & 19 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1860,25 +1860,6 @@ void Compiler::fgDumpFlowGraphLoops(FILE* file)
/*****************************************************************************/
#ifdef DEBUG

void Compiler::fgDispReach()
{
printf("------------------------------------------------\n");
printf("BBnum Reachable by \n");
printf("------------------------------------------------\n");

for (BasicBlock* const block : Blocks())
{
printf(FMT_BB " : ", block->bbNum);
BlockSetOps::Iter iter(this, block->bbReach);
unsigned bbNum = 0;
while (iter.NextElem(&bbNum))
{
printf(FMT_BB " ", bbNum);
}
printf("\n");
}
}

void Compiler::fgDispDoms()
{
// Don't bother printing this when we have a large number of BasicBlocks in the method
Expand Down
Loading
Loading