dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.82k stars 4.62k forks source link

JIT: nullcheck is not folded for PHI #104489

Open EgorBo opened 1 month ago

EgorBo commented 1 month ago

Seems like global assertprop bails out on the following snippet

bool Test(bool cond)
{
    object tmp;
    if (cond)
        tmp = "1111";
    else
        tmp = "2222";
    return tmp != null;
}

Current codegen:

; Assembly listing for method Proga:Test(ubyte):ubyte (FullOpts)
G_M26246_IG01:  ;; offset=0x0000
G_M26246_IG02:  ;; offset=0x0000
       mov      rax, 0x20000209798      ; '2222'
       mov      rdx, 0x200002097B8      ; '1111'
       test     cl, cl
       cmovne   rax, rdx
       test     rax, rax
       setne    al
       movzx    rax, al
G_M26246_IG03:  ;; offset=0x0023
       ret      

Expected codegen:

; Assembly listing for method Proga:Test(ubyte):ubyte (FullOpts)
G_M26246_IG01:  ;; offset=0x0000
G_M26246_IG02:  ;; offset=0x0000
       mov      eax, 1
G_M26246_IG03:  ;; offset=0x0023
       ret      
dotnet-policy-service[bot] commented 1 month ago

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

EgorBo commented 1 week ago

@EgorBot -intel --runtimes net9.0 net8.0 net7.0 --disasm --envvars DOTNET_ReadyToRun:0

using BenchmarkDotNet.Attributes;

public class Bench
{
    string _str1 = "1234";
    string _str2 = "1235";

