Skip to content

Commit cd88b84

Browse files
authored
JIT: strengthen checking of the loop table (#71184)
Add loop table checking to the post-phase list, conditional on whether the table is expected to be valid. Declare that the table is valid from the end of the find loops phase to the end of the optimization phases. Add checks that sibling loops are fully disjoint, no child shares top with its parent, and all top-entry loops have at most one non-loop backedge. Expand set of phases that opt into the "common" poost phase checks to include all those between find loops and hoisting. Closes #71084. Closes #71071.
1 parent 3fb9511 commit cd88b84

15 files changed

+340
-194
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,13 @@ Compiler::fgWalkResult Compiler::optAddCopiesCallback(GenTree** pTree, fgWalkDat
462462
return WALK_CONTINUE;
463463
}
464464

465-
/*****************************************************************************
466-
*
467-
* Add new copies before Assertion Prop.
468-
*/
469-
470-
void Compiler::optAddCopies()
465+
//------------------------------------------------------------------------------
466+
// optAddCopies: Add new copies before Assertion Prop.
467+
//
468+
// Returns:
469+
// suitable phase satus
470+
//
471+
PhaseStatus Compiler::optAddCopies()
471472
{
472473
unsigned lclNum;
473474
LclVarDsc* varDsc;
@@ -477,19 +478,16 @@ void Compiler::optAddCopies()
477478
{
478479
printf("\n*************** In optAddCopies()\n\n");
479480
}
480-
if (verboseTrees)
481-
{
482-
printf("Blocks/Trees at start of phase\n");
483-
fgDispBasicBlocks(true);
484-
}
485481
#endif
486482

487483
// Don't add any copies if we have reached the tracking limit.
488484
if (lvaHaveManyLocals())
489485
{
490-
return;
486+
return PhaseStatus::MODIFIED_NOTHING;
491487
}
492488

489+
bool modified = false;
490+
493491
for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
494492
{
495493
var_types typ = varDsc->TypeGet();
@@ -893,6 +891,8 @@ void Compiler::optAddCopies()
893891
tree->gtFlags |= (copyAsgn->gtFlags & GTF_ALL_EFFECT);
894892
}
895893

894+
modified = true;
895+
896896
#ifdef DEBUG
897897
if (verbose)
898898
{
@@ -902,6 +902,8 @@ void Compiler::optAddCopies()
902902
}
903903
#endif
904904
}
905+
906+
return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
905907
}
906908

907909
//------------------------------------------------------------------------------

src/coreclr/jit/compiler.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,11 +4848,14 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
48484848

48494849
if (opts.OptimizationEnabled())
48504850
{
4851+
// Introduce copies for some single-def locals to make them more
4852+
// amenable to optimization
4853+
//
4854+
DoPhase(this, PHASE_OPTIMIZE_ADD_COPIES, &Compiler::optAddCopies);
4855+
48514856
// Optimize boolean conditions
48524857
//
48534858
DoPhase(this, PHASE_OPTIMIZE_BOOLS, &Compiler::optOptimizeBools);
4854-
4855-
// optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
48564859
}
48574860

48584861
// Figure out the order in which operators are to be evaluated
@@ -4862,7 +4865,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
48624865
// Weave the tree lists. Anyone who modifies the tree shapes after
48634866
// this point is responsible for calling fgSetStmtSeq() to keep the
48644867
// nodes properly linked.
4865-
// This can create GC poll calls, and create new BasicBlocks (without updating dominators/reachability).
48664868
//
48674869
DoPhase(this, PHASE_SET_BLOCK_ORDER, &Compiler::fgSetBlockOrder);
48684870

@@ -4991,7 +4993,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
49914993
#endif
49924994

49934995
// Dominator and reachability sets are no longer valid.
4994-
fgDomsComputed = false;
4996+
// The loop table is no longer valid.
4997+
fgDomsComputed = false;
4998+
optLoopTableValid = false;
49954999

49965000
// Insert GC Polls
49975001
DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls);

