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

JIT: strengthen checking of the loop table #71184

Merged
merged 8 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from 7 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
26 changes: 14 additions & 12 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,12 +462,13 @@ Compiler::fgWalkResult Compiler::optAddCopiesCallback(GenTree** pTree, fgWalkDat
return WALK_CONTINUE;
}

/*****************************************************************************
*
* Add new copies before Assertion Prop.
*/

void Compiler::optAddCopies()
//------------------------------------------------------------------------------
// optAddCopies: Add new copies before Assertion Prop.
//
// Returns:
// suitable phase satus
//
PhaseStatus Compiler::optAddCopies()
{
unsigned lclNum;
LclVarDsc* varDsc;
Expand All @@ -477,19 +478,16 @@ void Compiler::optAddCopies()
{
printf("\n*************** In optAddCopies()\n\n");
}
if (verboseTrees)
{
printf("Blocks/Trees at start of phase\n");
fgDispBasicBlocks(true);
}
#endif

// Don't add any copies if we have reached the tracking limit.
if (lvaHaveManyLocals())
{
return;
return PhaseStatus::MODIFIED_NOTHING;
}

bool modified = false;

for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
{
var_types typ = varDsc->TypeGet();
Expand Down Expand Up @@ -893,6 +891,8 @@ void Compiler::optAddCopies()
tree->gtFlags |= (copyAsgn->gtFlags & GTF_ALL_EFFECT);
}

modified = true;

#ifdef DEBUG
if (verbose)
{
Expand All @@ -902,6 +902,8 @@ void Compiler::optAddCopies()
}
#endif
}

return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}

//------------------------------------------------------------------------------
Expand Down
11 changes: 7 additions & 4 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4840,11 +4840,13 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

if (opts.OptimizationEnabled())
{
// xxx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix comment

//
DoPhase(this, PHASE_OPTIMIZE_ADD_COPIES, &Compiler::optAddCopies);

// Optimize boolean conditions
//
DoPhase(this, PHASE_OPTIMIZE_BOOLS, &Compiler::optOptimizeBools);

// optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
}

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

Expand Down Expand Up @@ -4983,7 +4984,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
#endif

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

// Insert GC Polls
DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls);
Expand Down
39 changes: 15 additions & 24 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3245,7 +3245,7 @@ class Compiler

void lvaSortByRefCount();

void lvaMarkLocalVars(); // Local variable ref-counting
PhaseStatus lvaMarkLocalVars(); // Local variable ref-counting
void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);

Expand Down Expand Up @@ -4713,7 +4713,7 @@ class Compiler
inline bool PreciseRefCountsRequired();

// Performs SSA conversion.
void fgSsaBuild();
PhaseStatus fgSsaBuild();

// Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
void fgResetForSsa();
Expand All @@ -4737,7 +4737,7 @@ class Compiler

// Do value numbering (assign a value number to each
// tree node).
void fgValueNumber();
PhaseStatus fgValueNumber();

void fgValueNumberLocalStore(GenTree* storeNode,
GenTreeLclVarCommon* lclDefNode,
Expand Down Expand Up @@ -5263,12 +5263,12 @@ class Compiler

bool fgUpdateFlowGraph(bool doTailDup = false);

void fgFindOperOrder();
PhaseStatus fgFindOperOrder();

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

void fgSetBlockOrder();
PhaseStatus fgSetBlockOrder();

void fgRemoveReturnBlock(BasicBlock* block);

Expand Down Expand Up @@ -5917,7 +5917,7 @@ class Compiler

protected:
// Do hoisting for all loops.
void optHoistLoopCode();
PhaseStatus optHoistLoopCode();

// To represent sets of VN's that have already been hoisted in outer loops.
typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNSet;
Expand Down Expand Up @@ -5958,17 +5958,10 @@ class Compiler

// Do hoisting of all loops nested within loop "lnum" (an index into the optLoopTable), followed
// by the loop "lnum" itself.
//
// "m_pHoistedInCurLoop" helps a lot in eliminating duplicate expressions getting hoisted
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this comment was deleted?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like an inadvertent edit -- at one point I had modified the signature of optHoistLoopNest.

// and reducing the count of total expressions hoisted out of loop. When calculating the
// profitability, we compare this with number of registers and hence, lower the number of expressions
// getting hoisted, better chances that they will get enregistered and CSE considering them.
//
void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
bool optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);

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

