1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// Copyright 2021 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef HWY_TESTS_TEST_UTIL_H_
#define HWY_TESTS_TEST_UTIL_H_
// Target-independent helper functions for use by *_test.cc.
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <cmath> // std::isnan
#include <string>
#include "hwy/aligned_allocator.h"
#include "hwy/base.h"
#include "hwy/highway.h"
#include "hwy/highway_export.h"
#include "hwy/print.h"
namespace hwy {
// The maximum vector size used in tests when defining test data. DEPRECATED.
constexpr size_t kTestMaxVectorSize = 64;
// 64-bit random generator (Xorshift128+). Much smaller state than std::mt19937,
// which triggers a compiler bug.
class RandomState {
public:
explicit RandomState(const uint64_t seed = 0x123456789ull) {
s0_ = SplitMix64(seed + 0x9E3779B97F4A7C15ull);
s1_ = SplitMix64(s0_);
}
HWY_INLINE uint64_t operator()() {
uint64_t s1 = s0_;
const uint64_t s0 = s1_;
const uint64_t bits = s1 + s0;
s0_ = s0;
s1 ^= s1 << 23;
s1 ^= s0 ^ (s1 >> 18) ^ (s0 >> 5);
s1_ = s1;
return bits;
}
private:
static uint64_t SplitMix64(uint64_t z) {
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull;
z = (z ^ (z >> 27)) * 0x94D049BB133111EBull;
return z ^ (z >> 31);
}
uint64_t s0_;
uint64_t s1_;
};
static HWY_INLINE uint32_t Random32(RandomState* rng) {
return static_cast<uint32_t>((*rng)());
}
static HWY_INLINE uint64_t Random64(RandomState* rng) { return (*rng)(); }
// Prevents the compiler from eliding the computations that led to "output".
// Works by indicating to the compiler that "output" is being read and modified.
// The +r constraint avoids unnecessary writes to memory, but only works for
// built-in types.
template <class T>
inline void PreventElision(T&& output) {
#if HWY_COMPILER_MSVC
(void)output;
#else // HWY_COMPILER_MSVC
asm volatile("" : "+r"(output) : : "memory");
#endif // HWY_COMPILER_MSVC
}
HWY_TEST_DLLEXPORT bool BytesEqual(const void* p1, const void* p2,
const size_t size, size_t* pos = nullptr);
void AssertStringEqual(const char* expected, const char* actual,
const char* target_name, const char* filename, int line);
namespace detail {
template <typename T, typename TU = MakeUnsigned<T>>
TU ComputeUlpDelta(const T expected, const T actual) {
// Handle -0 == 0 and infinities.
if (expected == actual) return 0;
// Consider "equal" if both are NaN, so we can verify an expected NaN.
// Needs a special case because there are many possible NaN representations.
if (std::isnan(expected) && std::isnan(actual)) return 0;
// Compute the difference in units of last place. We do not need to check for
// differing signs; they will result in large differences, which is fine.
TU ux, uy;
CopySameSize(&expected, &ux);
CopySameSize(&actual, &uy);
// Avoid unsigned->signed cast: 2's complement is only guaranteed by C++20.
const TU ulp = HWY_MAX(ux, uy) - HWY_MIN(ux, uy);
return ulp;
}
HWY_TEST_DLLEXPORT bool IsEqual(const TypeInfo& info, const void* expected_ptr,
const void* actual_ptr);
HWY_TEST_DLLEXPORT HWY_NORETURN void PrintMismatchAndAbort(
const TypeInfo& info, const void* expected_ptr, const void* actual_ptr,
const char* target_name, const char* filename, int line, size_t lane = 0,
size_t num_lanes = 1);
HWY_TEST_DLLEXPORT void AssertArrayEqual(const TypeInfo& info,
const void* expected_void,
const void* actual_void, size_t N,
const char* target_name,
const char* filename, int line);
} // namespace detail
// Returns a name for the vector/part/scalar. The type prefix is u/i/f for
// unsigned/signed/floating point, followed by the number of bits per lane;
// then 'x' followed by the number of lanes. Example: u8x16. This is useful for
// understanding which instantiation of a generic test failed.
template <typename T>
std::string TypeName(T /*unused*/, size_t N) {
char string100[100];
detail::TypeName(detail::MakeTypeInfo<T>(), N, string100);
return string100;
}
// Compare non-vector, non-string T.
template <typename T>
HWY_INLINE bool IsEqual(const T expected, const T actual) {
const auto info = detail::MakeTypeInfo<T>();
return detail::IsEqual(info, &expected, &actual);
}
template <typename T>
HWY_INLINE void AssertEqual(const T expected, const T actual,
const char* target_name, const char* filename,
int line, size_t lane = 0) {
const auto info = detail::MakeTypeInfo<T>();
if (!detail::IsEqual(info, &expected, &actual)) {
detail::PrintMismatchAndAbort(info, &expected, &actual, target_name,
filename, line, lane);
}
}
template <typename T>
HWY_INLINE void AssertArrayEqual(const T* expected, const T* actual,
size_t count, const char* target_name,
const char* filename, int line) {
const auto info = hwy::detail::MakeTypeInfo<T>();
detail::AssertArrayEqual(info, expected, actual, count, target_name, filename,
line);
}
} // namespace hwy
#endif // HWY_TESTS_TEST_UTIL_H_
|