src/coreclr/jit/compiler.h

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,8 +1415,10 @@ enum class PhaseChecks
14151415
// Specify compiler data that a phase might modify
14161416
enum class PhaseStatus : unsigned
14171417
{
1418-
MODIFIED_NOTHING,
1419-
MODIFIED_EVERYTHING
1418+
MODIFIED_NOTHING, // Phase did not make any changes that warrant running post-phase checks or dumping
1419+
// the main jit data strutures.
1420+
MODIFIED_EVERYTHING, // Phase made changes that warrant running post-phase checks or dumping
1421+
// the main jit data strutures.
14201422
};
14211423

14221424
// The following enum provides a simple 1:1 mapping to CLR API's
@@ -3242,7 +3244,7 @@ class Compiler
32423244

32433245
void lvaSortByRefCount();
32443246

3245-
void lvaMarkLocalVars(); // Local variable ref-counting
3247+
PhaseStatus lvaMarkLocalVars(); // Local variable ref-counting
32463248
void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
32473249
void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);
32483250

@@ -4710,7 +4712,7 @@ class Compiler
47104712
inline bool PreciseRefCountsRequired();
47114713

47124714
// Performs SSA conversion.
4713-
void fgSsaBuild();
4715+
PhaseStatus fgSsaBuild();
47144716

47154717
// Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
47164718
void fgResetForSsa();
@@ -4734,7 +4736,7 @@ class Compiler
47344736

47354737
// Do value numbering (assign a value number to each
47364738
// tree node).
4737-
void fgValueNumber();
4739+
PhaseStatus fgValueNumber();
47384740

47394741
void fgValueNumberLocalStore(GenTree* storeNode,
47404742
GenTreeLclVarCommon* lclDefNode,
@@ -5177,7 +5179,7 @@ class Compiler
51775179

51785180
bool fgCheckRemoveStmt(BasicBlock* block, Statement* stmt);
51795181

5180-
void fgCreateLoopPreHeader(unsigned lnum);
5182+
bool fgCreateLoopPreHeader(unsigned lnum);
51815183

51825184
void fgUnreachableBlock(BasicBlock* block);
51835185

@@ -5260,12 +5262,12 @@ class Compiler
52605262

52615263
bool fgUpdateFlowGraph(bool doTailDup = false);
52625264

5263-
void fgFindOperOrder();
5265+
PhaseStatus fgFindOperOrder();
52645266

52655267
// method that returns if you should split here
52665268
typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
52675269

5268-
void fgSetBlockOrder();
5270+
PhaseStatus fgSetBlockOrder();
52695271

52705272
void fgRemoveReturnBlock(BasicBlock* block);
52715273

@@ -5914,7 +5916,7 @@ class Compiler
59145916

59155917
protected:
59165918
// Do hoisting for all loops.
5917-
void optHoistLoopCode();
5919+
PhaseStatus optHoistLoopCode();
59185920

59195921
// To represent sets of VN's that have already been hoisted in outer loops.
59205922
typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNSet;
@@ -5955,17 +5957,10 @@ class Compiler
59555957

59565958
// Do hoisting of all loops nested within loop "lnum" (an index into the optLoopTable), followed
59575959
// by the loop "lnum" itself.
5958-
//
5959-
// "m_pHoistedInCurLoop" helps a lot in eliminating duplicate expressions getting hoisted
5960-
// and reducing the count of total expressions hoisted out of loop. When calculating the
5961-
// profitability, we compare this with number of registers and hence, lower the number of expressions
5962-
// getting hoisted, better chances that they will get enregistered and CSE considering them.
5963-
//
5964-
void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5960+
bool optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
59655961

59665962
// Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5967-
// Returns the new preheaders created.
5968-
void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt, BasicBlockList* existingPreHeaders);
5963+
bool optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt, BasicBlockList* existingPreHeaders);
59695964

