JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

JIT: Convert multi-target switches to branchless checks - #124567

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch
Feb 24, 2026
Merged

JIT: Convert multi-target switches to branchless checks#124567
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:optPatternMatchSwitch

Conversation

@JulieLeeMSFT

@JulieLeeMSFTJulieLeeMSFT commented Feb 18, 2026

Copy link
Copy Markdown
Member

Fixes#123858.

This PR improves JIT codegen for multi-target switch-style tests by converting eligible cases into branchless checks. The goal is to produce optimal codegen that matches the intent of C# pattern matching with or (e.g., x is A or B or C).

When a switch has exactly 2 unique successors (all non-default cases target one block, default targets another), convert it from Switch to an unsigned range comparison (In fgOptimizeSwitchBranches).
When both targets are simple return blocks, fgFoldCondToReturnBlock further folds this into branchless return.

Example

privatestaticboolIsLetterCategory(UnicodeCategoryuc){returnuc==UnicodeCategory.UppercaseLetter||uc==UnicodeCategory.LowercaseLetter||uc==UnicodeCategory.TitlecaseLetter||uc==UnicodeCategory.ModifierLetter||uc==UnicodeCategory.OtherLetter;}

Before

cmpecx,4ja SHORT G_M22758_IG05moveax,1retG_M22758_IG05:xoreax,eaxret

After

cmpecx,4setbe almovzxrax,alret

Details

  • The comparison direction is chosen to GT_LT.
  • Edge dup counts are fixed up after conversion.
  • Added tests for zero-based and non-zero-based consecutive ranges.

ASMDiffs

  • SPMI asmdiffs show code size improvements of 83 bytes.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Feb 18, 2026
CopilotAI review requested due to automatic review settings February 18, 2026 19:25
@JulieLeeMSFTJulieLeeMSFT added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 18, 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.

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, PTAL.
CC @dotnet/jit-contrib.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes multi-target switches where all non-default cases target a single block (distinct from the default target) by converting them into unsigned range comparisons. This enables branchless code generation when both targets are simple return blocks, addressing the disparity between pattern matching and explicit equality comparisons noted in issue #123858.

Changes:

  • Adds logic in fgOptimizeSwitchBranches to detect and optimize switches with exactly 2 unique successors
  • Transforms such switches into unsigned LE/GT comparisons, choosing the direction to favor fall-through
  • Adds comprehensive test coverage for both zero-based and non-zero-based consecutive ranges

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
src/coreclr/jit/fgopt.cppImplements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates
src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.csAdds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
CopilotAI review requested due to automatic review settings February 18, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

CopilotAI review requested due to automatic review settings February 18, 2026 23:01

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBo, I addressed all comments. It's ready to review.

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
Comment threadsrc/coreclr/jit/fgopt.cpp Outdated

@EgorBoEgorBo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with a few suggestions

Co-authored-by: Egor Bogatov <egorbo@gmail.com>
CopilotAI review requested due to automatic review settings February 23, 2026 19:53
Co-authored-by: Egor Bogatov <egorbo@gmail.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment threadsrc/coreclr/jit/fgopt.cpp
Comment threadsrc/coreclr/jit/fgopt.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g Failures are timeouts in Android pipeline. Not related to this PR.

@JulieLeeMSFT
JulieLeeMSFT merged commit c94ed87 into dotnet:mainFeb 24, 2026
133 of 135 checks passed
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
Fixesdotnet#123858.
This PR improves JIT codegen for multi-target `switch`-style tests by
converting eligible cases into branchless checks. The goal is to produce
optimal codegen that matches the intent of C# pattern matching with `or`
(e.g., `x is A or B or C`).
When a switch has exactly 2 unique successors (all non-default cases
target one block, default targets another), convert it from Switch to an
unsigned range comparison (In `fgOptimizeSwitchBranches`).
When both targets are simple return blocks, `fgFoldCondToReturnBlock`
further folds this into branchless return.
## Example
```csharp
private static bool IsLetterCategory(UnicodeCategory uc)
{
return uc == UnicodeCategory.UppercaseLetter
|| uc == UnicodeCategory.LowercaseLetter
|| uc == UnicodeCategory.TitlecaseLetter
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter;
}
```
## Before
```asm
cmp ecx, 4
ja SHORT G_M22758_IG05
mov eax, 1
ret
G_M22758_IG05:
xor eax, eax
ret
```
## After
```asm
cmp ecx, 4
setbe al
movzx rax, al
ret
```
## Details
- The comparison direction is chosen to GT_LT. - Edge dup counts are fixed up after conversion.
- Added tests for zero-based and non-zero-based consecutive ranges.
## ASMDiffs
- SPMI asmdiffs show code size improvements of 83 bytes.
---------
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

IL and asm differences from pattern matching vs comparisons

3 participants

@JulieLeeMSFT@EgorBo