[gcc r16-8778] libstdc++: Implement P4012R1 while reverting P3844R2 (consteval simd broadcast)

Matthias Kretz mkretz@gcc.gnu.org
Tue Apr 21 13:49:07 GMT 2026


https://gcc.gnu.org/g:804bde962de4819138951aed24b2c8ba768d7344

commit r16-8778-g804bde962de4819138951aed24b2c8ba768d7344
Author: Matthias Kretz <m.kretz@gsi.de>
Date:   Wed Apr 15 18:04:29 2026 +0200

    libstdc++: Implement P4012R1 while reverting P3844R2 (consteval simd broadcast)
    
    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>

Diff:
---
 libstdc++-v3/include/bits/simd_details.h         |  9 ------
 libstdc++-v3/include/bits/simd_mask.h            | 17 ++++++------
 libstdc++-v3/include/bits/simd_vec.h             | 22 +++------------
 libstdc++-v3/testsuite/std/simd/arithmetic.cc    | 35 ++++++++++++------------
 libstdc++-v3/testsuite/std/simd/mask.cc          |  6 ++--
 libstdc++-v3/testsuite/std/simd/simd_alg.cc      |  5 ++--
 libstdc++-v3/testsuite/std/simd/traits_common.cc |  4 +--
 libstdc++-v3/testsuite/std/simd/traits_math.cc   |  2 +-
 8 files changed, 39 insertions(+), 61 deletions(-)

diff --git a/libstdc++-v3/include/bits/simd_details.h b/libstdc++-v3/include/bits/simd_details.h
index 31bd6ac45ab2..3880d8a19166 100644
--- a/libstdc++-v3/include/bits/simd_details.h
+++ b/libstdc++-v3/include/bits/simd_details.h
@@ -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
    */
diff --git a/libstdc++-v3/include/bits/simd_mask.h b/libstdc++-v3/include/bits/simd_mask.h
index 27eff4ca01a7..0a7cfa03cedd 100644
--- a/libstdc++-v3/include/bits/simd_mask.h
+++ b/libstdc++-v3/include/bits/simd_mask.h
@@ -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>());
diff --git a/libstdc++-v3/include/bits/simd_vec.h b/libstdc++-v3/include/bits/simd_vec.h
index 2574bf7c3ad7..5f3bd7fd2f61 100644
--- a/libstdc++-v3/include/bits/simd_vec.h
+++ b/libstdc++-v3/include/bits/simd_vec.h
@@ -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)
diff --git a/libstdc++-v3/testsuite/std/simd/arithmetic.cc b/libstdc++-v3/testsuite/std/simd/arithmetic.cc
index e662a26866c6..adf94f0a87fa 100644
--- a/libstdc++-v3/testsuite/std/simd/arithmetic.cc
+++ b/libstdc++-v3/testsuite/std/simd/arithmetic.cc
@@ -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);
diff --git a/libstdc++-v3/testsuite/std/simd/mask.cc b/libstdc++-v3/testsuite/std/simd/mask.cc
index ebd9dc7728d3..117cf37beaaa 100644
--- a/libstdc++-v3/testsuite/std/simd/mask.cc
+++ b/libstdc++-v3/testsuite/std/simd/mask.cc
@@ -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>);
 	  }
 
diff --git a/libstdc++-v3/testsuite/std/simd/simd_alg.cc b/libstdc++-v3/testsuite/std/simd/simd_alg.cc
index 03ba83de8d40..8cfd61802e14 100644
--- a/libstdc++-v3/testsuite/std/simd/simd_alg.cc
+++ b/libstdc++-v3/testsuite/std/simd/simd_alg.cc
@@ -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) {
diff --git a/libstdc++-v3/testsuite/std/simd/traits_common.cc b/libstdc++-v3/testsuite/std/simd/traits_common.cc
index ecbceef06bf3..a026e359bacd 100644
--- a/libstdc++-v3/testsuite/std/simd/traits_common.cc
+++ b/libstdc++-v3/testsuite/std/simd/traits_common.cc
@@ -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>
diff --git a/libstdc++-v3/testsuite/std/simd/traits_math.cc b/libstdc++-v3/testsuite/std/simd/traits_math.cc
index fc71ff9e3590..1f90cf34c2e3 100644
--- a/libstdc++-v3/testsuite/std/simd/traits_math.cc
+++ b/libstdc++-v3/testsuite/std/simd/traits_math.cc
@@ -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


More information about the Libstdc++-cvs mailing list