From 55bf122104efdc24c7198f804e2ff46bc4386387 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Sat, 27 May 2023 21:57:01 +0200 Subject: [PATCH 1/2] JIT: Clean up BB successor iteration * Remove old code * Use visitor with an array as part of AllSuccessorEnumerator --- src/coreclr/jit/block.cpp | 91 +++----------- src/coreclr/jit/block.h | 224 +++------------------------------ src/coreclr/jit/compiler.hpp | 111 +++++----------- src/coreclr/jit/ssabuilder.cpp | 7 +- 4 files changed, 71 insertions(+), 362 deletions(-) diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index 7c57df63822c7..252c8317f4fa7 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -68,89 +68,32 @@ unsigned SsaStressHashHelper() } #endif -EHSuccessorIterPosition::EHSuccessorIterPosition(Compiler* comp, BasicBlock* block) - : m_remainingRegSuccs(block->NumSucc(comp)) - , m_numRegSuccs(m_remainingRegSuccs) - , m_curRegSucc(nullptr) - , m_curTry(comp->ehGetBlockExnFlowDsc(block)) +AllSuccessorEnumerator::AllSuccessorEnumerator(Compiler* comp, BasicBlock* block) : m_block(block) { - // If "block" is a "leave helper" block (the empty BBJ_ALWAYS block that pairs with a - // preceding BBJ_CALLFINALLY block to implement a "leave" IL instruction), then no exceptions - // can occur within it, so clear m_curTry if it's non-null. - if (m_curTry != nullptr) - { - if (block->isBBCallAlwaysPairTail()) + m_numSuccs = 0; + block->VisitAllSuccs(comp, [this](BasicBlock* succ) { + if (m_numSuccs < ArrLen(m_successors)) { - m_curTry = nullptr; + m_successors[m_numSuccs] = succ; } - } - - if (m_curTry == nullptr && m_remainingRegSuccs > 0) - { - // Examine the successors to see if any are the start of try blocks. - FindNextRegSuccTry(comp, block); - } -} - -void EHSuccessorIterPosition::FindNextRegSuccTry(Compiler* comp, BasicBlock* block) -{ - assert(m_curTry == nullptr); - - // Must now consider the next regular successor, if any. - while (m_remainingRegSuccs > 0) - { - m_curRegSucc = block->GetSucc(m_numRegSuccs - m_remainingRegSuccs, comp); - m_remainingRegSuccs--; - if (comp->bbIsTryBeg(m_curRegSucc)) - { - assert(m_curRegSucc->hasTryIndex()); // Since it is a try begin. - unsigned newTryIndex = m_curRegSucc->getTryIndex(); - - // If the try region started by "m_curRegSucc" (represented by newTryIndex) contains m_block, - // we've already yielded its handler, as one of the EH handler successors of m_block itself. - if (comp->bbInExnFlowRegions(newTryIndex, block)) - { - continue; - } - // Otherwise, consider this try. - m_curTry = comp->ehGetDsc(newTryIndex); - break; - } - } -} + m_numSuccs++; + return BasicBlockVisit::Continue; + }); -void EHSuccessorIterPosition::Advance(Compiler* comp, BasicBlock* block) -{ - assert(m_curTry != nullptr); - if (m_curTry->ebdEnclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX) + if (m_numSuccs > ArrLen(m_successors)) { - m_curTry = comp->ehGetDsc(m_curTry->ebdEnclosingTryIndex); + m_pSuccessors = new (comp, CMK_BasicBlock) BasicBlock*[m_numSuccs]; - // If we've gone over into considering try's containing successors, - // then the enclosing try must have the successor as its first block. - if (m_curRegSucc == nullptr || m_curTry->ebdTryBeg == m_curRegSucc) - { - return; - } + unsigned numSuccs = 0; + block->VisitAllSuccs(comp, [this, &numSuccs](BasicBlock* succ) { + assert(numSuccs < m_numSuccs); + m_pSuccessors[numSuccs++] = succ; + return BasicBlockVisit::Continue; + }); - // Otherwise, give up, try the next regular successor. - m_curTry = nullptr; + assert(numSuccs == m_numSuccs); } - else - { - m_curTry = nullptr; - } - - // We've exhausted all try blocks. - // See if there are any remaining regular successors that start try blocks. - FindNextRegSuccTry(comp, block); -} - -BasicBlock* EHSuccessorIterPosition::Current(Compiler* comp, BasicBlock* block) -{ - assert(m_curTry != nullptr); - return m_curTry->ExFlowBlock(); } FlowEdge* Compiler::BlockPredsWithEH(BasicBlock* blk) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 425c5d9d5a892..2cf6c1518c8d3 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -199,133 +199,6 @@ struct allMemoryKinds } }; -// This encapsulates the "exception handling" successors of a block. That is, -// if a basic block BB1 occurs in a try block, we consider the first basic block -// BB2 of the corresponding handler to be an "EH successor" of BB1. Because we -// make the conservative assumption that control flow can jump from a try block -// to its handler at any time, the immediate (regular control flow) -// predecessor(s) of the first block of a try block are also considered to -// have the first block of the handler as an EH successor. This makes variables that -// are "live-in" to the handler become "live-out" for these try-predecessor block, -// so that they become live-in to the try -- which we require. -// -// This class maintains the minimum amount of state necessary to implement -// successor iteration. The basic block whose successors are enumerated and -// the compiler need to be provided by Advance/Current's callers. In addition -// to iterators, this allows the use of other approaches that are more space -// efficient. -class EHSuccessorIterPosition -{ - // The number of "regular" (i.e., non-exceptional) successors that remain to - // be considered. If BB1 has successor BB2, and BB2 is the first block of a - // try block, then we consider the catch block of BB2's try to be an EH - // successor of BB1. This captures the iteration over the successors of BB1 - // for this purpose. (In reverse order; we're done when this field is 0). - unsigned m_remainingRegSuccs; - unsigned m_numRegSuccs; - - // The current "regular" successor of "m_block" that we're considering. - BasicBlock* m_curRegSucc; - - // The current try block. If non-null, then the current successor "m_curRegSucc" - // is the first block of the handler of this block. While this try block has - // enclosing try's that also start with "m_curRegSucc", the corresponding handlers will be - // further EH successors. - EHblkDsc* m_curTry; - - // Requires that "m_curTry" is NULL. Determines whether there is, as - // discussed just above, a regular successor that's the first block of a - // try; if so, sets "m_curTry" to that try block. (As noted above, selecting - // the try containing the current regular successor as the "current try" may cause - // multiple first-blocks of catches to be yielded as EH successors: trys enclosing - // the current try are also included if they also start with the current EH successor.) - void FindNextRegSuccTry(Compiler* comp, BasicBlock* block); - -public: - // Constructs a position that "points" to the first EH successor of `block`. - EHSuccessorIterPosition(Compiler* comp, BasicBlock* block); - - // Constructs a position that "points" past the last EH successor of `block` ("end" position). - EHSuccessorIterPosition() : m_remainingRegSuccs(0), m_numRegSuccs(0), m_curTry(nullptr) - { - } - - // Go on to the next EH successor. - void Advance(Compiler* comp, BasicBlock* block); - - // Returns the current EH successor. - // Requires that "*this" is not equal to the "end" position. - BasicBlock* Current(Compiler* comp, BasicBlock* block); - - // Returns "true" iff "*this" is equal to "ehsi". - bool operator==(const EHSuccessorIterPosition& ehsi) - { - return m_curTry == ehsi.m_curTry && m_remainingRegSuccs == ehsi.m_remainingRegSuccs; - } - - bool operator!=(const EHSuccessorIterPosition& ehsi) - { - return !((*this) == ehsi); - } -}; - -// Yields both normal and EH successors (in that order) in one iteration. -// -// This class maintains the minimum amount of state necessary to implement -// successor iteration. The basic block whose successors are enumerated and -// the compiler need to be provided by Advance/Current's callers. In addition -// to iterators, this allows the use of other approaches that are more space -// efficient. -class AllSuccessorIterPosition -{ - // Normal successor position - unsigned m_numNormSuccs; - unsigned m_remainingNormSucc; - // EH successor position - EHSuccessorIterPosition m_ehIter; - - // True iff m_blk is a BBJ_CALLFINALLY block, and the current try block of m_ehIter, - // the first block of whose handler would be next yielded, is the jump target of m_blk. - inline bool CurTryIsBlkCallFinallyTarget(Compiler* comp, BasicBlock* block); - -public: - // Constructs a position that "points" to the first successor of `block`. - inline AllSuccessorIterPosition(Compiler* comp, BasicBlock* block); - - // Constructs a position that "points" past the last successor of `block` ("end" position). - AllSuccessorIterPosition() : m_remainingNormSucc(0), m_ehIter() - { - } - - // Go on to the next successor. - inline void Advance(Compiler* comp, BasicBlock* block); - - // Returns the current successor. - // Requires that "*this" is not equal to the "end" position. - inline BasicBlock* Current(Compiler* comp, BasicBlock* block); - - bool IsCurrentEH() - { - return m_remainingNormSucc == 0; - } - - bool HasCurrent() - { - return *this != AllSuccessorIterPosition(); - } - - // Returns "true" iff "*this" is equal to "asi". - bool operator==(const AllSuccessorIterPosition& asi) - { - return (m_remainingNormSucc == asi.m_remainingNormSucc) && (m_ehIter == asi.m_ehIter); - } - - bool operator!=(const AllSuccessorIterPosition& asi) - { - return !((*this) == asi); - } -}; - // PredEdgeList: adapter class for forward iteration of the predecessor edge linked list using range-based `for`, // normally used via BasicBlock::PredEdges(), e.g.: // for (FlowEdge* const edge : block->PredEdges()) ... @@ -1347,16 +1220,6 @@ struct BasicBlock : private LIR::Range } }; - Successors GetEHSuccs(Compiler* comp) - { - return Successors(comp, this); - } - - Successors GetAllSuccs(Compiler* comp) - { - return Successors(comp, this); - } - template BasicBlockVisit VisitAllSuccs(Compiler* comp, TFunc func); @@ -1988,72 +1851,25 @@ inline PredBlockList::iterator& PredBlockList::iterator::operator++() void* emitCodeGetCookie(BasicBlock* block); -AllSuccessorIterPosition::AllSuccessorIterPosition(Compiler* comp, BasicBlock* block) - : m_numNormSuccs(block->NumSucc(comp)), m_remainingNormSucc(m_numNormSuccs), m_ehIter(comp, block) -{ - if (CurTryIsBlkCallFinallyTarget(comp, block)) - { - m_ehIter.Advance(comp, block); - } -} - -bool AllSuccessorIterPosition::CurTryIsBlkCallFinallyTarget(Compiler* comp, BasicBlock* block) -{ - return (block->bbJumpKind == BBJ_CALLFINALLY) && (m_ehIter != EHSuccessorIterPosition()) && - (block->bbJumpDest == m_ehIter.Current(comp, block)); -} - -void AllSuccessorIterPosition::Advance(Compiler* comp, BasicBlock* block) -{ - if (m_remainingNormSucc > 0) - { - m_remainingNormSucc--; - } - else - { - m_ehIter.Advance(comp, block); - - // If the original block whose successors we're iterating over - // is a BBJ_CALLFINALLY, that finally clause's first block - // will be yielded as a normal successor. Don't also yield as - // an exceptional successor. - if (CurTryIsBlkCallFinallyTarget(comp, block)) - { - m_ehIter.Advance(comp, block); - } - } -} - -// Requires that "this" is not equal to the standard "end" iterator. Returns the -// current successor. -BasicBlock* AllSuccessorIterPosition::Current(Compiler* comp, BasicBlock* block) -{ - if (m_remainingNormSucc > 0) - { - return block->GetSucc(m_numNormSuccs - m_remainingNormSucc, comp); - } - else - { - return m_ehIter.Current(comp, block); - } -} - -typedef BasicBlock::Successors::iterator EHSuccessorIter; -typedef BasicBlock::Successors::iterator AllSuccessorIter; - // An enumerator of a block's all successors. In some cases (e.g. SsaBuilder::TopologicalSort) // using iterators is not exactly efficient, at least because they contain an unnecessary // member - a pointer to the Compiler object. class AllSuccessorEnumerator { - BasicBlock* m_block; - AllSuccessorIterPosition m_pos; + BasicBlock* m_block; + union { + // We store up to 4 successors inline in the enumerator. For ASP.NET + // and libraries.pmi this is enough in 99.7% of cases. + BasicBlock* m_successors[4]; + BasicBlock** m_pSuccessors; + }; + + unsigned m_numSuccs; + unsigned m_curSucc = UINT_MAX; public: // Constructs an enumerator of all `block`'s successors. - AllSuccessorEnumerator(Compiler* comp, BasicBlock* block) : m_block(block), m_pos(comp, block) - { - } + AllSuccessorEnumerator(Compiler* comp, BasicBlock* block); // Gets the block whose successors are enumerated. BasicBlock* Block() @@ -2061,23 +1877,21 @@ class AllSuccessorEnumerator return m_block; } - // Returns true if the next successor is an EH successor. - bool IsNextEHSuccessor() - { - return m_pos.IsCurrentEH(); - } - // Returns the next available successor or `nullptr` if there are no more successors. BasicBlock* NextSuccessor(Compiler* comp) { - if (!m_pos.HasCurrent()) + m_curSucc++; + if (m_curSucc >= m_numSuccs) { return nullptr; } - BasicBlock* succ = m_pos.Current(comp, m_block); - m_pos.Advance(comp, m_block); - return succ; + if (m_numSuccs <= ArrLen(m_successors)) + { + return m_successors[m_curSucc]; + } + + return m_pSuccessors[m_curSucc]; } }; diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index b22bc7c519b0c..c79c5edbeea1b 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -430,36 +430,34 @@ static BasicBlockVisit VisitSuccessorEHSuccessors(Compiler* comp, BasicBlock* bl } //------------------------------------------------------------------------------ -// VisitAllSuccsInternal: Internal helper function to visit all successors -// (including EH successors) of a block. +// VisitAllSuccs: Visit all successors (including EH successors) of this block. // // Arguments: // comp - Compiler instance -// block - The block // func - Callback // // Returns: // Whether or not the visiting was aborted. // template -static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, TFunc func) +BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func) { - switch (block->bbJumpKind) + switch (bbJumpKind) { case BBJ_EHFILTERRET: - RETURN_ON_ABORT(func(block->bbJumpDest)); - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbJumpDest, func)); + RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbJumpDest, func)); break; case BBJ_EHFINALLYRET: { - EHblkDsc* ehDsc = comp->ehGetDsc(block->getHndIndex()); + EHblkDsc* ehDsc = comp->ehGetDsc(getHndIndex()); assert(ehDsc->HasFinallyHandler()); BasicBlock* begBlk; BasicBlock* endBlk; - comp->ehGetCallFinallyBlockRange(block->getHndIndex(), &begBlk, &endBlk); + comp->ehGetCallFinallyBlockRange(getHndIndex(), &begBlk, &endBlk); BasicBlock* finBeg = ehDsc->ebdHndBeg; @@ -475,7 +473,7 @@ static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, RETURN_ON_ABORT(func(bcall->bbNext)); } - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext) { @@ -485,7 +483,7 @@ static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, } assert(bcall->isBBCallAlwaysPair()); - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, bcall->bbNext, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bcall->bbNext, func)); } break; @@ -494,61 +492,61 @@ static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, case BBJ_CALLFINALLY: case BBJ_EHCATCHRET: case BBJ_LEAVE: - RETURN_ON_ABORT(func(block->bbJumpDest)); - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbJumpDest, func)); + RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbJumpDest, func)); break; case BBJ_ALWAYS: - RETURN_ON_ABORT(func(block->bbJumpDest)); + RETURN_ON_ABORT(func(bbJumpDest)); - // If "block" is a "leave helper" block (the empty BBJ_ALWAYS block + // If this is a "leave helper" block (the empty BBJ_ALWAYS block // that pairs with a preceding BBJ_CALLFINALLY block to implement a // "leave" IL instruction), then no exceptions can occur within it // and we skip its normal EH successors. - if (!block->isBBCallAlwaysPairTail()) + if (!isBBCallAlwaysPairTail()) { - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); } - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbJumpDest, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbJumpDest, func)); break; case BBJ_NONE: - RETURN_ON_ABORT(func(block->bbNext)); - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbNext, func)); + RETURN_ON_ABORT(func(bbNext)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbNext, func)); break; case BBJ_COND: - RETURN_ON_ABORT(func(block->bbNext)); + RETURN_ON_ABORT(func(bbNext)); - if (block->bbJumpDest != block->bbNext) + if (bbJumpDest != bbNext) { - RETURN_ON_ABORT(func(block->bbJumpDest)); + RETURN_ON_ABORT(func(bbJumpDest)); } - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbNext, func)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbNext, func)); - if (block->bbJumpDest != block->bbNext) + if (bbJumpDest != bbNext) { - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, block->bbJumpDest, func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, bbJumpDest, func)); } break; case BBJ_SWITCH: { - Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(block); + Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this); for (unsigned i = 0; i < sd.numDistinctSuccs; i++) { RETURN_ON_ABORT(func(sd.nonDuplicates[i])); } - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); for (unsigned i = 0; i < sd.numDistinctSuccs; i++) { - RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, block, sd.nonDuplicates[i], func)); + RETURN_ON_ABORT(VisitSuccessorEHSuccessors(comp, this, sd.nonDuplicates[i], func)); } break; @@ -557,7 +555,7 @@ static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, case BBJ_THROW: case BBJ_RETURN: case BBJ_EHFAULTRET: - RETURN_ON_ABORT(VisitEHSuccessors(comp, block, func)); + RETURN_ON_ABORT(VisitEHSuccessors(comp, this, func)); break; default: @@ -567,51 +565,6 @@ static BasicBlockVisit VisitAllSuccsInternal(Compiler* comp, BasicBlock* block, return BasicBlockVisit::Continue; } -//------------------------------------------------------------------------------ -// VisitAllSuccs: Visit all successors (including EH successors) of this block. -// -// Arguments: -// comp - Compiler instance -// func - Callback -// -// Returns: -// Whether or not the visiting was aborted. -// -template -BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func) -{ -#ifdef DEBUG - // Compare callback-based successors with old iterator based successors. - BasicBlock* succs[64]; - unsigned index = 0; - - VisitAllSuccsInternal(comp, this, [&succs, &index](BasicBlock* succ) { - if (index < ArrLen(succs)) - { - succs[index] = succ; - } - - index++; - return BasicBlockVisit::Continue; - }); - - unsigned index2 = 0; - for (BasicBlock* succ : GetAllSuccs(comp)) - { - if (index2 < ArrLen(succs)) - { - assert(succs[index2] == succ); - } - - index2++; - } - - assert(index == index2); -#endif - - return VisitAllSuccsInternal(comp, this, func); -} - #undef RETURN_ON_ABORT #if defined(FEATURE_EH_FUNCLETS) diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index b78786a7fa7de..77586b0525af2 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -164,15 +164,14 @@ int SsaBuilder::TopologicalSort(BasicBlock** postOrder, int count) unsigned index = 0; while (true) { - bool isEHsucc = successors.IsNextEHSuccessor(); - BasicBlock* succ = successors.NextSuccessor(comp); + BasicBlock* succ = successors.NextSuccessor(comp); if (succ == nullptr) { break; } - printf("%s%s" FMT_BB, (index++ ? ", " : ""), (isEHsucc ? "[EH]" : ""), succ->bbNum); + printf("%s" FMT_BB, (index++ ? ", " : ""), succ->bbNum); } printf("]\n"); } @@ -210,7 +209,7 @@ int SsaBuilder::TopologicalSort(BasicBlock** postOrder, int count) DBG_SSA_JITDUMP("[SsaBuilder::TopologicalSort] postOrder[%d] = " FMT_BB "\n", postIndex, block->bbNum); postOrder[postIndex] = block; block->bbPostorderNum = postIndex; - postIndex += 1; + postIndex++; } } From 1f49b3b8991ff0b078f41772897823ad896bea03 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Sat, 27 May 2023 22:07:49 +0200 Subject: [PATCH 2/2] Function header --- src/coreclr/jit/block.cpp | 7 +++++++ src/coreclr/jit/ssabuilder.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index 252c8317f4fa7..5284e747092bd 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -68,6 +68,13 @@ unsigned SsaStressHashHelper() } #endif +//------------------------------------------------------------------------ +// AllSuccessorEnumerator: Construct an instance of the enumerator. +// +// Arguments: +// comp - Compiler instance +// block - The block whose successors are to be iterated +// AllSuccessorEnumerator::AllSuccessorEnumerator(Compiler* comp, BasicBlock* block) : m_block(block) { m_numSuccs = 0; diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index 77586b0525af2..774e51ee8f987 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -143,7 +143,7 @@ SsaBuilder::SsaBuilder(Compiler* pCompiler) // // Return Value: // The number of nodes visited while performing DFS on the graph. - +// int SsaBuilder::TopologicalSort(BasicBlock** postOrder, int count) { Compiler* comp = m_pCompiler;