Advent of Compiler Optimisations

Matt Godbolt of Compiler Explorer fame is doing a video Advent calendar about compiler optimisations, you can check it out here :christmas_tree: :santa_claus: :mrs_claus: :mx_claus:.

For day 2, he looked at adding two integers, and why on x86 processors the compiler does not use the add instruction and instead uses lea (load effective address). He uses C++ for his videos, so I tested out his example with Fortran instead. With the following code,

integer function add(x,y) result(res)
    implicit none
    integer, intent(in) :: x
    integer, intent(in) :: y
    res = x+y
end function add

gfortran, flang, and ifx all generate the same assembly code with -O1 optimization,

"add_":
        mov     eax, DWORD PTR [rsi]
        add     eax, DWORD PTR [rdi]
        ret

I’m not so well versed in assembly code, but I suppose the reason why there is no lea instruction in this case is that the arguments are passed by reference (so rsi and rdi holds pointers to x and y) and need to be fetched, or?

If I modify the function so that the arguments have the value attribute,

integer function add(x,y) result(res)
    implicit none
    integer, value :: x
    integer, value :: y
    res = x+y
end function add

then gfortran and flang will use an lea instruction,

"add_":
        lea     eax, [rdi+rsi]
        ret

while ifx generates the same assembly as the previous case.

5 Likes

What happens with higher optimisation levels? I have no idea what the real (oops, integer, I mean) difference is between these instructions, but I can imagine that different compilers make different choices for each optimisation level.

1 Like

Nothing changes at -O3 for this case, but if the bind(c) attribute is added to the second version, then also ifx will use the lea instruction.

1 Like