Skip to content

JIT: (bug) XOR-based rotation recognition produces a wrong result when the shift count is a multiple of the operand width #133864

Description

@EgorBo

fgOperIsBitwiseRotationRoot accepts GT_XOR as a rotation root, but OR and XOR are only interchangeable when
the two shifted values have disjoint bits. With a variable count that is a multiple of the operand width both
sub-shifts equal x, so the XOR must be 0 while ROL(x, 0) is x.

Minimal Repro

using System;
using System.Runtime.CompilerServices;

public class Program
{
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    static int Test(int x, int y) => (x << (y & 31)) ^ (int)((uint)x >>> ((32 - y) & 31));

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    static long TestLong(long x, int y) => (x << (y & 63)) ^ (long)((ulong)x >>> ((64 - y) & 63));

    static void Main()
    {
        Console.WriteLine(Test(0x12345678, 0));
        Console.WriteLine(Test(0x12345678, 32));
        Console.WriteLine(TestLong(0x1234, 0));
    }
}

Both shift counts are explicitly masked, so no unspecified out-of-range shift behavior is involved.

Expected

0
0
0

(also what DOTNET_JITMinOpts=1 produces)

Actual

305419896
305419896
4660

The entire XOR tree collapses to a single rol, which is a no-op for count 0:

; Program:Test(int,int):int (FullOpts)
       mov      eax, ecx
       mov      ecx, edx
       rol      eax, cl
       ret

Notes

fgRecognizeAndMorphBitwiseRotation (morph.cpp) has no nonzero-count requirement for the GT_XOR root.
The GT_OR root is fine — (x << 0) | (x >>> N) yields x, matching ROL(x, 0).
Only the GT_XOR root with a variable rotate amount is affected; constant counts of 0 are already rejected
earlier by the overmask check.
Possible fix: only allow a GT_XOR root when the rotate amount is provably not a multiple of the operand width.
Also reproduces on .NET 10.0.12.

Activity

  1. added this to the 12.0.0 milestone on Sep 14, 2026
  2. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Sep 14, 2026
  3. dotnet-policy-service commented on Sep 14, 2026

    @dotnet-policy-service
    Contributor

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

  4. EgorBo commented on Sep 18, 2026

    @EgorBo
    MemberAuthor

    Affected SDK versions:

    • 8.0.425
    • 9.0.318
    • 10.0.401
    • 11.0.100-rc.2.26467.112
  5. added a commit that references this issue on Sep 24, 2026
    a3b1efa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions