Skip to content

Commit 48c9656

Browse files
committed
Implement P4012R1 and revert P3844R2 (consteval broadcast)
Keep the old behavior behind VIR_CONSTEVAL_BROADCAST but default to the C++26 behavior. Rewrite uses of the consteval broadcast to use std::cw or cast to value_type instead. Adjust the deploy.sh script to also deploy tests. ChangeLog: * README.md: Update P4012R1 status to done. * codegen/select.c++: * constexpr_tests.cpp: * deploy.sh: * include/bits/simd_complex.h: * include/bits/simd_details.h: * include/bits/simd_mask.h: * include/bits/simd_math.h: * include/bits/simd_vec.h: * lib/hypot2.cpp: * lib/hypot3.cpp: * lib/support.h: * math-traits_tests.cpp: * tests/arithmetic.cpp: * tests/complex-math.cpp: * tests/mask.cpp: * tests/math.cpp: * tests/simd_alg.cpp: * tests/unittest_pch.h:
1 parent f97504b commit 48c9656

19 files changed

Lines changed: 153 additions & 59 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
| [P3983R0](https://wg21.link/P3983R0) simd object representation | 🔴 open (still in design phase) |
3030
| [P3985R0](https://wg21.link/P3985R0) Concepts for std::simd | 🔴 open (still in design phase) |
3131
| [P3844R4](https://wg21.link/P3844R4) Reword [simd.math] for consteval conversions | ✅ done |
32-
| [P4012R1](https://wg21.link/P4012R1) value-preserving consteval broadcast to simd::vec | 🔴 open |
32+
| [P4012R1](https://wg21.link/P4012R1) value-preserving consteval broadcast to simd::vec | ✅ done |
3333
| [P4042R0](https://wg21.link/P4042R0) Fix LWG4543: incorrect cast between `simd::vec` and `simd::mask` [...] | ✅ done |
3434

3535
| Issue | Status |

codegen/select.c++

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ V0 test0b(V0::mask_type a)
5050
{ return simd::select(a, char(1), char(0)); }
5151

5252
V0 test0c(V0::mask_type a)
53-
{ return simd::select(a, V0(1), V0()); }
53+
{ return simd::select(a, V0(char(1)), V0()); }
5454

5555
V0 test0d(V0 a, V0 b, V0 c)
5656
{ return simd::select(a == a, b, c); }
@@ -92,7 +92,7 @@ V1 test1b(V1::mask_type a)
9292
{ return simd::select(a, T1(1), T1()); }
9393

9494
V1 test1c(V1::mask_type a)
95-
{ return simd::select(a, V1(1), V1()); }
95+
{ return simd::select(a, V1(T1(1)), V1()); }
9696

9797
/* codegen
9898
^"test2a(
@@ -123,7 +123,7 @@ V2 test2b(V2::mask_type a)
123123
{ return simd::select(a, short(1), short()); }
124124

125125
V2 test2c(V2::mask_type a)
126-
{ return simd::select(a, V2(1), V2()); }
126+
{ return simd::select(a, V2(short(1)), V2()); }
127127

128128
V2 test2d(V2 a, V2 b, V2 c)
129129
{ return simd::select(a == a, b, c); }

constexpr_tests.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,18 @@ namespace LWG4420
4949
simd::vec<float, 4> vh2f_b = float16_t();
5050

5151
simd::vec<float16_t, 4> vf2h = {f4, simd::flag_convert};
52+
#if VIR_CONSTEVAL_BROADCAST
5253
simd::vec<float16_t, 4> vf2h_b{float()};
54+
#endif
5355

5456
vh2f = vf2h;
5557
vf2h = static_cast<decltype(vf2h)>(vh2f);
5658

59+
#if VIR_CONSTEVAL_BROADCAST
5760
return all_of(vh2f == vh2f_b) && all_of(vf2h == vf2h_b);
61+
#else
62+
return all_of(vh2f == vh2f_b);
63+
#endif
5864
}());
5965
}
6066
#endif
@@ -141,7 +147,11 @@ namespace test02
141147
// ensure 'true ? int : vec<float>' doesn't work
142148
template <typename T>
143149
concept has_type_member = requires { typename T::type; };
150+
#if VIR_CONSTEVAL_BROADCAST
144151
static_assert(has_type_member<common_type<int, simd::vec<float>>>);
152+
#else
153+
static_assert(!has_type_member<common_type<int, simd::vec<float>>>);
154+
#endif
145155

146156
constexpr simd::vec<complex<double>>::mask_type k = {};
147157
}
@@ -176,7 +186,11 @@ static_assert( std::convertible_to<Ic<1>, simd::vec<float>>);
176186
static_assert(!std::convertible_to<Ic<1.1>, simd::vec<float>>);
177187
static_assert(!std::convertible_to<simd::vec<int, 4>, simd::vec<float, 4>>);
178188
static_assert(!std::convertible_to<simd::vec<float, 4>, simd::vec<int, 4>>);
189+
#if VIR_CONSTEVAL_BROADCAST
179190
static_assert( std::convertible_to<int, simd::vec<float>>);
191+
#else
192+
static_assert(!std::convertible_to<int, simd::vec<float>>);
193+
#endif
180194
static_assert( std::convertible_to<simd::vec<int, 4>, simd::vec<double, 4>>);
181195

182196
template <typename V>

deploy.sh

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ set -e
1010

1111
# Source and destination directories
1212
SRC_DIR="include/bits"
13-
DEST_DIR="/home/mkretz/src/gcc-simd/libstdc++-v3/include/bits"
13+
DEST_DIR="/home/mkretz/src/gcc-master/libstdc++-v3/include/bits"
14+
TEST_DIR="/home/mkretz/src/gcc-master/libstdc++-v3/testsuite/std/simd"
1415

15-
# Create destination directory if it doesn't exist
16-
mkdir -p "$DEST_DIR"
16+
if ! test -d "$DEST_DIR"; then echo "$DEST_DIR is missing"; fi
17+
if ! test -d "$TEST_DIR"; then echo "$TEST_DIR is missing"; fi
1718

1819
filter() {
1920
invert=0
@@ -146,22 +147,34 @@ EOF
146147
grep '^$' -A100000
147148
}
148149

150+
all_filters() {
151+
filter VIR_EXTENSIONS \
152+
| filter VIR_PATCH_PERMUTE_DYNAMIC \
153+
| filter VIR_PATCH_MATH \
154+
| filter VIR_PATCH_IMPROVE_CX \
155+
| filter VIR_PATCH_MISSED_OPT \
156+
| filter VIR_PATCH_TEST_STORES \
157+
| filter VIR_ASSERT_SANITY \
158+
| filter VIR_CONSTEVAL_BROADCAST \
159+
| fix_copyright
160+
}
161+
149162
# Process each .h file in the source directory
150163
for file in "$SRC_DIR"/*.h; do
151164
if [ -f "$file" ]; then
152165
filename=$(basename "$file")
153166
echo "Processing $filename..."
154-
155-
# Use awk to handle VIR_EXTENSIONS conditional blocks
156-
cat "$file" | filter VIR_EXTENSIONS \
157-
| filter VIR_PATCH_PERMUTE_DYNAMIC \
158-
| filter VIR_PATCH_MATH \
159-
| filter VIR_PATCH_IMPROVE_CX \
160-
| filter VIR_PATCH_MISSED_OPT \
161-
| filter VIR_PATCH_TEST_STORES \
162-
| filter VIR_ASSERT_SANITY \
163-
| fix_copyright > "$DEST_DIR/$filename"
167+
cat "$file" | all_filters > "$DEST_DIR/$filename"
164168
fi
165169
done
166170

167-
echo "Deployment complete. Processed files copied to $DEST_DIR/"
171+
cat math-traits_tests.cpp | all_filters > "$TEST_DIR/traits_math.cc"
172+
cat constexpr_tests.cpp | all_filters > "$TEST_DIR/traits_common.cc"
173+
cat generic-traits_tests.cpp | all_filters > "$TEST_DIR/traits_impl.cc"
174+
for file in tests/*.cpp; do
175+
filename=$(basename "$file")
176+
echo "Processing $filename..."
177+
cat "$file" | all_filters > "$TEST_DIR/${filename%.cpp}.cc"
178+
done
179+
180+
echo "Deployment complete. Processed files copied to $DEST_DIR/ and $TEST_DIR/"

include/bits/simd_complex.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,19 @@ namespace simd
11021102
// TODO: conversion extensions
11031103

11041104
// [simd.ctor] broadcast constructor ------------------------------------
1105+
#if !VIR_CONSTEVAL_BROADCAST
1106+
template <__broadcast_constructible<value_type> _Up>
1107+
[[__gnu__::__always_inline__]]
1108+
constexpr
1109+
basic_vec(_Up&& __x) noexcept
1110+
: _M_data([&](int __i) {
1111+
if constexpr (__complex_like<_Up>)
1112+
return (__i & 1) == 0 ? __x.real() : __x.imag();
1113+
else
1114+
return (__i & 1) == 0 ? __x : _T0();
1115+
})
1116+
{}
1117+
#else
11051118
template <__explicitly_convertible_to<value_type> _Up>
11061119
[[__gnu__::__always_inline__]]
11071120
constexpr explicit(!__broadcast_constructible<_Up, value_type>)
@@ -1119,6 +1132,7 @@ namespace simd
11191132
basic_vec(const _Up& __x)
11201133
: basic_vec(__value_preserving_cast<value_type>(__x))
11211134
{}
1135+
#endif
11221136

11231137
// [simd.ctor] conversion constructor -----------------------------------
11241138
template <__complex_like _Up, typename _UAbi>
@@ -2266,6 +2280,22 @@ namespace simd
22662280
// TODO: conversion extensions
22672281

22682282
// [simd.ctor] broadcast constructor ------------------------------------
2283+
#if !VIR_CONSTEVAL_BROADCAST
2284+
template <__broadcast_constructible<value_type> _Up>
2285+
requires __complex_like<_Up>
2286+
[[__gnu__::__always_inline__]]
2287+
constexpr
2288+
basic_vec(_Up&& __x) noexcept
2289+
: _M_real(__x.real()), _M_imag(__x.imag())
2290+
{}
2291+
2292+
template <__broadcast_constructible<value_type> _Up>
2293+
[[__gnu__::__always_inline__]]
2294+
constexpr
2295+
basic_vec(_Up&& __x) noexcept
2296+
: _M_real(__x), _M_imag()
2297+
{}
2298+
#else
22692299
template <__explicitly_convertible_to<value_type> _Up>
22702300
requires __complex_like<_Up>
22712301
[[__gnu__::__always_inline__]]
@@ -2286,6 +2316,7 @@ namespace simd
22862316
basic_vec(const _Up& __x)
22872317
: _M_real(__x), _M_imag()
22882318
{}
2319+
#endif
22892320

22902321
// [simd.ctor] conversion constructor -----------------------------------
22912322
template <__complex_like _Up, typename _UAbi>

include/bits/simd_details.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,7 @@ namespace simd
15831583
return static_cast<_To>(__x);
15841584
}
15851585

1586+
#if VIR_CONSTEVAL_BROADCAST
15861587
template <typename _From, typename _To>
15871588
concept __simd_vec_bcast_consteval
15881589
= __explicitly_convertible_to<_From, _To>
@@ -1592,6 +1593,7 @@ namespace simd
15921593
|| (is_same_v<remove_cvref_t<_From>, int> && is_integral_v<_To>)
15931594
|| (is_same_v<remove_cvref_t<_From>, unsigned> && unsigned_integral<_To>));
15941595

1596+
#endif
15951597
/** @internal
15961598
* std::pair is not trivially copyable, this one is
15971599
*/

include/bits/simd_mask.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -915,11 +915,12 @@ namespace simd
915915
using _Ip = typename _VecType::value_type;
916916
_VecType __v0 = _Ip(__val);
917917
constexpr int __bits_per_element = sizeof(_Ip) * __CHAR_BIT__;
918-
constexpr _VecType __pow2 = _VecType(1) << (__iota<_VecType> % __bits_per_element);
918+
constexpr _VecType __pow2 = _VecType(cw<1>)
919+
<< (__iota<_VecType> % cw<__bits_per_element>);
919920
if constexpr (_S_size < __bits_per_element)
920-
return ((__v0 & __pow2) > 0)._M_concat_data();
921+
return ((__v0 & __pow2) > cw<0>)._M_concat_data();
921922
else if constexpr (_S_size == __bits_per_element)
922-
return ((__v0 & __pow2) != 0)._M_concat_data();
923+
return ((__v0 & __pow2) != cw<0>)._M_concat_data();
923924
else
924925
{
925926
static_assert(_Bytes == 1);
@@ -936,7 +937,7 @@ namespace simd
936937
};
937938
__v1 *= 0x0101'0101'0101'0101ull;
938939
__v0 = __builtin_bit_cast(_VecType, __v1);
939-
return ((__v0 & __pow2) != 0)._M_data;
940+
return ((__v0 & __pow2) != cw<0>)._M_data;
940941
}
941942
else
942943
{
@@ -945,7 +946,7 @@ namespace simd
945946
__v0 = _VecType::_S_static_permute(__v1, [](int __i) {
946947
return __i / __CHAR_BIT__;
947948
});
948-
return ((__v0 & __pow2) != 0)._M_data;
949+
return ((__v0 & __pow2) != cw<0>)._M_data;
949950
}
950951
}
951952
}
@@ -1041,7 +1042,7 @@ namespace simd
10411042
else
10421043
{
10431044
using _UV = basic_vec<_Up, _UAbi>;
1044-
return __select_impl(static_cast<_UV::mask_type>(*this), _UV(1), _UV(0));
1045+
return __select_impl(static_cast<_UV::mask_type>(*this), _Up(1), _UV());
10451046
}
10461047
}
10471048

@@ -1138,7 +1139,7 @@ namespace simd
11381139
constexpr int __n = _IV::size();
11391140
if constexpr (_Bytes * __CHAR_BIT__ >= __n) // '1 << __iota' cannot overflow
11401141
{ // reduce(select(k, powers_of_2, 0))
1141-
constexpr _IV __pow2 = _IV(1) << __iota<_IV>;
1142+
constexpr _IV __pow2 = _IV(cw<1>) << __iota<_IV>;
11421143
return _Ur(_U0(__select_impl(__k, __pow2, _IV())
11431144
._M_reduce(bit_or<>()))) << _Offset;
11441145
}
@@ -1151,7 +1152,7 @@ namespace simd
11511152
}
11521153
else
11531154
{ // limit powers_of_2 to 1, 2, 4, ..., 128
1154-
constexpr _IV __pow2 = _IV(1) << (__iota<_IV> % _IV(__CHAR_BIT__));
1155+
constexpr _IV __pow2 = _IV(cw<1>) << (__iota<_IV> % _IV(cw<__CHAR_BIT__>));
11551156
_IV __x = __select_impl(__k, __pow2, _IV());
11561157
// partial reductions of 8 neighboring elements
11571158
__x |= _IV::_S_static_permute(__x, _SwapNeighbors<4>());

include/bits/simd_math.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ namespace simd
919919
__lerp(_Vp __a, _Vp __b, _Vp __t) noexcept
920920
{
921921
constexpr _Vp __zero = {};
922-
constexpr _Vp __one(1);
922+
constexpr _Vp __one(cw<1>);
923923
using _Mp = typename _Vp::mask_type;
924924
925925
// TODO: benchmark which method of computing the mask is better

include/bits/simd_vec.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ namespace simd
318318
if constexpr (_S_is_partial)
319319
if (__do_sanitize)
320320
return __select_impl(mask_type::_S_init(mask_type::_S_implicit_mask),
321-
*this, 0)._M_data;
321+
*this, __canon_value_type())._M_data;
322322
return _M_data;
323323
}
324324
#else
@@ -1169,6 +1169,14 @@ namespace simd
11691169
*
11701170
* @note The constructor is implicit if the conversion (if any) is value-preserving.
11711171
*/
1172+
#if !VIR_CONSTEVAL_BROADCAST
1173+
template <__broadcast_constructible<value_type> _Up>
1174+
[[__gnu__::__always_inline__]]
1175+
constexpr
1176+
basic_vec(_Up&& __x) noexcept
1177+
: _M_data(_DataType() == _DataType() ? static_cast<value_type>(__x) : value_type())
1178+
{}
1179+
#else
11721180
template <__explicitly_convertible_to<value_type> _Up>
11731181
[[__gnu__::__always_inline__]]
11741182
constexpr explicit(!__broadcast_constructible<_Up, value_type>)
@@ -1182,6 +1190,7 @@ namespace simd
11821190
: _M_data(_DataType() == _DataType()
11831191
? __value_preserving_cast<value_type>(__x) : value_type())
11841192
{}
1193+
#endif
11851194

11861195
// [simd.ctor] conversion constructor -----------------------------------
11871196
template <typename _Up, typename _UAbi, _TargetTraits _Traits = {}>
@@ -2257,6 +2266,14 @@ namespace simd
22572266
{ return _M_concat_data(); }
22582267

22592268
// [simd.ctor] broadcast constructor ------------------------------------
2269+
#if !VIR_CONSTEVAL_BROADCAST
2270+
template <__broadcast_constructible<value_type> _Up>
2271+
[[__gnu__::__always_inline__]]
2272+
constexpr
2273+
basic_vec(_Up&& __x) noexcept
2274+
: _M_data0(static_cast<value_type>(__x)), _M_data1(static_cast<value_type>(__x))
2275+
{}
2276+
#else
22602277
template <__explicitly_convertible_to<value_type> _Up>
22612278
[[__gnu__::__always_inline__]]
22622279
constexpr explicit(!__broadcast_constructible<_Up, value_type>)
@@ -2270,6 +2287,7 @@ namespace simd
22702287
: _M_data0(__value_preserving_cast<value_type>(__x)),
22712288
_M_data1(__value_preserving_cast<value_type>(__x))
22722289
{}
2290+
#endif
22732291

22742292
// [simd.ctor] conversion constructor -----------------------------------
22752293
template <typename _Up, typename _UAbi>

lib/hypot2.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ namespace std::simd
7575
// NaN inputs to min/max are UB (requires totally_ordered), replace inputs where a NaN output
7676
// is needed with precise 3²+4²=5².
7777
const M nan = isunordered(x, y);
78-
const V absx = select(nan, V(3), fabs(x)); // no error
79-
const V absy = select(nan, V(4), fabs(y)); // no error
78+
const V absx = select(nan, T(3), fabs(x)); // no error
79+
const V absy = select(nan, T(4), fabs(y)); // no error
8080
V hi = max(absx, absy); // no error
8181
V lo = min(absx, absy); // no error
8282
const auto huge_diff = is_large_diff(hi, lo);
@@ -88,11 +88,11 @@ namespace std::simd
8888
const V scale_back = rescale_factors(hi, lo);
8989
return scale_back * sqrt((lo * lo)._M_assoc_barrier() + hi * hi);
9090
}
91-
else if (all_of(isnormal(x) || x == 0) && all_of(isnormal(y) || y == 0))
91+
else if (all_of(isnormal(x) || x == T(0)) && all_of(isnormal(y) || y == T(0)))
9292
{ // more likely and cheaper than the branch below
93-
const auto k0 = lo == 0;
93+
const auto k0 = lo == T(0);
9494
const auto h0 = hi;
95-
hi = select(hi == 0, V(1), hi);
95+
hi = select(hi == T(0), T(1), hi);
9696
const V scale_back = rescale_factors(hi, lo);
9797
const V r = scale_back * sqrt((lo * lo)._M_assoc_barrier() + hi * hi);
9898
return select(k0, h0, r);
@@ -104,7 +104,7 @@ namespace std::simd
104104
// slower path to support subnormals
105105
// if hi is subnormal, avoid scaling by inf & final mul by 0
106106
// (which yields NaN) by using min()
107-
constexpr V subnorm_scale = 1 / norm_min_v<V>;
107+
constexpr V subnorm_scale = T(1) / norm_min_v<V>;
108108
// invert exponent w/o error and w/o using the slow divider
109109
// unit: xor inverts the exponent but off by 1. Multiplication
110110
// with .5 adjusts for the discrepancy.
@@ -131,7 +131,7 @@ namespace std::simd
131131
// ISA has FMAs (because h1² + lo is an FMA, but the
132132
// intermediate
133133
// h1² must be kept)
134-
return select(lo == 0 || nan || inf, fixup, r);
134+
return select(lo == T(0) || nan || inf, fixup, r);
135135
}
136136
}
137137

0 commit comments

Comments
 (0)