// Hoist all expressions in "blocks" that are invariant in loop "loopNum" (an index into the optLoopTable)
// outside of that loop.
Expand Down Expand Up @@ -6018,7 +6011,7 @@ class Compiler
void optPerformHoistExpr(GenTree* expr, BasicBlock* exprBb, unsigned lnum);

public:
void optOptimizeBools();
PhaseStatus optOptimizeBools();

public:
PhaseStatus optInvertLoops(); // Invert loops so they're entered at top and tested at bottom.
Expand Down Expand Up @@ -6273,6 +6266,7 @@ class Compiler

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

Expand All @@ -6298,7 +6292,7 @@ class Compiler
BasicBlock* exit,
unsigned char exitCnt);

void optClearLoopIterInfo();
PhaseStatus optClearLoopIterInfo();

#ifdef DEBUG
void optPrintLoopInfo(unsigned lnum, bool printVerbose = false);
Expand Down Expand Up @@ -6909,9 +6903,9 @@ class Compiler
GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
GenTree* optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
bool optDoEarlyPropForBlock(BasicBlock* block);
bool optDoEarlyPropForFunc();
void optEarlyProp();
void optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
bool optDoEarlyPropForFunc();
PhaseStatus optEarlyProp();
bool optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
GenTree* optFindNullCheckToFold(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
bool optIsNullCheckFoldingLegal(GenTree* tree,
GenTree* nullCheckTree,
Expand Down Expand Up @@ -7310,7 +7304,7 @@ class Compiler
static void optDumpAssertionIndices(const char* header, ASSERT_TP assertions, const char* footer = nullptr);
static void optDumpAssertionIndices(ASSERT_TP assertions, const char* footer = nullptr);

void optAddCopies();
PhaseStatus optAddCopies();

/**************************************************************************
* Range checks
Expand Down Expand Up @@ -7366,9 +7360,6 @@ class Compiler

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

protected:
bool optLoopsMarked;

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compphases.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops",
CompPhaseNameMacro(PHASE_CLEAR_LOOP_INFO, "Clear loop info", "LP-CLEAR", false, -1, false)
CompPhaseNameMacro(PHASE_HOIST_LOOP_CODE, "Hoist loop code", "LP-HOIST", false, -1, false)
CompPhaseNameMacro(PHASE_MARK_LOCAL_VARS, "Mark local vars", "MARK-LCL", false, -1, false)
CompPhaseNameMacro(PHASE_OPTIMIZE_ADD_COPIES, "Opt add copies", "OPT-ADD-CP", false, -1, false)
CompPhaseNameMacro(PHASE_OPTIMIZE_BOOLS, "Optimize bools", "OPT-BOOL", false, -1, false)
CompPhaseNameMacro(PHASE_FIND_OPER_ORDER, "Find oper order", "OPER-ORD", false, -1, false)
CompPhaseNameMacro(PHASE_SET_BLOCK_ORDER, "Set block order", "BLK-ORD", false, -1, true)
Expand Down
47 changes: 26 additions & 21 deletions src/coreclr/jit/earlyprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ void Compiler::optCheckFlagsAreSet(unsigned methodFlag,
//------------------------------------------------------------------------------------------
// optEarlyProp: The entry point of the early value propagation.
//
// Returns:
// suitable phase status
//
// Notes:
// This phase performs an SSA-based value propagation, including
// 1. Array length propagation.
Expand All @@ -90,21 +93,18 @@ void Compiler::optCheckFlagsAreSet(unsigned methodFlag,
// Null check folding tries to find GT_INDIR(obj + const) that GT_NULLCHECK(obj) can be folded into
// and removed. Currently, the algorithm only matches GT_INDIR and GT_NULLCHECK in the same basic block.

void Compiler::optEarlyProp()
PhaseStatus Compiler::optEarlyProp()
{
#ifdef DEBUG
if (verbose)
{
printf("*************** In optEarlyProp()\n");
}
#else
if (!optDoEarlyPropForFunc())
{
return;
// We perhaps should verify the OMF are set properly
//
JITDUMP("no arrays or null checks in the method\n");
return PhaseStatus::MODIFIED_NOTHING;
}
#endif

assert(fgSsaPassesCompleted == 1);
unsigned numChanges = 0;

for (BasicBlock* const block : Blocks())
{
Expand Down Expand Up @@ -148,19 +148,15 @@ void Compiler::optEarlyProp()
assert(optDoEarlyPropForFunc() && optDoEarlyPropForBlock(block));
gtSetStmtInfo(stmt);
fgSetStmtSeq(stmt);
numChanges++;
}

stmt = next;
}
}

#ifdef DEBUG
if (verbose)
{
JITDUMP("\nAfter optEarlyProp:\n");
fgDispBasicBlocks(/*dumpTrees*/ true);
}
#endif
JITDUMP("\nOptimized %u trees\n", numChanges);
return numChanges > 0 ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}

