comparison src/impl/gcc.c @ 28:c6c99ab1088a

*: add min/max functions and a big big refactor (again) agh, this time I added a few more implementations (and generally made the code just a little faster...)
author Paper <paper@tflc.us>
date Thu, 24 Apr 2025 00:54:02 -0400
parents
children
comparison
equal deleted inserted replaced
27:d00b95f95dd1 28:c6c99ab1088a
1 /**
2 * vec - a tiny SIMD vector library in C99
3 *
4 * Copyright (c) 2024 Paper
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 **/
24
25 #include "vec/impl/gcc.h"
26
27 // -----------------------------------------------------------------
28
29 #define VEC_GENERIC_OPERATION(op, sign, csign, bits, size) \
30 do { \
31 for (int i = 0; i < size; i++) \
32 ((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] = (op); \
33 \
34 return vec1; \
35 } while (0)
36
37 #define VEC_GENERIC_BUILTIN_OPERATION(op, sign, csign, bits, size) \
38 VEC_GENERIC_OPERATION(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] op ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i], sign, csign, bits, size)
39
40 #define VEC_GENERIC_CMP(op, sign, csign, bits, size) \
41 VEC_GENERIC_OPERATION((((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] op ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]) ? VEC_UINT##bits##_MAX : 0, sign, csign, bits, size)
42
43 // TODO implement these so we don't waste stack space by doing the
44 // generics
45 #define VEC_GENERIC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \
46 union v##sign##int##bits##x##size##_impl_data { \
47 v##sign##int##bits##x##size vec; \
48 vec_##sign##int##bits impl[size]; \
49 }; \
50 \
51 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \
52 { \
53 v##sign##int##bits##x##size vec; \
54 for (int i = 0; i < size; i++) \
55 ((union v##sign##int##bits##x##size##_impl_data *)&vec)->impl[i] = x; \
56 return vec; \
57 } \
58 \
59 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \
60 { \
61 v##sign##int##bits##x##size vec; \
62 memcpy(&vec, in, sizeof(vec_##sign##int##bits) * size); \
63 return vec; \
64 } \
65 \
66 VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
67 { \
68 memcpy(out, &vec, sizeof(vec_##sign##int##bits) * size); \
69 } \
70 \
71 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
72 { \
73 VEC_GENERIC_BUILTIN_OPERATION(+, sign, csign, bits, size); \
74 } \
75 \
76 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
77 { \
78 VEC_GENERIC_BUILTIN_OPERATION(-, sign, csign, bits, size); \
79 } \
80 \
81 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
82 { \
83 VEC_GENERIC_BUILTIN_OPERATION(*, sign, csign, bits, size); \
84 } \
85 \
86 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
87 { \
88 VEC_GENERIC_OPERATION(((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i] ? (((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i] / ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]) : 0, sign, csign, bits, size); \
89 } \
90 \
91 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
92 { \
93 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
94 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
95 \
96 for (int i = 0; i < size; i++) \
97 vec1d->impl[i] = vec_##sign##avg(vec1d->impl[i], vec2d->impl[i]); \
98 \
99 return vec1d->vec; \
100 } \
101 \
102 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
103 { \
104 VEC_GENERIC_BUILTIN_OPERATION(&, sign, csign, bits, size); \
105 } \
106 \
107 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
108 { \
109 VEC_GENERIC_BUILTIN_OPERATION(|, sign, csign, bits, size); \
110 } \
111 \
112 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
113 { \
114 VEC_GENERIC_BUILTIN_OPERATION(^, sign, csign, bits, size); \
115 } \
116 \
117 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
118 { \
119 VEC_GENERIC_CMP(<, sign, csign, bits, size); \
120 } \
121 \
122 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
123 { \
124 return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmpgt(vec1, vec2)); \
125 } \
126 \
127 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
128 { \
129 VEC_GENERIC_CMP(==, sign, csign, bits, size); \
130 } \
131 \
132 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
133 { \
134 return v##sign##int##bits##x##size##_not(v##sign##int##bits##x##size##_cmplt(vec1, vec2)); \
135 } \
136 \
137 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
138 { \
139 VEC_GENERIC_CMP(>, sign, csign, bits, size); \
140 } \
141 \
142 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
143 { \
144 VEC_GENERIC_OPERATION(vec_##sign##lshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \
145 } \
146 \
147 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
148 { \
149 VEC_GENERIC_OPERATION(vec_##sign##rshift(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i], ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \
150 } \
151 \
152 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
153 { \
154 VEC_GENERIC_OPERATION(vec_lrshift((vec_uint##bits)(((union v##sign##int##bits##x##size##_impl_data *)&vec1)->impl[i]), ((union v##sign##int##bits##x##size##_impl_data *)&vec2)->impl[i]), sign, csign, bits, size); \
155 } \
156 \
157 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
158 { \
159 v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmplt(vec1, vec2); \
160 \
161 v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \
162 v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \
163 \
164 return v##sign##int##bits##x##size##_or(a, b); \
165 } \
166 \
167 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
168 { \
169 v##sign##int##bits##x##size cmplt = v##sign##int##bits##x##size##_cmpgt(vec1, vec2); \
170 \
171 v##sign##int##bits##x##size a = v##sign##int##bits##x##size##_and(vec1, cmplt); \
172 v##sign##int##bits##x##size b = v##sign##int##bits##x##size##_and(vec2, v##sign##int##bits##x##size##_not(cmplt)); \
173 \
174 return v##sign##int##bits##x##size##_or(a, b); \
175 } \
176 \
177 const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \
178 .splat = v##sign##int##bits##x##size##_generic_splat, \
179 .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \
180 .load = v##sign##int##bits##x##size##_generic_load_aligned, \
181 .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \
182 .store = v##sign##int##bits##x##size##_generic_store_aligned, \
183 .add = v##sign##int##bits##x##size##_generic_add, \
184 .sub = v##sign##int##bits##x##size##_generic_sub, \
185 .mul = v##sign##int##bits##x##size##_generic_mul, \
186 .div = v##sign##int##bits##x##size##_generic_div, \
187 .avg = v##sign##int##bits##x##size##_generic_avg, \
188 .band = v##sign##int##bits##x##size##_generic_and, \
189 .bor = v##sign##int##bits##x##size##_generic_or, \
190 .bxor = v##sign##int##bits##x##size##_generic_xor, \
191 .lshift = v##sign##int##bits##x##size##_generic_lshift, \
192 .rshift = v##sign##int##bits##x##size##_generic_rshift, \
193 .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \
194 .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \
195 .cmple = v##sign##int##bits##x##size##_generic_cmple, \
196 .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \
197 .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \
198 .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \
199 .min = v##sign##int##bits##x##size##_generic_min, \
200 .max = v##sign##int##bits##x##size##_generic_max, \
201 };
202
203 #define VEC_GENERIC_DEFINE_OPERATIONS(bits, size) \
204 VEC_GENERIC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \
205 VEC_GENERIC_DEFINE_OPERATIONS_SIGN( , , bits, size)
206
207 VEC_GENERIC_DEFINE_OPERATIONS(8, 2)
208 VEC_GENERIC_DEFINE_OPERATIONS(16, 2)
209 VEC_GENERIC_DEFINE_OPERATIONS(32, 2)
210 VEC_GENERIC_DEFINE_OPERATIONS(64, 2)
211
212 #undef VEC_GENERIC_DEFINE_OPERATIONS
213 #undef VEC_GENERIC_DEFINE_OPERATIONS_SIGN
214
215 // -----------------------------------------------------------------
216 // now we can just keep doubling the same implementation
217
218 #define VEC_GENERIC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size, halfsize) \
219 union v##sign##int##bits##x##size##_impl_data { \
220 v##sign##int##bits##x##size vec; \
221 v##sign##int##bits##x##halfsize impl[2]; \
222 }; \
223 \
224 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_splat(vec_##sign##int##bits x) \
225 { \
226 union v##sign##int##bits##x##size##_impl_data vec; \
227 vec.impl[0] = v##sign##int##bits##x##halfsize##_splat(x); \
228 vec.impl[1] = v##sign##int##bits##x##halfsize##_splat(x); \
229 return vec.vec; \
230 } \
231 \
232 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load_aligned(const vec_##sign##int##bits in[size]) \
233 { \
234 union v##sign##int##bits##x##size##_impl_data vec; \
235 vec.impl[0] = v##sign##int##bits##x##halfsize##_load_aligned(in); \
236 vec.impl[1] = v##sign##int##bits##x##halfsize##_load_aligned(in + halfsize); \
237 return vec.vec; \
238 } \
239 \
240 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_load(const vec_##sign##int##bits in[size]) \
241 { \
242 union v##sign##int##bits##x##size##_impl_data vec; \
243 vec.impl[0] = v##sign##int##bits##x##halfsize##_load(in); \
244 vec.impl[1] = v##sign##int##bits##x##halfsize##_load(in + halfsize); \
245 return vec.vec; \
246 } \
247 \
248 VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
249 { \
250 union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \
251 \
252 v##sign##int##bits##x##halfsize##_store_aligned(vecd->impl[0], out); \
253 v##sign##int##bits##x##halfsize##_store_aligned(vecd->impl[1], out + halfsize); \
254 } \
255 \
256 VEC_FUNC_IMPL void v##sign##int##bits##x##size##_generic_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
257 { \
258 union v##sign##int##bits##x##size##_impl_data *vecd = (union v##sign##int##bits##x##size##_impl_data *)&vec; \
259 \
260 v##sign##int##bits##x##halfsize##_store(vecd->impl[0], out); \
261 v##sign##int##bits##x##halfsize##_store(vecd->impl[1], out + halfsize); \
262 } \
263 \
264 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
265 { \
266 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
267 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
268 \
269 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_add(vec1d->impl[0], vec2d->impl[0]); \
270 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_add(vec1d->impl[1], vec2d->impl[1]); \
271 \
272 return vec1d->vec; \
273 } \
274 \
275 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
276 { \
277 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
278 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
279 \
280 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_sub(vec1d->impl[0], vec2d->impl[0]); \
281 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_sub(vec1d->impl[1], vec2d->impl[1]); \
282 \
283 return vec1d->vec; \
284 } \
285 \
286 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
287 { \
288 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
289 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
290 \
291 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_mul(vec1d->impl[0], vec2d->impl[0]); \
292 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_mul(vec1d->impl[1], vec2d->impl[1]); \
293 \
294 return vec1d->vec; \
295 } \
296 \
297 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
298 { \
299 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
300 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
301 \
302 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_div(vec1d->impl[0], vec2d->impl[0]); \
303 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_div(vec1d->impl[1], vec2d->impl[1]); \
304 \
305 return vec1d->vec; \
306 } \
307 \
308 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
309 { \
310 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
311 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
312 \
313 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_avg(vec1d->impl[0], vec2d->impl[0]); \
314 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_avg(vec1d->impl[1], vec2d->impl[1]); \
315 \
316 return vec1d->vec; \
317 } \
318 \
319 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
320 { \
321 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
322 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
323 \
324 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_and(vec1d->impl[0], vec2d->impl[0]); \
325 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_and(vec1d->impl[1], vec2d->impl[1]); \
326 \
327 return vec1d->vec; \
328 } \
329 \
330 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
331 { \
332 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
333 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
334 \
335 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_or(vec1d->impl[0], vec2d->impl[0]); \
336 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_or(vec1d->impl[1], vec2d->impl[1]); \
337 \
338 return vec1d->vec; \
339 } \
340 \
341 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
342 { \
343 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
344 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
345 \
346 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_xor(vec1d->impl[0], vec2d->impl[0]); \
347 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_xor(vec1d->impl[1], vec2d->impl[1]); \
348 \
349 return vec1d->vec; \
350 } \
351 \
352 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
353 { \
354 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
355 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \
356 \
357 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_lshift(vec1d->impl[0], vec2d->impl[0]); \
358 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_lshift(vec1d->impl[1], vec2d->impl[1]); \
359 \
360 return vec1d->vec; \
361 } \
362 \
363 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
364 { \
365 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
366 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \
367 \
368 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_rshift(vec1d->impl[0], vec2d->impl[0]); \
369 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_rshift(vec1d->impl[1], vec2d->impl[1]); \
370 \
371 return vec1d->vec; \
372 } \
373 \
374 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
375 { \
376 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
377 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \
378 \
379 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_lrshift(vec1d->impl[0], vec2d->impl[0]); \
380 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_lrshift(vec1d->impl[1], vec2d->impl[1]); \
381 \
382 return vec1d->vec; \
383 } \
384 \
385 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
386 { \
387 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
388 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
389 \
390 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmplt(vec1d->impl[0], vec2d->impl[0]); \
391 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmplt(vec1d->impl[1], vec2d->impl[1]); \
392 \
393 return vec1d->vec; \
394 } \
395 \
396 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
397 { \
398 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
399 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
400 \
401 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmple(vec1d->impl[0], vec2d->impl[0]); \
402 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmple(vec1d->impl[1], vec2d->impl[1]); \
403 \
404 return vec1d->vec; \
405 } \
406 \
407 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
408 { \
409 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
410 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
411 \
412 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpeq(vec1d->impl[0], vec2d->impl[0]); \
413 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpeq(vec1d->impl[1], vec2d->impl[1]); \
414 \
415 return vec1d->vec; \
416 } \
417 \
418 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
419 { \
420 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
421 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
422 \
423 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpge(vec1d->impl[0], vec2d->impl[0]); \
424 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpge(vec1d->impl[1], vec2d->impl[1]); \
425 \
426 return vec1d->vec; \
427 } \
428 \
429 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
430 { \
431 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
432 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
433 \
434 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_cmpgt(vec1d->impl[0], vec2d->impl[0]); \
435 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_cmpgt(vec1d->impl[1], vec2d->impl[1]); \
436 \
437 return vec1d->vec; \
438 } \
439 \
440 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_min(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
441 { \
442 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
443 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
444 \
445 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[0], vec2d->impl[0]); \
446 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_min(vec1d->impl[1], vec2d->impl[1]); \
447 \
448 return vec1d->vec; \
449 } \
450 \
451 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_generic_max(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
452 { \
453 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
454 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
455 \
456 vec1d->impl[0] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[0], vec2d->impl[0]); \
457 vec1d->impl[1] = v##sign##int##bits##x##halfsize##_max(vec1d->impl[1], vec2d->impl[1]); \
458 \
459 return vec1d->vec; \
460 } \
461 \
462 const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_generic = { \
463 .splat = v##sign##int##bits##x##size##_generic_splat, \
464 .load_aligned = v##sign##int##bits##x##size##_generic_load_aligned, \
465 .load = v##sign##int##bits##x##size##_generic_load, \
466 .store_aligned = v##sign##int##bits##x##size##_generic_store_aligned, \
467 .store = v##sign##int##bits##x##size##_generic_store, \
468 .add = v##sign##int##bits##x##size##_generic_add, \
469 .sub = v##sign##int##bits##x##size##_generic_sub, \
470 .mul = v##sign##int##bits##x##size##_generic_mul, \
471 .div = v##sign##int##bits##x##size##_generic_div, \
472 .avg = v##sign##int##bits##x##size##_generic_avg, \
473 .band = v##sign##int##bits##x##size##_generic_and, \
474 .bor = v##sign##int##bits##x##size##_generic_or, \
475 .bxor = v##sign##int##bits##x##size##_generic_xor, \
476 .lshift = v##sign##int##bits##x##size##_generic_lshift, \
477 .rshift = v##sign##int##bits##x##size##_generic_rshift, \
478 .lrshift = v##sign##int##bits##x##size##_generic_lrshift, \
479 .cmplt = v##sign##int##bits##x##size##_generic_cmplt, \
480 .cmple = v##sign##int##bits##x##size##_generic_cmple, \
481 .cmpeq = v##sign##int##bits##x##size##_generic_cmpeq, \
482 .cmpge = v##sign##int##bits##x##size##_generic_cmpge, \
483 .cmpgt = v##sign##int##bits##x##size##_generic_cmpgt, \
484 .min = v##sign##int##bits##x##size##_generic_min, \
485 .max = v##sign##int##bits##x##size##_generic_max, \
486 };
487
488 #define VEC_GENERIC_DEFINE_OPERATIONS(bits, size, halfsize) \
489 VEC_GENERIC_DEFINE_OPERATIONS_SIGN(u, U, bits, size, halfsize) \
490 VEC_GENERIC_DEFINE_OPERATIONS_SIGN( , , bits, size, halfsize)
491
492 // 32-bit
493 VEC_GENERIC_DEFINE_OPERATIONS(8, 4, 2)
494
495 // 64-bit
496 VEC_GENERIC_DEFINE_OPERATIONS(8, 8, 4)
497 VEC_GENERIC_DEFINE_OPERATIONS(16, 4, 2)
498
499 // 128-bit
500 VEC_GENERIC_DEFINE_OPERATIONS(8, 16, 8)
501 VEC_GENERIC_DEFINE_OPERATIONS(16, 8, 4)
502 VEC_GENERIC_DEFINE_OPERATIONS(32, 4, 2)
503
504 // 256-bit
505 VEC_GENERIC_DEFINE_OPERATIONS(8, 32, 16)
506 VEC_GENERIC_DEFINE_OPERATIONS(16, 16, 8)
507 VEC_GENERIC_DEFINE_OPERATIONS(32, 8, 4)
508 VEC_GENERIC_DEFINE_OPERATIONS(64, 4, 2)
509
510 // 512-bit
511 VEC_GENERIC_DEFINE_OPERATIONS(8, 64, 32)
512 VEC_GENERIC_DEFINE_OPERATIONS(16, 32, 16)
513 VEC_GENERIC_DEFINE_OPERATIONS(32, 16, 8)
514 VEC_GENERIC_DEFINE_OPERATIONS(64, 8, 4)
515
516 #undef VEC_GENERIC_DEFINE_OPERATIONS
517 #undef VEC_GENERIC_DEFINE_OPERATIONS_SIGN