Search code examples
c++optimizationstlc++20

is there an overhead when using operator<=> compared to operator< etc


will there be a difference in performance between these examples and use < or == operators?

struct Data {
    int x;
    int y;

    bool operator<(const Data& other) const {
        if (x != other.x) return x < other.x;
        return y < other.y;
    }

    bool operator==(const Data& other) const {
        return x == other.x && y == other.y;
    }

    bool operator>(const Data& other) const {
        return !(*this < other) && !(*this == other);
    }
};
struct Data {
    int x;
    int y;

    auto operator<=>(const Data& other) const = default;
};

how i see on disassembly we have overhead function call https://godbolt.org/z/17EbTabG5


Solution

  • Thanks for comment and example Drew Dormann

    https://godbolt.org/z/5bjcMqc4b - This example shows the minor differences between the GCC assembler of 2 classes with different implementations. And the difference is minimal.

    where the first Data here has faster ordering comparisons, but the second Data has faster equality

    testeq(Data&, Data&):
            mov     edx, DWORD PTR [rsi]
            xor     eax, eax
            cmp     DWORD PTR [rdi], edx
            je      .L5
            ret
    .L5:
            mov     eax, DWORD PTR [rsi+4]
            cmp     DWORD PTR [rdi+4], eax
            sete    al
            ret
    testeq(Data2&, Data2&):
            mov     edx, DWORD PTR [rsi]
            xor     eax, eax
            cmp     DWORD PTR [rdi], edx
            jne     .L6
            mov     eax, DWORD PTR [rsi+4]
            cmp     DWORD PTR [rdi+4], eax
            sete    al
    .L6:
            ret
    testlt(Data&, Data&):
            mov     eax, DWORD PTR [rsi]
            cmp     DWORD PTR [rdi], eax
            jne     .L12
            mov     eax, DWORD PTR [rsi+4]
            cmp     DWORD PTR [rdi+4], eax
    .L12:
            setl    al
            ret
    testlt(Data2&, Data2&):
            mov     ecx, DWORD PTR [rdi]
            mov     edx, DWORD PTR [rsi]
            cmp     ecx, edx
            setl    al
            je      .L18
            ret
    .L18:
            mov     edx, DWORD PTR [rsi+4]
            mov     ecx, DWORD PTR [rdi+4]
            cmp     ecx, edx
            mov     edx, 0
            setl    al
            cmove   eax, edx
            ret
    

    https://godbolt.org/z/ozTcvb848 - In the same example, if we choose Clang, we will see that there is no difference in the assembler at all.

    testeq(Data&, Data&):
            movq    xmm0, qword ptr [rdi]
            movq    xmm1, qword ptr [rsi]
            pcmpeqd xmm1, xmm0
            pshufd  xmm0, xmm1, 80
            movmskpd        eax, xmm0
            cmp     eax, 3
            sete    al
            ret
    
    testeq(Data2&, Data2&):
            movq    xmm0, qword ptr [rdi]
            movq    xmm1, qword ptr [rsi]
            pcmpeqd xmm1, xmm0
            pshufd  xmm0, xmm1, 80
            movmskpd        eax, xmm0
            cmp     eax, 3
            sete    al
            ret
    
    testlt(Data&, Data&):
            mov     ecx, dword ptr [rdi]
            mov     eax, dword ptr [rdi + 4]
            xor     edx, edx
            cmp     eax, dword ptr [rsi + 4]
            setl    dl
            xor     eax, eax
            cmp     ecx, dword ptr [rsi]
            setl    al
            cmove   eax, edx
            ret
    
    testlt(Data2&, Data2&):
            mov     ecx, dword ptr [rdi]
            mov     eax, dword ptr [rdi + 4]
            xor     edx, edx
            cmp     eax, dword ptr [rsi + 4]
            setl    dl
            xor     eax, eax
            cmp     ecx, dword ptr [rsi]
            setl    al
            cmove   eax, edx
            ret