//----------------------------------------------------------------
Expand All @@ -178,11 +174,12 @@ GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheck
{
GenTree* objectRefPtr = nullptr;
optPropKind propKind = optPropKind::OPK_INVALID;
bool folded = false;

if (tree->OperIsIndirOrArrLength())
{
// optFoldNullCheck takes care of updating statement info if a null check is removed.
optFoldNullCheck(tree, nullCheckMap);
folded = optFoldNullCheck(tree, nullCheckMap);
}
else
{
Expand All @@ -196,12 +193,12 @@ GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheck
}
else
{
return nullptr;
return folded ? tree : nullptr;
}

if (!objectRefPtr->OperIsScalarLocal() || !lvaInSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
{
return nullptr;
return folded ? tree : nullptr;
}
#ifdef DEBUG
else
Expand Down Expand Up @@ -415,13 +412,16 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
// tree - The input indirection tree.
// nullCheckMap - Map of the local numbers to the latest NULLCHECKs on those locals in the current basic block
//
// Returns:
// true if a null check was folded
//
// Notes:
// If a GT_NULLCHECK node is post-dominated by an indirection node on the same local and the trees between
// the GT_NULLCHECK and the indirection don't have unsafe side effects, the GT_NULLCHECK can be removed.
// The indir will cause a NullReferenceException if and only if GT_NULLCHECK will cause the same
// NullReferenceException.

void Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap)
bool Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap)
{
#ifdef DEBUG
if (tree->OperGet() == GT_NULLCHECK)
Expand All @@ -432,13 +432,14 @@ void Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nu
#else
if ((compCurBB->bbFlags & BBF_HAS_NULLCHECK) == 0)
{
return;
return false;
}
#endif

GenTree* nullCheckTree = optFindNullCheckToFold(tree, nullCheckMap);
GenTree* nullCheckParent = nullptr;
Statement* nullCheckStmt = nullptr;
bool folded = false;
if ((nullCheckTree != nullptr) && optIsNullCheckFoldingLegal(tree, nullCheckTree, &nullCheckParent, &nullCheckStmt))
{
#ifdef DEBUG
Expand Down Expand Up @@ -470,13 +471,17 @@ void Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nu
Statement* curStmt = compCurStmt;
fgMorphBlockStmt(compCurBB, nullCheckStmt DEBUGARG("optFoldNullCheck"));
compCurStmt = curStmt;

folded = true;
}

if ((tree->OperGet() == GT_NULLCHECK) && (tree->gtGetOp1()->OperGet() == GT_LCL_VAR))
{
nullCheckMap->Set(tree->gtGetOp1()->AsLclVarCommon()->GetLclNum(), tree,
LocalNumberToNullCheckTreeMap::SetKind::Overwrite);
}

return folded;
}

//----------------------------------------------------------------
Expand Down
Loading