]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement P4012R1 while reverting P3844R2 (consteval simd broadcast)
authorMatthias Kretz <m.kretz@gsi.de>
Wed, 15 Apr 2026 16:04:29 +0000 (18:04 +0200)
committerMatthias Kretz <m.kretz@gsi.de>
Tue, 21 Apr 2026 13:48:43 +0000 (15:48 +0200)
P3844R2 added consteval conversion for value-preserving conversion from
constants. It had been approved by LEWG in Kona. Therefore, the current
implementation has the consteval broadcast constructor. In Croydon, LEWG
reversed the decision but changed the overload set to keep the design
space open for C++29.

This patch implements the removal of the consteval constructor and
changes the broadcast constructor according to P4012R1, to keep the
design space open.

libstdc++-v3/ChangeLog:

* include/bits/simd_details.h (__value_preserving_cast): Remove.
* include/bits/simd_mask.h (basic_mask): Replace plain 0 and 1
literals with cw<0> and cw<1>. Replace explicit basic_vec
construction from 0 and 1 with default init and broadcast from
_Up(1).
(_M_to_uint): Replace 1 with cw<1>.
* include/bits/simd_vec.h (basic_vec): Remove consteval
broadcast overload. Remove explicit broadcast from
non-value-preserving types.
* testsuite/std/simd/arithmetic.cc: Replace ill-formed integer
literals with explicit cast to T or use cw.
* testsuite/std/simd/mask.cc: Likewise.
* testsuite/std/simd/simd_alg.cc: Likewise.
* testsuite/std/simd/traits_common.cc: Adjust for resulting
traits changes.
* testsuite/std/simd/traits_math.cc: Likewise.

Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
libstdc++-v3/include/bits/simd_details.h
libstdc++-v3/include/bits/simd_mask.h
libstdc++-v3/include/bits/simd_vec.h
libstdc++-v3/testsuite/std/simd/arithmetic.cc
libstdc++-v3/testsuite/std/simd/mask.cc
libstdc++-v3/testsuite/std/simd/simd_alg.cc
libstdc++-v3/testsuite/std/simd/traits_common.cc
libstdc++-v3/testsuite/std/simd/traits_math.cc

index 31bd6ac45ab2d6aa8d08ed06992465f37ae93b71..3880d8a1916636533d251398ef08e7d6355a6af9 100644 (file)
@@ -1241,15 +1241,6 @@ namespace simd
       return static_cast<_To>(__x);
     }
 
-  template <typename _From, typename _To>
-    concept __simd_vec_bcast_consteval
-      = __explicitly_convertible_to<_From, _To>
-         && is_arithmetic_v<remove_cvref_t<_From>> && convertible_to<_From, _To>
-         && !__value_preserving_convertible_to<remove_cvref_t<_From>, _To>
-         && (is_same_v<common_type_t<_From, _To>, _To>
-               || (is_same_v<remove_cvref_t<_From>, int> && is_integral_v<_To>)
-               || (is_same_v<remove_cvref_t<_From>, unsigned> && unsigned_integral<_To>));
-
   /** @internal
    * std::pair is not trivially copyable, this one is
    */
index 27eff4ca01a7f6a1c25a793483522226768707fa..0a7cfa03ceddc530ed8ab1e44c05d3ab4719444f 100644 (file)
@@ -865,11 +865,12 @@ namespace simd
                using _Ip = typename _VecType::value_type;
                _VecType __v0 = _Ip(__val);
                constexpr int __bits_per_element = sizeof(_Ip) * __CHAR_BIT__;
-               constexpr _VecType __pow2 = _VecType(1) << (__iota<_VecType> % __bits_per_element);
+               constexpr _VecType __pow2 = _VecType(cw<1>)
+                                             << (__iota<_VecType> % cw<__bits_per_element>);
                if constexpr (_S_size < __bits_per_element)
-                 return ((__v0 & __pow2) > 0)._M_concat_data();
+                 return ((__v0 & __pow2) > cw<0>)._M_concat_data();
                else if constexpr (_S_size == __bits_per_element)
-                 return ((__v0 & __pow2) != 0)._M_concat_data();
+                 return ((__v0 & __pow2) != cw<0>)._M_concat_data();
                else
                  {
                    static_assert(_Bytes == 1);
@@ -886,7 +887,7 @@ namespace simd
                        };
                        __v1 *= 0x0101'0101'0101'0101ull;
                        __v0 = __builtin_bit_cast(_VecType, __v1);
