title: Generate tail call opcode
body: <p>Out of curiosity I was trying to generate a tail call opcode using C#.  Fibinacci is an easy one, so my c# example looks like this:</p>
  
  <pre><code>    private static void Main(string[] args)
      {
          Console.WriteLine(Fib(int.MaxValue, 0));
      }
  
      public static int Fib(int i, int acc)
      {
          if (i == 0)
          {
              return acc;
          }
  
          return Fib(i - 1, acc + i);
      }
  </code></pre>
  
  <p>If I build it in release and run it without debugging I do not get a stack overflow. Debugging or running it without optimizations and I do get a stack overflow, implying that tail call is working when in release with optimizations on (which is what I expected).</p>
  
  <p>The MSIL for this looks like this:</p>
  
  <pre><code>.method public hidebysig static int32 Fib(int32 i, int32 acc) cil managed
  {
      // Method Start RVA 0x205e
      // Code Size 17 (0x11)
      .maxstack 8
      L_0000: ldarg.0 
      L_0001: brtrue.s L_0005
      L_0003: ldarg.1 
      L_0004: ret 
      L_0005: ldarg.0 
      L_0006: ldc.i4.1 
      L_0007: sub 
      L_0008: ldarg.1 
      L_0009: ldarg.0 
      L_000a: add 
      L_000b: call int32 [ConsoleApplication2]ConsoleApplication2.Program::Fib(int32,int32)
      L_0010: ret 
  }
  </code></pre>
  
  <p>I would've expected to see a tail opcode, per the <a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.tailcall%28v=vs.100%29.aspx" rel="noreferrer">msdn</a>, but it's not there.  This got me wondering if the JIT compiler was responsible for putting it in there?  I tried to ngen the assembly (using <code>ngen install &lt;exe&gt;</code>, navigating to the windows assemblies list to get it) and load it back up in ILSpy but it looks the same to me:</p>
  
  <pre><code>.method public hidebysig static int32 Fib(int32 i, int32 acc) cil managed
  {
      // Method Start RVA 0x3bfe
      // Code Size 17 (0x11)
      .maxstack 8
      L_0000: ldarg.0 
      L_0001: brtrue.s L_0005
      L_0003: ldarg.1 
      L_0004: ret 
      L_0005: ldarg.0 
      L_0006: ldc.i4.1 
      L_0007: sub 
      L_0008: ldarg.1 
      L_0009: ldarg.0 
      L_000a: add 
      L_000b: call int32 [ConsoleApplication2]ConsoleApplication2.Program::Fib(int32,int32)
      L_0010: ret 
  }
  </code></pre>
  
  <p>I still don't see it.  </p>
  
  <p>I know F# handles tail call well, so I wanted to compare what F# did with what C# did. My F# example looks like this:</p>
  
  <pre><code>let rec fibb i acc =  
      if i = 0 then
          acc
      else 
          fibb (i-1) (acc + i)
  
  
  Console.WriteLine (fibb 3 0)
  </code></pre>
  
  <p>And the generated IL for the fib method looks like this:</p>
  
  <pre><code>.method public static int32 fibb(int32 i, int32 acc) cil managed
  {
      // Method Start RVA 0x2068
      // Code Size 18 (0x12)
      .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = { int32[](Mono.Cecil.CustomAttributeArgument[]) }
      .maxstack 5
      L_0000: nop 
      L_0001: ldarg.0 
      L_0002: brtrue.s L_0006
      L_0004: ldarg.1 
      L_0005: ret 
      L_0006: ldarg.0 
      L_0007: ldc.i4.1 
      L_0008: sub 
      L_0009: ldarg.1 
      L_000a: ldarg.0 
      L_000b: add 
      L_000c: starg.s acc
      L_000e: starg.s i
      L_0010: br.s L_0000
  }
  </code></pre>
  
  <p>Which, according to ILSpy, is equivalent to this:</p>
  
  <pre><code>[Microsoft.FSharp.Core.CompilationArgumentCounts(Mono.Cecil.CustomAttributeArgument[])]
  public static int32 fibb(int32 i, int32 acc)
  {
      label1:
      if !(((i != 0))) 
      {
          return acc;
      }
      (i - 1);
      i = acc = (acc + i);;
      goto label1;
  }
  </code></pre>
  
  <p>So F# generated tail call using goto statements? This isn't what I was expecting.  </p>
  
  <p>I'm not trying to rely on tail call anywhere, but I am just curious where exactly does that opcode get set? How is C# doing this?</p>