Why so big difference with clang?

I dig into assembly of my "hot" function, and see really strange assembler.

I made two consecutive f64::sin_cos function calls. Full code can seen here (at godbolt.org) .

Usage of f64::sin_cos on Linux/glibc cause call of sincos function, that has such signature void sincos(double x, double *sin, double *cos), and clang and rustc generates call to this function, but for some reason Rust can not use proper addresses?

        lea     rdi, [rsp + 48]
        lea     rsi, [rsp + 40]
        mov     r14, qword ptr [rip + sincos@GOTPCREL]
        call    r14
        movsd   xmm0, qword ptr [rsp + 48]
        movsd   qword ptr [rsp + 8], xmm0
        movsd   xmm0, qword ptr [rsp + 40]
        movsd   qword ptr [rsp], xmm0

rustc passes [rsp + 48] [rsp + 40] as pointers to sincos call, and then load from memory locations ([rsp + 48] [rsp + 40]) and store result to [rsp + 8] and [rsp].

Why it can not just pass proper address ([rsp + 8] and [rsp]) to the sincos at the first place?

4 Likes

This seems to be caused by the automatic sin&cos -> sincos optimization that rust uses. If you change the C++ code to explicit sin and cos calls and add the -fno-math-errno flag you get the same behaviour except the load of the function pointer in a register.

godbolt

3 Likes

Thanks, I created llvm issue for this.

May be rust stdlib can use sincos directly in case of Linux/glibc ?

4 Likes