comparison src/impl/arm/neon.c @ 32:0de48dc864ea

Backed out changeset d00b95f95dd1
author Paper <paper@tflc.us>
date Fri, 25 Apr 2025 17:40:38 -0400
parents bf6ad516f1e6
children
comparison
equal deleted inserted replaced
31:bf6ad516f1e6 32:0de48dc864ea
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE. 22 * SOFTWARE.
23 **/ 23 **/
24 24
25 #include "vec/impl/arm/neon.h" 25 #include "vec/impl/arm/neon.h"
26 #include "vec/impl/generic.h"
27 26
28 #include <arm_neon.h> 27 #include <arm_neon.h>
29 28
30 // There is LOTS of preprocessor hacking here (as if the other files 29 // There is LOTS of preprocessor hacking here (as if the other files
31 // weren't bad enough... lol) 30 // weren't bad enough... lol)
32 31
33 #define VEC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \ 32 #define VEC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \
34 union v##sign##int##bits##x##size##_impl_data { \
35 v##sign##int##bits##x##size vec; \
36 sign##int##bits##x##size##_t neon; \
37 }; \
38 \
39 VEC_STATIC_ASSERT(VEC_ALIGNOF(sign##int##bits##x##size##_t) <= VEC_ALIGNOF(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " alignment needs to be expanded to fit intrinsic type size"); \
40 VEC_STATIC_ASSERT(sizeof(sign##int##bits##x##size##_t) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \
41 \
42 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \ 33 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \
43 { \ 34 { \
44 union v##sign##int##bits##x##size##_impl_data vec; \ 35 v##sign##int##bits##x##size vec; \
45 vec.neon = vld1_##sign##bits(in); \ 36 vec.neon = vld1_##sign##bits(in); \
46 return vec.vec; \ 37 return vec; \
47 } \ 38 } \
48 \ 39 \
49 static void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ 40 static void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
50 { \ 41 { \
51 vstore_lane_##bits(sign, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->neon, out); \ 42 vstore_lane_##bits(sign, vec.neon, out); \
52 } \ 43 } \
53 \ 44 \
54 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 45 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
55 { \ 46 { \
56 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 47 v##sign##int##bits##x##size vec; \
57 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 48 vec.neon = vadd_##sign##bits(vec1.neon, vec2.neon); \
58 \ 49 return vec; \
59 vec1d->neon = vadd_##sign##bits(vec1d->neon, vec2d->neon); \
60 return vec1d->vec; \
61 } \ 50 } \
62 \ 51 \
63 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 52 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
64 { \ 53 { \
65 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 54 v##sign##int##bits##x##size vec; \
66 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 55 vec.neon = vsub_##sign##bits(vec1.neon, vec2.neon); \
67 \ 56 return vec; \
68 vec1d->neon = vsub_##sign##bits(vec1d->neon, vec2d->neon); \
69 return vec1d->vec; \
70 } \ 57 } \
71 \ 58 \
72 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 59 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
73 { \ 60 { \
74 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 61 v##sign##int##bits##x##size vec; \
75 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 62 vec.neon = vmul_##sign##bits(vec1.neon, vec2.neon); \
76 \ 63 return vec; \
77 vec1d->neon = vmul_##sign##bits(vec1d->neon, vec2d->neon); \
78 return vec1d->vec; \
79 } \ 64 } \
80 \ 65 \
81 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \ 66 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
82 { \ 67 { \
83 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 68 v##sign##int##bits##x##size vec; \
84 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ 69 vec.neon = vshl_##sign##bits(vec1.neon, vreinterpret_##bits##_u##bits(vec2.neon)); \
85 \ 70 return vec; \
86 vec1d->neon = vshl_##sign##bits(vec1d->neon, (vreinterpret_##bits##_u##bits)vec2d->neon); \
87 return vec1d->vec; \
88 } \ 71 } \
89 \ 72 \
90 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 73 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
91 { \ 74 { \
92 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 75 v##sign##int##bits##x##size vec; \
93 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 76 vec.neon = vand_##sign##bits(vec1.neon, vec2.neon); \
94 \ 77 return vec; \
95 vec1d->neon = vand_##sign##bits(vec1d->neon, vec2d->neon); \
96 return vec1d->vec; \
97 } \ 78 } \
98 \ 79 \
99 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 80 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
100 { \ 81 { \
101 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 82 v##sign##int##bits##x##size vec; \
102 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 83 vec.neon = vorr_##sign##bits(vec1.neon, vec2.neon); \
103 \ 84 return vec; \
104 vec1d->neon = vorr_##sign##bits(vec1d->neon, vec2d->neon); \
105 return vec1d->vec; \
106 } \ 85 } \
107 \ 86 \
108 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \ 87 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
109 { \ 88 { \
110 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 89 v##sign##int##bits##x##size vec; \
111 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 90 vec.neon = veor_##sign##bits(vec1.neon, vec2.neon); \
112 \ 91 return vec; \
113 vec1d->neon = veor_##sign##bits(vec1d->neon, vec2d->neon); \
114 return vec1d->vec; \
115 } \ 92 } \
116 \ 93 \
117 static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ 94 static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \
118 v##sign##int##bits##x##size##_fallback_splat, \ 95 /* .splat = */ NULL, \
119 v##sign##int##bits##x##size##_neon_load_aligned, \ 96 v##sign##int##bits##x##size##_neon_load_aligned, \
120 v##sign##int##bits##x##size##_neon_load_aligned, \ 97 v##sign##int##bits##x##size##_neon_load_aligned, \
121 v##sign##int##bits##x##size##_neon_store_aligned, \ 98 v##sign##int##bits##x##size##_neon_store_aligned, \
122 v##sign##int##bits##x##size##_neon_store_aligned, \ 99 v##sign##int##bits##x##size##_neon_store_aligned, \
123 v##sign##int##bits##x##size##_neon_add, \ 100 v##sign##int##bits##x##size##_neon_add, \
124 v##sign##int##bits##x##size##_neon_sub, \ 101 v##sign##int##bits##x##size##_neon_sub, \
125 v##sign##int##bits##x##size##_neon_mul, \ 102 v##sign##int##bits##x##size##_neon_mul, \
126 v##sign##int##bits##x##size##_fallback_div, \ 103 /* .div = */ NULL, \
127 v##sign##int##bits##x##size##_fallback_avg, \ 104 /* .avg = */ NULL, \
128 v##sign##int##bits##x##size##_neon_and, \ 105 v##sign##int##bits##x##size##_neon_and, \
129 v##sign##int##bits##x##size##_neon_or, \ 106 v##sign##int##bits##x##size##_neon_or, \
130 v##sign##int##bits##x##size##_neon_xor, \ 107 v##sign##int##bits##x##size##_neon_xor, \
131 v##sign##int##bits##x##size##_fallback_not, \ 108 /* .not = */ NULL, \
132 v##sign##int##bits##x##size##_neon_lshift, \ 109 v##sign##int##bits##x##size##_neon_lshift, \
133 v##sign##int##bits##x##size##_fallback_rshift, \ 110 /* .rshift = */ NULL, \
134 v##sign##int##bits##x##size##_fallback_lrshift, \ 111 /* .lrshift = */ NULL, \
135 v##sign##int##bits##x##size##_fallback_cmplt, \
136 v##sign##int##bits##x##size##_fallback_cmple, \
137 v##sign##int##bits##x##size##_fallback_cmpeq, \
138 v##sign##int##bits##x##size##_fallback_cmpge, \
139 v##sign##int##bits##x##size##_fallback_cmpgt, \
140 }; 112 };
141 113
142 #define VEC_DEFINE_OPERATIONS(bits, size) \ 114 #define VEC_DEFINE_OPERATIONS(bits, size) \
143 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \ 115 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) \
144 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) 116 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size)
145 117
146 // Ok, we'll start out with the 64-bit types. 118 // Ok, we'll start out with the 64-bit types.
147 119
148 #define vadd_8 vadd_s8 120 #define vadd_8 vadd_s8
149 #define vadd_16 vadd_s16 121 #define vadd_16 vadd_s16
381 #define vreinterpret_8_u8(x) vreinterpretq_s8_u8(x) 353 #define vreinterpret_8_u8(x) vreinterpretq_s8_u8(x)
382 #define vreinterpret_16_u16(x) vreinterpretq_s16_u16(x) 354 #define vreinterpret_16_u16(x) vreinterpretq_s16_u16(x)
383 #define vreinterpret_32_u32(x) vreinterpretq_s32_u32(x) 355 #define vreinterpret_32_u32(x) vreinterpretq_s32_u32(x)
384 #define vreinterpret_64_u64(x) vreinterpretq_s64_u64(x) 356 #define vreinterpret_64_u64(x) vreinterpretq_s64_u64(x)
385 357
358 #define VEC_DEFINE_OPERATIONS_SIGN(sign, csign, bits, size) \
359 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \
360 { \
361 v##sign##int##bits##x##size vec; \
362 vec.neon = vld1_##sign##bits(in); \
363 return vec; \
364 } \
365 \
366 static void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
367 { \
368 vstore_lane_##bits(sign, vec.neon, out); \
369 } \
370 \
371 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
372 { \
373 v##sign##int##bits##x##size vec; \
374 vec.neon = vadd_##sign##bits(vec1.neon, vec2.neon); \
375 return vec; \
376 } \
377 \
378 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
379 { \
380 v##sign##int##bits##x##size vec; \
381 vec.neon = vsub_##sign##bits(vec1.neon, vec2.neon); \
382 return vec; \
383 } \
384 \
385 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
386 { \
387 v##sign##int##bits##x##size vec; \
388 vec.neon = vmul_##sign##bits(vec1.neon, vec2.neon); \
389 return vec; \
390 } \
391 \
392 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
393 { \
394 v##sign##int##bits##x##size vec; \
395 vec.neon = vshl_##sign##bits(vec1.neon, vreinterpret_##bits##_u##bits(vec2.neon)); \
396 return vec; \
397 } \
398 \
399 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
400 { \
401 v##sign##int##bits##x##size vec; \
402 vec.neon = vand_##sign##bits(vec1.neon, vec2.neon); \
403 return vec; \
404 } \
405 \
406 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
407 { \
408 v##sign##int##bits##x##size vec; \
409 vec.neon = vorr_##sign##bits(vec1.neon, vec2.neon); \
410 return vec; \
411 } \
412 \
413 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
414 { \
415 v##sign##int##bits##x##size vec; \
416 vec.neon = veor_##sign##bits(vec1.neon, vec2.neon); \
417 return vec; \
418 } \
419 \
420 static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \
421 /* .splat = */ NULL, \
422 v##sign##int##bits##x##size##_neon_load_aligned, \
423 v##sign##int##bits##x##size##_neon_load_aligned, \
424 v##sign##int##bits##x##size##_neon_store_aligned, \
425 v##sign##int##bits##x##size##_neon_store_aligned, \
426 v##sign##int##bits##x##size##_neon_add, \
427 v##sign##int##bits##x##size##_neon_sub, \
428 v##sign##int##bits##x##size##_neon_mul, \
429 /* .div = */ NULL, \
430 /* .avg = */ NULL, \
431 v##sign##int##bits##x##size##_neon_and, \
432 v##sign##int##bits##x##size##_neon_or, \
433 v##sign##int##bits##x##size##_neon_xor, \
434 /* .not = */ NULL, \
435 v##sign##int##bits##x##size##_neon_lshift, \
436 /* .rshift = */ NULL, \
437 /* .lrshift = */ NULL, \
438 };
439
440 #define VEC_DEFINE_OPERATIONS(bits, size) \
441 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) \
442 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size)
443
386 VEC_DEFINE_OPERATIONS(8, 16) 444 VEC_DEFINE_OPERATIONS(8, 16)
387 VEC_DEFINE_OPERATIONS(16, 8) 445 VEC_DEFINE_OPERATIONS(16, 8)
388 VEC_DEFINE_OPERATIONS(32, 4) 446 VEC_DEFINE_OPERATIONS(32, 4)
389 VEC_DEFINE_OPERATIONS(64, 2) 447 VEC_DEFINE_OPERATIONS(64, 2)
390 448