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

Emit switch for suitable 'or' patterns #45679

Closed
YairHalberstadt opened this issue Jul 6, 2020 · 2 comments · Fixed by #65874
Closed

Emit switch for suitable 'or' patterns #45679

YairHalberstadt opened this issue Jul 6, 2020 · 2 comments · Fixed by #65874
Assignees
Labels
Area-Compilers Bug Code Gen Quality Room for improvement in the quality of the compiler's generated code Feature - Pattern Matching Pattern Matching help wanted The issue is "up for grabs" - add a comment if you are interested in working on it
Milestone

Comments

@YairHalberstadt
Copy link
Contributor

Version Used: master as of 3rd July

Steps to Reproduce:

Look at the IL for this code:

public class C 
{
    public bool M1(string a)
    {
        return (a is "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8");
    }
    public bool M2(string a)
    {
        switch (a) 
        {
            case "1":
            case "2":
            case "3":
            case "4":
            case "5":
            case "6":
            case "7":
            case "8":
                return true;
            default:
                return false;       
        }
    }
    
    public bool M1(int a)
    {
        return (a is 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8);
    }
    public bool M2(int a)
    {
        switch (a) 
        {
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
                return true;
            default:
                return false;       
        }
    }
}

IL:

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit C
    extends [System.Private.CoreLib]System.Object
{
    // Methods
    .method public hidebysig 
        instance bool M1 (
            string a
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 105 (0x69)
        .maxstack 2

        IL_0000: ldarg.1
        IL_0001: ldstr "1"
        IL_0006: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_000b: brtrue.s IL_0067

        IL_000d: ldarg.1
        IL_000e: ldstr "2"
        IL_0013: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0018: brtrue.s IL_0067

        IL_001a: ldarg.1
        IL_001b: ldstr "3"
        IL_0020: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0025: brtrue.s IL_0067

        IL_0027: ldarg.1
        IL_0028: ldstr "4"
        IL_002d: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0032: brtrue.s IL_0067

        IL_0034: ldarg.1
        IL_0035: ldstr "5"
        IL_003a: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_003f: brtrue.s IL_0067

        IL_0041: ldarg.1
        IL_0042: ldstr "6"
        IL_0047: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_004c: brtrue.s IL_0067

        IL_004e: ldarg.1
        IL_004f: ldstr "7"
        IL_0054: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0059: brtrue.s IL_0067

        IL_005b: ldarg.1
        IL_005c: ldstr "8"
        IL_0061: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0066: ret

        IL_0067: ldc.i4.1
        IL_0068: ret
    } // end of method C::M1

    .method public hidebysig 
        instance bool M2 (
            string a
        ) cil managed 
    {
        // Method begins at RVA 0x20c8
        // Code size 240 (0xf0)
        .maxstack 2
        .locals init (
            [0] uint32
        )

        // sequence point: hidden
        IL_0000: ldarg.1
        IL_0001: call uint32 '<PrivateImplementationDetails>'::ComputeStringHash(string)
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldc.i4 856466825
        IL_000d: bgt.un.s IL_0047

        IL_000f: ldloc.0
        IL_0010: ldc.i4 822911587
        IL_0015: bgt.un.s IL_002f

        IL_0017: ldloc.0
        IL_0018: ldc.i4 806133968
        IL_001d: beq IL_00b2

        IL_0022: ldloc.0
        IL_0023: ldc.i4 822911587
        IL_0028: beq.s IL_00a3

        IL_002a: br IL_00ee

        IL_002f: ldloc.0
        IL_0030: ldc.i4 839689206
        IL_0035: beq IL_00d0

        IL_003a: ldloc.0
        IL_003b: ldc.i4 856466825
        IL_0040: beq.s IL_00c1

        IL_0042: br IL_00ee

        IL_0047: ldloc.0
        IL_0048: ldc.i4 906799682
        IL_004d: bgt.un.s IL_0064

        IL_004f: ldloc.0
        IL_0050: ldc.i4 873244444
        IL_0055: beq.s IL_0076

        IL_0057: ldloc.0
        IL_0058: ldc.i4 906799682
        IL_005d: beq.s IL_0094

        IL_005f: br IL_00ee

        IL_0064: ldloc.0
        IL_0065: ldc.i4 923577301
        IL_006a: beq.s IL_0085

        IL_006c: ldloc.0
        IL_006d: ldc.i4 1024243015
        IL_0072: beq.s IL_00df

        IL_0074: br.s IL_00ee

        IL_0076: ldarg.1
        IL_0077: ldstr "1"
        IL_007c: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0081: brtrue.s IL_00ec

        IL_0083: br.s IL_00ee

        IL_0085: ldarg.1
        IL_0086: ldstr "2"
        IL_008b: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_0090: brtrue.s IL_00ec

        IL_0092: br.s IL_00ee

        IL_0094: ldarg.1
        IL_0095: ldstr "3"
        IL_009a: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_009f: brtrue.s IL_00ec

        IL_00a1: br.s IL_00ee

        IL_00a3: ldarg.1
        IL_00a4: ldstr "4"
        IL_00a9: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_00ae: brtrue.s IL_00ec

        IL_00b0: br.s IL_00ee

        IL_00b2: ldarg.1
        IL_00b3: ldstr "5"
        IL_00b8: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_00bd: brtrue.s IL_00ec

        IL_00bf: br.s IL_00ee

        IL_00c1: ldarg.1
        IL_00c2: ldstr "6"
        IL_00c7: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_00cc: brtrue.s IL_00ec

        IL_00ce: br.s IL_00ee

        IL_00d0: ldarg.1
        IL_00d1: ldstr "7"
        IL_00d6: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_00db: brtrue.s IL_00ec

        IL_00dd: br.s IL_00ee

        IL_00df: ldarg.1
        IL_00e0: ldstr "8"
        IL_00e5: call bool [System.Private.CoreLib]System.String::op_Equality(string, string)
        IL_00ea: brfalse.s IL_00ee

        IL_00ec: ldc.i4.1
        IL_00ed: ret

        IL_00ee: ldc.i4.0
        IL_00ef: ret
    } // end of method C::M2

    .method public hidebysig 
        instance bool M1 (
            int32 a
        ) cil managed 
    {
        // Method begins at RVA 0x21c4
        // Code size 35 (0x23)
        .maxstack 8

        IL_0000: ldarg.1
        IL_0001: ldc.i4.1
        IL_0002: beq.s IL_0021

        IL_0004: ldarg.1
        IL_0005: ldc.i4.2
        IL_0006: beq.s IL_0021

        IL_0008: ldarg.1
        IL_0009: ldc.i4.3
        IL_000a: beq.s IL_0021

        IL_000c: ldarg.1
        IL_000d: ldc.i4.4
        IL_000e: beq.s IL_0021

        IL_0010: ldarg.1
        IL_0011: ldc.i4.5
        IL_0012: beq.s IL_0021

        IL_0014: ldarg.1
        IL_0015: ldc.i4.6
        IL_0016: beq.s IL_0021

        IL_0018: ldarg.1
        IL_0019: ldc.i4.7
        IL_001a: beq.s IL_0021

        IL_001c: ldarg.1
        IL_001d: ldc.i4.8
        IL_001e: ceq
        IL_0020: ret

        IL_0021: ldc.i4.1
        IL_0022: ret
    } // end of method C::M1

    .method public hidebysig 
        instance bool M2 (
            int32 a
        ) cil managed 
    {
        // Method begins at RVA 0x21e8
        // Code size 10 (0xa)
        .maxstack 8

        // sequence point: hidden
        IL_0000: ldarg.1
        IL_0001: ldc.i4.1
        IL_0002: sub
        IL_0003: ldc.i4.7
        IL_0004: bgt.un.s IL_0008

        IL_0006: ldc.i4.1
        IL_0007: ret

        IL_0008: ldc.i4.0
        IL_0009: ret
    } // end of method C::M2

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x21f3
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: ret
    } // end of method C::.ctor

} // end of class C

