4

I'm making a small language that is very similar to hlsl but supports only pixel shaders. This language uses reflection.emit to build .NET assemblies that implement the same functionality. I'm currently testing my implementation of the branch instruction if and in one of my unit tests (a large if with inner if/elses) failed with the following error message:

System.NotSupportedException : Illegal one-byte branch at position: 32. Requested branch was: 132.

I've traced the problem to the use of short form instructions in my case OpCodes.Br_S. The solution was simple, I've replaced OpCodes.Br_S with OpCodes.Br however I have a couple of questions about this solution:

Does this solution have an impact on the performance of the generated code?

If I want to correctly generate Br_S for single byte and Br for the other cases how can I do that? The problem here is that I'm using a visitor pattern and for a branch instruction like the if I have to output Br or Br_s first and at that point, I have no way of knowing if the remaining code will require more than a single byte to jump to the label. To better illustrate my question this is the code that I generate for the following statements:

My Language:

int a = -1; if (1>1) { a=1; } else if (2>2) { a=2; }

IL:

.method public virtual final instance int32 Main() cil managed
{

    .maxstack 4
    .locals init (
        [0] int32 num)
    L_0000: ldc.i4.m1 
    L_0001: stloc.0 
    L_0002: ldc.i4.1 
    L_0003: ldc.i4.1 
    L_0004: ble.s L_000a
    L_0006: ldc.i4.1 
    L_0007: stloc.0 
    L_0008: br.s L_0010
    L_000a: ldc.i4.2 
    L_000b: ldc.i4.2 
    L_000c: ble.s L_0010
    L_000e: ldc.i4.2 
    L_000f: stloc.0 
    L_0010: ldloc.0 
    L_0011: ret 
}

In this case, I'm using two short form instructions ble.s and br.s to implement the ifs just like what the .NET compiler does. However .NET compiler is able to choose br.s or br according to the cases, my problem is how can I do something similar?

Tnks

Sasha
  • 827
  • 1
  • 9
  • 16
Ivo Leitão
  • 337
  • 1
  • 4
  • 16
  • 3
    Your IL is a bit bigger, no big deal. Trust the JIT compiler to get this right. These micro optimizations are not worth your time. – Hans Passant Aug 12 '10 at 18:05
  • I would like to do that but i need to generate the IL myself because there is no c# compiler in silverlight for example. I would like to use this in silverlight and also in other environments that do not have a compiler available... – Ivo Leitão Aug 12 '10 at 18:07
  • I believe Hans is suggesting that you not bother with the short form (which you're having a problem with) and use the standard long-form one since this optimization will happen automatically with the JIT (which Silverlight has, just like any other CLR impl) – Kirk Woll Aug 12 '10 at 23:05
  • Humm ? That is strange... if that is the case why two different opcodes ? If the Jit compiler is smart enough to make this optimization I can not really understand the short form versions of the opcodes. Anyone knows why they exist then ? Also there's a lot of libraries out there that explicitly take care of similar situations for example they do something like this if (index <= Byte.MaxValue) ig.Emit(OpCodes.Ldarg_S, (byte)index); else ig.Emit(OpCodes.Ldarg, index); – Ivo Leitão Aug 12 '10 at 23:20

1 Answers1

7

If you want to do this, you'll need to calculate the offset to the branch target before generating the branch itself, and then determine if the offset is small enough to be reached by the short form instruction. I don't think that there's a particularly easy way to do this using the Reflection.Emit library.

kvb
  • 54,864
  • 2
  • 91
  • 133
  • Please, i'm interested in understanding this response. I'm having a similar problem. What offest are you talking about? Can you explain with some kind of illustration. You can also point me to other resources that i can benefit from. Thanks in advance. – Orson Sep 24 '12 at 08:00
  • 3
    @ColourBlend - Branch instructions have a target, which is specified as an offset in IL code, even though the `ILGenerator` API lets you just pass in a label (and the framework calculates the relevant offset based on where the label is placed). `Br_S` (and other short instructions) require that the offset can fit into a byte (that is, an offset of no more than 127 bytes in the instruction stream). Does that help? – kvb Sep 24 '12 at 14:03
  • Thanks. It was helpful. I looked into it a bit before you reply though. Does a DynamicMethod run faster than it's equivalent static method (Design time methods)? Will translating a design time method into MSIL improve performance? – Orson Sep 24 '12 at 16:15
  • I'm currently working on small Data Access Mapper just for stored procedures. I have a working version with most of the basic features. I want to optimize it's performance and i would like to know if you can be of help. – Orson Sep 25 '12 at 07:30
  • @ColourBlend - My suggestion would be to implement things both ways and profile them to see which one is faster. If you have a specific question, better to open a new question here than ask it in the comments. – kvb Sep 25 '12 at 13:41
  • How can i contact you personally (facebook, email, twitter, ...)? – Orson Sep 25 '12 at 13:59
  • @ColourBlend - Sorry, I don't publicize my contact info. – kvb Sep 25 '12 at 19:34