dotnet / runtime

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

JIT: Optimize "x & cns == cns" pattern #101000

Open EgorBo opened 7 months ago

EgorBo commented 7 months ago

Noticed in https://github.com/dotnet/runtime/pull/100999:

void Foo(int x)
{
    if ((x & 0xC000000) == 0xC000000)
        Console.WriteLine();
}

Codegen on arm64:

            and     w0, w1, #0xC000000
            mov     w1, #0xC000000
            cmp     w0, w1
            bne     G_M37282_IG05

Expected codegen:

            mov     w1, #0xC000000
            bics    wzr, w8, w1
            bne     G_M37282_IG05

x64 is suboptimal for it as well, current codegen:

       and      edx, 0xC000000
       cmp      edx, 0xC000000
       jne      SHORT G_M37282_IG04

^ should be not + test.

dotnet-policy-service[bot] commented 7 months ago

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

quantumhu commented 6 months ago

Hi, I'd like to attempt this issue if no one else is, thanks!

quantumhu commented 5 months ago

I gave this fix a try, it seems to work for ARM, generating the bics instruction without a cmp.

However, on x_arch, I can get the andn instruction to be generated when hw intrinsics are enabled, but I'm unable to get the not test structure.

I can't figure out how to transform the tree of CMP(AND(NOT(x), y)) to turn into a test. There are options for GT_TEST_EQ and GT_TEST_NE, neither of which are what I want. I just want a TEST(NOT(x), y) structure where y is not necessarily 0 (TEST_EQ and TEST_NE both assume the second operand is 0). When I change the node type to GT_TEST, there's assert errors

Any tips that people can share about getting past this?

quantumhu commented 4 months ago

Hi @EgorBo, sorry to ping you, I figured out how to do the optimization change but I'm not sure how to interpret the pipeline results as I see some of them timed out. I also see a couple that are formatting related, but I can't seem to access the artifacts as described in the logs.

Here's the pull request: https://github.com/dotnet/runtime/pull/103868

Edit, to be more specific, I see some of these errors:

Assertion failed 'OperIs(GT_CNS_INT)' in 'System.Decimal:IsEvenInteger(System.Decimal):ubyte'

I tried to find this assert, wasn't sure which it was. I also tried to JitDisasm this, but couldn't get it to work. In addition, I am looking for a flag to set (but not sure what exists) that will make the bics save the result to wzr instead of an actual register

Thank you very much!