1 /* This file is part of the Vc library. {{{
2 Copyright © 2010-2016 Matthias Kretz <kretz@kde.org>
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 * Neither the names of contributing organizations nor the
12 names of its contributors may be used to endorse or promote products
13 derived from this software without specific prior written permission.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 }}}*/
27
28 #include "generators.h"
29 #include "unittest.h"
30
31 using namespace Vc;
32
TEST_TYPES(V,reads,concat<AllVectors,SimdArrayList>)33 TEST_TYPES(V, reads, concat<AllVectors, SimdArrayList>)
34 {
35 typedef typename V::EntryType T;
36
37 V a = V(0);
38 const T zero = 0;
39 for (size_t i = 0; i < V::Size; ++i) {
40 const T x = a[i];
41 COMPARE(x, zero);
42 }
43 a = V([](T n) { return n; });
44 for (size_t i = 0; i < V::Size; ++i) {
45 const T x = a[i];
46 const T y = i;
47 COMPARE(x, y);
48 }
49 // The non-const operator[] returns a smart reference that mimics an lvalue reference.
50 // But since it's not an actual lvalue reference the proxy is supposed to live as
51 // short as possible. To achieve this all move & copy operations must be disabled.
52 VERIFY(std::is_move_constructible<decltype(a[0])>::value);
53 VERIFY(!std::is_copy_constructible<decltype(a[0])>::value);
54 VERIFY(!std::is_move_assignable<decltype(a[0])>::value);
55 VERIFY(!std::is_copy_assignable<decltype(a[0])>::value);
56 VERIFY(!std::is_reference<decltype(a[0])>::value);
57 COMPARE(typeid(decltype(a[0])), typeid(typename V::reference));
58
59 // the operator[] const overload returns an rvalue T and is therefore not constrained
60 // in the same way as the non-const operator[]
61 const V b = a;
62 VERIFY(std::is_move_constructible<decltype(b[0])>::value);
63 VERIFY(std::is_copy_constructible<decltype(b[0])>::value);
64 VERIFY(std::is_move_assignable<decltype(b[0])>::value);
65 VERIFY(std::is_copy_assignable<decltype(b[0])>::value);
66 VERIFY(!std::is_reference<decltype(b[0])>::value);
67 COMPARE(typeid(decltype(b[0])), typeid(typename V::value_type));
68 }
69
readsConstantIndexTest(V a,V b)70 template <typename V, size_t Index> inline void readsConstantIndexTest(V a, V b)
71 {
72 typedef typename V::EntryType T;
73 {
74 const T x = a[Index];
75 const T zero = 0;
76 COMPARE(x, zero) << Index;
77 }{
78 const T x = b[Index];
79 const T y = Index;
80 COMPARE(x, y) << Index;
81 }
82 }
83
84 template<typename V, size_t Index>
85 struct ReadsConstantIndex
86 {
ReadsConstantIndexReadsConstantIndex87 ReadsConstantIndex(const V &a, const V &b)
88 {
89 readsConstantIndexTest<V, Index>(a, b);
90 ReadsConstantIndex<V, Index - 1>(a, b);
91 }
92 };
93
94
95 template<typename V>
96 struct ReadsConstantIndex<V, 0>
97 {
ReadsConstantIndexReadsConstantIndex98 ReadsConstantIndex(const V &a, const V &b) { readsConstantIndexTest<V, 0>(a, b); }
99 };
100
TEST_TYPES(V,readsConstantIndex,concat<AllVectors,SimdArrayList>)101 TEST_TYPES(V, readsConstantIndex, concat<AllVectors, SimdArrayList>)
102 {
103 V a = V(0);
104 V b = V([](int n) { return n; });
105 ReadsConstantIndex<V, V::Size - 1>(a, b);
106 }
107
TEST_TYPES(V,writes,concat<AllVectors,SimdArrayList>)108 TEST_TYPES(V, writes, concat<AllVectors, SimdArrayList>)
109 {
110 typedef typename V::EntryType T;
111
112 V a = 0;
113 std::array<T, V::size()> reference = {0};
114 int i = 0;
115 iterateNumericRange<T>([&](T x) {
116 reference[i] = x;
117 a[i] = x;
118 COMPARE(a, V(&reference[0]));
119 i = (i + 1) % V::size();
120 });
121 }
122
123 template <typename T> using decayed = typename std::decay<T>::type;
124 template <typename V> using EntryType = typename decayed<V>::EntryType;
125
126 #define INT_OP(op, name) \
127 template <typename V> bool test_##name##_assign(V &&, float, int) { return false; } \
128 template <typename V, \
129 typename = decltype(std::declval<V>()[0] op## = EntryType<V>())> \
130 bool test_##name##_assign(V &&a, int x, int y) \
131 { \
132 using T = EntryType<V>; \
133 COMPARE(a[0] op## = T(x), T(y)); \
134 COMPARE(a[0], T(y)); \
135 return true; \
136 } \
137 Vc_NOTHING_EXPECTING_SEMICOLON
138 INT_OP(+, plus);
139 INT_OP(-, minus);
140 INT_OP(*, times);
141 INT_OP(/, divide);
142 INT_OP(%, percent);
143 INT_OP(<<, lshift);
144 INT_OP(>>, rshift);
145 INT_OP(|, bor);
146 INT_OP(&, band);
147 INT_OP(^, bxor);
148 #undef INT_OP
149
150 #define UNARY_OP(op, name) \
151 template <typename V> bool test_unary_##name(V &&, ...) { return false; } \
152 template <typename V> \
153 bool test_unary_##name(V &&a, decltype(op(std::declval<V>()[0])) x) \
154 { \
155 COMPARE(op a[0], x); \
156 return true; \
157 } \
158 template <typename V> bool test_unary_##name##_nosubscript(V &&, ...) \
159 { \
160 return false; \
161 } \
162 template <typename V> \
163 bool test_unary_##name##_nosubscript(V &&a, decltype(op std::declval<V>()) x) \
164 { \
165 COMPARE(op a, x); \
166 return true; \
167 } \
168 Vc_NOTHING_EXPECTING_SEMICOLON
169 UNARY_OP(!, not);
170 UNARY_OP(+, plus);
171 UNARY_OP(-, minus);
172 UNARY_OP(~, bitflip);
173 #undef UNARY_OP
174
test_pre_increment(V &&,float)175 template <typename V> bool test_pre_increment(V &&, float) { return false; }
176 template <typename V, typename = decltype(++std::declval<V>()[0])>
test_pre_increment(V && a,int x)177 bool test_pre_increment(V &&a, int x)
178 {
179 using T = EntryType<V>;
180 COMPARE(++a[0], T(x));
181 COMPARE(a[0], T(x));
182 return true;
183 }
test_post_increment(V &&,float)184 template <typename V> bool test_post_increment(V &&, float) { return false; }
185 template <typename V, typename = decltype(std::declval<V>()[0]++)>
test_post_increment(V && a,int x)186 bool test_post_increment(V &&a, int x)
187 {
188 using T = EntryType<V>;
189 COMPARE(a[0]++, T(x - 1));
190 COMPARE(a[0], T(x));
191 return true;
192 }
test_pre_decrement(V &&,float)193 template <typename V> bool test_pre_decrement(V &&, float) { return false; }
194 template <typename V, typename = decltype(--std::declval<V>()[0])>
test_pre_decrement(V && a,int x)195 bool test_pre_decrement(V &&a, int x)
196 {
197 using T = EntryType<V>;
198 COMPARE(--a[0], T(x));
199 COMPARE(a[0], T(x));
200 return true;
201 }
test_post_decrement(V &&,float)202 template <typename V> bool test_post_decrement(V &&, float) { return false; }
203 template <typename V, typename = decltype(std::declval<V>()[0]--)>
test_post_decrement(V && a,int x)204 bool test_post_decrement(V &&a, int x)
205 {
206 using T = EntryType<V>;
207 COMPARE(a[0]--, T(x + 1));
208 COMPARE(a[0], T(x));
209 return true;
210 }
211
TEST_TYPES(V,operators,concat<AllVectors,SimdArrayList>)212 TEST_TYPES(V, operators, concat<AllVectors, SimdArrayList>)
213 {
214 using T = EntryType<V>;
215 V a = 10;
216 VERIFY(test_unary_not(a, false));
217 VERIFY(test_unary_plus(a, 10));
218 VERIFY(test_unary_minus(a, -10));
219 COMPARE(test_unary_bitflip(a, ~10), std::is_integral<T>::value);
220 VERIFY(test_plus_assign(a, 1, 11));
221 VERIFY(test_minus_assign(a, 1, 10));
222 VERIFY(test_times_assign(a, 2, 20));
223 VERIFY(test_divide_assign(a, 2, 10));
224 VERIFY(test_pre_decrement(a, 9));
225 VERIFY(test_post_decrement(a, 8));
226 VERIFY(test_pre_increment(a, 9));
227 VERIFY(test_post_increment(a, 10));
228 COMPARE(test_percent_assign(a, 6, 4), std::is_integral<T>::value);
229 COMPARE(test_lshift_assign(a, 1, 8), std::is_integral<T>::value);
230 COMPARE(test_rshift_assign(a, 2, 2), std::is_integral<T>::value);
231 COMPARE(test_bor_assign(a, 9, 11), std::is_integral<T>::value);
232 COMPARE(test_band_assign(a, 13, 9), std::is_integral<T>::value);
233 COMPARE(test_bxor_assign(a, 1, 8), std::is_integral<T>::value);
234
235 // assignment operators should never work on const ref
236 a = 10;
237 const auto &x = a[0];
238 COMPARE(x, T(10));
239 VERIFY(!test_plus_assign(x, 1, 11));
240 VERIFY(!test_minus_assign(x, 1, 10));
241 VERIFY(!test_times_assign(x, 2, 20));
242 VERIFY(!test_divide_assign(x, 2, 10));
243 VERIFY(!test_pre_decrement(x, 9));
244 VERIFY(!test_post_decrement(x, 8));
245 VERIFY(!test_pre_increment(x, 9));
246 VERIFY(!test_post_increment(x, 10));
247 VERIFY(!test_percent_assign(x, 6, 4));
248 VERIFY(!test_lshift_assign(x, 1, 8));
249 VERIFY(!test_rshift_assign(x, 2, 2));
250 VERIFY(!test_bor_assign(x, 9, 11));
251 VERIFY(!test_band_assign(x, 13, 9));
252 VERIFY(!test_bxor_assign(x, 1, 8));
253
254 // unary operators should work, though
255 VERIFY(test_unary_not_nosubscript(x, false));
256 VERIFY(test_unary_plus_nosubscript(x, 10));
257 VERIFY(test_unary_minus_nosubscript(x, -10));
258 COMPARE(test_unary_bitflip_nosubscript(x, ~10), std::is_integral<T>::value);
259
260 // Just to make sure, the assignment operators also should not work on lvalue
261 // references
262 decltype(a[0]) *y = nullptr;
263 VERIFY(!test_plus_assign(*y, 1, 11));
264 VERIFY(!test_minus_assign(*y, 1, 10));
265 VERIFY(!test_times_assign(*y, 2, 20));
266 VERIFY(!test_divide_assign(*y, 2, 10));
267 VERIFY(!test_pre_decrement(*y, 9));
268 VERIFY(!test_post_decrement(*y, 8));
269 VERIFY(!test_pre_increment(*y, 9));
270 VERIFY(!test_post_increment(*y, 10));
271 VERIFY(!test_percent_assign(*y, 6, 4));
272 VERIFY(!test_lshift_assign(*y, 1, 8));
273 VERIFY(!test_rshift_assign(*y, 2, 2));
274 VERIFY(!test_bor_assign(*y, 9, 11));
275 VERIFY(!test_band_assign(*y, 13, 9));
276 VERIFY(!test_bxor_assign(*y, 1, 8));
277
278 auto k0 = a == a;
279 const auto &k1 = k0;
280 VERIFY(test_unary_not(k0, 0));
281 VERIFY(test_unary_not(k1, 0));
282 k0 = a != a;
283 VERIFY(test_unary_not(k0, 1));
284 }
285
TEST_TYPES(V,ensure_noexcept,concat<AllVectors,SimdArrayList>)286 TEST_TYPES(V, ensure_noexcept, concat<AllVectors, SimdArrayList>)
287 {
288 V a{};
289 {
290 const V &b = a;
291 EntryType<V> x = a[0]; if (x == x) {}
292 VERIFY(noexcept(a[0]));
293 VERIFY(noexcept(x = b[0]));
294 VERIFY(noexcept(x = a[0]));
295 VERIFY(noexcept(a[0] = 1));
296 VERIFY(noexcept(a[0] += 1));
297 VERIFY(noexcept(a[0] -= 1));
298 VERIFY(noexcept(a[0] *= 1));
299 VERIFY(noexcept(a[0] /= 1));
300 VERIFY(noexcept(++a[0]));
301 VERIFY(noexcept(--a[0]));
302 VERIFY(noexcept(a[0]++));
303 VERIFY(noexcept(a[0]--));
304 }
305 {
306 auto k0 = a == a;
307 const auto &k1 = k0;
308 bool x = false; if (x) {}
309 VERIFY(noexcept(k0[0]));
310 VERIFY(noexcept(x = k1[0]));
311 VERIFY(noexcept(x = k0[0]));
312 VERIFY(noexcept(k0[0] = 1));
313 }
314 }
315