Optimizing temporary/intermediate variables.

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
In our C++ code base, our coding rules require that we separate and identify otherwise arbitrary values with temporaries: please note, this sample code is wholly artificial, entirely pointless/meaningless and was created solely for the purpose of generating
some IL code a little further down.
Our C++ code policy encourages breaking down of complex calculations into named intermediate variables.
I realize that - in the following examples, theres no reason not to make MeaningOfLife a private/internal member variable; however our C++ code policy discourages this for single-use values because they can easily become separated from the code to which
they are relevant.

Also, I realize that, were it a member, we could similarly initialize "lifeRoot" as a static member or something, given that the source value is static.
However: The code is a reduction/simplification of the recurring concept of intermediate steps of calculation where, for code legibility, you want to temporarily assign a calculated value a name in source only as with the "lifeRoot"

<div style="color:Black;background-color:White; <pre>
<span style="color:Green; // C++ code

<span style="color:Blue; float SumRoots(<span style="color:Blue; int n1, <span style="color:Blue; int n2)
{
<span style="color:Green; // Local intermediates: that is, the value wont
<span style="color:Green; // change for the lifetime of any given call of this
<span style="color:Green; // function, so the compiler can effectively optimize
<span style="color:Green; // them out.
<span style="color:Green; // NOTE: This is different than C#s definition of const.
<span style="color:Blue; const <span style="color:Blue; float root1 = sqrt(n1) ;
<span style="color:Blue; const <span style="color:Blue; float root2 = sqrt(n2) ;

<span style="color:Green; // Our one and only references to root1 and root2.
<span style="color:Blue; const <span style="color:Blue; float rootSum = root1 + root2 ;

<span style="color:Blue; return rootSum ;
}
[/code]
Converting this vaguely to C#:
<div style="color:Black;background-color:White; <pre>
<span style="color:Blue; public <span style="color:Blue; float SumRoots(<span style="color:Blue; int n1, <span style="color:Blue; int n2)
{
<span style="color:Blue; double root1 = Math.Sqrt(n1) ;
<span style="color:Blue; double root2 = Math.Sqrt(n2) ;

<span style="color:Blue; double rootSum = root1 + root2 ;

<span style="color:Blue; return rootSum ;
}

[/code]
What surprised me here was the resulting IL code produced with optimization enabled [and I mean, Build -> Optimize code checked, not just assuming its optimizing in Release mode :)]
<pre>// Code size 22 (0x16)
.maxstack 2
.locals init ([0] float64 root1,
[1] float64 root2,
[2] float64 rootSum)
IL_0000: ldarg.0
IL_0001: conv.r8
IL_0002: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_0007: stloc.0
IL_0008: ldarg.1
IL_0009: conv.r8
IL_000a: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_000f: stloc.1
IL_0010: ldloc.0
IL_0011: ldloc.1
IL_0012: add
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ret[/code]
Id expected (having been spoiled by C++ optimizers etc) something more akin to:
<pre> // Code size 16 (0x10)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.r8
IL_0002: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_0007: ldarg.1
IL_0008: conv.r8
IL_0009: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_000e: add
IL_000f: ret
[/code]
But the C# compilers optimizer doesnt seem to perform the same kind of local elimination that the C/C++/CLI-C++ compilers do. While I appreciate it might be done by the JIT instead, this seems to unduly bloat the size of the resulting assemblies.
Im wondering:
a. Is there a way to provide this kind of hint to the C# compiler?
b. Is the C#-generated variant better for parallelization?


View the full article
 
Back
Top