Skip to content

JumpThreading: don't give up on phis in non-ambiguous preds#126711

Closed
EgorBo wants to merge 1 commit intodotnet:mainfrom
EgorBo:rbo-fix
Closed

JumpThreading: don't give up on phis in non-ambiguous preds#126711
EgorBo wants to merge 1 commit intodotnet:mainfrom
EgorBo:rbo-fix

Conversation

@EgorBo
Copy link
Copy Markdown
Member

@EgorBo EgorBo commented Apr 9, 2026

testing a fix for #126703

Copilot AI review requested due to automatic review settings April 9, 2026 14:54
@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 Apr 9, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
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

Updates CoreCLR JIT redundant-branch/jump-threading logic to avoid prematurely bailing out of PHI-based threading when PHI “problem” cases exist but all predecessors can be fully classified, addressing the missed optimization opportunity described in #126703.

Changes:

  • Extend optJumpThreadCheck with an optional out-parameter to report (instead of immediately rejecting) problematic PHIs during PHI-based jump threading.
  • In optJumpThreadPhi, defer the “problematic PHI” bail-out until after predecessor classification and only bail when ambiguous predecessors remain.
  • Update the JIT compiler interface in compiler.h to match the new optJumpThreadCheck signature.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/coreclr/jit/redundantbranchopts.cpp Adds deferred handling for problematic PHIs during PHI-based jump threading; bails only when ambiguous preds remain.
src/coreclr/jit/compiler.h Updates optJumpThreadCheck declaration to include an optional out-parameter.

Comment on lines +1060 to +1062
// 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
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The pHasGlobalPhiUse out-parameter is also set for promoted-field PHIs (lvIsStructField), not just “global phi uses” as the name/docstring implies. Consider renaming this to something like pHasProblematicPhi (or splitting promoted-field vs global-use flags) and updating the comment so callers don’t misinterpret what it indicates.

Suggested change
// 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
// pHasGlobalPhiUse - optional output; when non-null, PHI cases that are
// problematic for jump threading are reported here instead
// of causing an immediate bail-out. This currently includes
// global phi uses and promoted-field PHIs, letting the
// caller decide (e.g. allow threading when every

Copilot uses AI. Check for mistakes.
Comment on lines 1416 to 1422
// 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)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

hasGlobalPhiUse is used as a general “problematic PHI present” indicator (it’s set for promoted-field PHIs too), but the surrounding comment and later bail-out message talk only about “global phi”. Please align the naming/messages with the actual semantics (e.g., mention promoted-field PHIs here as well, or rename the flag).

Copilot uses AI. Check for mistakes.
Comment on lines +1650 to +1662
// 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;
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

This change is intended to unlock a specific codegen improvement (issue #126703), but there’s no regression test exercising the TrailingZeroCount(x) + sentinel compare pattern. Consider adding a JIT disasm-check test (see existing HasDisasmCheck tests under src/tests/JIT/opt/Compares/) that asserts the extra compare/cmove is eliminated for the idx != -1 case.

Copilot uses AI. Check for mistakes.
@AndyAyersMS
Copy link
Copy Markdown
Member

I think this may run into issues like #76636 and #76507, where downstream phases now make bad inferences.

@EgorBo
Copy link
Copy Markdown
Member Author

EgorBo commented Apr 9, 2026

I think this may run into issues like #76636 and #76507, where downstream phases now make bad inferences.

Sure, just wanted to estimate diffs, feel free to take over

@EgorBo EgorBo closed this Apr 9, 2026
@AndyAyersMS
Copy link
Copy Markdown
Member

We may be able to do something like the following:

  • if there is a phi def in the jump thread block with a small number of (global) uses, and no phi uses, then
    • search successor blocks to see if we can find all the global uses
    • if we can find them all, and the successors with uses are join-free, we can rewrite the uses during jump threading

This will catch the example here as there is just one global use, it's in one of the successors, and that successor is join-free.

If we can't account for local vs global uses accurately, we would also need to scan the jump thread block and count up its uses.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants