]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / experimental / simd / tests / bits / verify.h
1 // Copyright (C) 2020-2024 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 #ifndef TESTS_BITS_VERIFY_H_
19 #define TESTS_BITS_VERIFY_H_
20
21 #include <experimental/simd>
22 #include <sstream>
23 #include <iomanip>
24 #include "ulp.h"
25
26 #ifdef _GLIBCXX_SIMD_HAVE_NEON
27 // work around PR89357:
28 #define alignas(...) __attribute__((aligned(__VA_ARGS__)))
29 #endif
30
31 using schar = signed char;
32 using uchar = unsigned char;
33 using ushort = unsigned short;
34 using uint = unsigned int;
35 using ulong = unsigned long;
36 using llong = long long;
37 using ullong = unsigned long long;
38 using ldouble = long double;
39 using wchar = wchar_t;
40 using char16 = char16_t;
41 using char32 = char32_t;
42
43 template <class T>
44 T
45 make_value_unknown(const T& x)
46 {
47 if constexpr (std::is_constructible_v<T, const volatile T&>)
48 {
49 const volatile T& y = x;
50 return y;
51 }
52 else
53 {
54 T y = x;
55 asm("" : "+m"(y));
56 return y;
57 }
58 }
59
60 class verify
61 {
62 const bool m_failed = false;
63 size_t m_ip = 0;
64
65 template <typename T,
66 typename = decltype(std::declval<std::stringstream&>()
67 << std::declval<const T&>())>
68 void
69 print(const T& x, int) const
70 {
71 std::stringstream ss;
72 ss << x;
73 __builtin_fprintf(stderr, "%s", ss.str().c_str());
74 }
75
76 template <typename T>
77 void
78 print(const T& x, ...) const
79 {
80 if constexpr (std::experimental::is_simd_v<T>)
81 {
82 std::stringstream ss;
83 if constexpr (std::is_floating_point_v<typename T::value_type>)
84 {
85 ss << '(' << x[0] << " == " << std::hexfloat << x[0]
86 << std::defaultfloat << ')';
87 for (unsigned i = 1; i < x.size(); ++i)
88 {
89 ss << (i % 4 == 0 ? ",\n(" : ", (") << x[i]
90 << " == " << std::hexfloat << x[i] << std::defaultfloat
91 << ')';
92 }
93 }
94 else
95 {
96 ss << +x[0];
97 for (unsigned i = 1; i < x.size(); ++i)
98 {
99 ss << ", " << +x[i];
100 }
101 }
102 __builtin_fprintf(stderr, "%s", ss.str().c_str());
103 }
104 else if constexpr (std::experimental::is_simd_mask_v<T>)
105 {
106 __builtin_fprintf(stderr, (x[0] ? "[1" : "[0"));
107 for (unsigned i = 1; i < x.size(); ++i)
108 {
109 __builtin_fprintf(stderr, (x[i] ? "1" : "0"));
110 }
111 __builtin_fprintf(stderr, "]");
112 }
113 else
114 {
115 print_hex(&x, sizeof(T));
116 }
117 }
118
119 void
120 print_hex(const void* x, std::size_t n) const
121 {
122 __builtin_fprintf(stderr, "0x");
123 const auto* bytes = static_cast<const unsigned char*>(x);
124 for (std::size_t i = 0; i < n; ++i)
125 {
126 __builtin_fprintf(stderr, (i && i % 4 == 0) ? "'%02x" : "%02x",
127 bytes[i]);
128 }
129 }
130
131 public:
132 template <typename... Ts>
133 [[gnu::always_inline]]
134 verify(bool ok, const char* file, const int line,
135 const char* func, const char* cond, const Ts&... extra_info)
136 : m_failed(!ok), m_ip(get_ip())
137 {
138 if (m_failed)
139 [&] {
140 __builtin_fprintf(stderr, "%s:%d: (%s):\nInstruction Pointer: %zx\n"
141 "Assertion '%s' failed.\n",
142 file, line, func, m_ip, cond);
143 (print(extra_info, int()), ...);
144 }();
145 }
146
147 [[gnu::always_inline]] ~verify()
148 {
149 if (m_failed)
150 {
151 __builtin_fprintf(stderr, "\n");
152 __builtin_abort();
153 }
154 }
155
156 template <typename T>
157 [[gnu::always_inline]]
158 const verify&
159 operator<<(const T& x) const
160 {
161 if (m_failed)
162 print(x, int());
163 return *this;
164 }
165
166 template <typename... Ts>
167 [[gnu::always_inline]]
168 const verify&
169 on_failure(const Ts&... xs) const
170 {
171 if (m_failed)
172 [&] { (print(xs, int()), ...); }();
173 return *this;
174 }
175
176 [[gnu::always_inline]] static inline
177 size_t
178 get_ip()
179 {
180 size_t _ip = 0;
181 #ifdef __x86_64__
182 asm volatile("lea 0(%%rip),%0" : "=r"(_ip));
183 #elif defined __i386__
184 asm volatile("1: movl $1b,%0" : "=r"(_ip));
185 #elif defined __arm__
186 asm volatile("mov %0,pc" : "=r"(_ip));
187 #elif defined __aarch64__
188 asm volatile("adr %0,." : "=r"(_ip));
189 #endif
190 return _ip;
191 }
192 };
193
194 #if __FLT_EVAL_METHOD__ != 0
195 template <typename T>
196 [[gnu::always_inline]] inline decltype(auto)
197 force_fp_truncation(const T& x)
198 {
199 namespace stdx = std::experimental;
200 if constexpr (stdx::is_simd_v<T>)
201 {
202 using U = typename T::value_type;
203 if constexpr (std::is_floating_point_v<typename T::value_type>
204 && sizeof(U) <= 8 && (sizeof(T) < 16 || std::is_same_v<
205 T, stdx::fixed_size_simd<U, T::size()>>))
206 {
207 T y = x;
208 asm("" : "+m"(y));
209 return y;
210 }
211 else
212 return x;
213 }
214 else if constexpr (std::is_floating_point_v<T> && sizeof(T) <= 8)
215 {
216 T y = x;
217 asm("" : "+m"(y));
218 return y;
219 }
220 else
221 return x;
222 }
223
224 #define COMPARE(_a, _b) \
225 [&](auto&& _aa, auto&& _bb) { \
226 return verify(std::experimental::all_of(_aa == _bb), __FILE__, __LINE__, \
227 __PRETTY_FUNCTION__, #_a " == " #_b, #_a " = ", _aa, \
228 "\n" #_b " = ", _bb); \
229 }(force_fp_truncation(_a), force_fp_truncation(_b))
230 #else
231 #define COMPARE(_a, _b) \
232 [&](auto&& _aa, auto&& _bb) { \
233 return verify(std::experimental::all_of(_aa == _bb), __FILE__, __LINE__, \
234 __PRETTY_FUNCTION__, #_a " == " #_b, #_a " = ", _aa, \
235 "\n" #_b " = ", _bb); \
236 }((_a), (_b))
237 #endif
238
239 #define VERIFY(_test) \
240 verify(_test, __FILE__, __LINE__, __PRETTY_FUNCTION__, #_test)
241
242 // ulp_distance_signed can raise FP exceptions and thus must be conditionally
243 // executed
244 #define ULP_COMPARE(_a, _b, _allowed_distance) \
245 [&](auto&& _aa, auto&& _bb) { \
246 const bool success = std::experimental::all_of( \
247 vir::test::ulp_distance(_aa, _bb) <= (_allowed_distance)); \
248 return verify(success, __FILE__, __LINE__, __PRETTY_FUNCTION__, \
249 #_a " ~~ " #_b, #_a " = ", _aa, "\n" #_b " = ", _bb, \
250 "\ndistance = ", \
251 success ? 0 : vir::test::ulp_distance_signed(_aa, _bb)); \
252 }((_a), (_b))
253
254 namespace vir {
255 namespace test
256 {
257 template <typename T>
258 inline T _S_fuzzyness = 0;
259
260 template <typename T>
261 void
262 setFuzzyness(T x)
263 { _S_fuzzyness<T> = x; }
264 } // namespace test
265 } // namespace vir
266
267 #define FUZZY_COMPARE(_a, _b) \
268 ULP_COMPARE( \
269 _a, _b, \
270 vir::test::_S_fuzzyness<vir::test::value_type_t<decltype((_a) + (_b))>>)
271
272 template <typename V>
273 void
274 test();
275
276 template <typename V>
277 void
278 invoke_test(...)
279 {}
280
281 template <typename V, typename = decltype(V())>
282 void
283 invoke_test(int)
284 {
285 test<V>();
286 __builtin_fprintf(stderr, "PASS: %s\n", __PRETTY_FUNCTION__);
287 }
288
289 #endif // TESTS_BITS_VERIFY_H_