Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numerical < and == comparisons aren't fused into <= #78385

Closed
stephentoub opened this issue Nov 15, 2022 · 7 comments · Fixed by #78786
Closed

Numerical < and == comparisons aren't fused into <= #78385

stephentoub opened this issue Nov 15, 2022 · 7 comments · Fixed by #78786
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@stephentoub
Copy link
Member

Repro:
SharpLab

#nullable disable
using System.Numerics;
using SharpLab.Runtime;

public class C
{
    [JitGeneric(typeof(int))]
    public static bool M1<T>(T value) where T : INumberBase<T> =>
        T.IsNegative(value) || T.IsZero(value);
    
    public static bool M2(int value) =>
        value < 0 || value == 0;
    
    [JitGeneric(typeof(int))]
    public static bool M3<T>(T value) where T : INumberBase<T>, IComparisonOperators<T,T,bool> =>
        value <= T.Zero;
    
    public static bool M4(int value) =>
        value <= 0;
}

Both M1 (generic) and M2 (non-generic) that do separate negative and zero checks produce:

    L0000: test ecx, ecx
    L0002: jl short L000c
    L0004: xor eax, eax
    L0006: test ecx, ecx
    L0008: sete al
    L000b: ret
    L000c: mov eax, 1
    L0011: ret

whereas both M3 (generic) and M4 (non-generic) that do combined negative and zero checks produce:

    L0000: xor eax, eax
    L0002: test ecx, ecx
    L0004: setle al
    L0007: ret

Similarly for >=.

The approved design of #78222 was based on the idea that these would be the same, and thus the generic methods there could constrain T to just being INumberBase<T> and not require IComparisonOperators<T,T,bool> as well, but if it's going to remain producing worse code, we should reconsider.

cc: @EgorBo, @tannergooding

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 15, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Nov 15, 2022
@ghost
Copy link

ghost commented Nov 15, 2022

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

Issue Details

Repro:
SharpLab

#nullable disable
using System.Numerics;
using SharpLab.Runtime;

public class C
{
    [JitGeneric(typeof(int))]
    public static bool M1<T>(T value) where T : INumberBase<T> =>
        T.IsNegative(value) || T.IsZero(value);
    
    public static bool M2(int value) =>
        value < 0 || value == 0;
    
    [JitGeneric(typeof(int))]
    public static bool M3<T>(T value) where T : INumberBase<T>, IComparisonOperators<T,T,bool> =>
        value <= T.Zero;
    
    public static bool M4(int value) =>
        value <= 0;
}

Both M1 (generic) and M2 (non-generic) that do separate negative and zero checks produce:

    L0000: test ecx, ecx
    L0002: jl short L000c
    L0004: xor eax, eax
    L0006: test ecx, ecx
    L0008: sete al
    L000b: ret
    L000c: mov eax, 1
    L0011: ret

whereas both M3 (generic) and M4 (non-generic) that do combined negative and zero checks produce:

    L0000: xor eax, eax
    L0002: test ecx, ecx
    L0004: setle al
    L0007: ret

Similarly for >=.

The approved design of #78222 was based on the idea that these would be the same, and thus the generic methods there could constrain T to just being INumberBase<T> and not require IComparisonOperators<T,T,bool> as well, but if it's going to remain producing worse code, we should reconsider.

cc: @EgorBo, @tannergooding

Author: stephentoub
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@EgorBo
Copy link
Member

EgorBo commented Nov 15, 2022

I have a branch that does this, it's just that I didn't see a lot of diffs from it and gave up, might give it a try again.
This might also be handled in optOptimizeBools. It looks similar to what we landed there recently by some community PR.

@stephentoub
Copy link
Member Author

I didn't see a lot of diffs from it

I expect that will change once #78222 happens and rolls out. :)

It's good to know this is fixable such that we don't need to change the API shape.

@EgorBo
Copy link
Member

EgorBo commented Nov 15, 2022

Similar to #61940 in case if @drewnoakes is interested in extending that to this case

@drewnoakes
Copy link
Member

Pinging @pedrobsaila who provided the implementation for that issue.

@EgorBo
Copy link
Member

EgorBo commented Nov 15, 2022

Ah, oops, pinged author of the issue instead of author of the PR 😄

@pedrobsaila
Copy link
Contributor

Interested :) You can assign the issue to me

@EgorBo EgorBo added this to the 8.0.0 milestone Nov 15, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Nov 15, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Nov 23, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jun 10, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Jul 10, 2023
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 a pull request may close this issue.

4 participants