59705965
// Hoist all expressions in "blocks" that are invariant in loop "loopNum" (an index into the optLoopTable)
59715966
// outside of that loop.
@@ -6015,7 +6010,7 @@ class Compiler
60156010
void optPerformHoistExpr(GenTree* expr, BasicBlock* exprBb, unsigned lnum);
60166011

60176012
public:
6018-
void optOptimizeBools();
6013+
PhaseStatus optOptimizeBools();
60196014

60206015
public:
60216016
PhaseStatus optInvertLoops(); // Invert loops so they're entered at top and tested at bottom.
@@ -6104,6 +6099,8 @@ class Compiler
61046099
int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
61056100
int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or across this loop
61066101

6102+
bool lpHoistAddedPreheader; // The loop preheader was added during hoisting
6103+
61076104
typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, FieldKindForVN>
61086105
FieldHandleSet;
61096106
FieldHandleSet* lpFieldsModified; // This has entries for all static field and object instance fields modified
@@ -6270,6 +6267,7 @@ class Compiler
62706267

62716268
public:
62726269
LoopDsc* optLoopTable; // loop descriptor table
6270+
bool optLoopTableValid; // info in loop table should be valid
62736271
unsigned char optLoopCount; // number of tracked loops
62746272
unsigned char loopAlignCandidates; // number of loops identified for alignment
62756273

@@ -6295,7 +6293,7 @@ class Compiler
62956293
BasicBlock* exit,
62966294
unsigned char exitCnt);
62976295

6298-
void optClearLoopIterInfo();
6296+
PhaseStatus optClearLoopIterInfo();
62996297

63006298
#ifdef DEBUG
63016299
void optPrintLoopInfo(unsigned lnum, bool printVerbose = false);
@@ -6906,9 +6904,9 @@ class Compiler
69066904
GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
69076905
GenTree* optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
69086906
bool optDoEarlyPropForBlock(BasicBlock* block);
6909-
bool optDoEarlyPropForFunc();
6910-
void optEarlyProp();
6911-
void optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
6907+
bool optDoEarlyPropForFunc();
6908+
PhaseStatus optEarlyProp();
6909+
bool optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
69126910
GenTree* optFindNullCheckToFold(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
69136911
bool optIsNullCheckFoldingLegal(GenTree* tree,
69146912
GenTree* nullCheckTree,
@@ -7308,7 +7306,7 @@ class Compiler
73087306
static void optDumpAssertionIndices(const char* header, ASSERT_TP assertions, const char* footer = nullptr);
73097307
static void optDumpAssertionIndices(ASSERT_TP assertions, const char* footer = nullptr);
73107308

7311-
void optAddCopies();
7309+
PhaseStatus optAddCopies();
73127310

73137311
/**************************************************************************
73147312
* Range checks
@@ -7364,9 +7362,6 @@ class Compiler
73647362

73657363
bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
73667364

7367-
protected:
7368-
bool optLoopsMarked;
7369-
73707365
/*
73717366
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
73727367
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

src/coreclr/jit/compphases.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops",
6666
CompPhaseNameMacro(PHASE_CLEAR_LOOP_INFO, "Clear loop info", "LP-CLEAR", false, -1, false)
6767
CompPhaseNameMacro(PHASE_HOIST_LOOP_CODE, "Hoist loop code", "LP-HOIST", false, -1, false)
6868
CompPhaseNameMacro(PHASE_MARK_LOCAL_VARS, "Mark local vars", "MARK-LCL", false, -1, false)
69+
CompPhaseNameMacro(PHASE_OPTIMIZE_ADD_COPIES, "Opt add copies", "OPT-ADD-CP", false, -1, false)
6970
CompPhaseNameMacro(PHASE_OPTIMIZE_BOOLS, "Optimize bools", "OPT-BOOL", false, -1, false)
7071
CompPhaseNameMacro(PHASE_FIND_OPER_ORDER, "Find oper order", "OPER-ORD", false, -1, false)
7172
CompPhaseNameMacro(PHASE_SET_BLOCK_ORDER, "Set block order", "BLK-ORD", false, -1, true)

0 commit comments

Comments
 (0)