Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
* simplify IfConvertCheckStmts * small things
9792586 to
5c1616c
Compare
There was a problem hiding this comment.
Pull request overview
This PR simplifies the CoreCLR JIT if-conversion implementation by collapsing the prior multi-block flow search into a single, direct-flow check, under the assumption that Then/Else paths do not contain empty/chained blocks.
Changes:
- Replace the prior bounded “walk” of Then/Else chains with a single
IfConvertCheckFlow()check. - Simplify statement validation to operate on a single block (ignoring NOPs) rather than scanning a block chain to
m_finalBlock. - Simplify debug dumping and block removal to target only the identified Then/Else blocks.
| m_doElseConversion = trueBb->GetUniquePred(m_compiler) != nullptr; | ||
| m_finalBlock = m_doElseConversion ? trueBb->GetUniqueSucc() : trueBb; | ||
| m_mainOper = GT_STORE_LCL_VAR; | ||
|
|
||
| for (int thenLimit = 0; thenLimit < m_checkLimit; thenLimit++) | ||
| if (m_finalBlock == nullptr) | ||
| { | ||
| if (!IfConvertCheckInnerBlockFlow(thenBlock)) | ||
| assert(m_doElseConversion); | ||
| if (falseBb->KindIs(BBJ_RETURN) && trueBb->KindIs(BBJ_RETURN)) | ||
| { | ||
| // Then block is not in a valid flow. | ||
| return true; | ||
| m_mainOper = GT_RETURN; | ||
| } | ||
| BasicBlock* thenBlockNext = thenBlock->GetUniqueSucc(); | ||
|
|
||
| if (thenBlockNext == m_finalBlock) | ||
| { | ||
| // All the Then blocks up to m_finalBlock are in a valid flow. | ||
| m_flowFound = true; | ||
| if (thenBlock->KindIs(BBJ_RETURN)) | ||
| { | ||
| assert(m_finalBlock == nullptr); | ||
| m_mainOper = GT_RETURN; | ||
| } | ||
| else | ||
| { | ||
| m_mainOper = GT_STORE_LCL_VAR; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| if (thenBlockNext == nullptr) | ||
| else | ||
| { | ||
| // Invalid Then and Else combination. | ||
| return false; | ||
| } | ||
|
|
||
| thenBlock = thenBlockNext; | ||
| } | ||
|
|
||
| // Nothing found. Still valid to continue. | ||
| return true; | ||
| } | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // IfConvertFindFlow | ||
| // | ||
| // Find a valid if conversion flow from m_startBlock to a final block. | ||
| // There might be multiple Then and Else blocks in the flow - use m_checkLimit to limit this. | ||
| // | ||
| // Notes: | ||
| // Sets m_flowFound, m_finalBlock, m_doElseConversion and m_mainOper. | ||
| // | ||
| void OptIfConversionDsc::IfConvertFindFlow() | ||
| { | ||
| // First check for flow with no else case. The final block is the destination of the jump. | ||
| m_doElseConversion = false; | ||
| m_finalBlock = m_startBlock->GetTrueTarget(); | ||
| assert(m_finalBlock != nullptr); | ||
| if (!IfConvertCheckThenFlow() || m_flowFound) | ||
| { | ||
| // Either the flow is invalid, or a flow was found. | ||
| return; | ||
| } | ||
|
|
||
| // Look for flows with else blocks. The final block is the block after the else block. | ||
| m_doElseConversion = true; | ||
| for (int elseLimit = 0; elseLimit < m_checkLimit; elseLimit++) | ||
| { | ||
| BasicBlock* elseBlock = m_finalBlock; | ||
| if (elseBlock == nullptr || !IfConvertCheckInnerBlockFlow(elseBlock)) | ||
| { | ||
| // Need a valid else block in a valid flow . | ||
| return; | ||
| } | ||
|
|
||
| m_finalBlock = elseBlock->GetUniqueSucc(); | ||
|
|
||
| if (!IfConvertCheckThenFlow() || m_flowFound) | ||
| { | ||
| // Either the flow is invalid, or a flow was found. | ||
| return; | ||
| } | ||
| } | ||
| return falseBb->GetUniqueSucc() == m_finalBlock; |
There was a problem hiding this comment.
IfConvertCheckFlow now requires the Then/Else blocks to be direct predecessors of the merge (via GetUniqueSucc equality). However the JIT can introduce empty BBJ_ALWAYS fallthrough blocks (e.g., BBF_INTERNAL blocks from fgNormalizeEH), which previously would have been handled by walking a short chain. This makes the change unlikely to be truly “zero-diff” and can silently disable if-conversion for methods with EH normalization artifacts. Consider skipping/peeling empty fallthrough blocks (similar to SkipFallthroughBlocks in switchrecognition.cpp) or reintroducing a bounded walk so the optimization remains robust in the presence of empty blocks.
Zero-diff change that simplifies if-conversion based on the assumption that there are no empty blocks inside the Then and Else case. See: #125072 (comment)