Mercurial > vec
comparison src/impl/arm/neon.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 | d00b95f95dd1 |
children | bf6ad516f1e6 |
comparison
equal
deleted
inserted
replaced
27:d00b95f95dd1 | 28:c6c99ab1088a |
---|---|
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 static v##sign##int##bits##x##size v##sign##int##bits##x##size##_neon_load_aligned(const vec_##sign##int##bits in[size]) \ | 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]) \ |
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 static void v##sign##int##bits##x##size##_neon_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \ | 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]) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 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) \ | 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) \ |
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 static v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ | 117 const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_neon = { \ |
118 v##sign##int##bits##x##size##_fallback_splat, \ | 118 .load = v##sign##int##bits##x##size##_neon_load_aligned, \ |
119 v##sign##int##bits##x##size##_neon_load_aligned, \ | 119 .load_aligned = v##sign##int##bits##x##size##_neon_load_aligned, \ |
120 v##sign##int##bits##x##size##_neon_load_aligned, \ | 120 .store = v##sign##int##bits##x##size##_neon_store_aligned, \ |
121 v##sign##int##bits##x##size##_neon_store_aligned, \ | 121 .store_aligned = v##sign##int##bits##x##size##_neon_store_aligned, \ |
122 v##sign##int##bits##x##size##_neon_store_aligned, \ | 122 .add = v##sign##int##bits##x##size##_neon_add, \ |
123 v##sign##int##bits##x##size##_neon_add, \ | 123 .sub = v##sign##int##bits##x##size##_neon_sub, \ |
124 v##sign##int##bits##x##size##_neon_sub, \ | 124 .mul = v##sign##int##bits##x##size##_neon_mul, \ |
125 v##sign##int##bits##x##size##_neon_mul, \ | 125 .band = v##sign##int##bits##x##size##_neon_and, \ |
126 v##sign##int##bits##x##size##_fallback_div, \ | 126 .bor = v##sign##int##bits##x##size##_neon_or, \ |
127 v##sign##int##bits##x##size##_fallback_avg, \ | 127 .bxor = v##sign##int##bits##x##size##_neon_xor, \ |
128 v##sign##int##bits##x##size##_neon_and, \ | 128 .lshift = v##sign##int##bits##x##size##_neon_lshift, \ |
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, \ | |
140 }; | 129 }; |
141 | 130 |
142 #define VEC_DEFINE_OPERATIONS(bits, size) \ | 131 #define VEC_DEFINE_OPERATIONS(bits, size) \ |
143 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \ | 132 VEC_DEFINE_OPERATIONS_SIGN(u, U, bits, size) \ |
144 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) | 133 VEC_DEFINE_OPERATIONS_SIGN( , , bits, size) |
242 | 231 |
243 // Now we can go ahead and do the 128-bit ones. | 232 // Now we can go ahead and do the 128-bit ones. |
244 | 233 |
245 // NEON doesn't have native 64-bit multiplication, so we have | 234 // NEON doesn't have native 64-bit multiplication, so we have |
246 // to do it ourselves | 235 // to do it ourselves |
247 static inline int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b) | 236 VEC_FUNC_IMPL int64x2_t vmulq_s64(const int64x2_t a, const int64x2_t b) |
248 { | 237 { |
249 const uint32x2_t ac = vreinterpret_u32_s32(vmovn_s64(a)); | 238 const uint32x2_t ac = vreinterpret_u32_s32(vmovn_s64(a)); |
250 const uint32x2_t pr = vreinterpret_u32_s32(vmovn_s64(b)); | 239 const uint32x2_t pr = vreinterpret_u32_s32(vmovn_s64(b)); |
251 | 240 |
252 const int32x4_t hi = vmulq_s32(vreinterpretq_s32_s64(b), vreinterpretq_s32_s64(a)); | 241 const int32x4_t hi = vmulq_s32(vreinterpretq_s32_s64(b), vreinterpretq_s32_s64(a)); |
253 | 242 |
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)); | 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)); |
255 } | 244 } |
256 | 245 |
257 static inline uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b) | 246 VEC_FUNC_IMPL uint64x2_t vmulq_u64(const uint64x2_t a, const uint64x2_t b) |
258 { | 247 { |
259 const uint32x2_t ac = vmovn_u64(a); | 248 const uint32x2_t ac = vmovn_u64(a); |
260 const uint32x2_t pr = vmovn_u64(b); | 249 const uint32x2_t pr = vmovn_u64(b); |
261 | 250 |
262 const uint32x4_t hi = vmulq_u32(vreinterpretq_u32_u64(b), vreinterpretq_u32_u64(a)); | 251 const uint32x4_t hi = vmulq_u32(vreinterpretq_u32_u64(b), vreinterpretq_u32_u64(a)); |