Runtime: Is op switch bad performance or it just hard to use when compile code ?

Created on 17 Aug 2020  路  6Comments  路  Source: dotnet/runtime

Sample code

```C#
public int switcher(int Input)
{
switch (Input)
{
case 0:
return 255;
case 1:
return 128;
case 2:
case 3:
return 32;
default:
return -1;
}
}

### IL compile from code
.method public 
    instance int32 switcher (
        int32 Input
    ) cil managed 
{
    // Method begins at RVA 0x2058
    // Code size 42 (0x2a)
    .maxstack 2
    .locals init (
        [0] int32 switcher,
        [1] int32
    )

    IL_0000: ldarg.1
    IL_0001: stloc.1
    IL_0002: ldloc.1
    IL_0003: brtrue.s IL_000d

    IL_0005: ldc.i4 255
    IL_000a: stloc.0
    IL_000b: br.s IL_0028

    IL_000d: ldloc.1
    IL_000e: ldc.i4.1
    IL_000f: bne.un.s IL_0019

    IL_0011: ldc.i4 128
    IL_0016: stloc.0
    IL_0017: br.s IL_0028

    IL_0019: ldloc.1
    IL_001a: ldc.i4.2
    IL_001b: blt.s IL_0026

    IL_001d: ldloc.1
    IL_001e: ldc.i4.3
    IL_001f: bgt.s IL_0026

    IL_0021: ldc.i4.s 32
    IL_0023: stloc.0
    IL_0024: br.s IL_0028

    IL_0026: ldc.i4.m1
    IL_0027: stloc.0

    IL_0028: ldloc.0
    IL_0029: ret
} // end of method C::switcher
### What I think it should be
.method public 
    int32 switcher (int32 Input) cil managed 
{
    .maxstack 1

    ldarg.0
    switch(case0, case1, case2, case2)
            ldc.i4.m1
            ret
    case0:
            ldc.i4 256
            ret
    case1:
            ldc.i4 128
            ret
    case2:
            ldc.i4.s 32
           ret
}

```
I thought op switch work like Pigeonhole sort or indexing array, should it better performance then conditioning each branch ?

tenet-performance untriaged

All 6 comments

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

Compiling in debug?

e.g. dotnet build vs dotnet build -c Release

Debug sharplab.io

    .method public hidebysig 
        instance int32 switcher (
            int32 Input
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 56 (0x38)
        .maxstack 1
        .locals init (
            [0] int32,
            [1] int32,
            [2] int32
        )

        IL_0000: nop
        IL_0001: ldarg.1
        IL_0002: stloc.1
        // sequence point: hidden
        IL_0003: ldloc.1
        IL_0004: stloc.0
        // sequence point: hidden
        IL_0005: ldloc.0
        IL_0006: switch (IL_001d, IL_0025, IL_002d, IL_002d)

        IL_001b: br.s IL_0032

        IL_001d: ldc.i4 255
        IL_0022: stloc.2
        IL_0023: br.s IL_0036

        IL_0025: ldc.i4 128
        IL_002a: stloc.2
        IL_002b: br.s IL_0036

        IL_002d: ldc.i4.s 32
        IL_002f: stloc.2
        IL_0030: br.s IL_0036

        IL_0032: ldc.i4.m1
        IL_0033: stloc.2
        IL_0034: br.s IL_0036

        IL_0036: ldloc.2
        IL_0037: ret
    } // end of method C::switcher

Release sharplab.io

    .method public hidebysig 
        instance int32 switcher (
            int32 Input
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 41 (0x29)
        .maxstack 8

        // sequence point: hidden
        IL_0000: ldarg.1
        IL_0001: switch (IL_0018, IL_001e, IL_0024, IL_0024)

        IL_0016: br.s IL_0027

        IL_0018: ldc.i4 255
        IL_001d: ret

        IL_001e: ldc.i4 128
        IL_0023: ret

        IL_0024: ldc.i4.s 32
        IL_0026: ret

        IL_0027: ldc.i4.m1
        IL_0028: ret
    } // end of method C::switcher

