Vecmat 0.2.3
C math and linear algebra library for 2D/3D graphics, physics, and science.
Loading...
Searching...
No Matches
vector4_ptr.c
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025-2026 Igal Alkon
2// SPDX-FileCopyrightText: 2026 ALKONTEK <git@alkontek.com>
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <immintrin.h>
6#include <math.h>
7#include <vecmat.h>
8
9#if defined(VECMAT_USE_F64)
10
11static inline __m256d load4(const vector4 *v)
12{
13 return _mm256_loadu_pd(v->v);
14}
15
16static inline void store4(vector4 *v, const __m256d x)
17{
18 _mm256_storeu_pd(v->v, x);
19}
20
21static inline __m256d hadamard_div(__m256d a, __m256d b)
22{
23 const __m256d zero = _mm256_setzero_pd();
24 const __m256d eqz = _mm256_cmp_pd(b, zero, _CMP_EQ_OQ);
25 const __m256d safe = _mm256_blendv_pd(b, _mm256_set1_pd(1.0), eqz);
26 return _mm256_andnot_pd(eqz, _mm256_div_pd(a, safe));
27}
28
29static inline __m256d sign4(__m256d x)
30{
31 const __m256d zero = _mm256_setzero_pd();
32 const __m256d pos = _mm256_and_pd(_mm256_cmp_pd(x, zero, _CMP_GT_OQ), _mm256_set1_pd(1.0));
33 const __m256d neg = _mm256_and_pd(_mm256_cmp_pd(x, zero, _CMP_LT_OQ), _mm256_set1_pd(-1.0));
34 return _mm256_or_pd(pos, neg);
35}
36
37void vec4_add_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
38{
39 store4(res, _mm256_add_pd(load4(a), load4(b)));
40}
41
42void vec4_sub_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
43{
44 store4(res, _mm256_sub_pd(load4(a), load4(b)));
45}
46
47void vec4_mul_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
48{
49 store4(res, _mm256_mul_pd(load4(a), load4(b)));
50}
51
53{
54 store4(res, _mm256_mul_pd(load4(v), _mm256_set1_pd(s)));
55}
56
58{
59 if (s == 0.0) {
60 store4(res, _mm256_setzero_pd());
61 return;
62 }
63 store4(res, _mm256_div_pd(load4(v), _mm256_set1_pd(s)));
64}
65
66void vec4_neg_ptr_avx2(vector4 *res, const vector4 *v)
67{
68 store4(res, _mm256_xor_pd(load4(v), _mm256_set1_pd(-0.0)));
69}
70
71void vec4_abs_ptr_avx2(vector4 *res, const vector4 *v)
72{
73 const __m256d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFFLL));
74 store4(res, _mm256_and_pd(load4(v), mask));
75}
76
78{
79 const __m256d x = load4(v);
80 const __m256d sq = _mm256_mul_pd(x, x);
81 const __m128d hi = _mm256_extractf128_pd(sq, 1);
82 const __m128d lo = _mm256_castpd256_pd128(sq);
83 __m128d sum = _mm_add_pd(lo, hi);
84 sum = _mm_add_sd(sum, _mm_unpackhi_pd(sum, sum));
85 const double len2 = _mm_cvtsd_f64(sum);
86 if (len2 == 0.0) {
87 *res = *v;
88 return;
89 }
90 double y = (double)_mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss((float)len2)));
91 y = y * fma(-0.5 * len2, y * y, 1.5);
92 y = y * fma(-0.5 * len2, y * y, 1.5);
93 store4(res, _mm256_mul_pd(x, _mm256_set1_pd(y)));
94}
95
96void vec4_min_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
97{
98 store4(res, _mm256_min_pd(load4(a), load4(b)));
99}
100
101void vec4_max_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
102{
103 store4(res, _mm256_max_pd(load4(a), load4(b)));
104}
105
106void vec4_lerp_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
107{
108 const __m256d va = load4(a);
109 store4(res, _mm256_fmadd_pd(_mm256_set1_pd(t), _mm256_sub_pd(load4(b), va), va));
110}
111
113 const vector4 *min, const vector4 *max)
114{
115 store4(res, _mm256_min_pd(load4(max), _mm256_max_pd(load4(min), load4(v))));
116}
117
118void vec4_div_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
119{
120 store4(res, hadamard_div(load4(a), load4(b)));
121}
122
124{
125 store4(res, _mm256_add_pd(load4(v), _mm256_set1_pd(s)));
126}
127
129{
130 store4(res, _mm256_sub_pd(load4(v), _mm256_set1_pd(s)));
131}
132
133void vec4_clamp_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
134{
135 store4(res, _mm256_min_pd(_mm256_set1_pd(max), _mm256_max_pd(_mm256_set1_pd(min), load4(v))));
136}
137
139{
140 store4(res, _mm256_min_pd(_mm256_set1_pd(1.0), _mm256_max_pd(_mm256_setzero_pd(), load4(v))));
141}
142
144{
145 store4(res, sign4(load4(v)));
146}
147
149{
150 store4(res, _mm256_floor_pd(load4(v)));
151}
152
154{
155 store4(res, _mm256_ceil_pd(load4(v)));
156}
157
159{
160 const __m256d x = load4(v);
161 const __m256d abs_mask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFFLL));
162 const __m256d sign = _mm256_andnot_pd(abs_mask, x);
163 const __m256d mag = _mm256_floor_pd(_mm256_add_pd(_mm256_and_pd(x, abs_mask), _mm256_set1_pd(0.5)));
164 store4(res, _mm256_or_pd(mag, sign));
165}
166
168{
169 const __m256d x = load4(v);
170 store4(res, _mm256_sub_pd(x, _mm256_floor_pd(x)));
171}
172
174{
175 if (VECMAT_FABS(v->w) > VECMAT_EPSILON) {
176 store4(res, _mm256_mul_pd(load4(v), _mm256_set1_pd(1.0 / v->w)));
177 res->w = 1.0;
178 } else {
179 store4(res, _mm256_setzero_pd());
180 }
181}
182
183void quat_mul_ptr_avx2(quaternion *res, const quaternion *a, const quaternion *b)
184{
185 const __m256d va = _mm256_loadu_pd(a->v);
186 const __m256d vb = _mm256_loadu_pd(b->v);
187 const __m128d a_lo = _mm256_castpd256_pd128(va);
188 const __m128d a_hi = _mm256_extractf128_pd(va, 1);
189 const double ax = _mm_cvtsd_f64(a_lo);
190 const double ay = _mm_cvtsd_f64(_mm_unpackhi_pd(a_lo, a_lo));
191 const double az = _mm_cvtsd_f64(a_hi);
192 const double aw = _mm_cvtsd_f64(_mm_unpackhi_pd(a_hi, a_hi));
193 const __m128d b_lo = _mm256_castpd256_pd128(vb);
194 const __m128d b_hi = _mm256_extractf128_pd(vb, 1);
195 const double bx = _mm_cvtsd_f64(b_lo);
196 const double by = _mm_cvtsd_f64(_mm_unpackhi_pd(b_lo, b_lo));
197 const double bz = _mm_cvtsd_f64(b_hi);
198 const double bw = _mm_cvtsd_f64(_mm_unpackhi_pd(b_hi, b_hi));
199 _mm256_storeu_pd(res->v, _mm256_setr_pd(
200 fma(aw, bx, fma(ax, bw, fma(ay, bz, -az * by))),
201 fma(aw, by, fma(-ax, bz, fma(ay, bw, az * bx))),
202 fma(aw, bz, fma(ax, by, fma(-ay, bx, az * bw))),
203 fma(aw, bw, fma(-ax, bx, fma(-ay, by, -az * bz)))));
204}
205
207{
208 vec4_normalize_ptr_avx2((vector4 *)res, (const vector4 *)q);
209}
210
211#else /* float */
212
213static inline __m128 load4(const vector4 *v)
214{
215 return _mm_loadu_ps(v->v);
216}
217
218static inline void store4(vector4 *v, const __m128 x)
219{
220 _mm_storeu_ps(v->v, x);
221}
222
223static inline __m128 hadamard_div(__m128 a, __m128 b)
224{
225 const __m128 zero = _mm_setzero_ps();
226 const __m128 eqz = _mm_cmpeq_ps(b, zero);
227 const __m128 safe = _mm_blendv_ps(b, _mm_set1_ps(1.0f), eqz);
228 return _mm_andnot_ps(eqz, _mm_div_ps(a, safe));
229}
230
231static inline __m128 sign4(__m128 x)
232{
233 const __m128 zero = _mm_setzero_ps();
234 const __m128 pos = _mm_and_ps(_mm_cmpgt_ps(x, zero), _mm_set1_ps(1.0f));
235 const __m128 neg = _mm_and_ps(_mm_cmplt_ps(x, zero), _mm_set1_ps(-1.0f));
236 return _mm_or_ps(pos, neg);
237}
238
239void vec4_add_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
240{
241 store4(res, _mm_add_ps(load4(a), load4(b)));
242}
243
244void vec4_sub_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
245{
246 store4(res, _mm_sub_ps(load4(a), load4(b)));
247}
248
249void vec4_mul_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
250{
251 store4(res, _mm_mul_ps(load4(a), load4(b)));
252}
253
254void vec4_mul_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
255{
256 store4(res, _mm_mul_ps(load4(v), _mm_set1_ps(s)));
257}
258
259void vec4_div_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
260{
261 if (s == 0.0f) {
262 store4(res, _mm_setzero_ps());
263 return;
264 }
265 store4(res, _mm_div_ps(load4(v), _mm_set1_ps(s)));
266}
267
268void vec4_neg_ptr_avx2(vector4 *res, const vector4 *v)
269{
270 store4(res, _mm_xor_ps(load4(v), _mm_set1_ps(-0.0f)));
271}
272
273void vec4_abs_ptr_avx2(vector4 *res, const vector4 *v)
274{
275 const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
276 store4(res, _mm_and_ps(load4(v), mask));
277}
278
279void vec4_normalize_ptr_avx2(vector4 *res, const vector4 *v)
280{
281 const __m128 x = load4(v);
282 const __m128 len2 = _mm_dp_ps(x, x, 0xFF);
283 if (_mm_cvtss_f32(len2) == 0.0f) {
284 *res = *v;
285 return;
286 }
287 const __m128 y = _mm_rsqrt_ps(len2);
288 const __m128 inv = _mm_mul_ps(y, _mm_fnmadd_ps(
289 _mm_mul_ps(_mm_set1_ps(0.5f), len2), _mm_mul_ps(y, y), _mm_set1_ps(1.5f)));
290 store4(res, _mm_mul_ps(x, inv));
291}
292
293void vec4_min_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
294{
295 store4(res, _mm_min_ps(load4(a), load4(b)));
296}
297
298void vec4_max_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
299{
300 store4(res, _mm_max_ps(load4(a), load4(b)));
301}
302
303void vec4_lerp_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
304{
305 const __m128 va = load4(a);
306 store4(res, _mm_fmadd_ps(_mm_set1_ps(t), _mm_sub_ps(load4(b), va), va));
307}
308
309void vec4_clamp_ptr_avx2(vector4 *res, const vector4 *v, const vector4 *min, const vector4 *max)
310{
311 store4(res, _mm_min_ps(load4(max), _mm_max_ps(load4(min), load4(v))));
312}
313
314void vec4_div_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
315{
316 store4(res, hadamard_div(load4(a), load4(b)));
317}
318
319void vec4_add_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
320{
321 store4(res, _mm_add_ps(load4(v), _mm_set1_ps(s)));
322}
323
324void vec4_sub_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
325{
326 store4(res, _mm_sub_ps(load4(v), _mm_set1_ps(s)));
327}
328
329void vec4_clamp_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
330{
331 store4(res, _mm_min_ps(_mm_set1_ps(max), _mm_max_ps(_mm_set1_ps(min), load4(v))));
332}
333
334void vec4_saturate_ptr_avx2(vector4 *res, const vector4 *v)
335{
336 store4(res, _mm_min_ps(_mm_set1_ps(1.0f), _mm_max_ps(_mm_setzero_ps(), load4(v))));
337}
338
339void vec4_sign_ptr_avx2(vector4 *res, const vector4 *v)
340{
341 store4(res, sign4(load4(v)));
342}
343
344void vec4_floor_ptr_avx2(vector4 *res, const vector4 *v)
345{
346 store4(res, _mm_floor_ps(load4(v)));
347}
348
349void vec4_ceil_ptr_avx2(vector4 *res, const vector4 *v)
350{
351 store4(res, _mm_ceil_ps(load4(v)));
352}
353
354void vec4_round_ptr_avx2(vector4 *res, const vector4 *v)
355{
356 const __m128 x = load4(v);
357 const __m128 abs_mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
358 const __m128 sign = _mm_andnot_ps(abs_mask, x);
359 const __m128 mag = _mm_floor_ps(_mm_add_ps(_mm_and_ps(x, abs_mask), _mm_set1_ps(0.5f)));
360 store4(res, _mm_or_ps(mag, sign));
361}
362
363void vec4_fract_ptr_avx2(vector4 *res, const vector4 *v)
364{
365 const __m128 x = load4(v);
366 store4(res, _mm_sub_ps(x, _mm_floor_ps(x)));
367}
368
369void vec4_homogenize_ptr_avx2(vector4 *res, const vector4 *v)
370{
371 if (VECMAT_FABS(v->w) > VECMAT_EPSILON) {
372 store4(res, _mm_mul_ps(load4(v), _mm_set1_ps(1.0f / v->w)));
373 res->w = 1.0f;
374 } else {
375 store4(res, _mm_setzero_ps());
376 }
377}
378
379static inline __m128 quat_mul_f32(__m128 a, __m128 b)
380{
381 const __m128 aw = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3));
382 const __m128 ax = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
383 const __m128 ay = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
384 const __m128 az = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
385
386 const __m128 t1 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 1, 2, 3)),
387 _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f));
388 const __m128 t2 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 0, 3, 2)),
389 _mm_set_ps(-0.0f, -0.0f, 0.0f, 0.0f));
390 const __m128 t3 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 3, 0, 1)),
391 _mm_set_ps(-0.0f, 0.0f, 0.0f, -0.0f));
392
393 return _mm_fmadd_ps(az, t3, _mm_fmadd_ps(ay, t2, _mm_fmadd_ps(ax, t1, _mm_mul_ps(aw, b))));
394}
395
396void quat_mul_ptr_avx2(quaternion *res, const quaternion *a, const quaternion *b)
397{
398 _mm_storeu_ps(res->v, quat_mul_f32(_mm_loadu_ps(a->v), _mm_loadu_ps(b->v)));
399}
400
402{
403 vec4_normalize_ptr_avx2((vector4 *)res, (const vector4 *)q);
404}
405
406#endif
void vec4_add_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
void vec4_abs_ptr_avx2(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:71
void vec4_div_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
void vec4_neg_ptr_avx2(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:66
void vec4_clamp_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
void vec4_sub_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
void quat_normalize_ptr_avx2(quaternion *res, const quaternion *q)
void vec4_sub_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:42
void vec4_round_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_homogenize_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_lerp_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
void vec4_ceil_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_add_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:37
void vec4_min_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:96
void vec4_max_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
void vec4_clamp_ptr_avx2(vector4 *res, const vector4 *v, const vector4 *min, const vector4 *max)
void vec4_floor_ptr_avx2(vector4 *res, const vector4 *v)
void quat_mul_ptr_avx2(quaternion *res, const quaternion *a, const quaternion *b)
void vec4_mul_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
Definition vector4_ptr.c:52
void vec4_mul_ptr_avx2(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:47
void vec4_sign_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_fract_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_saturate_ptr_avx2(vector4 *res, const vector4 *v)
void vec4_div_scalar_ptr_avx2(vector4 *res, const vector4 *v, const vm_float_t s)
Definition vector4_ptr.c:57
void vec4_normalize_ptr_avx2(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:77
static void store4(vector4 *v, const __m256d x)
Definition vector4_ptr.c:16
static __m256d hadamard_div(__m256d a, __m256d b)
Definition vector4_ptr.c:21
static __m256d sign4(__m256d x)
Definition vector4_ptr.c:29
static __m256d load4(const vector4 *v)
Definition vector4_ptr.c:11
vm_float_t v[VECMAT_QUAT_SIZE]
Definition vecmat.h:368
vm_float_t v[VECMAT_VEC4_SIZE]
Definition vecmat.h:153
vm_float_t w
Definition vecmat.h:151
#define VECMAT_EPSILON
Definition vecmat.h:377
double vm_float_t
Definition vecmat.h:79
#define VECMAT_FABS(x)
Definition vecmat.h:413