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

Loop refactoring and commenting improvements #61496

Merged
merged 1 commit into from
Nov 15, 2021
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
9 changes: 3 additions & 6 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4877,14 +4877,12 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
//
DoPhase(this, PHASE_COMPUTE_REACHABILITY, &Compiler::fgComputeReachability);

// Discover and classify natural loops
// (e.g. mark iterative loops as such). Also marks loop blocks
// and sets bbWeight to the loop nesting levels
// Discover and classify natural loops (e.g. mark iterative loops as such). Also marks loop blocks
// and sets bbWeight to the loop nesting levels.
//
DoPhase(this, PHASE_FIND_LOOPS, &Compiler::optFindLoops);

// Clone loops with optimization opportunities, and
// choose one based on dynamic condition evaluation.
// Clone loops with optimization opportunities, and choose one based on dynamic condition evaluation.
//
DoPhase(this, PHASE_CLONE_LOOPS, &Compiler::optCloneLoops);

Expand Down Expand Up @@ -8675,7 +8673,6 @@ void cLoop(Compiler* comp, Compiler::LoopDsc* loop)
static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
printf("===================================================================== Loop %u\n", sequenceNumber++);
printf("HEAD " FMT_BB "\n", loop->lpHead->bbNum);
printf("FIRST " FMT_BB "\n", loop->lpFirst->bbNum);
printf("TOP " FMT_BB "\n", loop->lpTop->bbNum);
printf("ENTRY " FMT_BB "\n", loop->lpEntry->bbNum);
if (loop->lpExitCnt == 1)
Expand Down
49 changes: 22 additions & 27 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6324,10 +6324,7 @@ class Compiler
GenTreeCall* fgMorphArgs(GenTreeCall* call);
GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);

void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
GenTreeCall::Use* args,
unsigned argIndex,
CORINFO_CLASS_HANDLE copyBlkClass);
void fgMakeOutgoingStructArgCopy(GenTreeCall* call, GenTreeCall::Use* args, CORINFO_CLASS_HANDLE copyBlkClass);

GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);

Expand Down Expand Up @@ -6714,18 +6711,16 @@ class Compiler
// bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
// in bbNext order; we use comparisons on the bbNum to decide order.)
// The blocks that define the body are
// first <= top <= entry <= bottom .
// top <= entry <= bottom
// The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
// single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
// Compiler::optFindNaturalLoops().
struct LoopDsc
{
BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
// loop, but not the outer loop.)
BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
// same)
BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here). Lexically first block (in bbNext
// order) reachable in this loop.
BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)

Expand Down Expand Up @@ -6826,69 +6821,68 @@ class Compiler
// Returns "true" iff "*this" contains the blk.
bool lpContains(BasicBlock* blk) const
{
return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
return lpTop->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
}
// Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
// to be equal, but requiring bottoms to be different.)
bool lpContains(BasicBlock* first, BasicBlock* bottom) const
{
return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
return lpTop->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
}

// Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
// bottoms to be different.)
bool lpContains(const LoopDsc& lp2) const
{
return lpContains(lp2.lpFirst, lp2.lpBottom);
return lpContains(lp2.lpTop, lp2.lpBottom);
}

// Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
// (allowing firsts to be equal, but requiring bottoms to be different.)
bool lpContainedBy(BasicBlock* first, BasicBlock* bottom) const
{
return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
return first->bbNum <= lpTop->bbNum && lpBottom->bbNum < bottom->bbNum;
}

// Returns "true" iff "*this" is (properly) contained by "lp2"
// (allowing firsts to be equal, but requiring bottoms to be different.)
bool lpContainedBy(const LoopDsc& lp2) const
{
return lpContains(lp2.lpFirst, lp2.lpBottom);
return lpContains(lp2.lpTop, lp2.lpBottom);
}

// Returns "true" iff "*this" is disjoint from the range [top, bottom].
bool lpDisjoint(BasicBlock* first, BasicBlock* bottom) const
{
return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
return bottom->bbNum < lpTop->bbNum || lpBottom->bbNum < first->bbNum;
}
// Returns "true" iff "*this" is disjoint from "lp2".
bool lpDisjoint(const LoopDsc& lp2) const
{
return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
return lpDisjoint(lp2.lpTop, lp2.lpBottom);
}
// Returns "true" iff the loop is well-formed (see code for defn).
bool lpWellFormed() const
{
return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
lpEntry->bbNum <= lpBottom->bbNum &&
return lpTop->bbNum <= lpEntry->bbNum && lpEntry->bbNum <= lpBottom->bbNum &&
(lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
}

// LoopBlocks: convenience method for enabling range-based `for` iteration over all the
// blocks in a loop, e.g.:
// for (BasicBlock* const block : loop->LoopBlocks()) ...
// Currently, the loop blocks are expected to be in linear, lexical, `bbNext` order
// from `lpFirst` through `lpBottom`, inclusive. All blocks in this range are considered
// from `lpTop` through `lpBottom`, inclusive. All blocks in this range are considered
// to be part of the loop.
//
BasicBlockRangeList LoopBlocks() const
{
return BasicBlockRangeList(lpFirst, lpBottom);
return BasicBlockRangeList(lpTop, lpBottom);
}
};

protected:
bool fgMightHaveLoop(); // returns true if there are any backedges
bool fgMightHaveLoop(); // returns true if there are any back edges
bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability

public:
Expand All @@ -6901,7 +6895,6 @@ class Compiler
#endif // DEBUG

