Skip to content

JIT: Transform '(cmp & x) | (cmp & y)' to 'cmp & (x | y)'#126070

Draft
BoyBaykiller wants to merge 2 commits intodotnet:mainfrom
BoyBaykiller:transform-double-and-or
Draft

JIT: Transform '(cmp & x) | (cmp & y)' to 'cmp & (x | y)'#126070
BoyBaykiller wants to merge 2 commits intodotnet:mainfrom
BoyBaykiller:transform-double-and-or

Conversation

@BoyBaykiller
Copy link
Contributor

No description provided.

@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 Mar 25, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 25, 2026
@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.

@BoyBaykiller
Copy link
Contributor Author

I am having a problem identifying certain cases.
Currently I detect such IR:

[000007] ----------- \--* OR int [000003] ----------- +--* AND int [000001] ----------- | +--* LCL_VAR int V02 arg2 [000002] ----------- | \--* CNS_INT int 256 [000006] ----------- \--* AND int [000004] ----------- +--* LCL_VAR int V02 arg2 (last use) [000005] ----------- \--* CNS_INT int 512 

Which works fine for (flags & 256) | (flags & 512),
but breaks down if I add a operation in front like 1 + (flags & 256) | (flags & 512). Then the IR is:

[000008] ----------- \--* OR int [000004] ----------- +--* ADD int [000000] ----------- | +--* CNS_INT int 1 [000003] ----------- | \--* AND int [000001] ----------- | +--* LCL_VAR int V01 arg1 [000002] ----------- | \--* CNS_INT int 256 [000007] ----------- \--* AND int [000005] ----------- +--* LCL_VAR int V01 arg1 [000006] ----------- \--* CNS_INT int 512 

When adding explicit parentheses like 1 + ((flags & 256) | (flags & 512)) it works again:

[000008] ----------- \--* ADD int [000000] ----------- +--* CNS_INT int 1 [000007] ----------- \--* OR int [000003] ----------- +--* AND int [000001] ----------- | +--* LCL_VAR int V01 arg1 [000002] ----------- | \--* CNS_INT int 256 [000006] ----------- \--* AND int [000004] ----------- +--* LCL_VAR int V01 arg1 [000005] ----------- \--* CNS_INT int 512 

But this shouldn't be needed. It shouldnt get confused by some extra commutative arithmetic like the ADD(1) here. What is the general way to fix this?

@huoyaoyuan
Copy link
Member

but breaks down if I add a operation in front like 1 + (flags & 256) | (flags & 512). Then the IR is:

The operator priority of | is lower than +. 1 + (flags & 256) | (flags & 512) means (1 + (flags & 256)) | (flags & 512). Check sharplab.

// Fold "(cmp & x) | (cmp & y)" to "cmp & (x | y)".
if (varTypeIsIntegralOrI(orOp) && op1->OperIs(GT_AND) && op2->OperIs(GT_AND))
{
if (GenTree::Compare(op1->gtGetOp1(), op2->gtGetOp1()))
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is legal - cmp may have side-effect or be a local whose value is changed via x or y

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

3 participants