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.