Skip to content

JIT: Constant fold SequenceEqual with the help of VN#121985

Merged
EgorBo merged 21 commits into
dotnet:mainfrom
hez2010:memcmp-fold
Mar 30, 2026
Merged

JIT: Constant fold SequenceEqual with the help of VN#121985
EgorBo merged 21 commits into
dotnet:mainfrom
hez2010:memcmp-fold

Conversation

@hez2010

@hez2010 hez2010 commented Nov 26, 2025

Copy link
Copy Markdown
Contributor

Try to fold SequenceEqual with the help of VN.

Codegen for

Test.CompareStr();

class Test
{
    public static string Str1 => "abcdef";
    public static string Str2 => "bcdefg";

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static bool CompareStr()
    {
        return Str1.Equals(Str2);
    }
}

Before:

G_M64625_IG01:  ;; offset=0x0000
                                                ;; size=0 bbWeight=1 PerfScore 0.00
G_M64625_IG02:  ;; offset=0x0000
       mov      rax, 0x2DA4A1AEFF0      ; 'abcdef'
       add      rax, 12
       mov      rcx, 0x2DA4A1AF024
       mov      rdx, qword ptr [rax]
       mov      rax, qword ptr [rax+0x04]
       mov      r8, qword ptr [rcx]
       xor      rdx, r8
       xor      rax, qword ptr [rcx+0x04]
       or       rax, rdx
       sete     al
       movzx    rax, al
                                                ;; size=50 bbWeight=1 PerfScore 11.50
G_M64625_IG03:  ;; offset=0x0032
       ret
                                                ;; size=1 bbWeight=1 PerfScore 1.00

After:

G_M64625_IG01:  ;; offset=0x0000
                                                ;; size=0 bbWeight=1 PerfScore 0.00
G_M64625_IG02:  ;; offset=0x0000
       xor      eax, eax
                                                ;; size=2 bbWeight=1 PerfScore 0.25
G_M64625_IG03:  ;; offset=0x0002
       ret
                                                ;; size=1 bbWeight=1 PerfScore 1.00

Copilot AI review requested due to automatic review settings November 26, 2025 12:09
@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 Nov 26, 2025
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Nov 26, 2025
@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.

Copilot AI 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 adds a JIT optimization to constant fold SequenceEqual operations using Value Numbering (VN). When the length is known at compile time and within unrolling thresholds, the JIT can either fold to a constant (if both memory regions are immutable and known) or unroll into an efficient load/compare chain using XOR and OR operations.

Key Changes

  • Adds optVNBasedFoldExpr_Call_Memcmp to unroll NI_System_SpanHelpers_SequenceEqual for constant-length comparisons
  • Introduces Memcmp to the UnrollKind enum with platform-specific thresholds (4x maxRegSize, 12x on ARM64)
  • Implements XOR+OR accumulation pattern for comparing memory chunks, similar to existing memcpy/memmove optimizations

Reviewed changes

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

File Description
src/coreclr/jit/compiler.h Adds function declaration for optVNBasedFoldExpr_Call_Memcmp, adds Memcmp to UnrollKind enum, and sets unroll thresholds
src/coreclr/jit/assertionprop.cpp Implements the core optimization logic to unroll SequenceEqual, including constant folding and XOR-based comparison chain generation

@EgorBo

EgorBo commented Nov 26, 2025

Copy link
Copy Markdown
Member

If you want to fold SequenceEquals to true/false, then you can do that in the valuenum phase.
For the unrolling to a set of IND nodes - I don't see what it can catch that LowerCallMemcmp won't handle to be honest, any example?

@EgorBo

EgorBo commented Nov 26, 2025

Copy link
Copy Markdown
Member

E.g. the point of optVNBasedFoldExpr_Call_Memmove to exist is that it can see RVA const data and emit const values to be memmoved - LowerMemmove cannot do it. In your case you don't take advantage of seeing string's content when you unroll to indirs (JitOptRepeat probably could help, but we cannot use it today)

@hez2010

hez2010 commented Nov 26, 2025

Copy link
Copy Markdown
Contributor Author

For the unrolling to a set of IND nodes - I don't see what it can catch that LowerCallMemcmp won't handle to be honest, any example?

Yeah. I noticed this as well. Well there was several minor differences on register selection and unaligned loads btw. Removed the IND nodes unrolling.

Comment thread src/coreclr/jit/assertionprop.cpp
Comment thread src/coreclr/jit/assertionprop.cpp
Comment thread src/coreclr/jit/assertionprop.cpp Outdated
Comment thread src/coreclr/jit/assertionprop.cpp Outdated
Comment thread src/coreclr/jit/assertionprop.cpp Outdated
@hez2010

hez2010 commented Nov 26, 2025

Copy link
Copy Markdown
Contributor Author

@MihuBot

@EgorBo EgorBo 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, thanks. I'll move the importervectorization.cpp to that function eventually.

PS: Just Equality to 1/0 could've been done in the VN phase, but this is fine too as it might find more cases after assertions.

@EgorBo

EgorBo commented Nov 26, 2025

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib

Comment thread src/coreclr/jit/assertionprop.cpp Outdated
Comment thread src/coreclr/jit/assertionprop.cpp Outdated
@AndyAyersMS

Copy link
Copy Markdown
Member

PS: Just Equality to 1/0 could've been done in the VN phase, but this is fine too as it might find more cases after assertions.

But doing it in VN might unblock RBO, etc...

Copilot AI 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 4 out of 4 changed files in this pull request and generated no new comments.

@EgorBo EgorBo 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, thanks!

Copilot AI review requested due to automatic review settings February 23, 2026 02:31

Copilot AI 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 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/assertionprop.cpp
Copilot AI review requested due to automatic review settings March 5, 2026 08:38

Copilot AI 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 4 out of 4 changed files in this pull request and generated no new comments.

@EgorBo EgorBo merged commit d473783 into dotnet:main Mar 30, 2026
129 of 135 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 30, 2026
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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants