Skip to content
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
2 changes: 1 addition & 1 deletion src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ enum BasicBlockFlags : unsigned __int64
// Flags to update when two blocks are compacted

BBF_COMPACT_UPD = BBF_GC_SAFE_POINT | BBF_HAS_JMP | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_BACKWARD_JUMP | \
BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF,
BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF | BBF_LOOP_PREHEADER,

// Flags a block should not have had before it is split.

Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5003,8 +5003,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

// Dominator and reachability sets are no longer valid.
// The loop table is no longer valid.
fgDomsComputed = false;
optLoopTableValid = false;
fgDomsComputed = false;
optLoopTableValid = false;
optLoopsRequirePreHeaders = false;

#ifdef DEBUG
DoPhase(this, PHASE_STRESS_SPLIT_TREE, &Compiler::StressSplitTree);
Expand Down
22 changes: 10 additions & 12 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5232,7 +5232,7 @@ class Compiler
void vnPrint(ValueNum vn, unsigned level);
#endif

bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
bool fgDominate(const BasicBlock* b1, const BasicBlock* b2); // Return true if b1 dominates b2

// Dominator computation member functions
// Not exposed outside Compiler
Expand Down Expand Up @@ -6193,7 +6193,7 @@ class Compiler
bool optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);

// Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
bool optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt, BasicBlockList* existingPreHeaders);
bool optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);

// Hoist all expressions in "blocks" that are invariant in loop "loopNum" (an index into the optLoopTable)
// outside of that loop.
Expand Down Expand Up @@ -6262,7 +6262,6 @@ class Compiler

PhaseStatus optCloneLoops();
void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
void optEnsureUniqueHead(unsigned loopInd, weight_t ambientWeight);
PhaseStatus optUnrollLoops(); // Unrolls loops (needs to have cost info)
void optRemoveRedundantZeroInits();
PhaseStatus optIfConversion(); // If conversion
Expand Down Expand Up @@ -6339,8 +6338,6 @@ class Compiler
int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or across this loop

bool lpHoistAddedPreheader; // The loop preheader was added during hoisting

typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, FieldKindForVN>
FieldHandleSet;
FieldHandleSet* lpFieldsModified; // This has entries for all static field and object instance fields modified
Expand Down Expand Up @@ -6512,10 +6509,11 @@ class Compiler
bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability

public:
LoopDsc* optLoopTable; // loop descriptor table
bool optLoopTableValid; // info in loop table should be valid
unsigned char optLoopCount; // number of tracked loops
unsigned char loopAlignCandidates; // number of loops identified for alignment
LoopDsc* optLoopTable; // loop descriptor table
bool optLoopTableValid; // info in loop table should be valid
bool optLoopsRequirePreHeaders; // Do we require that all loops (in the loop table) have pre-headers?
unsigned char optLoopCount; // number of tracked loops
unsigned char loopAlignCandidates; // number of loops identified for alignment

// Every time we rebuild the loop table, we increase the global "loop epoch". Any loop indices or
// loop table pointers from the previous epoch are invalid.
Expand Down Expand Up @@ -6575,7 +6573,7 @@ class Compiler
bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
bool optPopulateInitInfo(unsigned loopInd, BasicBlock* initBlock, GenTree* init, unsigned iterVar);
bool optExtractInitTestIncr(
BasicBlock* head, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
BasicBlock** pInitBlock, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);

void optFindNaturalLoops();

Expand Down Expand Up @@ -6642,7 +6640,7 @@ class Compiler
bool optIsLoopEntry(BasicBlock* block) const;

// The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
unsigned optLoopDepth(unsigned lnum)
unsigned optLoopDepth(unsigned lnum) const
{
assert(lnum < optLoopCount);
unsigned depth = 0;
Expand Down Expand Up @@ -7650,7 +7648,7 @@ class Compiler
bool optCheckLoopCloningGDVTestProfitable(GenTreeOp* guard, LoopCloneVisitorInfo* info);
bool optIsHandleOrIndirOfHandle(GenTree* tree, GenTreeFlags handleType);

bool optLoopCloningEnabled();
static bool optLoopCloningEnabled();

#ifdef DEBUG
void optDebugLogLoopCloning(BasicBlock* block, Statement* insertBefore);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4971,6 +4971,8 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)

JITDUMP("fgRemoveBlock " FMT_BB ", unreachable=%s\n", block->bbNum, dspBool(unreachable));

assert(unreachable || !optLoopsRequirePreHeaders || ((block->bbFlags & BBF_LOOP_PREHEADER) == 0));

// If we've cached any mappings from switch blocks to SwitchDesc's (which contain only the
// *unique* successors of the switch block), invalidate that cache, since an entry in one of
// the SwitchDescs might be removed.
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4335,6 +4335,7 @@ void Compiler::fgDebugCheckSsa()
// - All basic blocks with loop numbers set have a corresponding loop in the table
// - All basic blocks without a loop number are not in a loop
// - All parents of the loop with the block contain that block
// - If optLoopsRequirePreHeaders is true, the loop has a pre-header
// - If the loop has a pre-header, it is valid
// - The loop flags are valid
// - no loop shares `top` with any of its children
Expand Down Expand Up @@ -4593,6 +4594,11 @@ void Compiler::fgDebugCheckLoopTable()
}
}

if (optLoopsRequirePreHeaders)
{
assert((loop.lpFlags & LPFLG_HAS_PREHEAD) != 0);
}

// If the loop has a pre-header, ensure the pre-header form is correct.
if ((loop.lpFlags & LPFLG_HAS_PREHEAD) != 0)
{
Expand Down
21 changes: 7 additions & 14 deletions src/coreclr/jit/fgflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,27 +361,20 @@ void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
fgRemoveRefPred(bNext, bNext->bbPreds->getSourceBlock());
}
}
fgRemoveRefPred(block->bbJumpDest, block);
break;

FALLTHROUGH;

case BBJ_COND:
case BBJ_ALWAYS:
case BBJ_EHCATCHRET:

/* Update the predecessor list for 'block->bbJumpDest' and 'block->bbNext' */
fgRemoveRefPred(block->bbJumpDest, block);

if (block->bbJumpKind != BBJ_COND)
{
break;
}

/* If BBJ_COND fall through */
FALLTHROUGH;
break;

case BBJ_NONE:
fgRemoveRefPred(block->bbNext, block);
break;

/* Update the predecessor list for 'block->bbNext' */
case BBJ_COND:
fgRemoveRefPred(block->bbJumpDest, block);
fgRemoveRefPred(block->bbNext, block);
break;

Expand Down
51 changes: 32 additions & 19 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
// Assumptions:
// -- Dominators have been calculated (`fgDomsComputed` is true).
//
bool Compiler::fgDominate(BasicBlock* b1, BasicBlock* b2)
bool Compiler::fgDominate(const BasicBlock* b1, const BasicBlock* b2)
{
noway_assert(fgDomsComputed);

Expand Down Expand Up @@ -60,17 +60,6 @@ bool Compiler::fgDominate(BasicBlock* b1, BasicBlock* b2)

if (b1->bbNum > fgDomBBcount)
{
// If b1 is a loop preheader (that was created after the dominators were calculated),
// then it has a single successor that is the loop entry, and it is the only non-loop
// predecessor of the loop entry. Thus, b1 dominates the loop entry and also dominates
// what the loop entry dominates.
if (b1->bbFlags & BBF_LOOP_PREHEADER)
{
BasicBlock* loopEntry = b1->GetUniqueSucc();
assert(loopEntry != nullptr);
return fgDominate(loopEntry, b2);
}

// unknown dominators; err on the safe side and return false
return false;
}
Expand Down Expand Up @@ -1947,6 +1936,17 @@ bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext)
return false;
}

// Don't allow removing an empty loop pre-header.
// We can compact a pre-header `bNext` into an empty `block` since BBF_COMPACT_UPD propagates
// BBF_LOOP_PREHEADER to `block`.
if (optLoopsRequirePreHeaders)
{
if (((block->bbFlags & BBF_LOOP_PREHEADER) != 0) && (bNext->countOfInEdges() != 1))
{
return false;
}
}

// Don't compact the first block if it was specially created as a scratch block.
if (fgBBisScratch(block))
{
Expand Down Expand Up @@ -1983,16 +1983,14 @@ bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext)
}
}

// We cannot compact a block that participates in loop
// alignment.
// We cannot compact a block that participates in loop alignment.
//
if ((bNext->countOfInEdges() > 1) && bNext->isLoopAlign())
{
return false;
}

// If we are trying to compact blocks from different loops
// that don't do it.
// Don't compact blocks from different loops.
//
if ((block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) && (bNext->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) &&
(block->bbNatLoopNum != bNext->bbNatLoopNum))
Expand Down Expand Up @@ -2058,8 +2056,13 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext)
JITDUMP("Second block has %u other incoming edges\n", bNext->countOfInEdges());
assert(block->isEmpty());

// `block` can no longer be a loop pre-header (if it was before).
// When loops require pre-headers, `block` cannot be a pre-header.
// We should have screened this out in fgCanCompactBlocks().
//
// When pre-headers are not required, then if `block` was a pre-header,
// it no longer is.
//
assert(!optLoopsRequirePreHeaders || ((block->bbFlags & BBF_LOOP_PREHEADER) == 0));
block->bbFlags &= ~BBF_LOOP_PREHEADER;

// Retarget all the other edges incident on bNext. Do this
Expand Down Expand Up @@ -3053,6 +3056,15 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block)
break;
}

// Don't delete empty loop pre-headers.
if (optLoopsRequirePreHeaders)
{
if ((block->bbFlags & BBF_LOOP_PREHEADER) != 0)
{
break;
}
}

/* special case if this is the last BB */
if (block == fgLastBB)
{
Expand Down Expand Up @@ -6027,8 +6039,9 @@ PhaseStatus Compiler::fgUpdateFlowGraphPhase()

// Dominator and reachability sets are no longer valid.
// The loop table is no longer valid.
fgDomsComputed = false;
optLoopTableValid = false;
fgDomsComputed = false;
optLoopTableValid = false;
optLoopsRequirePreHeaders = false;

return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}
Expand Down
Loading