title: IL optimization attempt results in slower execution
body: <p>Consider this more of an academic question rather than practical.</p>
  
  <p>While reinventing a wheel, that is, writing a mini-ORM/type mapper, I've emitted some IL to convert properties of an object into SqlParameters that are added to a SqlCommand.</p>
  
  <p>My first attempt was basically to write the C# code and translate it into IL 1:1, resulting in the following code (which works flawlessly). Note that comments denote the stack after running the following emitted IL:</p>
  
  <pre><code>int paramLocIndex = localIndex++;
  
   // Get the type handler [typeHandler]
  il.Emit(OpCodes.Call, ClrTypeHandlers[prop.PropertyType].GetType().GetMethod("GetTypeHandler", BindingFlags.NonPublic | BindingFlags.Static));
  
  // Load the object [typeHandler, object]
  il.Emit(OpCodes.Ldloc_0);
  
  // Get the property value [typeHandler, value]
  il.Emit(OpCodes.Call, prop.GetMethod);
  
  // Box the value [typeHandler, boxedValue]
  il.Emit(OpCodes.Box, prop.PropertyType);
  
  // Let the type handler create the param [param]
  il.Emit(OpCodes.Callvirt, typeof(SqlTypeHandler).GetMethod("CreateParamFromValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object) }, null));
  
  // Store the parameter as a variable []
  il.DeclareLocal(typeof(SqlParameter));
  il.Emit(OpCodes.Stloc, paramLocIndex);
  
  // Load the parameter again [param]
  il.Emit(OpCodes.Ldloc, paramLocIndex);
  
  // Load the parameter name [param, paramName]
  il.Emit(OpCodes.Ldstr, paramName);
  
  // Set the parameter name []
  il.Emit(OpCodes.Call, typeof(SqlParameter).GetMethod("set_ParameterName"));
  
  // Load the command [cmd]
  il.Emit(OpCodes.Ldarg_0);
  
  // Load the parameter collection [paramCollection]
  il.Emit(OpCodes.Call, typeof(SqlCommand).GetMethod("get_Parameters"));
  
  // Load the parameter [paramCollection, param]
  il.Emit(OpCodes.Ldloc, paramLocIndex);
  
  // Add the parameter to the collection [param]
  il.Emit(OpCodes.Call, typeof(SqlParameterCollection).GetMethod("Add", new[] { typeof(SqlParameter) }));
  
  // Get rid of the added parameter, as returned by SqlParameterCollection.Add []
  il.Emit(OpCodes.Pop);
  </code></pre>
  
  <p>While the above works, I wanted to try to optimize it. This resulted in the following code, which also works flawlessly:</p>
  
  <pre><code>// Load the command [cmd]
  il.Emit(OpCodes.Ldarg_0);
  
  // Load the parameter collection [paramCollection]
  il.Emit(OpCodes.Call, typeof(SqlCommand).GetMethod("get_Parameters"));
  
  // Get the type handler [paramCollection, typeHandler]
  il.Emit(OpCodes.Call, ClrTypeHandlers[prop.PropertyType].GetType().GetMethod("GetTypeHandler", BindingFlags.NonPublic | BindingFlags.Static));
  
  // Load the object [paramCollection, typeHandler, object]
  il.Emit(OpCodes.Ldloc_0);
  
  // Get the property value [paramCollection, typeHandler, value]
  il.Emit(OpCodes.Call, prop.GetMethod);
  
  // Box the value [paramCollection, typeHandler, boxedValue]
  il.Emit(OpCodes.Box, prop.PropertyType);
  
  // Let the type handler create the param [paramCollection, param]
  il.Emit(OpCodes.Callvirt, typeof(SqlTypeHandler).GetMethod("CreateParamFromValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object) }, null));
  
  // Add the parameter to the collection [param]
  il.Emit(OpCodes.Call, typeof(SqlParameterCollection).GetMethod("Add", new[] { typeof(SqlParameter) }));
  
  // Load the parameter name [param, paramName]
  il.Emit(OpCodes.Ldstr, paramName);
  
  // Set the parameter name []
  il.Emit(OpCodes.Call, typeof(SqlParameter).GetMethod("set_ParameterName"));
  </code></pre>
  
  <p>While the optimized attempt results in way fewer instructions, avoiding variables, etc. it still runs slower. The first attempt runs in 21500 ticks while the "optimized" version runs in 75000 ticks.</p>
  
  <p>Both of these are plenty fast, but I am curious as to why the first one runs so much faster. I know there's a second level of compilation from IL to machine code - and the answer probably lies in the optimizations performed by the IL compiler. The question is, what are my options if I want to explore this further? Any obvious reasons why the second IL attempt runs slower?</p>