Skip to content

JIT: Simplify if-conversion#125347

Open
BoyBaykiller wants to merge 3 commits intodotnet:mainfrom
BoyBaykiller:simplify-if-conv
Open

JIT: Simplify if-conversion#125347
BoyBaykiller wants to merge 3 commits intodotnet:mainfrom
BoyBaykiller:simplify-if-conv

Conversation

@BoyBaykiller
Copy link
Contributor

@BoyBaykiller BoyBaykiller commented Mar 9, 2026

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)

@BoyBaykiller BoyBaykiller changed the title JIT: Simplify if conv JIT: Simplify if-conversion Mar 9, 2026
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 9, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 9, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Comment on lines +83 to +100
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;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants