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

            Bug ID: 89819
           Summary: [9 Regression] std::variant operators regressed since
                    GCC 8.3
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Keywords: missed-optimization
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: antoshkka at gmail dot com
  Target Milestone: ---

The following code


#include <variant>

struct my_type{};
bool operator==(const my_type&, const my_type&) noexcept;

using V1 = std::variant<int, float, long, double, my_type>;
auto test1(const V1& v) { return v == v; }


Was producing a jump table of size 5 on GCC 8.3. GCC 9 produces huge jump
tables with over 30 entries. This leads to ~15 times bigger binaries with GCC 9
and ~25% compilation slowdown. https://godbolt.org/z/yoAIrP

This could be fixed by changing the `_VARIANT_RELATION_FUNCTION_TEMPLATE` from
binary visitation to unary via first checking the `index()` of `__lhs` +
`__rhs` and doing the visitation only if they match (hold the same type).

Pseudo-code:

#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP, __NAME) \
  template<typename... _Types> \
    constexpr bool operator __OP(const variant<_Types...>& __lhs, \
                                 const variant<_Types...>& __rhs) \
    { \
      bool __ret = true; \
      if ((__lhs.index() + 1) != (__rhs.index() + 1)) { \
          return (__lhs.index() + 1) __OP (__rhs.index() + 1); \
      } \
      __do_visit([&__ret, &__lhs] \
                 (auto&& __rhs_mem) mutable     \
                   -> __detail::__variant::__variant_cookie \
        { \
          using __Type = remove_reference_t<decltype(__rhs_mem)>; \
          if constexpr (!is_same_v< \
                                  __Type, \
                                  __detail::__variant::__variant_cookie>) \
            __ret =
__detail::__variant::__get<__detail::__variant::__index_of_v<__Type,
_Types...>>(__this_mem) __OP __rhs_mem; \
          return {}; \
        }, __rhs); \
      return __ret; \
    } \
\
  constexpr bool operator __OP(monostate, monostate) noexcept \
{ return 0 __OP 0; }

Reply via email to