-                       return ((__v0 & __pow2) != 0)._M_data;
+                       return ((__v0 & __pow2) != cw<0>)._M_data;
                      }
                    else
                      {
@@ -895,7 +896,7 @@ namespace simd
                        __v0 = _VecType::_S_static_permute(__v1, [](int __i) {
                                 return __i / __CHAR_BIT__;
                               });
-                       return ((__v0 & __pow2) != 0)._M_data;
+                       return ((__v0 & __pow2) != cw<0>)._M_data;
                      }
                  }
              }
@@ -991,7 +992,7 @@ namespace simd
          else
            {
              using _UV = basic_vec<_Up, _UAbi>;
-             return __select_impl(static_cast<_UV::mask_type>(*this), _UV(1), _UV(0));
+             return __select_impl(static_cast<_UV::mask_type>(*this), _Up(1), _UV());
            }
        }
 
@@ -1066,7 +1067,7 @@ namespace simd
              constexpr int __n = _IV::size();
              if constexpr (_Bytes * __CHAR_BIT__ >= __n) // '1 << __iota' cannot overflow
                { // reduce(select(k, powers_of_2, 0))
-                 constexpr _IV __pow2 = _IV(1) << __iota<_IV>;
+                 constexpr _IV __pow2 = _IV(cw<1>) << __iota<_IV>;
                  return _Ur(_U0(__select_impl(__k, __pow2, _IV())
                                   ._M_reduce(bit_or<>()))) << _Offset;
                }
@@ -1079,7 +1080,7 @@ namespace simd
                }
              else
                { // limit powers_of_2 to 1, 2, 4, ..., 128
-                 constexpr _IV __pow2 = _IV(1) << (__iota<_IV> % _IV(__CHAR_BIT__));
+                 constexpr _IV __pow2 = _IV(cw<1>) << (__iota<_IV> % _IV(cw<__CHAR_BIT__>));
                  _IV __x = __select_impl(__k, __pow2, _IV());
                  // partial reductions of 8 neighboring elements
                  __x |= _IV::_S_static_permute(__x, _SwapNeighbors<4>());
index 2574bf7c3ad7df3c66ab812a5f3824416d836535..5f3bd7fd2f61f8a29f19f3d587c932e88b6bd76e 100644 (file)
@@ -1135,20 +1135,13 @@ namespace simd
        *
        * @note The constructor is implicit if the conversion (if any) is value-preserving.
        */
-      template <__explicitly_convertible_to<value_type> _Up>
+      template <__broadcast_constructible<value_type> _Up>
        [[__gnu__::__always_inline__]]
-       constexpr explicit(!__broadcast_constructible<_Up, value_type>)
+       constexpr
        basic_vec(_Up&& __x) noexcept
          : _M_data(_DataType() == _DataType() ? static_cast<value_type>(__x) : value_type())
        {}
 
-      template <__simd_vec_bcast_consteval<value_type> _Up>
-       consteval
-       basic_vec(_Up&& __x)
-       : _M_data(_DataType() == _DataType()
-                   ? __value_preserving_cast<value_type>(__x) : value_type())
-       {}
-
       // [simd.ctor] conversion constructor -----------------------------------
       template <typename _Up, typename _UAbi, _TargetTraits _Traits = {}>
        requires (_S_size == _UAbi::_S_size)
@@ -2037,20 +2030,13 @@ namespace simd
       { return _M_concat_data(); }
 
       // [simd.ctor] broadcast constructor ------------------------------------
-      template <__explicitly_convertible_to<value_type> _Up>
+      template <__broadcast_constructible<value_type> _Up>
        [[__gnu__::__always_inline__]]
-       constexpr explicit(!__broadcast_constructible<_Up, value_type>)
+       constexpr
        basic_vec(_Up&& __x) noexcept
          : _M_data0(static_cast<value_type>(__x)), _M_data1(static_cast<value_type>(__x))
        {}
 
-      template <__simd_vec_bcast_consteval<value_type> _Up>
-       consteval
-       basic_vec(_Up&& __x)
-       : _M_data0(__value_preserving_cast<value_type>(__x)),
-         _M_data1(__value_preserving_cast<value_type>(__x))
-       {}
-
       // [simd.ctor] conversion constructor -----------------------------------
       template <typename _Up, typename _UAbi>
        requires (_S_size == _UAbi::_S_size)
index e662a26866c6697b7d76ea08324cea1f4bb9d8b4..adf94f0a87fa2389db76bb1b5984857e0a7a5e27 100644 (file)
@@ -88,7 +88,8 @@ template <typename V>
     };
 
     ADD_TEST(multiplication) {
-      std::tuple {V(), V(RealV(1), RealV()), V(RealV(), RealV(1)), init_vec<V, C(0, 2), C(2, 0), C(-1, 2)>},
+      std::tuple {V(), V(RealV(Real(1)), RealV()), V(RealV(), RealV(Real(1))),
+                 init_vec<V, C(0, 2), C(2, 0), C(-1, 2)>},
       [](auto& t, V x, V one, V I, V z) {
        t.verify_equal(x * x, x);
        t.verify_equal(x * z, x);
@@ -181,11 +182,11 @@ template <typename V>
        t.verify_equal(y, x - T(1));
        t.verify_equal(x - x, y);
        t.verify_equal(x = z - x, init_vec<V, 0, 1, 2, 3, 4, 5, 6>);
-       t.verify_equal(x = z - x, V(1));
+       t.verify_equal(x = z - x, T(1));
        t.verify_equal(z -= x, init_vec<V, 0, 1, 2, 3, 4, 5, 6>);
        t.verify_equal(z, init_vec<V, 0, 1, 2, 3, 4, 5, 6>);
-       t.verify_equal(z -= z, V(0));
-       t.verify_equal(z, V(0));
+       t.verify_equal(z -= z, V());
+       t.verify_equal(z, V());
       }
     };
 
@@ -259,10 +260,10 @@ template <typename V>
     ADD_TEST(divide0, std::is_floating_point_v<T> && !is_iec559) {
       std::tuple{T(2), init_vec<V, 1, 2, 3, 4, 5, 6, 7>},
       [](auto& t, V x, V y) {
-       t.verify_equal_to_ulp(x / x, V(T(1)), 1);
-       t.verify_equal_to_ulp(T(3) / x, V(T(3) / T(2)), 1);
-       t.verify_equal_to_ulp(x / T(3), V(T(2) / T(3)), 1);
-       t.verify_equal_to_ulp(y / x, init_vec<V, .5, 1, 1.5, 2, 2.5, 3, 3.5>, 1);
+       t.verify_equal_to_ulp(x / x, V(T(1)), std::cw<1>);
+       t.verify_equal_to_ulp(T(3) / x, V(T(3) / T(2)), std::cw<1>);
+       t.verify_equal_to_ulp(x / T(3), V(T(2) / T(3)), std::cw<1>);
+       t.verify_equal_to_ulp(y / x, init_vec<V, .5, 1, 1.5, 2, 2.5, 3, 3.5>, std::cw<1>);
       }
     };
 
@@ -272,18 +273,18 @@ template <typename V>
       [](auto& t, V a) {
        V b = std::cw<2>;
        V ref([&](int i) { return a[i] / 2; });
-       t.verify_equal_to_ulp(a / b, ref, 1);
+       t.verify_equal_to_ulp(a / b, ref, std::cw<1>);
        a = select(a == std::cw<0>, T(1), a);
        // -freciprocal-math together with flush-to-zero makes
        // the following range restriction necessary (i.e.
        // 1/|a| must be >= min). Intel vrcpps and vrcp14ps
        // need some extra slack (use 1.1 instead of 1).
        a = select(fabs(a) >= T(1.1) / norm_min, T(1), a);
-       t.verify_equal_to_ulp(a / a, V(1), 1)("\na = ", a);
+       t.verify_equal_to_ulp(a / a, V(std::cw<1>), std::cw<1>)("\na = ", a);
        ref = V([&](int i) { return 2 / a[i]; });
-       t.verify_equal_to_ulp(b / a, ref, 1)("\na = ", a);
-       t.verify_equal_to_ulp(b /= a, ref, 1);
-       t.verify_equal_to_ulp(b, ref, 1);
+       t.verify_equal_to_ulp(b / a, ref, std::cw<1>)("\na = ", a);
+       t.verify_equal_to_ulp(b /= a, ref, std::cw<1>);
+       t.verify_equal_to_ulp(b, ref, std::cw<1>);
       }
     };
 