Aside you may want to file in https://github.com/dotnet/roslyn repo which is where the C# compiler is

Thanks @benaadams , I see so it was out of update VB compiler cause this, I use ILadsm and recheck with Shapelab.io but not recheck with C# code.

Original code

    Function switcher(Input As int) As int
        Select Case Input
            Case 0
                Return 255
            Case 1
                Return 128
            Case 2 To 3
                Return 32
            Case Else
                Return -1
        End Select
    End Function

Yeah the VB does generate that sharplab.io; however its because of the 2 To 3; which is using more fancy conditional switching (similar to C#'s pattern matching switches)

Changing to a fall through like the C# you originally posted; then it ends up like you expect? sharplab.io

public class C
    Function switcher(Input As Integer) As Integer
        Select Case Input
            Case 0
                Return 255
            Case 1
                Return 128
            Case 2
            Case 3
                Return 32
        End Select
        Return -1
    End Function
End Class
    .method public specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2050
        // 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

    .method public 
        instance int32 switcher (
            int32 Input
        ) cil managed 
    {
        // Method begins at RVA 0x2058
        // Code size 51 (0x33)
        .maxstack 1
        .locals init (
            [0] int32 switcher,
            [1] int32
        )

        IL_0000: ldarg.1
        IL_0001: stloc.1
        IL_0002: ldloc.1
        IL_0003: switch (IL_001a, IL_0022, IL_002f, IL_002a)

        IL_0018: br.s IL_002f

        IL_001a: ldc.i4 255
        IL_001f: stloc.0
        IL_0020: br.s IL_0031

        IL_0022: ldc.i4 128
        IL_0027: stloc.0
        IL_0028: br.s IL_0031

        IL_002a: ldc.i4.s 32
        IL_002c: stloc.0
        IL_002d: br.s IL_0031

        IL_002f: ldc.i4.m1
        IL_0030: stloc.0

        IL_0031: ldloc.0
        IL_0032: ret
    } // end of method C::switcher

} // end of class C

Aside the https://github.com/dotnet/roslyn repo is also where the VB compiler is 馃槈

Case 2 goto IL_002f, it will return -1 instead 32; VB can't go through like C#.

Ah 馃槩 sharplab.io

public class C
    Function switcher(Input As Integer) As Integer
        Select Case Input
            Case 0
                Return 255
            Case 1
                Return 128
            Case 2
                Return 32
            Case 3
                Return 32
            Case Else 
                Return -1
        End Select
    End Function
End Class
.class public auto ansi C
    extends [System.Private.CoreLib]System.Object
{
    // Methods
    .method public specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2050
        // 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

    .method public 
        instance int32 switcher (
            int32 Input
        ) cil managed 
    {
        // Method begins at RVA 0x2058
        // Code size 56 (0x38)
        .maxstack 1
        .locals init (
            [0] int32 switcher,
            [1] int32
        )

        IL_0000: ldarg.1
        IL_0001: stloc.1
        IL_0002: ldloc.1
        IL_0003: switch (IL_001a, IL_0022, IL_002a, IL_002f)

        IL_0018: br.s IL_0034

        IL_001a: ldc.i4 255
        IL_001f: stloc.0
        IL_0020: br.s IL_0036

        IL_0022: ldc.i4 128
        IL_0027: stloc.0
        IL_0028: br.s IL_0036

        IL_002a: ldc.i4.s 32
        IL_002c: stloc.0
        IL_002d: br.s IL_0036

        IL_002f: ldc.i4.s 32
        IL_0031: stloc.0
        IL_0032: br.s IL_0036

        IL_0034: ldc.i4.m1
        IL_0035: stloc.0

        IL_0036: ldloc.0
        IL_0037: ret
    } // end of method C::switcher

} // end of class C
Was this page helpful?
0 / 5 - 0 ratings

Related issues

sahithreddyk picture sahithreddyk  路  3Comments

Timovzl picture Timovzl  路  3Comments

bencz picture bencz  路  3Comments

nalywa picture nalywa  路  3Comments

matty-hall picture matty-hall  路  3Comments