Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't C# inline functions with struct parameters?

At http://blogs.msdn.com/ericgu/archive/2004/01/29/64717.aspx, we learn that C# will not inline methods with structs as formal parameters. Is this due to potential dependence on the stack, e.g. for recursion? If so, could I potentially benefit by turning struct parameters into ref parameters like this?

public int Sum(int i)
{
  return array1[i] + array2[i];
}

turns into:

public int Sum(ref int i)
{
  return array1[i] + array2[i];
}

Edit: I went to attempt a test, but I can't get anything in inline. Here is what I tried:

class Program
{
  private static string result;
  static void Main(string[] args)
  {
    Console.WriteLine(MethodBase.GetCurrentMethod().Name);
    Console.WriteLine();
    m1();
    Console.WriteLine(result);
  }
  private static void m1()
  {
    result = MethodBase.GetCurrentMethod().Name;
  }
}

It prints "m1" as the second line, which indicates that it did not get inlined. I built a Release build and ran it with Ctrl-F5 (to not attach the debugger). Any ideas?

like image 548
Fantius Avatar asked Oct 14 '22 15:10

Fantius


2 Answers

As Jon said, it's a very old post. I can confirm that in the following code:

using System;
using System.Runtime.CompilerServices;

struct MyStruct
{
   public MyStruct(int p)
   {
      X = p;
   }
   public int X;

   // prevents optimization of the whole thing to a constant.
   [MethodImpl(MethodImplOptions.NoInlining)]
   static int GetSomeNumber()
   {
       return new Random().Next();
   }

   static void Main(string[] args)
   {
      MyStruct x = new MyStruct(GetSomeNumber());
      // the following line is to prevent further optimization:
      for (int i = inlinetest(x); i != 100 ; i /= 2) ; 
   }

   static int inlinetest(MyStruct x)
   {
      return x.X + 1;
   }
}

inlinetest method is inlined.

Main method disassembly:

; set up the stack frame:
00000000  push        ebp
00000001  mov         ebp,esp 

; calls GetSomeNumber:
00000003  call        dword ptr ds:[005132D8h] 

; inlined function:
00000009  inc         eax  

; the dummy for loop:
0000000a  cmp         eax,64h 
0000000d  je          0000001B 
0000000f  sar         eax,1 
00000011  jns         00000016 
00000013  adc         eax,0 
00000016  cmp         eax,64h 
00000019  jne         0000000F 
0000001b  pop         ebp  
0000001c  ret 

I've tested this on x86 .NET Framework 3.5 SP1 on Windows 7 x64 RC.

As I believed there's nothing inherently wrong with inlining methods with struct parameters. Probably, JIT has not been smart enough at that time.

like image 115
mmx Avatar answered Oct 18 '22 14:10

mmx


Here's a better article describing why some methods will not be inlined. And here is a MS connect feedback entry with comments that include benchmark results (FWIW)

like image 25
Ryan Emerle Avatar answered Oct 18 '22 14:10

Ryan Emerle