Skip to content

JIT: Improve codegen around unsigned comparisons#105593

Merged
EgorBo merged 3 commits intodotnet:mainfrom
EgorBo:extend-never-negative
Oct 4, 2024
Merged

JIT: Improve codegen around unsigned comparisons#105593
EgorBo merged 3 commits intodotnet:mainfrom
EgorBo:extend-never-negative

Conversation

@EgorBo
Copy link
Member

@EgorBo EgorBo commented Jul 27, 2024

  1. Recognize more "known non-negative" idioms in VN
  2. Normalize unsigned comparisons to signed when both of their operands are known non-negatives. Many existing optimizations such as RBO often give up on unsigned comparisons

Diffs

Motivated by #104728 (comment)

@ghost ghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 27, 2024
@EgorBo EgorBo added this to the 10.0.0 milestone Jul 27, 2024
@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.

@hez2010
Copy link
Contributor

hez2010 commented Jul 28, 2024

In System.Globalization.TextInfo:ChangeCaseCommon[System.Globalization.TextInfo+ToLowerConversion](System.String):System.String:this (Instrumented Tier1), a new bound check appears which seems to be a regression.

@EgorBo
Copy link
Member Author

EgorBo commented Jul 28, 2024

a new bound check appears which seems to be a regression.

Changes like these always produce a few regressions. In this case the problem that VN version of IsNeverNegative currently is not able to recognize Span.Length. It's something I want to fix one day

@xtqqczze
Copy link
Contributor

@MihuBot

@EgorBo
Copy link
Member Author

EgorBo commented Jul 30, 2024

an unrelated quick test:

@EgorBot -amd -arm64 -profiler

using System.Text.Json;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

public class MyBench
{
    public static IEnumerable<MyObj[]> TestData()
    {
        MyObj[] testData = new MyObj[100];
        for (int i = 0; i < testData.Length; i++)
        {
            MyObj obj1 = new("Some long ASCII text bla bla bla", 42, Guid.NewGuid(), DateTime.Now, null);
            MyObj obj2 = new("Какой-то non-ASCII text", i, Guid.NewGuid(), DateTime.Now, obj1);
            testData[i] = obj2;
        }
        yield return testData;
    }

    [Benchmark]
    [ArgumentsSource(nameof(TestData))]
    public object JsonStatham(MyObj[] arrays) => JsonSerializer.Serialize(arrays);
}

public record MyObj(string Name, int Age, Guid Id, DateTime Time, MyObj? InnerObj);

@EgorBot
Copy link

EgorBot commented Jul 30, 2024

Benchmark results on Amd
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
AMD EPYC 7763, 1 CPU, 8 logical and 4 physical cores
  Job-GOPINH : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
  Job-DTNGOB : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Method Toolchain arrays Mean Error Ratio
JsonStatham Main MyObj[100] 83.71 μs 0.071 μs 1.00
JsonStatham PR MyObj[100] 80.19 μs 0.093 μs 0.96

BDN_Artifacts.zip

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

@EgorBot
Copy link

EgorBot commented Jul 30, 2024

Benchmark results on Arm64
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
  Job-UQFNPH : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
  Job-LAMLQO : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Method Toolchain arrays Mean Error Ratio
JsonStatham Main MyObj[100] 82.63 μs 0.232 μs 1.00
JsonStatham PR MyObj[100] 82.04 μs 0.125 μs 0.99

BDN_Artifacts.zip

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

@dotnet dotnet deleted a comment from EgorBot Jul 30, 2024
@dotnet dotnet deleted a comment from EgorBot Jul 30, 2024
@EgorBo
Copy link
Member Author

EgorBo commented Oct 4, 2024

PTAL @AndyAyersMS @BruceForstall @dotnet/jit-contrib
small change, diffs.

TLDR: if we have op1 unsigned-relop op2 and we know that op1 and op2 are never negative - we can "normalize" the comparison to "signed-relop". Many existing branch/etc optimizations give up on unsigned relops due to, potentially, complex semantics.

PS: Will approved the PR (before the snap) but the approval is no longer green 😐

@EgorBo EgorBo merged commit 4bf7a2b into dotnet:main Oct 4, 2024
@EgorBo EgorBo deleted the extend-never-negative branch October 4, 2024 14:32
sirntar pushed a commit to sirntar/runtime that referenced this pull request Oct 8, 2024
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.

6 participants