Is there a reason why Roslyn does not optimize multiple increments?

Viewed 156

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

Question

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
1 Answers

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
Related