]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/experimental/simd/tests/operators.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / experimental / simd / tests / operators.cc
1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 //
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
17
18 // expensive: * [1-9] * *
19 #include "bits/verify.h"
20 #include "bits/make_vec.h"
21 #include "bits/test_values.h"
22
23 template <class T>
24 constexpr T
25 genHalfBits()
26 {
27 if constexpr (std::is_floating_point_v<T>)
28 return 0;
29 else
30 return std::__finite_max_v<T> >> (std::__digits_v<T> / 2);
31 }
32
33 template <typename V>
34 void
35 test()
36 {
37 using M = typename V::mask_type;
38 using T = typename V::value_type;
39 constexpr auto min = std::__finite_min_v<T>;
40 constexpr auto norm_min = std::__norm_min_v<T>;
41 constexpr auto max = std::__finite_max_v<T>;
42 { // compares
43 COMPARE(V(0) == make_vec<V>({0, 1}, 0), make_mask<M>({1, 0}));
44 COMPARE(V(0) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({1, 0, 0}));
45 COMPARE(V(1) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 1, 0}));
46 COMPARE(V(2) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 0, 1}));
47 COMPARE(V(0) < make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 1, 1}));
48
49 constexpr T half = genHalfBits<T>();
50 for (T lo_ : {min, T(min + 1), T(-1), T(0), norm_min, T(1), T(half - 1),
51 half, T(half + 1), T(max - 1)})
52 {
53 for (T hi_ : {T(min + 1), T(-1), T(0), norm_min, T(1), T(half - 1),
54 half, T(half + 1), T(max - 1), max})
55 {
56 if (hi_ <= lo_)
57 continue;
58
59 for (std::size_t pos = 0; pos < V::size(); ++pos)
60 {
61 V lo = lo_;
62 V hi = hi_;
63 lo[pos] = 0; // have a different value in the vector in case
64 hi[pos] = 1; // this affects neighbors
65 COMPARE(hi, hi);
66 VERIFY(all_of(hi != lo)) << "hi: " << hi << ", lo: " << lo;
67 VERIFY(all_of(lo != hi)) << "hi: " << hi << ", lo: " << lo;
68 VERIFY(none_of(hi != hi)) << "hi: " << hi << ", lo: " << lo;
69 VERIFY(none_of(hi == lo)) << "hi: " << hi << ", lo: " << lo;
70 VERIFY(none_of(lo == hi)) << "hi: " << hi << ", lo: " << lo;
71 VERIFY(all_of(lo < hi)) << "hi: " << hi << ", lo: " << lo
72 << ", lo < hi: " << (lo < hi);
73 VERIFY(none_of(hi < lo)) << "hi: " << hi << ", lo: " << lo;
74 VERIFY(none_of(hi <= lo)) << "hi: " << hi << ", lo: " << lo;
75 VERIFY(all_of(hi <= hi)) << "hi: " << hi << ", lo: " << lo;
76 VERIFY(all_of(hi > lo)) << "hi: " << hi << ", lo: " << lo;
77 VERIFY(none_of(lo > hi)) << "hi: " << hi << ", lo: " << lo;
78 VERIFY(all_of(hi >= lo)) << "hi: " << hi << ", lo: " << lo;
79 VERIFY(all_of(hi >= hi)) << "hi: " << hi << ", lo: " << lo;
80 }
81 }
82 }
83 }
84 { // subscripting
85 V x = max;
86 for (std::size_t i = 0; i < V::size(); ++i)
87 {
88 COMPARE(x[i], max);
89 x[i] = 0;
90 }
91 COMPARE(x, V{0});
92 for (std::size_t i = 0; i < V::size(); ++i)
93 {
94 COMPARE(x[i], T(0));
95 x[i] = max;
96 }
97 COMPARE(x, V{max});
98 COMPARE(typeid(x[0] * x[0]), typeid(T() * T()));
99 COMPARE(typeid(x[0] * T()), typeid(T() * T()));
100 COMPARE(typeid(T() * x[0]), typeid(T() * T()));
101 COMPARE(typeid(x * x[0]), typeid(x));
102 COMPARE(typeid(x[0] * x), typeid(x));
103
104 x = V([](auto i) -> T { return i; });
105 for (std::size_t i = 0; i < V::size(); ++i)
106 {
107 COMPARE(x[i], T(i));
108 }
109 for (std::size_t i = 0; i + 1 < V::size(); i += 2)
110 {
111 using std::swap;
112 swap(x[i], x[i + 1]);
113 }
114 for (std::size_t i = 0; i + 1 < V::size(); i += 2)
115 {
116 COMPARE(x[i], T(i + 1)) << x;
117 COMPARE(x[i + 1], T(i)) << x;
118 }
119 x = 1;
120 V y = 0;
121 COMPARE(x[0], T(1));
122 x[0] = y[0]; // make sure non-const smart_reference assignment works
123 COMPARE(x[0], T(0));
124 x = 1;
125 x[0] = x[0]; // self-assignment on smart_reference
126 COMPARE(x[0], T(1));
127
128 std::experimental::simd<typename V::value_type,
129 std::experimental::simd_abi::scalar>
130 z = 2;
131 x[0] = z[0];
132 COMPARE(x[0], T(2));
133 x = 3;
134 z[0] = x[0];
135 COMPARE(z[0], T(3));
136
137 // TODO: check that only value-preserving conversions happen on subscript
138 // assignment
139 }
140 { // not
141 V x = 0;
142 COMPARE(!x, M{true});
143 V y = 1;
144 COMPARE(!y, M{false});
145 }
146
147 { // unary minus
148 V x = 0;
149 COMPARE(-x, V(T(-T(0))));
150 V y = 1;
151 COMPARE(-y, V(T(-T(1))));
152 }
153
154 { // plus
155 V x = 0;
156 V y = 0;
157 COMPARE(x + y, x);
158 COMPARE(x = x + T(1), V(1));
159 COMPARE(x + x, V(2));
160 y = make_vec<V>({1, 2, 3, 4, 5, 6, 7});
161 COMPARE(x = x + y, make_vec<V>({2, 3, 4, 5, 6, 7, 8}));
162 COMPARE(x = x + -y, V(1));
163 COMPARE(x += y, make_vec<V>({2, 3, 4, 5, 6, 7, 8}));
164 COMPARE(x, make_vec<V>({2, 3, 4, 5, 6, 7, 8}));
165 COMPARE(x += -y, V(1));
166 COMPARE(x, V(1));
167 }
168
169 { // minus
170 V x = 1;
171 V y = 0;
172 COMPARE(x - y, x);
173 COMPARE(x - T(1), y);
174 COMPARE(y, x - T(1));
175 COMPARE(x - x, y);
176 y = make_vec<V>({1, 2, 3, 4, 5, 6, 7});
177 COMPARE(x = y - x, make_vec<V>({0, 1, 2, 3, 4, 5, 6}));
178 COMPARE(x = y - x, V(1));
179 COMPARE(y -= x, make_vec<V>({0, 1, 2, 3, 4, 5, 6}));
180 COMPARE(y, make_vec<V>({0, 1, 2, 3, 4, 5, 6}));
181 COMPARE(y -= y, V(0));
182 COMPARE(y, V(0));
183 }
184
185 { // multiplies
186 V x = 1;
187 V y = 0;
188 COMPARE(x * y, y);
189 COMPARE(x = x * T(2), V(2));
190 COMPARE(x * x, V(4));
191 y = make_vec<V>({1, 2, 3, 4, 5, 6, 7});
192 COMPARE(x = x * y, make_vec<V>({2, 4, 6, 8, 10, 12, 14}));
193 y = 2;
194 // don't test norm_min/2*2 in the following. There's no guarantee, in
195 // general, that the result isn't flushed to zero (e.g. NEON without
196 // subnormals)
197 for (T n :
198 {T(max - 1), std::is_floating_point_v<T> ? T(norm_min * 3) : min})
199 {
200 x = n / 2;
201 COMPARE(x * y, V(n));
202 }
203 if (std::is_integral<T>::value && std::is_unsigned<T>::value)
204 {
205 // test modulo arithmetics
206 T n = max;
207 x = n;
208 for (T m : {T(2), T(7), T(max / 127), max})
209 {
210 y = m;
211 // if T is of lower rank than int, `n * m` will promote to int
212 // before executing the multiplication. In this case an overflow
213 // will be UB (and ubsan will warn about it). The solution is to
214 // cast to uint in that case.
215 using U
216 = std::conditional_t<(sizeof(T) < sizeof(int)), unsigned, T>;
217 COMPARE(x * y, V(T(U(n) * U(m))));
218 }
219 }
220 x = 2;
221 COMPARE(x *= make_vec<V>({1, 2, 3}), make_vec<V>({2, 4, 6}));
222 COMPARE(x, make_vec<V>({2, 4, 6}));
223 }
224
225 // divides
226 constexpr bool is_iec559 = __GCC_IEC_559 >= 2;
227 if constexpr (std::is_floating_point_v<T> && !is_iec559)
228 { // avoid testing subnormals and expect minor deltas for non-IEC559 float
229 V x = 2;
230 ULP_COMPARE(x / x, V(1), 1);
231 ULP_COMPARE(T(3) / x, V(T(3) / T(2)), 1);
232 ULP_COMPARE(x / T(3), V(T(2) / T(3)), 1);
233 V y = make_vec<V>({1, 2, 3, 4, 5, 6, 7});
234 ULP_COMPARE(y / x,
235 make_vec<V>(
236 {T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)}),
237 1);
238
239 test_values<V>({norm_min * 1024, T(1), T(), T(-1), max / 1024,
240 max / 4.1, max, min},
241 [&](V a) {
242 V b = 2;
243 V ref([&](auto i) { return a[i] / 2; });
244 ULP_COMPARE(a / b, ref, 1);
245 where(a == 0, a) = 1;
246 // -freciprocal-math together with flush-to-zero makes
247 // the following range restriction necessary (i.e.
248 // 1/|a| must be >= min). Intel vrcpps and vrcp14ps
249 // need some extra slack (use 1.1 instead of 1).
250 where(abs(a) >= T(1.1) / norm_min, a) = 1;
251 ULP_COMPARE(a / a, V(1), 1) << "\na = " << a;
252 ref = V([&](auto i) { return 2 / a[i]; });
253 ULP_COMPARE(b / a, ref, 1) << "\na = " << a;
254 ULP_COMPARE(b /= a, ref, 1);
255 ULP_COMPARE(b, ref, 1);
256 });
257 }
258 else
259 {
260 V x = 2;
261 COMPARE(x / x, V(1));
262 COMPARE(T(3) / x, V(T(3) / T(2)));
263 COMPARE(x / T(3), V(T(2) / T(3)));
264 V y = make_vec<V>({1, 2, 3, 4, 5, 6, 7});
265 COMPARE(y / x,
266 make_vec<V>({T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)}));
267
268 y = make_vec<V>({max, norm_min});
269 V ref = make_vec<V>({T(max / 2), T(norm_min / 2)});
270 COMPARE(y / x, ref);
271
272 y = make_vec<V>({norm_min, max});
273 ref = make_vec<V>({T(norm_min / 2), T(max / 2)});
274 COMPARE(y / x, ref);
275
276 y = make_vec<V>({max, T(norm_min + 1)});
277 COMPARE(y / y, V(1));
278
279 ref = make_vec<V>({T(2 / max), T(2 / (norm_min + 1))});
280 COMPARE(x / y, ref);
281 COMPARE(x /= y, ref);
282 COMPARE(x, ref);
283 }
284
285 { // increment & decrement
286 const V from0 = make_vec<V>({0, 1, 2, 3}, 4);
287 V x = from0;
288 COMPARE(x++, from0);
289 COMPARE(x, from0 + 1);
290 COMPARE(++x, from0 + 2);
291 COMPARE(x, from0 + 2);
292
293 COMPARE(x--, from0 + 2);
294 COMPARE(x, from0 + 1);
295 COMPARE(--x, from0);
296 COMPARE(x, from0);
297 }
298 }