    [Benchmark]
    public bool StringEquals() => _str1 == _str2;
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-CMYLGI : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2 Job-HVKGGW : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job-MYVAUU : .NET 9.0.0 (9.0.24.40507), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI EnvironmentVariables=DOTNET_ReadyToRun=0 ``` | Method | Runtime | Mean | Error | Ratio | Code Size | |------------- |--------- |----------:|----------:|------:|----------:| | StringEquals | .NET 7.0 | 2.8705 ns | 0.0010 ns | 5.00 | 381 B | | StringEquals | .NET 8.0 | 2.9301 ns | 0.0024 ns | 5.11 | 452 B | | StringEquals | .NET 9.0 | 0.5739 ns | 0.0002 ns | 1.00 | 488 B | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_319521e7.zip)
EgorBo commented 1 week ago

@EgorBot -intel -arm

using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<PgoBenchmarks>(args: args);

[Config(typeof(MyEnvVars))]
[HideColumns("EnvironmentVariables", "Runtime")]
[DisassemblyDiagnoser]
public class PgoBenchmarks
{
    class MyEnvVars : ManualConfig
    {
        public MyEnvVars()
        {
            AddJob(Job.Default.WithId("8.0").WithRuntime(CoreRuntime.Core80));
            AddJob(Job.Default.WithId("8.0 R2R=0").WithRuntime(CoreRuntime.Core80)
                .WithEnvironmentVariables(
                    new EnvironmentVariable("DOTNET_ReadyToRun", "0")));

            AddJob(Job.Default.WithId("9.0").WithRuntime(CoreRuntime.Core90));
            AddJob(Job.Default.WithId("9.0 R2R=0").WithRuntime(CoreRuntime.Core90)
                .WithEnvironmentVariables(
                    new EnvironmentVariable("DOTNET_ReadyToRun", "0")));
        }
    }

    public static IEnumerable<object[]> TestData()
    {
        yield return new object[] { "1111", "1122" };
    }

    [Benchmark]
    [ArgumentsSource(nameof(TestData))]
    public bool StringEquals(string a, string b) => a == b;
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores 8.0 : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI 8.0 R2R=0 : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI 9.0 : .NET 9.0.0 (9.0.24.40507), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI 9.0 R2R=0 : .NET 9.0.0 (9.0.24.40507), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI ``` | Method | Job | a | b | Mean | Error | Code Size | |------------- |---------- |----- |----- |----------:|----------:|----------:| | StringEquals | 8.0 | 1111 | 1122 | 3.4578 ns | 0.0098 ns | 445 B | | StringEquals | 8.0 R2R=0 | 1111 | 1122 | 3.4430 ns | 0.0009 ns | 445 B | | StringEquals | 9.0 | 1111 | 1122 | 1.7208 ns | 0.0007 ns | 429 B | | StringEquals | 9.0 R2R=0 | 1111 | 1122 | 0.5740 ns | 0.0002 ns | 482 B | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_32b1d6c4.zip)
EgorBot commented 1 week ago
Benchmark results on Arm64 ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Unknown processor 8.0 : .NET 8.0.8 (8.0.824.36612), Arm64 RyuJIT AdvSIMD 8.0 R2R=0 : .NET 8.0.8 (8.0.824.36612), Arm64 RyuJIT AdvSIMD 9.0 : .NET 9.0.0 (9.0.24.40507), Arm64 RyuJIT AdvSIMD 9.0 R2R=0 : .NET 9.0.0 (9.0.24.40507), Arm64 RyuJIT AdvSIMD ``` | Method | Job | a | b | Mean | Error | Code Size | |------------- |---------- |----- |----- |---------:|----------:|----------:| | StringEquals | 8.0 | 1111 | 1122 | 4.674 ns | 0.0005 ns | 412 B | | StringEquals | 8.0 R2R=0 | 1111 | 1122 | 3.724 ns | 0.0005 ns | 412 B | | StringEquals | 9.0 | 1111 | 1122 | 3.250 ns | 0.0009 ns | 412 B | | StringEquals | 9.0 R2R=0 | 1111 | 1122 | 1.031 ns | 0.0003 ns | 432 B | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_8f06d4a3.zip)
EgorBo commented 1 week ago

@EgorBot -intel -arm64 -profiler -commit main

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBo commented 1 week ago

@EgorBot -intel -profiler -keep -commit main --envvars "DOTNETJitDisasm:GetType"

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBo commented 1 week ago

@EgorBot -intel -arm64 -profiler -commit main

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-VAJQNN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job=Job-VAJQNN EnvironmentVariables="DOTNET_JitDisasm=GetType_" Toolchain=CoreRun StdDev=0.0006 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 2.026 ns | 0.0007 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_301c7f40.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_301c7f40.svg) Hot asm: [Main](https://gist.github.com/EgorBot/ba28ac4810f8602f88d9afe0c050447b) Hot functions: [Main](https://gist.github.com/EgorBot/fe177b3c11561856e17e6729fdb0177d) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-CSOJHU : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job=Job-CSOJHU Toolchain=CoreRun StdDev=0.0011 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 1.417 ns | 0.0013 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_97ebad6b.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_97ebad6b.svg) Hot asm: [Main](https://gist.github.com/EgorBot/a87b8083f2b1fed88f1ed2bf2d68def3) Hot functions: [Main](https://gist.github.com/EgorBot/17bff4c5122cb901d60218e4a973585d) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBot commented 1 week ago
Benchmark results on Arm64 ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Unknown processor Job-PAJFFH : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD Job=Job-PAJFFH Toolchain=CoreRun StdDev=0.0014 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 3.079 ns | 0.0015 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_65604fde.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_65604fde.svg) Hot asm: [Main](https://gist.github.com/EgorBot/930195ed9698a522252c38f91906198d) Hot functions: [Main](https://gist.github.com/EgorBot/f03e45674df6b83013113eeec546e994) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBo commented 1 week ago

@EgorBot -intel -profiler -keep -commit main --envvars "DOTNETJitDisasm:GetType"

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBo commented 1 week ago

@EgorBot -intel -profiler -keep -commit main --envvars "DOTNETJitDisasm:GetType"

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-QFWLTK : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job=Job-QFWLTK EnvironmentVariables=DOTNET_JitDisasm=GetType_ Toolchain=CoreRun StdDev=0.0006 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 1.703 ns | 0.0006 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_d563da75.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_d563da75.svg) Hot asm: [Main](https://gist.github.com/EgorBot/0c5e09d0ea727f6c7a8556cef9609670) Hot functions: [Main](https://gist.github.com/EgorBot/9562c37b04fb14c54de6f1b869b30305) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBo commented 1 week ago

@EgorBot -intel -arm64 -profiler -commit main

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-HZRVFX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job=Job-HZRVFX Toolchain=CoreRun StdDev=0.0004 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 1.703 ns | 0.0005 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_0abe1800.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_0abe1800.svg) Hot asm: [Main](https://gist.github.com/EgorBot/91631c80d5583938b2b85bc1e5d28067) Hot functions: [Main](https://gist.github.com/EgorBot/c4fdfdf3df23ad76b80a85ae4971fa5b) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBo commented 1 week ago

@EgorBot -arm64 -profiler -commit main

using BenchmarkDotNet.Attributes;

public class Bench
{
        static object obj = new object();

        [Benchmark]
        public Type GetType_() => obj.GetType();
}
EgorBot commented 1 week ago
Benchmark results on Arm64 ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Unknown processor Job-QLXVYJ : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD Job=Job-QLXVYJ Toolchain=CoreRun StdDev=0.0014 ns ``` | Method | Mean | Error | |--------- |---------:|----------:| | GetType_ | 3.073 ns | 0.0015 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_00167357.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_00167357.svg) Hot asm: [Main](https://gist.github.com/EgorBot/1be0daf50697a8ab43e4dc4fa0e77e5e) Hot functions: [Main](https://gist.github.com/EgorBot/0acb60a6ae1d0374922716e33b2d99f4) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBo commented 1 week ago

@EgorBot -arm64 -intel -profiler -commit main

using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<PgoBenchmarks>(args: args);

public class PgoBenchmarks
{
    [Benchmark]
    public async Task<bool> Task1() => await Task2();

    [MethodImpl(MethodImplOptions.NoInlining)]
    public async Task<bool> Task2() => true;
}
EgorBot commented 1 week ago
Benchmark results on Intel ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores Job-YFCPJN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI Job=Job-YFCPJN Toolchain=CoreRun StdDev=0.049 ns ``` | Method | Mean | Error | |------- |---------:|---------:| | Task1 | 14.92 ns | 0.052 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_771404cd.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_771404cd.svg) Hot asm: [Main](https://gist.github.com/EgorBot/5a6ef5bb494a03b457af61fdcb672bd3) Hot functions: [Main](https://gist.github.com/EgorBot/b7c22ce1662ea9242ca66c21e17aa17a) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._
EgorBot commented 1 week ago
Benchmark results on Arm64 ``` BenchmarkDotNet v0.14.0, Ubuntu 22.04.4 LTS (Jammy Jellyfish) Unknown processor Job-HAVVTC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD Job=Job-HAVVTC Toolchain=CoreRun StdDev=0.012 ns ``` | Method | Mean | Error | |------- |---------:|---------:| | Task1 | 20.24 ns | 0.014 ns | [BDN_Artifacts.zip](https://telegafiles.blob.core.windows.net/telega/BDN_Artifacts_58eb65a8.zip) Flame graphs: [Main](https://telegafiles.blob.core.windows.net/telega/base_flamegraph_58eb65a8.svg) Hot asm: [Main](https://gist.github.com/EgorBot/f30f64b54ad0351db7d1a01e6366663c) Hot functions: [Main](https://gist.github.com/EgorBot/34166633e3262829b5c4e184c4cded0f) _For clean `perf` results, make sure you have just one `[Benchmark]` in your app._