.class private auto ansi sealed '<PrivateImplementationDetails>'
    extends [System.Private.CoreLib]System.Object
{
    .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    // Methods
    .method assembly hidebysig static 
        uint32 ComputeStringHash (
            string s
        ) cil managed 
    {
        // Method begins at RVA 0x21fc
        // Code size 44 (0x2c)
        .maxstack 2
        .locals init (
            [0] uint32,
            [1] int32
        )

        IL_0000: ldarg.0
        IL_0001: brfalse.s IL_002a

        IL_0003: ldc.i4 -2128831035
        IL_0008: stloc.0
        IL_0009: ldc.i4.0
        IL_000a: stloc.1
        IL_000b: br.s IL_0021
        // loop start (head: IL_0021)
            IL_000d: ldarg.0
            IL_000e: ldloc.1
            IL_000f: callvirt instance char [System.Private.CoreLib]System.String::get_Chars(int32)
            IL_0014: ldloc.0
            IL_0015: xor
            IL_0016: ldc.i4 16777619
            IL_001b: mul
            IL_001c: stloc.0
            IL_001d: ldloc.1
            IL_001e: ldc.i4.1
            IL_001f: add
            IL_0020: stloc.1

            IL_0021: ldloc.1
            IL_0022: ldarg.0
            IL_0023: callvirt instance int32 [System.Private.CoreLib]System.String::get_Length()
            IL_0028: blt.s IL_000d
        // end loop

        IL_002a: ldloc.0
        IL_002b: ret
    } // end of method '<PrivateImplementationDetails>'::ComputeStringHash

} // end of class <PrivateImplementationDetails>

Expected Behavior:
Same IL for both M1 and M2

Actual Behavior:
Differing IL for M1 and M2

@alrz

This comment was marked as duplicate.

@gafter gafter added Area-Compilers Code Gen Quality Room for improvement in the quality of the compiler's generated code Feature - Pattern Matching Pattern Matching labels Jul 6, 2020
@gafter gafter added this to the Compiler.Next milestone Jul 6, 2020
@jaredpar jaredpar added the Bug label Jul 7, 2020
@jcouv jcouv added the untriaged Issues and PRs which have not yet been triaged by a lead label Apr 15, 2022
@jcouv
Copy link
Member

jcouv commented Apr 15, 2022

Tagging @stephentoub as FYI (since closed #58246 as duplicate of this)

@jcouv jcouv modified the milestones: Compiler.Next, C# 11.0 Apr 27, 2022
@jcouv jcouv removed the untriaged Issues and PRs which have not yet been triaged by a lead label Apr 27, 2022
@jaredpar jaredpar modified the milestones: C# 11.0, 17.4 Jun 24, 2022
@jaredpar jaredpar modified the milestones: 17.4, Backlog Jul 20, 2022
@jaredpar jaredpar added the help wanted The issue is "up for grabs" - add a comment if you are interested in working on it label Jul 20, 2022
@jcouv jcouv closed this as completed in e5ef66e Jan 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Bug Code Gen Quality Room for improvement in the quality of the compiler's generated code Feature - Pattern Matching Pattern Matching help wanted The issue is "up for grabs" - add a comment if you are interested in working on it
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

6 participants