diff --git a/src/coreclr/jit/bitset.h b/src/coreclr/jit/bitset.h index 7360eb4424ac2..0e090e5a45a79 100644 --- a/src/coreclr/jit/bitset.h +++ b/src/coreclr/jit/bitset.h @@ -228,6 +228,8 @@ class BitSetOps // Destructively modify "bs1" to be the union of "bs1" and "bs2". static void UnionD(Env env, BitSetType& bs1, BitSetValueArgType bs2); + // Destructively modify "bs1" to be the union of "bs1" and "bs2"; return `true` if `bs1` changed. + static bool UnionDChanged(Env env, BitSetType& bs1, BitSetValueArgType bs2); // Returns a new BitSet that is the union of "bs1" and "bs2". static BitSetValueRetType Union(Env env, BitSetValueArgType bs1, BitSetValueArgType bs2); @@ -374,6 +376,11 @@ class BitSetOpsWithCounter BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_UnionD); BSO::UnionD(env, bs1, bs2); } + static bool UnionDChanged(Env env, BitSetType& bs1, BitSetValueArgType bs2) + { + BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_UnionDChanged); + return BSO::UnionDChanged(env, bs1, bs2); + } static BitSetValueRetType Union(Env env, BitSetValueArgType bs1, BitSetValueArgType bs2) { BitSetTraits::GetOpCounter(env)->RecordOp(BitSetSupport::BSOP_Union); diff --git a/src/coreclr/jit/bitsetasshortlong.h b/src/coreclr/jit/bitsetasshortlong.h index 0aa33bd916ad7..5a2e315673cbe 100644 --- a/src/coreclr/jit/bitsetasshortlong.h +++ b/src/coreclr/jit/bitsetasshortlong.h @@ -39,6 +39,7 @@ class BitSetOps +bool BitSetOps::UnionDLongChanged(Env env, + BitSetShortLongRep& bs1, + BitSetShortLongRep bs2) +{ + assert(!IsShort(env)); + bool changed = false; + unsigned len = BitSetTraits::GetArrSize(env); + for (unsigned i = 0; i < len; i++) + { + size_t bsCurrent = bs1[i]; + size_t bsNew = bsCurrent | bs2[i]; + changed |= bsNew != bsCurrent; + bs1[i] = bsNew; + } + return changed; +} + template void BitSetOpsbbReach); + BasicBlock* const block = fgBBReversePostorder[i]; bool predGcSafe = (block->bbPreds != nullptr); // Do all of our predecessor blocks have a GC safe bit? for (BasicBlock* const predBlock : block->PredBlocks()) { /* Union the predecessor's reachability set into newReach */ - BlockSetOps::UnionD(this, newReach, predBlock->bbReach); + change |= BlockSetOps::UnionDChanged(this, block->bbReach, predBlock->bbReach); if (!(predBlock->bbFlags & BBF_GC_SAFE_POINT)) { @@ -276,15 +277,15 @@ void Compiler::fgComputeReachabilitySets() { block->bbFlags |= BBF_GC_SAFE_POINT; } - - if (!BlockSetOps::Equal(this, newReach, block->bbReach)) - { - BlockSetOps::Assign(this, block->bbReach, newReach); - change = true; - } } + + ++changedIterCount; } while (change); +#if COUNT_BASIC_BLOCKS + computeReachabilitySetsIterationTable.record(changedIterCount); +#endif // COUNT_BASIC_BLOCKS + #ifdef DEBUG if (verbose) { @@ -598,15 +599,11 @@ PhaseStatus Compiler::fgComputeReachability() madeChanges |= fgRenumberBlocks(); // - // Compute fgEnterBlks + // Compute fgEnterBlks, reverse post-order, and bbReach. // fgComputeEnterBlocksSet(); - - // - // Compute bbReach - // - + fgDfsReversePostorder(); fgComputeReachabilitySets(); // @@ -618,6 +615,10 @@ PhaseStatus Compiler::fgComputeReachability() } while (changed); +#if COUNT_BASIC_BLOCKS + computeReachabilityIterationTable.record(passNum - 1); +#endif // COUNT_BASIC_BLOCKS + // // Now, compute the dominators // @@ -752,19 +753,24 @@ bool Compiler::fgRemoveDeadBlocks() // preorder and reverse postorder numbers, plus a reverse postorder for blocks. // // Notes: -// Assumes caller has computed the fgEnterBlkSet. +// Assumes caller has computed the fgEnterBlks set. +// +// Each block's `bbPreorderNum` and `bbPostorderNum` is set. // -// Assumes caller has allocated the fgBBReversePostorder array. -// It will be filled in with blocks in reverse post order. +// The `fgBBReversePostorder` array is filled in with the `BasicBlock*` in reverse post-order. // // This algorithm only pays attention to the actual blocks. It ignores any imaginary entry block. // void Compiler::fgDfsReversePostorder() { + assert(fgBBcount == fgBBNumMax); + assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1); + // Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is // an incoming edge into the block). assert(fgEnterBlksSetValid); - assert(fgBBReversePostorder != nullptr); + + fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{}; // visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid // backtracking. @@ -989,13 +995,6 @@ void Compiler::fgComputeDoms() assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1); #endif // DEBUG - BlockSet processedBlks(BlockSetOps::MakeEmpty(this)); - - fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{}; - - fgDfsReversePostorder(); - noway_assert(fgBBReversePostorder[0] == nullptr); - // flRoot and bbRoot represent an imaginary unique entry point in the flow graph. // All the orphaned EH blocks and fgFirstBB will temporarily have its predecessors list // (with bbRoot as the only basic block in it) set as flRoot. @@ -1012,9 +1011,11 @@ void Compiler::fgComputeDoms() FlowEdge flRoot(&bbRoot, nullptr); + noway_assert(fgBBReversePostorder[0] == nullptr); fgBBReversePostorder[0] = &bbRoot; // Mark both bbRoot and fgFirstBB processed + BlockSet processedBlks(BlockSetOps::MakeEmpty(this)); BlockSetOps::AddElemD(this, processedBlks, 0); // bbRoot == block #0 BlockSetOps::AddElemD(this, processedBlks, 1); // fgFirstBB == block #1 assert(fgFirstBB->bbNum == 1); @@ -1057,7 +1058,8 @@ void Compiler::fgComputeDoms() } // Now proceed to compute the immediate dominators for each basic block. - bool changed = true; + bool changed = true; + unsigned changedIterCount = 1; while (changed) { changed = false; @@ -1116,8 +1118,14 @@ void Compiler::fgComputeDoms() } BlockSetOps::AddElemD(this, processedBlks, block->bbNum); } + + ++changedIterCount; } +#if COUNT_BASIC_BLOCKS + domsChangedIterationTable.record(changedIterCount); +#endif // COUNT_BASIC_BLOCKS + // As stated before, once we have computed immediate dominance we need to clear // all the basic blocks whose predecessor list was set to flRoot. This // reverts that and leaves the blocks the same as before. @@ -1311,7 +1319,7 @@ void Compiler::fgNumberDomTree(DomTreeNode* domTree) // fgIntersectDom: Intersect two immediate dominator sets. // // Find the lowest common ancestor in the dominator tree between two basic blocks. The LCA in the dominance tree -// represents the closest dominator between the two basic blocks. Used to adjust the IDom value in fgComputDoms. +// represents the closest dominator between the two basic blocks. Used to adjust the IDom value in fgComputeDoms. // // Arguments: // a, b - two blocks to intersect diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index 17f976ead7927..2bab76036d482 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -763,7 +763,6 @@ void ProfileSynthesis::RandomizeLikelihoods() void ProfileSynthesis::BuildReversePostorder() { m_comp->EnsureBasicBlockEpoch(); - m_comp->fgBBReversePostorder = new (m_comp, CMK_Pgo) BasicBlock*[m_comp->fgBBNumMax + 1]{}; m_comp->fgComputeEnterBlocksSet(); m_comp->fgDfsReversePostorder();