2 * Copyright (c) 2014 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
8 * Test that the LLVM vector shuffle can be used from C code.
9 * http://clang.llvm.org/docs/LanguageExtensions.html#builtin-shufflevector
11 * We support the LLVM syntax only, the GCC equivalent isn't supported
13 * http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
15 * This test ensures that the compiler can generate code for vector
16 * shuffles without rejecting it (e.g. with some internal failure or
17 * validation error), and that the output it generates is as specified
18 * by the shuffle builtin's specification. It is fairly exhaustive and
19 * covers many shuffle patterns in an attempt to utilize shuffle
20 * patterns that compilers may choose to lower to better instructions on
21 * certain architectures:
23 * - Only the left-hand-side source is used to form the destination.
24 * - Only the right-hand-side source is used to form the destination.
25 * - Each index in a source is shuffled to each index in the destination.
26 * - The destination is identical to one of the inputs.
27 * - The destination is a broadcast from a single element in a source.
28 * - The destination interleaves elements from each source.
30 * The test is performed for all vector sizes and element sizes
31 * currently supported by PNaCl.
34 #include "native_client/src/include/nacl_macros.h"
41 // Functions are non-inlined to make sure that nothing gets
42 // pre-computed at compile time.
43 #define NO_INLINE __attribute__((noinline))
46 * Basic types that are supported inside vectors.
48 * TODO(jfb) Handle 64-bit int and double.
58 // All supported vector types are currently 128-bit wide.
61 // Vector types corresponding to each supported basic type.
62 typedef I8 VI8 __attribute__((vector_size(VEC_BYTES)));
63 typedef U8 VU8 __attribute__((vector_size(VEC_BYTES)));
64 typedef I16 VI16 __attribute__((vector_size(VEC_BYTES)));
65 typedef U16 VU16 __attribute__((vector_size(VEC_BYTES)));
66 typedef I32 VI32 __attribute__((vector_size(VEC_BYTES)));
67 typedef U32 VU32 __attribute__((vector_size(VEC_BYTES)));
68 typedef F32 VF32 __attribute__((vector_size(VEC_BYTES)));
70 // Reformat some types so they print nicely. Leave others as-is.
71 int32_t format(int8_t v) { return v; }
72 uint32_t format(uint8_t v) { return v; }
73 int32_t format(int16_t v) { return v; }
74 uint32_t format(uint16_t v) { return v; }
75 template <typename T> T format(T v) { return v; }
78 NO_INLINE std::string print(const T v) {
81 for (size_t i = 0, e = sizeof(v) / sizeof(v[0]); i != e; ++i)
82 ss << format(v[i]) << (i != e - 1 ? ',' : '}');
86 #define TEST_SHUFFLE(TYPE, LHS, RHS, ...) \
88 NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \
89 sizeof(LHS[0])); /* Types must match. */ \
90 NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \
91 sizeof(RHS[0])); /* Types must match. */ \
92 const V##TYPE result = __builtin_shufflevector(LHS, RHS, __VA_ARGS__); \
93 std::cout << #TYPE " __builtin_shufflevector(" << print(LHS) << ", " \
94 << print(RHS) << ", " #__VA_ARGS__ ") = " << print(result) \
98 // Shuffle BASE into different locations, filling with FILL otherwise.
99 #define TEST_8BIT_SHUFFLE_STEP(T, L, R, BASE, FILL) \
101 if (FILL != BASE) { \
102 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
103 FILL, FILL, FILL, FILL, FILL, FILL, FILL, BASE); \
104 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
105 FILL, FILL, FILL, FILL, FILL, FILL, BASE, FILL); \
106 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
107 FILL, FILL, FILL, FILL, FILL, BASE, FILL, FILL); \
108 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
109 FILL, FILL, FILL, FILL, BASE, FILL, FILL, FILL); \
110 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
111 FILL, FILL, FILL, BASE, FILL, FILL, FILL, FILL); \
112 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
113 FILL, FILL, BASE, FILL, FILL, FILL, FILL, FILL); \
114 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
115 FILL, BASE, FILL, FILL, FILL, FILL, FILL, FILL); \
116 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
117 BASE, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
118 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, BASE, \
119 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
120 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, BASE, FILL, \
121 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
122 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, BASE, FILL, FILL, \
123 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
124 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, BASE, FILL, FILL, FILL, \
125 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
126 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, BASE, FILL, FILL, FILL, FILL, \
127 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
128 TEST_SHUFFLE(T, L, R, FILL, FILL, BASE, FILL, FILL, FILL, FILL, FILL, \
129 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
130 TEST_SHUFFLE(T, L, R, FILL, BASE, FILL, FILL, FILL, FILL, FILL, FILL, \
131 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
132 TEST_SHUFFLE(T, L, R, BASE, FILL, FILL, FILL, FILL, FILL, FILL, FILL, \
133 FILL, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
136 TEST_SHUFFLE(T, L, R, BASE, BASE, BASE, BASE, BASE, BASE, BASE, BASE, \
137 BASE, BASE, BASE, BASE, BASE, BASE, BASE, BASE); \
140 #define TEST_8BIT_SHUFFLE(T, L, R) \
142 std::cout << "Shuffle L only, ignore R:" << std::endl; \
143 TEST_8BIT_SHUFFLE_STEP(T, L, R, 0, 0); \
144 TEST_8BIT_SHUFFLE_STEP(T, L, R, 1, 0); \
145 TEST_8BIT_SHUFFLE_STEP(T, L, R, 2, 0); \
146 TEST_8BIT_SHUFFLE_STEP(T, L, R, 3, 0); \
147 TEST_8BIT_SHUFFLE_STEP(T, L, R, 4, 0); \
148 TEST_8BIT_SHUFFLE_STEP(T, L, R, 5, 0); \
149 TEST_8BIT_SHUFFLE_STEP(T, L, R, 6, 0); \
150 TEST_8BIT_SHUFFLE_STEP(T, L, R, 7, 0); \
151 TEST_8BIT_SHUFFLE_STEP(T, L, R, 8, 0); \
152 TEST_8BIT_SHUFFLE_STEP(T, L, R, 9, 0); \
153 TEST_8BIT_SHUFFLE_STEP(T, L, R, 10, 0); \
154 TEST_8BIT_SHUFFLE_STEP(T, L, R, 11, 0); \
155 TEST_8BIT_SHUFFLE_STEP(T, L, R, 12, 0); \
156 TEST_8BIT_SHUFFLE_STEP(T, L, R, 13, 0); \
157 TEST_8BIT_SHUFFLE_STEP(T, L, R, 14, 0); \
158 TEST_8BIT_SHUFFLE_STEP(T, L, R, 15, 0); \
159 std::cout << "Shuffle R only, ignore L:" << std::endl; \
160 TEST_8BIT_SHUFFLE_STEP(T, L, R, 16, 16); \
161 TEST_8BIT_SHUFFLE_STEP(T, L, R, 17, 16); \
162 TEST_8BIT_SHUFFLE_STEP(T, L, R, 18, 16); \
163 TEST_8BIT_SHUFFLE_STEP(T, L, R, 19, 16); \
164 TEST_8BIT_SHUFFLE_STEP(T, L, R, 20, 16); \
165 TEST_8BIT_SHUFFLE_STEP(T, L, R, 21, 16); \
166 TEST_8BIT_SHUFFLE_STEP(T, L, R, 22, 16); \
167 TEST_8BIT_SHUFFLE_STEP(T, L, R, 23, 16); \
168 TEST_8BIT_SHUFFLE_STEP(T, L, R, 24, 16); \
169 TEST_8BIT_SHUFFLE_STEP(T, L, R, 25, 16); \
170 TEST_8BIT_SHUFFLE_STEP(T, L, R, 26, 16); \
171 TEST_8BIT_SHUFFLE_STEP(T, L, R, 27, 16); \
172 TEST_8BIT_SHUFFLE_STEP(T, L, R, 28, 16); \
173 TEST_8BIT_SHUFFLE_STEP(T, L, R, 29, 16); \
174 TEST_8BIT_SHUFFLE_STEP(T, L, R, 30, 16); \
175 TEST_8BIT_SHUFFLE_STEP(T, L, R, 31, 16); \
176 std::cout << "Identity:" << std::endl; \
177 TEST_SHUFFLE(T, L, R, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, \
179 TEST_SHUFFLE(T, L, R, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, \
181 std::cout << "Interleave:" << std::endl; \
182 TEST_SHUFFLE(T, L, R, 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, \
184 TEST_SHUFFLE(T, L, R, 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, \
188 // Shuffle BASE into different locations, filling with FILL otherwise.
189 #define TEST_16BIT_SHUFFLE_STEP(T, L, R, BASE, FILL) \
191 if (FILL != BASE) { \
192 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, FILL, BASE); \
193 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, FILL, BASE, FILL); \
194 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, FILL, BASE, FILL, FILL); \
195 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, FILL, BASE, FILL, FILL, FILL); \
196 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, BASE, FILL, FILL, FILL, FILL); \
197 TEST_SHUFFLE(T, L, R, FILL, FILL, BASE, FILL, FILL, FILL, FILL, FILL); \
198 TEST_SHUFFLE(T, L, R, FILL, BASE, FILL, FILL, FILL, FILL, FILL, FILL); \
199 TEST_SHUFFLE(T, L, R, BASE, FILL, FILL, FILL, FILL, FILL, FILL, FILL); \
202 TEST_SHUFFLE(T, L, R, BASE, BASE, BASE, BASE, BASE, BASE, BASE, BASE); \
205 #define TEST_16BIT_SHUFFLE(T, L, R) \
207 std::cout << "Shuffle L only, ignore R:" << std::endl; \
208 TEST_16BIT_SHUFFLE_STEP(T, L, R, 0, 0); \
209 TEST_16BIT_SHUFFLE_STEP(T, L, R, 1, 0); \
210 TEST_16BIT_SHUFFLE_STEP(T, L, R, 2, 0); \
211 TEST_16BIT_SHUFFLE_STEP(T, L, R, 3, 0); \
212 TEST_16BIT_SHUFFLE_STEP(T, L, R, 4, 0); \
213 TEST_16BIT_SHUFFLE_STEP(T, L, R, 5, 0); \
214 TEST_16BIT_SHUFFLE_STEP(T, L, R, 6, 0); \
215 TEST_16BIT_SHUFFLE_STEP(T, L, R, 7, 0); \
216 std::cout << "Shuffle R only, ignore L:" << std::endl; \
217 TEST_16BIT_SHUFFLE_STEP(T, L, R, 8, 8); \
218 TEST_16BIT_SHUFFLE_STEP(T, L, R, 9, 8); \
219 TEST_16BIT_SHUFFLE_STEP(T, L, R, 10, 8); \
220 TEST_16BIT_SHUFFLE_STEP(T, L, R, 11, 8); \
221 TEST_16BIT_SHUFFLE_STEP(T, L, R, 12, 8); \
222 TEST_16BIT_SHUFFLE_STEP(T, L, R, 13, 8); \
223 TEST_16BIT_SHUFFLE_STEP(T, L, R, 14, 8); \
224 TEST_16BIT_SHUFFLE_STEP(T, L, R, 15, 8); \
225 std::cout << "Identity:" << std::endl; \
226 TEST_SHUFFLE(T, L, R, 0, 1, 2, 3, 4, 5, 6, 7); \
227 TEST_SHUFFLE(T, L, R, 8, 9, 10, 11, 12, 13, 14, 15); \
228 std::cout << "Interleave:" << std::endl; \
229 TEST_SHUFFLE(T, L, R, 0, 8, 1, 9, 2, 10, 3, 11); \
230 TEST_SHUFFLE(T, L, R, 4, 12, 5, 13, 6, 14, 7, 15); \
233 // Shuffle BASE into different locations, filling with FILL otherwise.
234 #define TEST_32BIT_SHUFFLE_STEP(T, L, R, BASE, FILL) \
236 if (FILL != BASE) { \
237 TEST_SHUFFLE(T, L, R, FILL, FILL, FILL, BASE); \
238 TEST_SHUFFLE(T, L, R, FILL, FILL, BASE, FILL); \
239 TEST_SHUFFLE(T, L, R, FILL, BASE, FILL, FILL); \
240 TEST_SHUFFLE(T, L, R, BASE, FILL, FILL, FILL); \
243 TEST_SHUFFLE(T, L, R, BASE, BASE, BASE, BASE); \
246 #define TEST_32BIT_SHUFFLE(T, L, R) \
248 std::cout << "Shuffle L only, ignore R:" << std::endl; \
249 TEST_32BIT_SHUFFLE_STEP(T, L, R, 0, 0); \
250 TEST_32BIT_SHUFFLE_STEP(T, L, R, 1, 0); \
251 TEST_32BIT_SHUFFLE_STEP(T, L, R, 2, 0); \
252 TEST_32BIT_SHUFFLE_STEP(T, L, R, 3, 0); \
253 std::cout << "Shuffle R only, ignore L:" << std::endl; \
254 TEST_32BIT_SHUFFLE_STEP(T, L, R, 4, 4); \
255 TEST_32BIT_SHUFFLE_STEP(T, L, R, 5, 4); \
256 TEST_32BIT_SHUFFLE_STEP(T, L, R, 6, 4); \
257 TEST_32BIT_SHUFFLE_STEP(T, L, R, 7, 4); \
258 std::cout << "Identity:" << std::endl; \
259 TEST_SHUFFLE(T, L, R, 0, 1, 2, 3); \
260 TEST_SHUFFLE(T, L, R, 4, 5, 6, 7); \
261 std::cout << "Interleave:" << std::endl; \
262 TEST_SHUFFLE(T, L, R, 0, 4, 1, 5); \
263 TEST_SHUFFLE(T, L, R, 2, 6, 3, 7); \
266 // Vector values used in tests.
274 NO_INLINE void init(void) {
275 vi8[0] = (VI8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
277 (VI8) {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
279 vu8[0] = (VU8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
281 (VU8) {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
283 vi16[0] = (VI16) {1, 2, 3, 4, 5, 6, 7, 8};
284 vi16[1] = (VI16) {9, 10, 11, 12, 13, 14, 15, 16};
286 vu16[0] = (VU16) {1, 2, 3, 4, 5, 6, 7, 8};
287 vu16[1] = (VU16) {9, 10, 11, 12, 13, 14, 15, 16};
289 vi32[0] = (VI32) {1, 2, 3, 4};
290 vi32[1] = (VI32) {5, 6, 7, 8};
292 vu32[0] = (VU32) {1, 2, 3, 4};
293 vu32[1] = (VU32) {5, 6, 7, 8};
295 vf32[0] = (VF32) {1, 2, 3, 4};
296 vf32[1] = (VF32) {5, 6, 7, 8};
299 NO_INLINE void test(void) {
300 std::cout << "8 bit shuffles:" << std::endl;
301 TEST_8BIT_SHUFFLE(I8, vi8[0], vi8[1]);
302 TEST_8BIT_SHUFFLE(U8, vu8[0], vu8[1]);
303 std::cout << "16 bit shuffles:" << std::endl;
304 TEST_16BIT_SHUFFLE(I16, vi16[0], vi16[1]);
305 TEST_16BIT_SHUFFLE(U16, vu16[0], vu16[1]);
306 std::cout << "32 bit shuffles:" << std::endl;
307 TEST_32BIT_SHUFFLE(I32, vi32[0], vi32[1]);
308 TEST_32BIT_SHUFFLE(U32, vu32[0], vu32[1]);
309 TEST_32BIT_SHUFFLE(F32, vf32[0], vf32[1]);