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_avx(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_avx(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_avx(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_avx(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_avx(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 /* rsqrtss estimate + two Newton steps in double (no rsqrt.pd in AVX). */
91 double y = (double)_mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss((float)len2)));
92 y = y * (1.5 - 0.5 * len2 * y * y);
93 y = y * (1.5 - 0.5 * len2 * y * y);
94 store4(res, _mm256_mul_pd(x, _mm256_set1_pd(y)));
95}
96
97void vec4_min_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
98{
99 store4(res, _mm256_min_pd(load4(a), load4(b)));
100}
101
102void vec4_max_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
103{
104 store4(res, _mm256_max_pd(load4(a), load4(b)));
105}
106
107void vec4_lerp_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
108{
109 const __m256d va = load4(a);
110 const __m256d vb = load4(b);
111 store4(res, _mm256_add_pd(va, _mm256_mul_pd(_mm256_set1_pd(t), _mm256_sub_pd(vb, va))));
112}
113
115 const vector4 *min, const vector4 *max)
116{
117 store4(res, _mm256_min_pd(load4(max), _mm256_max_pd(load4(min), load4(v))));
118}
119
120void vec4_div_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
121{
122 store4(res, hadamard_div(load4(a), load4(b)));
123}
124
126{
127 store4(res, _mm256_add_pd(load4(v), _mm256_set1_pd(s)));
128}
129
131{
132 store4(res, _mm256_sub_pd(load4(v), _mm256_set1_pd(s)));
133}
134
135void vec4_clamp_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
136{
137 store4(res, _mm256_min_pd(_mm256_set1_pd(max), _mm256_max_pd(_mm256_set1_pd(min), load4(v))));
138}
139
141{
142 store4(res, _mm256_min_pd(_mm256_set1_pd(1.0), _mm256_max_pd(_mm256_setzero_pd(), load4(v))));
143}
144
146{
147 store4(res, sign4(load4(v)));
148}
149
151{
152 store4(res, _mm256_floor_pd(load4(v)));
153}
154
156{
157 store4(res, _mm256_ceil_pd(load4(v)));
158}
159
161{
162 const __m256d x = load4(v);
163 const __m256d abs_mask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFFLL));
164 const __m256d sign = _mm256_andnot_pd(abs_mask, x);
165 const __m256d mag = _mm256_floor_pd(_mm256_add_pd(_mm256_and_pd(x, abs_mask), _mm256_set1_pd(0.5)));
166 store4(res, _mm256_or_pd(mag, sign));
167}
168
170{
171 const __m256d x = load4(v);
172 store4(res, _mm256_sub_pd(x, _mm256_floor_pd(x)));
173}
174
176{
177 if (VECMAT_FABS(v->w) > VECMAT_EPSILON) {
178 store4(res, _mm256_mul_pd(load4(v), _mm256_set1_pd(1.0 / v->w)));
179 res->w = 1.0;
180 } else {
181 store4(res, _mm256_setzero_pd());
182 }
183}
184
185static inline __m256d quat_mul_avx(__m256d a, __m256d b)
186{
187 const __m128d a_lo = _mm256_castpd256_pd128(a);
188 const __m128d a_hi = _mm256_extractf128_pd(a, 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
194 const __m128d b_lo = _mm256_castpd256_pd128(b);
195 const __m128d b_hi = _mm256_extractf128_pd(b, 1);
196 const double bx = _mm_cvtsd_f64(b_lo);
197 const double by = _mm_cvtsd_f64(_mm_unpackhi_pd(b_lo, b_lo));
198 const double bz = _mm_cvtsd_f64(b_hi);
199 const double bw = _mm_cvtsd_f64(_mm_unpackhi_pd(b_hi, b_hi));
200
201 return _mm256_setr_pd(
202 aw * bx + ax * bw + ay * bz - az * by,
203 aw * by - ax * bz + ay * bw + az * bx,
204 aw * bz + ax * by - ay * bx + az * bw,
205 aw * bw - ax * bx - ay * by - az * bz);
206}
207
208void quat_mul_ptr_avx(quaternion *res, const quaternion *a, const quaternion *b)
209{
210 const __m256d r = quat_mul_avx(_mm256_loadu_pd(a->v), _mm256_loadu_pd(b->v));
211 _mm256_storeu_pd(res->v, r);
212}
213
215{
216 vec4_normalize_ptr_avx((vector4 *)res, (const vector4 *)q);
217}
218
219#else /* float */
220
221static inline __m128 load4(const vector4 *v)
222{
223 return _mm_loadu_ps(v->v);
224}
225
226static inline void store4(vector4 *v, const __m128 x)
227{
228 _mm_storeu_ps(v->v, x);
229}
230
231static inline __m128 hadamard_div(__m128 a, __m128 b)
232{
233 const __m128 zero = _mm_setzero_ps();
234 const __m128 eqz = _mm_cmpeq_ps(b, zero);
235 const __m128 safe = _mm_blendv_ps(b, _mm_set1_ps(1.0f), eqz);
236 return _mm_andnot_ps(eqz, _mm_div_ps(a, safe));
237}
238
239static inline __m128 sign4(__m128 x)
240{
241 const __m128 zero = _mm_setzero_ps();
242 const __m128 pos = _mm_and_ps(_mm_cmpgt_ps(x, zero), _mm_set1_ps(1.0f));
243 const __m128 neg = _mm_and_ps(_mm_cmplt_ps(x, zero), _mm_set1_ps(-1.0f));
244 return _mm_or_ps(pos, neg);
245}
246
247void vec4_add_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
248{
249 store4(res, _mm_add_ps(load4(a), load4(b)));
250}
251
252void vec4_sub_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
253{
254 store4(res, _mm_sub_ps(load4(a), load4(b)));
255}
256
257void vec4_mul_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
258{
259 store4(res, _mm_mul_ps(load4(a), load4(b)));
260}
261
262void vec4_mul_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
263{
264 store4(res, _mm_mul_ps(load4(v), _mm_set1_ps(s)));
265}
266
267void vec4_div_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
268{
269 if (s == 0.0f) {
270 store4(res, _mm_setzero_ps());
271 return;
272 }
273 store4(res, _mm_div_ps(load4(v), _mm_set1_ps(s)));
274}
275
276void vec4_neg_ptr_avx(vector4 *res, const vector4 *v)
277{
278 store4(res, _mm_xor_ps(load4(v), _mm_set1_ps(-0.0f)));
279}
280
281void vec4_abs_ptr_avx(vector4 *res, const vector4 *v)
282{
283 const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
284 store4(res, _mm_and_ps(load4(v), mask));
285}
286
287void vec4_normalize_ptr_avx(vector4 *res, const vector4 *v)
288{
289 const __m128 x = load4(v);
290 const __m128 len2 = _mm_dp_ps(x, x, 0xFF);
291 if (_mm_cvtss_f32(len2) == 0.0f) {
292 *res = *v;
293 return;
294 }
295 const __m128 y = _mm_rsqrt_ps(len2);
296 const __m128 half = _mm_set1_ps(0.5f);
297 const __m128 three_halves = _mm_set1_ps(1.5f);
298 const __m128 inv = _mm_mul_ps(y, _mm_sub_ps(three_halves,
299 _mm_mul_ps(_mm_mul_ps(half, len2), _mm_mul_ps(y, y))));
300 store4(res, _mm_mul_ps(x, inv));
301}
302
303void vec4_min_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
304{
305 store4(res, _mm_min_ps(load4(a), load4(b)));
306}
307
308void vec4_max_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
309{
310 store4(res, _mm_max_ps(load4(a), load4(b)));
311}
312
313void vec4_lerp_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
314{
315 const __m128 va = load4(a);
316 const __m128 vb = load4(b);
317 store4(res, _mm_add_ps(va, _mm_mul_ps(_mm_set1_ps(t), _mm_sub_ps(vb, va))));
318}
319
320void vec4_clamp_ptr_avx(vector4 *res, const vector4 *v,
321 const vector4 *min, const vector4 *max)
322{
323 store4(res, _mm_min_ps(load4(max), _mm_max_ps(load4(min), load4(v))));
324}
325
326void vec4_div_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
327{
328 store4(res, hadamard_div(load4(a), load4(b)));
329}
330
331void vec4_add_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
332{
333 store4(res, _mm_add_ps(load4(v), _mm_set1_ps(s)));
334}
335
336void vec4_sub_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
337{
338 store4(res, _mm_sub_ps(load4(v), _mm_set1_ps(s)));
339}
340
341void vec4_clamp_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
342{
343 store4(res, _mm_min_ps(_mm_set1_ps(max), _mm_max_ps(_mm_set1_ps(min), load4(v))));
344}
345
346void vec4_saturate_ptr_avx(vector4 *res, const vector4 *v)
347{
348 store4(res, _mm_min_ps(_mm_set1_ps(1.0f), _mm_max_ps(_mm_setzero_ps(), load4(v))));
349}
350
351void vec4_sign_ptr_avx(vector4 *res, const vector4 *v)
352{
353 store4(res, sign4(load4(v)));
354}
355
356void vec4_floor_ptr_avx(vector4 *res, const vector4 *v)
357{
358 store4(res, _mm_floor_ps(load4(v)));
359}
360
361void vec4_ceil_ptr_avx(vector4 *res, const vector4 *v)
362{
363 store4(res, _mm_ceil_ps(load4(v)));
364}
365
366void vec4_round_ptr_avx(vector4 *res, const vector4 *v)
367{
368 const __m128 x = load4(v);
369 const __m128 abs_mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
370 const __m128 sign = _mm_andnot_ps(abs_mask, x);
371 const __m128 mag = _mm_floor_ps(_mm_add_ps(_mm_and_ps(x, abs_mask), _mm_set1_ps(0.5f)));
372 store4(res, _mm_or_ps(mag, sign));
373}
374
375void vec4_fract_ptr_avx(vector4 *res, const vector4 *v)
376{
377 const __m128 x = load4(v);
378 store4(res, _mm_sub_ps(x, _mm_floor_ps(x)));
379}
380
381void vec4_homogenize_ptr_avx(vector4 *res, const vector4 *v)
382{
383 if (VECMAT_FABS(v->w) > VECMAT_EPSILON) {
384 store4(res, _mm_mul_ps(load4(v), _mm_set1_ps(1.0f / v->w)));
385 res->w = 1.0f;
386 } else {
387 store4(res, _mm_setzero_ps());
388 }
389}
390
391static inline __m128 quat_mul_f32(__m128 a, __m128 b)
392{
393 const __m128 aw = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3));
394 const __m128 ax = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
395 const __m128 ay = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
396 const __m128 az = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
397
398 const __m128 t1 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 1, 2, 3)),
399 _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f));
400 const __m128 t2 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 0, 3, 2)),
401 _mm_set_ps(-0.0f, -0.0f, 0.0f, 0.0f));
402 const __m128 t3 = _mm_xor_ps(_mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 3, 0, 1)),
403 _mm_set_ps(-0.0f, 0.0f, 0.0f, -0.0f));
404
405 __m128 r = _mm_mul_ps(aw, b);
406 r = _mm_add_ps(r, _mm_mul_ps(ax, t1));
407 r = _mm_add_ps(r, _mm_mul_ps(ay, t2));
408 r = _mm_add_ps(r, _mm_mul_ps(az, t3));
409 return r;
410}
411
412void quat_mul_ptr_avx(quaternion *res, const quaternion *a, const quaternion *b)
413{
414 _mm_storeu_ps(res->v, quat_mul_f32(_mm_loadu_ps(a->v), _mm_loadu_ps(b->v)));
415}
416
418{
419 vec4_normalize_ptr_avx((vector4 *)res, (const vector4 *)q);
420}
421
422#endif
void vec4_max_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
void vec4_homogenize_ptr_avx(vector4 *res, const vector4 *v)
void vec4_lerp_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b, const vm_float_t t)
void vec4_sub_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
static void store4(vector4 *v, const __m256d x)
Definition vector4_ptr.c:16
void vec4_add_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:37
void vec4_sub_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:42
void vec4_normalize_ptr_avx(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:77
void vec4_div_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
static __m256d hadamard_div(__m256d a, __m256d b)
Definition vector4_ptr.c:21
void vec4_min_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:97
static __m256d sign4(__m256d x)
Definition vector4_ptr.c:29
void vec4_neg_ptr_avx(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:66
void vec4_round_ptr_avx(vector4 *res, const vector4 *v)
void vec4_saturate_ptr_avx(vector4 *res, const vector4 *v)
void vec4_mul_ptr_avx(vector4 *res, const vector4 *a, const vector4 *b)
Definition vector4_ptr.c:47
void vec4_add_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
void vec4_abs_ptr_avx(vector4 *res, const vector4 *v)
Definition vector4_ptr.c:71
static __m256d load4(const vector4 *v)
Definition vector4_ptr.c:11
static __m256d quat_mul_avx(__m256d a, __m256d b)
void vec4_floor_ptr_avx(vector4 *res, const vector4 *v)
void vec4_div_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
Definition vector4_ptr.c:57
void vec4_clamp_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t min, const vm_float_t max)
void quat_normalize_ptr_avx(quaternion *res, const quaternion *q)
void vec4_fract_ptr_avx(vector4 *res, const vector4 *v)
void vec4_mul_scalar_ptr_avx(vector4 *res, const vector4 *v, const vm_float_t s)
Definition vector4_ptr.c:52
void vec4_clamp_ptr_avx(vector4 *res, const vector4 *v, const vector4 *min, const vector4 *max)
void vec4_sign_ptr_avx(vector4 *res, const vector4 *v)
void quat_mul_ptr_avx(quaternion *res, const quaternion *a, const quaternion *b)
void vec4_ceil_ptr_avx(vector4 *res, const vector4 *v)
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