comparison src/impl/arm/neon.c @ 31:bf6ad516f1e6

Backed out changeset c6c99ab1088a
author Paper <paper@tflc.us>
date Fri, 25 Apr 2025 17:40:33 -0400
parents c6c99ab1088a
children 0de48dc864ea
comparison
equal deleted inserted replaced
30:641d8c79b1da 31:bf6ad516f1e6
37 }; \ 37 }; \
38 \ 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"); \ 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"); \ 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 \ 41 \
42 VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \ 42 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \
43 { \ 43 { \
44 union v##sign##int##bits##x##size##_impl_data vec; \ 44 union v##sign##int##bits##x##size##_impl_data vec; \
45 vec.neon = vld1_##sign##bits(in); \ 45 vec.neon = vld1_##sign##bits(in); \
46 return vec.vec; \ 46 return vec.vec; \
47 } \ 47 } \
48 \ 48 \
49 VEC_FUNC_IMPL void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ 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]) \
50 { \ 50 { \
51 vstore_lane_##bits(sign, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->neon, out); \ 51 vstore_lane_##bits(sign, ((union v##sign##int##bits##x##size##_impl_data *)&vec)->neon, out); \
52 } \ 52 } \
53 \ 53 \
54 VEC_FUNC_IMPL 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) \ 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) \
55 { \ 55 { \
56 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 56 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
57 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 57 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
58 \ 58 \
59 vec1d->neon = vadd_##sign##bits(vec1d->neon, vec2d->neon); \ 59 vec1d->neon = vadd_##sign##bits(vec1d->neon, vec2d->neon); \
60 return vec1d->vec; \ 60 return vec1d->vec; \
61 } \ 61 } \
62 \ 62 \
63 VEC_FUNC_IMPL 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) \ 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) \
64 { \ 64 { \
65 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 65 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
66 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 66 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
67 \ 67 \
68 vec1d->neon = vsub_##sign##bits(vec1d->neon, vec2d->neon); \ 68 vec1d->neon = vsub_##sign##bits(vec1d->neon, vec2d->neon); \
69 return vec1d->vec; \ 69 return vec1d->vec; \
70 } \ 70 } \
71 \ 71 \
72 VEC_FUNC_IMPL 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) \ 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) \
73 { \ 73 { \
74 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 74 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
75 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 75 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
76 \ 76 \
77 vec1d->neon = vmul_##sign##bits(vec1d->neon, vec2d->neon); \ 77 vec1d->neon = vmul_##sign##bits(vec1d->neon, vec2d->neon); \
78 return vec1d->vec; \ 78 return vec1d->vec; \
79 } \ 79 } \
80 \ 80 \
81 VEC_FUNC_IMPL 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) \ 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) \
82 { \ 82 { \
83 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 83 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
84 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \ 84 union vuint##bits##x##size##_impl_data *vec2d = (union vuint##bits##x##size##_impl_data *)&vec2; \
85 \ 85 \
86 vec1d->neon = vshl_##sign##bits(vec1d->neon, (vreinterpret_##bits##_u##bits)vec2d->neon); \ 86 vec1d->neon = vshl_##sign##bits(vec1d->neon, (vreinterpret_##bits##_u##bits)vec2d->neon); \
87 return vec1d->vec; \ 87 return vec1d->vec; \
88 } \ 88 } \
89 \ 89 \
90 VEC_FUNC_IMPL 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) \ 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) \
91 { \ 91 { \
92 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 92 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
93 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 93 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
94 \ 94 \
95 vec1d->neon = vand_##sign##bits(vec1d->neon, vec2d->neon); \ 95 vec1d->neon = vand_##sign##bits(vec1d->neon, vec2d->neon); \
96 return vec1d->vec; \ 96 return vec1d->vec; \
97 } \ 97 } \
98 \ 98 \
99 VEC_FUNC_IMPL 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) \ 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) \
100 { \ 100 { \
101 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 101 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
102 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 102 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
103 \ 103 \
104 vec1d->neon = vorr_##sign##bits(vec1d->neon, vec2d->neon); \ 104 vec1d->neon = vorr_##sign##bits(vec1d->neon, vec2d->neon); \
105 return vec1d->vec; \ 105 return vec1d->vec; \
106 } \ 106 } \
107 \ 107 \
108 VEC_FUNC_IMPL 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) \ 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) \
109 { \ 109 { \
110 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \ 110 union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
111 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \ 111 union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
112 \ 112 \
113 vec1d->neon = veor_##sign##bits(vec1d->neon, vec2d->neon); \ 113 vec1d->neon = veor_##sign##bits(vec1d->neon, vec2d->neon); \
114 return vec1d->vec; \ 114 return vec1d->vec; \
115 } \ 115 } \
116 \ 116 \
117 const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ 117 static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \
118 .load = v##sign##int##bits##x##size##_neon_load_aligned, \ 118 v##sign##int##bits##x##size##_fallback_splat, \
119 .load_aligned = v##sign##int##bits##x##size##_neon_load_aligned, \ 119 v##sign##int##bits##x##size##_neon_load_aligned, \
120 .store = v##sign##int##bits##x##size##_neon_store_aligned, \ 120 v##sign##int##bits##x##size##_neon_load_aligned, \
121 .store_aligned = v##sign##int##bits##x##size##_neon_store_aligned, \ 121 v##sign##int##bits##x##size##_neon_store_aligned, \
122 .add = v##sign##int##bits##x##size##_neon_add, \ 122 v##sign##int##bits##x##size##_neon_store_aligned, \
123 .sub = v##sign##int##bits##x##size##_neon_sub, \ 123 v##sign##int##bits##x##size##_neon_add, \
124 .mul = v##sign##int##bits##x##size##_neon_mul, \ 124 v##sign##int##bits##x##size##_neon_sub, \
125 .band = v##sign##int##bits##x##size##_neon_and, \ 125 v##sign##int##bits##x##size##_neon_mul, \
126 .bor = v##sign##int##bits##x##size##_neon_or, \ 126 v##sign##int##bits##x##size##_fallback_div, \
127 .bxor = v##sign##int##bits##x##size##_neon_xor, \ 127 v##sign##int##bits##x##size##_fallback_avg, \
128 .lshift = v##sign##int##bits##x##size##_neon_lshift, \ 128 v##sign##int##bits##x##size##_neon_and, \
129 v##sign##int##bits##x##size##_neon_or, \
130 v##sign##int##bits##x##size##_neon_xor, \
131 v##sign##int##bits##x##size##_fallback_not, \
132 v##sign##int##bits##x##size##_neon_lshift, \
133 v##sign##int##bits##x##size##_fallback_rshift, \
134 v##sign##int##bits##x##size##_fallback_lrshift, \
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, \
129 }; 140 };
130 141
131 #define VEC_DEFINE_OPERATIONS(bits, size) \ 142 #define VEC_DEFINE_OPERATIONS(bits, size) \
132 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \ 143 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \
133 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) 144 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size)
231 242
232 // Now we can go ahead and do the 128-bit ones. 243 // Now we can go ahead and do the 128-bit ones.
233 244
234 // NEON doesn't have native 64-bit multiplication, so we have 245 // NEON doesn't have native 64-bit multiplication, so we have
235 // to do it ourselves 246 // to do it ourselves
236 VEC_FUNC_IMPL int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b) 247 static inline int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b)
237 { 248 {
238 const uint32x2_t ac = vreinterpret_u32_s32(vmovn_s64(a)); 249 const uint32x2_t ac = vreinterpret_u32_s32(vmovn_s64(a));
239 const uint32x2_t pr = vreinterpret_u32_s32(vmovn_s64(b)); 250 const uint32x2_t pr = vreinterpret_u32_s32(vmovn_s64(b));
240 251
241 const int32x4_t hi = vmulq_s32(vreinterpretq_s32_s64(b), vreinterpretq_s32_s64(a)); 252 const int32x4_t hi = vmulq_s32(vreinterpretq_s32_s64(b), vreinterpretq_s32_s64(a));
242 253
243 return vreinterpretq_s64_u64(vmlal_u32(vreinterpretq_u64_s64(vshlq_n_s64(vreinterpretq_s64_u64(vpaddlq_u32(vreinterpretq_u32_s32(hi))), 32)), ac, pr)); 254 return vreinterpretq_s64_u64(vmlal_u32(vreinterpretq_u64_s64(vshlq_n_s64(vreinterpretq_s64_u64(vpaddlq_u32(vreinterpretq_u32_s32(hi))), 32)), ac, pr));
244 } 255 }
245 256
246 VEC_FUNC_IMPL uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b) 257 static inline uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b)
247 { 258 {
248 const uint32x2_t ac = vmovn_u64(a); 259 const uint32x2_t ac = vmovn_u64(a);
249 const uint32x2_t pr = vmovn_u64(b); 260 const uint32x2_t pr = vmovn_u64(b);
250 261
251 const uint32x4_t hi = vmulq_u32(vreinterpretq_u32_u64(b), vreinterpretq_u32_u64(a)); 262 const uint32x4_t hi = vmulq_u32(vreinterpretq_u32_u64(b), vreinterpretq_u32_u64(a));