JIT: Simplify if-conversion#125347
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.
|
@a74nh @jakobbotsch What do you think? I guess the main question is whether this is a reasonable assumption to make in the first place: assert(m_startBlock->GetFalseTarget()->GetUniqueSucc() == m_finalBlock);
if (m_doElseConversion)
{
assert(m_startBlock->GetTrueTarget()->GetUniqueSucc() == m_finalBlock);
}Meaning no flow through empty blocks inside Then/Else cases. I simplified:
|
The original assumption was that the graph potentially could contain multiple blocks with a straight line flow between them. What could give that scenario?
Even if it's not a 100% correct assumption, sounds like we're still catching everything of relevance with your change. |
Do you mean something like this. Because it does get recognized. We just bail on profitability for the outer one: int a74nh(bool x, bool y)
{
if (x)
{
if (y)
{
return 1;
}
else
{
return 2;
}
}
else
{
return 3;
}
} mov eax, 3
mov ecx, 2
mov r10d, 1
test r8b, r8b
cmovne ecx, r10d
test dl, dl
cmovne eax, ecx
;; size=28 bbWeight=1 PerfScore 1.75
G_M25408_IG03: ;; offset=0x001C
ret Anyway so yeah, while there will still be Then/Else cases with multiple blocks that have linear flow this PR says: "Such cases won't be amendable to if-conversion anyway so let's bail in |
* add 'assert(m_cond->OperIsCompare())' * combine IfConvertCheckFlow + IfConvertCheckStmts into new IfConvertCheck * get m_mainOper from m_thenOperation instead of flow check
|
@a74nh does everything look ok now or are there other changes you would like me to do? |
a74nh
left a comment
There was a problem hiding this comment.
I'm happy with this now.
Although, looks like formatting needs fixing.
|
@BoyBaykiller Can you address the formatting issue? |
|
@BoyBaykiller The jit-format job uploads a patch file when the formatting fails that you can apply locally to fix it. You can also run jit-format locally before you even commit: https://github.com/dotnet/jitutils/blob/main/doc/formatting.md |
|
Thanks. I'll know that for the future. In this case vscode formatting did the job |
A Fuzzlyn-generated repro hits `assert(!block->HasFlag(BBF_DONT_REMOVE))` during the JIT's *If conversion* phase when the Then block is the start of a try region. Bisected to dea4756 (#125347), which simplified `IfConvertCheckFlow` and inadvertently dropped the `BasicBlock::sameEHRegion` check previously performed by `IfConvertCheckInnerBlockFlow`. Without it, if-conversion proceeds on a Then/Else block that begins an EH region, then trips the assert when later removing it. ## Changes - **`src/coreclr/jit/ifconversion.cpp`** — In `OptIfConversionDsc::IfConvertCheckFlow`, bail when `falseBb` (Then) or `trueBb` (Else, when present) is not in the same EH region as `m_startBlock`. After merging `origin/main`, the Else guard uses the new `HasElseBlock()` helper (which replaced the removed `m_doElseConversion` member). - **`src/tests/JIT/Regression/JitBlue/Runtime_127446/Runtime_127446.cs`** — Regression test using the original repro. The test source is added to the shared merged `src/tests/JIT/Regression/Regression_ro_2.csproj` (alongside other JitBlue regression tests); no per-test csproj or environment variables are needed. ```cpp if (falseBb->GetUniquePred(m_compiler) == nullptr) { return false; } // The Then/Else blocks will be removed by if-conversion, so they must be in the same // EH region as m_startBlock. Otherwise they may be the start of a try/handler region // (and thus marked BBF_DONT_REMOVE), or removing them could leave dangling EH state. if (!BasicBlock::sameEHRegion(falseBb, m_startBlock)) { return false; } m_finalBlock = HasElseBlock() ? trueBb->GetUniqueSucc() : trueBb; if (HasElseBlock() && !BasicBlock::sameEHRegion(trueBb, m_startBlock)) { return false; } ``` Verified the assert reproduces on the unfixed JIT and is gone with the fix; the new test passes through the merged test runner (`global::Runtime_127446.Runtime_127446.TestEntryPoint()` → Passed) after merging the latest `origin/main`. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com> Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com> Co-authored-by: Egor Bogatov <egorbo@gmail.com>
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)