views:

685

answers:

5

C#'s switch statement can compile to a CIL switch instruction, or if/else's, depending on the cases in the statement as mentioned here. Is there a way to force the compiler to always generate the if/else variant in a block of code?

+3  A: 

Can you provide more information about why you want to force a particular set of instructions to be generated?

Andrew
I have code generated by a lexical analyser that produces a lot of small switch statements with non-adjacent case's. When the code is compiled to IL and a jump table is used, it takes up massive amounts of memory.
Do you have any proof that this is happening or are you just guessing. I would expect the jitter to do what's best (or at least reasonably close to best) for each case
erikkallen
Yeah, I'm reading the generated IL code. For a switch with 3 case statements, depending on how far the values are apart, I can have a jump table of over 100 bytes. If you don't have many switch statements, or you have many adjacent cases, this is no big deal. For a lexical analyser that uses switch and can generate hundreds, or thousands of small switch's, this makes a big difference.
I would analyse the branches your program would like to emit and decide on a case-by-case basis whether to use `switch` or `if`/`else`, always assuming that the `switch` statement results in a jump table.
SealedSun
+5  A: 

The simplest way would be to use if/else in your code. Apart from anything else, that makes it clearer to the reader that that's what you want to happen instead of using a switch.

EDIT: Okay, so the readability isn't important for you - but basically if you want the compiled code to change, the source code is going to have to change. You could use the Mono compiler and modify it yourself, but I doubt that there's any way of getting the Microsoft compiler to effectively ignore that you're using a switch statement.

Jon Skeet
The switch statements are generated by a lexical analyser, so readability isn't a concern. Rewriting the generator to produce if/else's is a last resort :)
+1  A: 

Have you tried a different compiler (i.e., Mono), or tried to place your offending classes in a separate assembly and switch to a different language for it?

ballarewt
A: 

How are you making the compiler do this? I did a test with VS2008:

public static int DoSomething(int i) {
    switch (i) {
        case 1: return 0;
        case 100: return 1;
        case 1000: return 2;
        default: return 3;
    }
}

compiles to:

.method public hidebysig static int32 DoSomething(int32 i) cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 CS$1$0000,
        [1] int32 CS$4$0001)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: stloc.1 
    L_0003: ldloc.1 
    L_0004: ldc.i4.1 
    L_0005: beq.s L_0016
    L_0007: ldloc.1 
    L_0008: ldc.i4.s 100
    L_000a: beq.s L_001a
    L_000c: ldloc.1 
    L_000d: ldc.i4 0x3e8
    L_0012: beq.s L_001e
    L_0014: br.s L_0022
    L_0016: ldc.i4.0 
    L_0017: stloc.0 
    L_0018: br.s L_0026
    L_001a: ldc.i4.1 
    L_001b: stloc.0 
    L_001c: br.s L_0026
    L_001e: ldc.i4.2 
    L_001f: stloc.0 
    L_0020: br.s L_0026
    L_0022: ldc.i4.3 
    L_0023: stloc.0 
    L_0024: br.s L_0026
    L_0026: ldloc.0 
    L_0027: ret 
}

No switch instruction there.

Perhaps you should file a bug with Microsoft?

erikkallen
I don't have a compiler available ATM, but I'd be shocked if a jump table were created for a 3 case switch with values 1-1000 (so 1000 entries). Probably something closer to case 1: case 50:
So would I, but I would be surprised if the compiler didn't choose the optimal code also in your case. Note that just my three cases caused 20 IL instructions to be emitted.
erikkallen
The compiler does choose the optimal code for execution speed, I want to optimise for memory usage. the 20 IL instructions still take much less memory than a 50-100 entry jump table.
What does the JIT compiler do? It woudl be pointless to optimise the MSIL/CIL only to have the JIT compiler pessimize it.
Tim Long
A C# switch statement generates IL switch instructions only if your values are adjacent (give or take a few holes). It they're not, it will go with bgt (conditional jumps). VB's Select works the same way, for the switches, but will use regular if's if the values are not adjacent.
Yann Schwartz
A: 

No, you have no control over how the C# compiler will emit the CIL instructions. And even if you could, the AOT or JIT compiler might translate the CIL instructions to native machine code instructions vastly different than what you might expect due to advance compiler optimizations.

tgiphil