bool optRecordLoop(BasicBlock* head,
BasicBlock* first,
BasicBlock* top,
BasicBlock* entry,
BasicBlock* bottom,
Expand All @@ -6917,7 +6910,6 @@ class Compiler
#ifdef DEBUG
void optPrintLoopInfo(unsigned loopNum,
BasicBlock* lpHead,
BasicBlock* lpFirst,
BasicBlock* lpTop,
BasicBlock* lpEntry,
BasicBlock* lpBottom,
Expand All @@ -6930,9 +6922,12 @@ class Compiler
void optCheckPreds();
#endif

// Determine if there are any potential loops, and set BBF_LOOP_HEAD on potential loop heads.
void optMarkLoopHeads();

void optSetBlockWeights();

void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
void optScaleLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);

void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);

Expand Down Expand Up @@ -8290,7 +8285,7 @@ class Compiler

static fgWalkPreFn CountSharedStaticHelper;
static bool IsSharedStaticHelper(GenTree* tree);
static bool IsGcSafePoint(GenTree* tree);
static bool IsGcSafePoint(GenTreeCall* call);

static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
// returns true/false if 'field' is a Jit Data offset
Expand Down
38 changes: 17 additions & 21 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3674,34 +3674,30 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree)
return result1;
}

inline bool Compiler::IsGcSafePoint(GenTree* tree)
inline bool Compiler::IsGcSafePoint(GenTreeCall* call)
{
if (tree->IsCall())
if (!call->IsFastTailCall())
{
GenTreeCall* call = tree->AsCall();
if (!call->IsFastTailCall())
if (call->IsUnmanaged() && call->IsSuppressGCTransition())
{
if (call->IsUnmanaged() && call->IsSuppressGCTransition())
{
// Both an indirect and user calls can be unmanaged
// and have a request to suppress the GC transition so
// the check is done prior to the separate handling of
// indirect and user calls.
return false;
}
else if (call->gtCallType == CT_INDIRECT)
// Both an indirect and user calls can be unmanaged
// and have a request to suppress the GC transition so
// the check is done prior to the separate handling of
// indirect and user calls.
return false;
}
else if (call->gtCallType == CT_INDIRECT)
{
return true;
}
else if (call->gtCallType == CT_USER_FUNC)
{
if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
{
return true;
}
else if (call->gtCallType == CT_USER_FUNC)
{
if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
{
return true;
}
}
// otherwise we have a CT_HELPER
}
// otherwise we have a CT_HELPER
}

return false;
Expand Down
29 changes: 17 additions & 12 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4656,17 +4656,15 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)

if (fgDomsComputed && fgReachable(succBlock, block))
{
/* Mark all the reachable blocks between 'succBlock' and 'block', excluding 'block' */
optMarkLoopBlocks(succBlock, block, true);
// Mark all the reachable blocks between 'succBlock' and 'bPrev'
optScaleLoopBlocks(succBlock, bPrev);
}
}
else if (succBlock->isLoopHead() && bPrev && (succBlock->bbNum <= bPrev->bbNum))
{
skipUnmarkLoop = true;
}

noway_assert(succBlock);

// If this is the first Cold basic block update fgFirstColdBlock
if (block == fgFirstColdBlock)
{
Expand Down Expand Up @@ -4709,12 +4707,6 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
succBlock->bbRefs++;
}

fgUnlinkBlock(block);

/* mark the block as removed and set the change flag */

block->bbFlags |= BBF_REMOVED;

/* Update bbRefs and bbPreds.
* All blocks jumping to 'block' now jump to 'succBlock'.
* First, remove 'block' from the predecessor list of succBlock.
Expand Down Expand Up @@ -4804,6 +4796,9 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
break;
}
}

fgUnlinkBlock(block);
block->bbFlags |= BBF_REMOVED;
}

if (bPrev != nullptr)
Expand Down Expand Up @@ -5564,7 +5559,17 @@ BasicBlock* Compiler::fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE r
return bLast;
}

// return true if there is a possibility that the method has a loop (a backedge is present)
//------------------------------------------------------------------------
// fgMightHaveLoop: return true if there is a possibility that the method has a loop (a back edge is present).
// This function doesn't depend on any previous loop computations, including predecessors. It looks for any
// lexical back edge to a block previously seen in a forward walk of the block list.
//
// As it walks all blocks and all successors of each block (including EH successors), it is not cheap.
// It returns as soon as any possible loop is discovered.
//
// Return Value:
// true if there might be a loop
//
bool Compiler::fgMightHaveLoop()
{
// Don't use a BlockSet for this temporary bitset of blocks: we don't want to have to call EnsureBasicBlockEpoch()
Expand All @@ -5577,7 +5582,7 @@ bool Compiler::fgMightHaveLoop()
{
BitVecOps::AddElemD(&blockVecTraits, blocksSeen, block->bbNum);

for (BasicBlock* succ : block->GetAllSuccs(this))
for (BasicBlock* const succ : block->GetAllSuccs(this))
{
if (BitVecOps::IsMember(&blockVecTraits, blocksSeen, succ->bbNum))
{
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1632,7 +1632,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
}
}

// Add regions for the loops. Note that loops are assumed to be contiguous from `lpFirst` to `lpBottom`.
// Add regions for the loops. Note that loops are assumed to be contiguous from `lpTop` to `lpBottom`.

if (includeLoops)
{
Expand All @@ -1645,7 +1645,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
continue;
}
sprintf_s(name, sizeof(name), FMT_LP, loopNum);
rgnGraph.Insert(name, RegionGraph::RegionType::Loop, loop.lpFirst, loop.lpBottom);
rgnGraph.Insert(name, RegionGraph::RegionType::Loop, loop.lpTop, loop.lpBottom);
}
}

Expand Down
Loading