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