Allow range check cloning for BBJ_RETURN blocks#124705
Open
Conversation
Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Optimize consecutive range checks in array access
Allow range check cloning for BBJ_RETURN blocks
Feb 21, 2026
EgorBo
approved these changes
Feb 21, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request enables range check cloning optimization for BBJ_RETURN blocks, addressing issue #79490 where consecutive array/span accesses in return statements resulted in redundant bounds checks. The optimization allows the JIT to clone return blocks into fast and slow paths, eliminating redundant bounds checks in the common case.
Changes:
- Modified scanning phase to process bounds checks in BBJ_RETURN block return statements (guarded by JIT32_GCENCODER and genReturnBB checks)
- Updated clone phase to handle BBJ_RETURN blocks without creating a diamond/join shape - both fast and fallback paths become BBJ_RETURN directly
- Added comprehensive test covering constant-index, variable-offset, and span access patterns with exception verification
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/coreclr/jit/rangecheckcloning.cpp | Implements BBJ_RETURN block range check cloning with conditional splitting logic and updated edge/weight handling |
| src/tests/JIT/opt/RangeChecks/ReturnBlockRangeCheckCloning.cs | Test file verifying range check cloning works for array/span accesses in return statements |
| src/tests/JIT/opt/RangeChecks/ReturnBlockRangeCheckCloning.csproj | Test project configuration following established patterns |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This was referenced Feb 21, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Diffs (size regression from cloned blocks, but pure PerfScore improvement).
Description
optRangeCheckCloningskips the last statement of all terminator blocks viablock->HasTerminator() && (stmt == block->lastStmt()). This means bounds checks in return statements are never considered for cloning:Changes:
BBJ_RETURNblocks, guarded by#ifndef JIT32_GCENCODER(x86 epilogue limit) andblock != genReturnBB(shared return block)fastpathBbisBBJ_RETURNandlastStmtis its last statement, skip the tail split — both fast and fallback paths becomeBBJ_RETURNdirectly (no diamond/join block needed)ReturnBlockRangeCheckCloningcovering constant-index, variable-offset, and span access patterns in return statements, plus out-of-range exception verificationOriginal prompt
This section details on the original issue you should resolve
<issue_title>Consecutive range checks are not combined</issue_title>
<issue_description>### Description
Consider the following code (inspired by dotnet/csharplang#4082 (comment)):
Note that it accesses the array multiple times at increasing indexes, which I think is a relatively common pattern. This results in one range check for every array access:
This is annoying, because only the check for
abcd[3]is necessary, since there are no side-effects between the array accesses. Even though these range checks are likely to be well predicted by the CPU, I think it would be nice if they could be elided by the JIT.This may very well be a duplicate, but I couldn't find it. Or it may not be worth tracking, in which case, feel free to close.
Configuration
Current SharpLab: Core CLR 7.0.22.51805 on x86
Regression?
Not that I know of.
</issue_description>
<agent_instructions>Fix codegen for #79490 via optRangeCheckCloning. optRangeCheckCloning currently gives up on BBJ_RETURN blocks with checks inside it (if it has just one statement for example) via
block->HasTerminator() && (stmt == block->lastStmt())check. We need to allow it for BBJ_RETURN and in case of BBJ_RETURN we can just duplicate return blocks without the diamond shape (but don't or when JIT32_GCENCODER is defined or genReturnBB matches return see fgFoldCondToReturnBlock for example). Add some test under src\tests\JIT\opt</agent_instructions>Comments on the Issue (you are @copilot in this section)
@ Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch See info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.Issue Details
Description
Consider the following code (inspired by dotnet/csharplang#4082 (comment)):
Note that it accesses the array multiple times at increasing indexes, which I think is a relatively common pattern. This results in one range check for every array access:
This is annoying, because only the check for
abcd[3]is necessary, since there are no side-effects between the array accesses. Even though these range checks are likely to be well predicted by the CPU, I think it would be nice if they could be elided by the JIT.This may very well be a duplicate, but I couldn't find it. Or it may not be worth tracking, in which case, feel free to close.
Configuration
Current SharpLab: Core CLR 7.0.22.51805 on x86
Regression?
Not that I know of.
tenet-performance,area-CodeGen-coreclr,untriaged💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.