I was trying to see how Roslyn
optimizes the following snippet:
code
public int F(int n) {
++n;
++n;
++n;
++n;
return n;
}
asm
C.F(Int32)
L0000: inc edx
L0002: inc edx
L0004: inc edx
L0006: inc edx
L0008: mov eax, edx
L000a: ret
why doesn't Roslyn optimize it like an ahead-of-time C compiler like MSVC? 4 x INC
is slower (4 cycle latency vs. 1 even assuming mov-elimination, and 4 more uops than necessary for throughput; https://agner.org/optimize/).
C
"equivalent" of it:
int
f(void *dummy_this, int n) {
++n;
++n;
++n;
++n;
return n;
}
asm from MSVC, or GCC with __attribute__((ms_abi))
to use the same Windows x64 calling convention as the C# asm: https://godbolt.org/z/sK6h7KKcn
f:
lea eax, [rdx+4]
ret
The compiler does optimize. n
is a parameter though, so it can't be modified. The JIT compiler must modify a copy of the parameter's value.
If the value is assigned to a variable before incrementing, the Roslyn compiler will eliminate the increments. From this Sharplab.io snippet, this C# code :
public int F(int i) {
var n=i;
++n;
++n;
++n;
++n;
return n;
}
Will be translated to
public int F(int i)
{
return i + 1 + 1 + 1 + 1;
}
And eventually compiled to this assembly code:
C.F(Int32)
L0000: lea eax, [edx+4]
L0003: ret