JIT: Convert multi-target switches to branchless checks#124567
JIT: Convert multi-target switches to branchless checks#124567JulieLeeMSFT merged 4 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
@EgorBo, PTAL. |
There was a problem hiding this comment.
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
fgOptimizeSwitchBranchesto 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.
| File | Description |
|---|---|
| src/coreclr/jit/fgopt.cpp | Implements the switch-to-range-check optimization with edge weight/dup count fixup and profile weight updates |
| src/tests/JIT/opt/OptSwitchRecognition/optSwitchRecognition.cs | Adds tests for zero-based (0-4) and non-zero-based (10-14) consecutive value ranges with comprehensive boundary cases |
2b0a347 to
8eae723
Compare
|
@EgorBo, I addressed all comments. It's ready to review. |
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
Co-authored-by: Egor Bogatov <egorbo@gmail.com>
|
/ba-g Failures are timeouts in Android pipeline. Not related to this PR. |
Fixes dotnet#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>
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 withor(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,
fgFoldCondToReturnBlockfurther folds this into branchless return.Example
Before
After
Details
ASMDiffs