Skip to content

JIT: Don't transform infinite loops in fgOptimizeBranchToEmptyUnconditional #116822

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

Merged
merged 1 commit into from
Jun 20, 2025

Conversation

amanasifkhalid
Copy link
Member

Fixes #116701 (comment).

@Copilot Copilot AI review requested due to automatic review settings June 19, 2025 15:21
@amanasifkhalid
Copy link
Member Author

/azp run runtime-jit-experimental

@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 Jun 19, 2025
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

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 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 prevents the JIT from folding an unconditional jump into a target that immediately jumps back, avoiding an unintended infinite loop.
Key changes:

  • Introduce a new bDestTarget local and disable optimization when it would create a loop.
  • Update the removed-block check to use the bDestTarget variable.
  • Retain existing try-region and removal logic.
Comments suppressed due to low confidence (1)

src/coreclr/jit/fgopt.cpp:1307

  • Consider adding a unit test that covers the case where an empty block jumps back to its predecessor, verifying that fgOptimizeBranchToEmptyUnconditional does not perform the redirection and avoids an infinite loop.
    if (bDestTarget->GetUniqueSucc() == bDest)

Comment on lines +1305 to +1306
// entering an infinite loop.
//
Copy link
Preview

Copilot AI Jun 19, 2025

Choose a reason for hiding this comment

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

[nitpick] This standalone // line is empty—consider removing it or merging the adjacent comment blocks to improve readability.

Suggested change
// entering an infinite loop.
//
// entering an infinite loop, which would cause issues.

Copilot uses AI. Check for mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

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

The rest of this method follows this convention -- perhaps we ought to unify the comment style at some point.

@amanasifkhalid
Copy link
Member Author

@dotnet/jit-contrib PTAL. No diffs. runtime-jit-experimental passed.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

I believe this has broken this way before though I can't find any relevant issue.

Any way you can think of to avoid this sort of problem more definitively?

@amanasifkhalid
Copy link
Member Author

I believe this has broken this way before though I can't find any relevant issue.

The caller has a check for bDest unconditionally jumping to itself -- perhaps that was the case you're thinking of?

Any way you can think of to avoid this sort of problem more definitively?

For the infinite loop to trigger, bDest and bDestTarget have to both be empty, so they should both be compactable too. I suppose encoding some invariant into fgUpdateFlowGraph such that the flowgraph is as compact as possible at all times would reduce this case to the single-block infinite loop case, which we already cover. I was planning on revamping our block compaction strategy during flow opts to make it more efficient, but that work will certainly incur diffs.

@amanasifkhalid
Copy link
Member Author

Now that I'm thinking about it, I don't see why we need fgOptimizeBranchToEmptyUnconditional anymore. If we have some block that jumps to an empty BBJ_ALWAYS to somewhere else, we should always be able to compact the intermediate block away. I might be able to do this with minimal churn...

@AndyAyersMS
Copy link
Member

If that doesn't pan out we can take this fix and work on a more major revamping next release.

@amanasifkhalid
Copy link
Member Author

@AndyAyersMS the diffs are on the order of tens of thousands of bytes, in both directions. From a quick look, I can see that the different order of transformations during flow opts sometimes leaves branches swapped, churning downstream phases. These look like good opportunities to investigate, but I think we ought to take the easy fix for now.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

Sounds good.

@amanasifkhalid
Copy link
Member Author

/ba-g Build Analysis not picking up HostActivation.Tests known failure

@amanasifkhalid amanasifkhalid merged commit 296780d into dotnet:main Jun 20, 2025
121 of 124 checks passed
@amanasifkhalid amanasifkhalid deleted the flow-opts-infinite-loop branch June 20, 2025 16:32
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.

[jit-experimental] Regression_7 tests failing in
2 participants