@@ -291,15 +292,15 @@ template <typename V>
       std::tuple{T(2), init_vec<V, 1, 2, 3, 4, 5, 6, 7>, init_vec<V, T(max), T(norm_min)>,
                 init_vec<V, T(norm_min), T(max)>, init_vec<V, T(max), T(norm_min) + 1>},
       [](auto& t, V x, V y, V z, V a, V b) {
-       t.verify_equal(x / x, V(1));
-       t.verify_equal(T(3) / x, V(T(3) / T(2)));
-       t.verify_equal(x / T(3), V(T(2) / T(3)));
+       t.verify_equal(x / x, T(1));
+       t.verify_equal(T(3) / x, T(T(3) / T(2)));
+       t.verify_equal(x / T(3), T(T(2) / T(3)));
        t.verify_equal(y / x, init_vec<V, .5, 1, 1.5, 2, 2.5, 3, 3.5>);
        V ref = init_vec<V, T(max / 2), T(norm_min / 2)>;
        t.verify_equal(z / x, ref);
        ref = init_vec<V, T(norm_min / 2), T(max / 2)>;
        t.verify_equal(a / x, ref);
-       t.verify_equal(b / b, V(1));
+       t.verify_equal(b / b, T(1));
        ref = init_vec<V, T(2 / max), T(2 / (norm_min + 1))>;
        t.verify_equal(x / b, ref);
        t.verify_equal(x /= b, ref);
index ebd9dc7728d3605a69f42a8cf191af981cc2c47d..117cf37beaaa2fc18d22f5bd9a6fe79d6986e084 100644 (file)
@@ -54,14 +54,14 @@ template <typename V>
                   return i % 13 == 0 || i % 7 == 0;
       })},
       [](auto& t, const M k, const M tr, const M fa, const M k2) {
-       t.verify_equal(V(+tr), V(1));
+       t.verify_equal(V(+tr), T(1));
        t.verify_equal(V(+fa), V());
        t.verify_equal(V(+k), init_vec<V, 0, 1>);
 
        if constexpr (std::is_integral_v<T>)
          {
-           t.verify_equal(V(~tr), ~V(1));
-           t.verify_equal(V(~fa), ~V(0));
+           t.verify_equal(V(~tr), ~V(std::cw<1>));
+           t.verify_equal(V(~fa), ~V());
            t.verify_equal(V(~k), ~init_vec<V, 0, 1>);
          }
 
index 03ba83de8d4034091378b46cc602f987315e92a4..8cfd61802e144a26e5e3d3c89144dca7da0d701f 100644 (file)
@@ -13,8 +13,7 @@ template <typename V>
     using M = typename V::mask_type;
 
     using pair = std::pair<V, V>;
-    static constexpr std::conditional_t<std::is_floating_point_v<T>, short, T> x_max
-      = test_iota_max<V, 1>;
+    static constexpr T x_max = test_iota_max<V, 1>;
     static constexpr int x_max_int = static_cast<int>(x_max);
 
     static constexpr V
@@ -26,7 +25,7 @@ template <typename V>
          return static_cast<V>(std::to_underlying(x_max) - static_cast<Vu>(x));
        }
       else
-       return x_max - x;
+       return std::cw<x_max> - x;
     }
 
     ADD_TEST(Select) {
index ecbceef06bf3931a5e6aae583a27d4fa177b2757..a026e359bacd2220a44c5e61e9fb96ea472af099 100644 (file)
@@ -59,7 +59,7 @@ namespace test02
   // ensure 'true ? int : vec<float>' doesn't work
   template <typename T>
     concept has_type_member = requires { typename T::type; };
-  static_assert(has_type_member<common_type<int, simd::vec<float>>>);
+  static_assert(!has_type_member<common_type<int, simd::vec<float>>>);
 }
 
 #if defined __AVX__ && !defined __AVX2__
@@ -90,7 +90,7 @@ static_assert( std::convertible_to<Ic<1>, simd::vec<float>>);
 static_assert(!std::convertible_to<Ic<1.1>, simd::vec<float>>);
 static_assert(!std::convertible_to<simd::vec<int, 4>, simd::vec<float, 4>>);
 static_assert(!std::convertible_to<simd::vec<float, 4>, simd::vec<int, 4>>);
-static_assert( std::convertible_to<int, simd::vec<float>>);
+static_assert(!std::convertible_to<int, simd::vec<float>>);
 static_assert( std::convertible_to<simd::vec<int, 4>, simd::vec<double, 4>>);
 
 template <typename V>
index fc71ff9e3590c2f9b75fd177ca7db21c74535a7e..1f90cf34c2e314b436ff2d68131187b6d845e302 100644 (file)
@@ -25,7 +25,7 @@ namespace math_tests
     concept has_deduced_vec = requires { typename simd::__deduced_vec_t<T>; };
 
   static_assert(!has_common_type<vf2, vf4>);
-  static_assert( has_common_type<int, vf2>);
+  static_assert(!has_common_type<int, vf2>);
 
   template <typename T, bool Strict = false>
     struct holder