-
Notifications
You must be signed in to change notification settings - Fork 5.4k
JumpThreading: don't give up on phis in non-ambiguous preds #126711
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1055,13 +1055,17 @@ struct JumpThreadInfo | |
| // optJumpThreadCheck: see if block is suitable for jump threading. | ||
| // | ||
| // Arguments: | ||
| // block - block in question | ||
| // domBlock - dom block used in inferencing (if any) | ||
| // block - block in question | ||
| // domBlock - dom block used in inferencing (if any) | ||
| // pHasGlobalPhiUse - optional output; when non-null, global phi uses | ||
| // are reported here instead of causing an immediate bail-out, | ||
| // letting the caller decide (e.g. allow threading when every | ||
| // predecessor is fully classified). | ||
| // | ||
| // Returns: | ||
| // True if the block is suitable for jump threading. | ||
| // | ||
| bool Compiler::optJumpThreadCheck(BasicBlock* const block, BasicBlock* const domBlock) | ||
| bool Compiler::optJumpThreadCheck(BasicBlock* const block, BasicBlock* const domBlock, bool* pHasGlobalPhiUse) | ||
| { | ||
| // If the block is the first block of try-region, then skip jump threading | ||
| if (bbIsTryBeg(block)) | ||
|
|
@@ -1121,27 +1125,42 @@ bool Compiler::optJumpThreadCheck(BasicBlock* const block, BasicBlock* const dom | |
| unsigned const ssaNum = phiDef->GetSsaNum(); | ||
| LclVarDsc* const varDsc = lvaGetDesc(lclNum); | ||
|
|
||
| bool isProblematicPhi = false; | ||
|
|
||
| // We do not put implicit uses of promoted local fields into SSA. | ||
| // So assume the worst here, that there is some implicit use of this ssa | ||
| // def we don't know about. | ||
| // | ||
| if (varDsc->lvIsStructField) | ||
| { | ||
| JITDUMP(FMT_BB " has phi for promoted field V%02u.%u; no phi-based threading\n", block->bbNum, | ||
| lclNum, ssaNum); | ||
| return false; | ||
| isProblematicPhi = true; | ||
| } | ||
| else | ||
| { | ||
| LclSsaVarDsc* const ssaVarDsc = varDsc->GetPerSsaData(ssaNum); | ||
|
|
||
| LclSsaVarDsc* const ssaVarDsc = varDsc->GetPerSsaData(ssaNum); | ||
| // Bypassing a global use might require SSA updates. | ||
| // Note a phi use is ok if it's local (self loop) | ||
| // | ||
| if (ssaVarDsc->HasGlobalUse()) | ||
| { | ||
| isProblematicPhi = true; | ||
| } | ||
| } | ||
|
|
||
| // Bypassing a global use might require SSA updates. | ||
| // Note a phi use is ok if it's local (self loop) | ||
| // | ||
| if (ssaVarDsc->HasGlobalUse()) | ||
| if (isProblematicPhi) | ||
| { | ||
| JITDUMP(FMT_BB " has global phi for V%02u.%u; no phi-based threading\n", block->bbNum, lclNum, | ||
| ssaNum); | ||
| return false; | ||
| if (pHasGlobalPhiUse != nullptr) | ||
| { | ||
| // Caller will decide whether to bail based on pred classification. | ||
| *pHasGlobalPhiUse = true; | ||
| } | ||
| else | ||
| { | ||
| JITDUMP(FMT_BB " has global/promoted phi for V%02u.%u; no phi-based threading\n", | ||
| block->bbNum, lclNum, ssaNum); | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1395,8 +1414,11 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl | |
| bool Compiler::optJumpThreadPhi(BasicBlock* block, GenTree* tree, ValueNum treeNormVN) | ||
| { | ||
| // First see if block is eligible for threading. | ||
| // Defer the global-phi bail-out: when every predecessor is fully classified | ||
| // the block becomes unreachable after threading, so global phi uses are safe. | ||
| // | ||
| const bool check = optJumpThreadCheck(block, /* domBlock*/ nullptr); | ||
| bool hasGlobalPhiUse = false; | ||
| const bool check = optJumpThreadCheck(block, /* domBlock*/ nullptr, &hasGlobalPhiUse); | ||
| if (!check) | ||
|
Comment on lines
1416
to
1422
|
||
| { | ||
| return false; | ||
|
|
@@ -1625,6 +1647,20 @@ bool Compiler::optJumpThreadPhi(BasicBlock* block, GenTree* tree, ValueNum treeN | |
| } | ||
| } | ||
|
|
||
| // If there are ambiguous predecessors and a global phi use, we cannot | ||
| // safely thread because the block would remain reachable (from the | ||
| // ambiguous preds) with a broken PHI. | ||
| // | ||
| // When there are NO ambiguous preds, all preds are redirected, | ||
| // the block becomes unreachable, and global phi uses are harmless. | ||
| // | ||
| if (hasGlobalPhiUse && (jti.m_numAmbiguousPreds > 0)) | ||
| { | ||
| JITDUMP(FMT_BB " has global phi and %u ambiguous pred(s); no phi-based threading\n", | ||
| block->bbNum, jti.m_numAmbiguousPreds); | ||
| return false; | ||
| } | ||
|
Comment on lines
+1650
to
+1662
|
||
|
|
||
| // Do the optimization. | ||
| // | ||
| return optJumpThreadCore(jti); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
pHasGlobalPhiUseout-parameter is also set for promoted-field PHIs (lvIsStructField), not just “global phi uses” as the name/docstring implies. Consider renaming this to something likepHasProblematicPhi(or splitting promoted-field vs global-use flags) and updating the comment so callers don’t misinterpret what it indicates.