public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/105903] New: Missed optimization for __synth3way
@ 2022-06-08 23:43 barry.revzin at gmail dot com
  2022-06-08 23:53 ` [Bug tree-optimization/105903] " pinskia at gcc dot gnu.org
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: barry.revzin at gmail dot com @ 2022-06-08 23:43 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105903

            Bug ID: 105903
           Summary: Missed optimization for __synth3way
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

#include <compare>
#include <vector>

inline constexpr auto synth3way = std::__detail::__synth3way;

struct Iterator {
    std::vector<int>::iterator it;

    constexpr bool operator<(Iterator const& rhs) const {
        return it < rhs.it;
    }
    constexpr bool operator>(Iterator const& rhs) const {
        return it > rhs.it;
    }    
};

bool less(Iterator const& a, Iterator const& b) {
    return a < b;
}

bool less3way(Iterator const& a, Iterator const& b) {
    return synth3way(a, b) < 0;
}

Here, synth3way(a, b) < 0 produces identical code to a < b (compiling with gcc
12.1 --std=c++20 -O3), which is great. The compiler recognizes that it doesn't
have to do the second synthesized comparison. 

However, if we instead compared (sorry):

bool greater(Iterator const& a, Iterator const& b) {
    return a > b;
}

bool greater3way(Iterator const& a, Iterator const& b) {
    return synth3way(a, b) > 0;
}

This is now much worse:

greater(Iterator const&, Iterator const&):
        mov     rax, QWORD PTR [rdi]
        cmp     QWORD PTR [rsi], rax
        setb    al
        ret
greater3way(Iterator const&, Iterator const&):
        mov     rdx, QWORD PTR [rdi]
        mov     rcx, QWORD PTR [rsi]
        xor     eax, eax
        cmp     rdx, rcx
        jb      .L3
        cmp     rcx, rdx
        setb    al
.L3:
        ret

Interestingly, if we write this out:

bool greater3way(Iterator const& a, Iterator const& b) {
    auto const cmp = [&]{
        if (a < b) return std::weak_ordering::less;
        if (b < a) return std::weak_ordering::greater;
        return std::weak_ordering::equivalent;
    }();
    return cmp > 0;
}

bool greater3way_fold(Iterator const& a, Iterator const& b) {
    return [&]{
        if (a < b) return false;
        if (b < a) return true;
        return false;
    }();
}

The greater3way_fold implementation generates the same code as >, which
definitely suggests to me that the greater3way version is simply a missed
optimization. 

On compiler explorer: https://godbolt.org/z/1xvfsMrnf

Because synth3way is only used in contexts that require a weak ordering anyway,
it would be a valid optimization to replace synth3way(a, b) > 0 with b < a,
synth3way(a, b) <= 0 with !(b < a) and synth3way(a, b) >= 0 with !(a < b).
These replacements aren't generally true (because partial orders), but the
precondition on this type is that we have a weak order, so we should be able to
do better.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-07-31 17:14 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 23:43 [Bug c++/105903] New: Missed optimization for __synth3way barry.revzin at gmail dot com
2022-06-08 23:53 ` [Bug tree-optimization/105903] " pinskia at gcc dot gnu.org
2022-06-29  1:40 ` luoxhu at gcc dot gnu.org
2022-06-29  1:51 ` pinskia at gcc dot gnu.org
2022-07-01 22:04 ` pinskia at gcc dot gnu.org
2022-07-01 22:10 ` pinskia at gcc dot gnu.org
2022-07-02  5:18 ` pinskia at gcc dot gnu.org
2023-05-24  0:01 ` pinskia at gcc dot gnu.org
2023-05-24  0:06 ` pinskia at gcc dot gnu.org
2023-06-07  2:46 ` pinskia at gcc dot gnu.org
2023-06-07  2:47 ` pinskia at gcc dot gnu.org
2023-07-30  6:10 ` pinskia at gcc dot gnu.org
2023-07-30  6:12 ` pinskia at gcc dot gnu.org
2023-07-30  6:32 ` pinskia at gcc dot gnu.org
2023-07-30 21:14 ` pinskia at gcc dot gnu.org
2023-07-31 17:14 ` pinskia at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).