Skip to content

JIT: Add more specific range assertion for bitwise and/or#120980

Merged
adamperlin merged 10 commits intodotnet:mainfrom
adamperlin:adamperlin/optimize-and-range-assertion
Nov 7, 2025
Merged

JIT: Add more specific range assertion for bitwise and/or#120980
adamperlin merged 10 commits intodotnet:mainfrom
adamperlin:adamperlin/optimize-and-range-assertion

Conversation

@adamperlin
Copy link
Contributor

@adamperlin adamperlin commented Oct 22, 2025

This is an attempt to address #119962 by adding a new range assertion for x & cns when cns can be determined to be within [0, 1]. Possible improvements are incoming to generalize this to other constants, as well as new possible assertions for bitwise or.

@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 Oct 22, 2025
@dotnet-policy-service
Copy link
Contributor

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

@adamperlin adamperlin changed the title [test] JIT: Add more specific range assertion for bitwise and with 0, 1 JIT: Add more specific range assertion for bitwise and with 0, 1 Oct 24, 2025
@adamperlin adamperlin changed the title JIT: Add more specific range assertion for bitwise and with 0, 1 JIT: Add more specific range assertion for bitwise and/or Oct 29, 2025
@adamperlin adamperlin marked this pull request as ready for review October 30, 2025 21:11
Copilot AI review requested due to automatic review settings October 30, 2025 21:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances the integral range analysis in the JIT compiler's assertion propagation to improve range inference for bitwise AND (GT_AND) and OR (GT_OR) operations, as well as non-negative constant values (GT_CNS_INT). These improvements enable better optimization opportunities by providing more precise range information.

  • Adds range computation for GT_AND operations considering when operands are non-negative
  • Adds range computation for GT_OR operations when both operands are non-negative
  • Extends GT_CNS_INT handling to recognize all non-negative constants (not just 0 and 1)

@adamperlin
Copy link
Contributor Author

adamperlin commented Oct 30, 2025

There are a few interesting regressions here in some numeric operators like
System.Byte:System.Numerics.IBitwiseOperators.op_BitwiseAnd(byte,byte):byte:

@@ -17,14 +17,15 @@
 G_M24733_IG01:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref, nogc <-- Prolog IG
 						;; size=0 bbWeight=1 PerfScore 0.00
 G_M24733_IG02:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
-       and      ecx, edx
        movzx    rax, cl
-						;; size=5 bbWeight=1 PerfScore 0.50
+       movzx    rcx, dl
+       and      eax, ecx
+						;; size=8 bbWeight=1 PerfScore 0.75
 G_M24733_IG03:        ; bbWeight=1, epilog, nogc, extend
        ret      
 						;; size=1 bbWeight=1 PerfScore 1.00
 
-; Total bytes of code 6, prolog size 0, PerfScore 1.50, instruction count 3, allocated bytes for code 6 (MethodHash=105b9f62) for method System.Byte:System.Numerics.IBitwiseOperators<System.Byte,System.Byte,System.Byte>.op_BitwiseAnd(byte,byte):byte (FullOpts)
+; Total bytes of code 9, prolog size 0, PerfScore 1.75, instruction count 4, allocated bytes for code 9 (MethodHash=105b9f62) for method System.Byte:System.Numerics.IBitwiseOperators<System.Byte,System.Byte,System.Byte>.op_BitwiseAnd(byte,byte):byte (FullOpts)
 ; ============================================================

I investigated this some. The IL tree looks like this:

N007 (  9, 12) [000004] -----+-----                         *  RETURN    int    $VN.Void
N006 (  8, 11) [000003] -----+-----                         \--*  CAST      int <- ubyte <- int $103
N005 (  7,  9) [000002] -----+-----                            \--*  AND       int    $102
N002 (  3,  4) [000005] -----+-----                               +--*  CAST      int <- ubyte <- int $100
N001 (  2,  2) [000000] -----+-----                               |  \--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N004 (  3,  4) [000006] -----+-----                               \--*  CAST      int <- ubyte <- int $101
N003 (  2,  2) [000001] -----+-----                                  \--*  LCL_VAR   int    V01 arg1         u:1 (last use) $81

Before, the CAST(AND(CAST(x), CAST(y))) would be optimized to CAST(AND(x, y)) by fgSimpleLowerCastOfSmpOp during the rationalize phase, and we'd get:

N007 (  9, 12) [000004] -----+-----                         *  RETURN    int    $VN.Void
N006 (  8, 11) [000003] -----+-----                         \--*  CAST      int <- ubyte <- int $103
N005 (  7,  9) [000002] -----+-----                            \--*  AND       int    $102
N001 (  2,  2) [000000] -----+-----                               |  \--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N003 (  2,  2) [000001] -----+-----                                  \--*  LCL_VAR   int    V01 arg1         u:1 (last use) $81

Now this new optimization lets us remove the outermost cast in this case, but two inner two casts of the LCL_VAR nodes aren't removed, so we have:

N007 (  9, 12) [000004] -----+-----                         *  RETURN    int    $VN.Void
N005 (  7,  9) [000002] -----+-----                            \--*  AND       int    $102
N002 (  3,  4) [000005] -----+-----                               +--*  CAST      int <- ubyte <- int $100
N001 (  2,  2) [000000] -----+-----                               |  \--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N004 (  3,  4) [000006] -----+-----                               \--*  CAST      int <- ubyte <- int $101
N003 (  2,  2) [000001] -----+-----                                  \--*  LCL_VAR   int    V01 arg1         u:1 (last use) $81

I'm pretty sure this is what is accounting for the diff in cases like these.

@adamperlin
Copy link
Contributor Author

@EgorBo @tannergooding I think this one is ready for another look. I have opened issue #121384 to address the regression described above. After talking with Egor I decided not to add an OR case here to simplify this PR, though this could be addressed later and added back in. Diffs look good.

Copy link
Member

@tannergooding tannergooding left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@EgorBo EgorBo left a comment

Choose a reason for hiding this comment

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

LGTM!

@EgorBo
Copy link
Member

EgorBo commented Nov 6, 2025

/azp run Fuzzlyn

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamperlin adamperlin enabled auto-merge (squash) November 6, 2025 21:45
@adamperlin
Copy link
Contributor Author

Fuzzlyn failures seem expected, stemming from existing issues from previous runs as well as runtime async.

@adamperlin
Copy link
Contributor Author

/ba-g infrastructure issue with no specific error message

@adamperlin adamperlin merged commit c2e6bff into dotnet:main Nov 7, 2025
111 of 129 checks passed
@adamperlin adamperlin deleted the adamperlin/optimize-and-range-assertion branch November 7, 2025 22:43
@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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.

4 participants