commit a2774b681f32b51926c00d0f8b1bf774d3c3a497
parent 860475a1353e4d3f2d601417e0311bcad0ccda04
Author: vaplv <vaplv@free.fr>
Date: Thu, 23 Oct 2014 14:49:49 +0200
Implement and test the SIMD SoA Float2 functions
Diffstat:
7 files changed, 491 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
@@ -1,9 +1,12 @@
# RSIMD
This C89 library defines an interface that encapsulates and make easier the
-manipulation of SIMD instruction sets. It also provide a SIMD implementation
-of linear algebrae operations for 3x3 and 4x4 matrices arranged in an `Array of
-Structure`. Currently only the SSE2 instruction set is supported.
+manipulation of SIMD instruction sets. It also provides a SIMD implementation
+of linear algebrae operations for 3x3 and 4x4 matrices as well as quaternions
+arranged in an `Array of Structures` SIMD layout. Linear algebrae functions on
+two dimensionnal `Structure of Arrays` vectors are also implemented.
+
+Note that currently only the SSE2 instruction set is supported.
## How to build
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -85,6 +85,7 @@ new_test(test_v4i)
new_test(test_aosf33)
new_test(test_aosf44)
new_test(test_aosq)
+new_test(test_soa4f2)
################################################################################
# Install directives
diff --git a/src/rsimd.h b/src/rsimd.h
@@ -26,7 +26,7 @@
#define RSIMD_API extern IMPORT_SYM
#endif
-#ifdef SIMD_SSE
+#ifdef SIMD_SSE2
#include "sse/sse.h"
#else
#error Unsupported_Platform
diff --git a/src/soa4f2.h b/src/soa4f2.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2014 Vincent Forest (vaplv@free.fr)
+ *
+ * The RSIMD library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The RSIMD library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the RSIMD library. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SOA4F2_H
+#define SOA4F2_H
+
+/* Generate the common soa4fX funcs */
+#define SOA4FX_DIMENSION__ 2
+#include "soa4fX.h"
+
+static FINLINE v4f_T
+soa4f2_cross(const v4f_T a[2], const v4f_T b[2])
+{
+ ASSERT(a && b);
+ return v4f_sub(v4f_mul(a[0], b[1]), v4f_mul(a[1], b[0]));
+}
+
+#endif /* SOA4F2_H */
diff --git a/src/soa4fX.h b/src/soa4fX.h
@@ -0,0 +1,318 @@
+/* Copyright (C) 2014 Vincent Forest (vaplv@free.fr)
+ *
+ * The RSIMD library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The RSIMD library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the RSIMD library. If not, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * Header used to generate funcs on SoA SIMD float vectors of X dimensions
+ */
+#if !defined(SOA4FX_DIMENSION__)
+ #error Missing arguments
+#endif
+
+#if defined(SOA4FX_FUNC__)
+ #error Unexpected SOA4FX_FUNC__ macro defintion
+#endif
+
+#include "rsimd.h"
+
+STATIC_ASSERT(SOA4FX_DIMENSION__ > 1, Unexpected_value);
+
+#define SOA4FX_FUNC__(Func) \
+ CONCAT(CONCAT(CONCAT(soa4f, SOA4FX_DIMENSION__), _), Func)
+
+/* Helper macro */
+#define SIZEOF_SOA4FX__ sizeof(v4f_T[SOA4FX_DIMENSION__])
+
+#if SOA4FX_DIMENSION__ <= 4
+static FINLINE v4f_T*
+CONCAT(soa4f, SOA4FX_DIMENSION__)
+ (v4f_T* dst
+ ,const v4f_T x
+ ,const v4f_T y
+#if SOA4FX_DIMENSION__ > 2
+ ,const v4f_T z
+#endif
+#if SOA4FX_DIMENSION__ > 3
+ ,const v4f_T w
+#endif
+ )
+{
+ ASSERT(dst);
+ dst[0] = x;
+ dst[1] = y;
+#if SOA4FX_DIMENSION__ > 2
+ dst[2] = z;
+#endif
+#if SOA4FX_DIMENSION__ > 3
+ dst[3] = w;
+#endif
+ return dst;
+}
+#endif
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(splat)(v4f_T* dst, const v4f_T val)
+{
+ int i;
+ ASSERT(dst);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ dst[i] = val;
+ return dst;
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(set__)(v4f_T* dst, const v4f_T* src)
+{
+ int i;
+ ASSERT(dst && src);
+ ASSERT(!MEM_AREA_OVERLAP(dst, SIZEOF_SOA4FX__, src, SIZEOF_SOA4FX__));
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ dst[i] = src[i];
+ return dst;
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(set)(v4f_T* dst, const v4f_T* src)
+{
+ ASSERT(dst && src);
+ if(!MEM_AREA_OVERLAP(dst, SIZEOF_SOA4FX__, src, SIZEOF_SOA4FX__)) {
+ return SOA4FX_FUNC__(set__)(dst, src);
+ } else {
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ return SOA4FX_FUNC__(set__)(dst, SOA4FX_FUNC__(set__)(tmp, src));
+ }
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(dot)(const v4f_T* a, const v4f_T* b)
+{
+ v4f_T dot;
+ int i;
+ ASSERT(a && b);
+ dot = v4f_mul(a[0], b[0]);
+ FOR_EACH(i, 1, SOA4FX_DIMENSION__) {
+ dot = v4f_add(dot, v4f_mul(a[i], b[i]));
+ }
+ return dot;
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(len)(const v4f_T* a)
+{
+ ASSERT(a);
+ return v4f_sqrt(SOA4FX_FUNC__(dot)(a, a));
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(normalize)(v4f_T* dst, const v4f_T* a)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ v4f_T sqr_len, rcp_len;
+ v4f_T mask;
+ int i;
+ ASSERT(dst && a);
+
+ sqr_len = SOA4FX_FUNC__(dot)(a, a);
+ mask = v4f_neq(sqr_len, v4f_zero());
+ rcp_len = v4f_rsqrt(sqr_len);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_and(mask, v4f_mul(a[i], rcp_len));
+ SOA4FX_FUNC__(set__)(dst, tmp);
+ return v4f_mul(sqr_len, rcp_len);
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(is_normalized)(const v4f_T* a)
+{
+ return v4f_eq_eps(SOA4FX_FUNC__(len)(a), v4f_set1(1.f), v4f_set1(1.e-6f));
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(add)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_add(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(addf)(v4f_T* dst, const v4f_T* a, const v4f_T f)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_add(a[i], f);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(sub)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_sub(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(subf)(v4f_T* dst, const v4f_T* a, const v4f_T f)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_sub(a[i], f);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(mul)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_mul(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(mulf)(v4f_T* dst, const v4f_T* a, const v4f_T f)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_mul(a[i], f);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(div)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_div(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(divf)(v4f_T* dst, const v4f_T* a, const v4f_T f)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_div(a[i], f);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(minus)(v4f_T* dst, const v4f_T* a)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_minus(a[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(sum)(const v4f_T* a)
+{
+ v4f_T f;
+ int i = 0;
+ ASSERT(a);
+ f = a[i];
+ FOR_EACH(i, 1, SOA4FX_DIMENSION__)
+ f = v4f_add(f, a[i]);
+ return f;
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(lerp)
+ (v4f_T* dst,
+ const v4f_T* from,
+ const v4f_T* to,
+ const v4f_T t)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ v4f_T t_adjusted;
+ int i;
+ ASSERT(dst && from && to);
+ t_adjusted = v4f_min(v4f_max(t, v4f_zero()), v4f_set1(1.f));
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_add(from[i], v4f_mul(t_adjusted, v4f_sub(to[i], from[i])));
+ SOA4FX_FUNC__(set__)(dst, tmp);
+ return dst;
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(eq)(const v4f_T* a, const v4f_T* b)
+{
+ v4f_T is_eq;
+ int i = 0;
+ ASSERT(a && b);
+ is_eq = v4f_eq(a[0], b[0]);
+ FOR_EACH(i, 1, SOA4FX_DIMENSION__)
+ is_eq = v4f_and(is_eq, v4f_eq(a[i], b[i]));
+ return is_eq;
+}
+
+static FINLINE v4f_T
+SOA4FX_FUNC__(eq_eps)(const v4f_T* a, const v4f_T* b, const v4f_T eps)
+{
+ v4f_T is_eq;
+ int i = 0;
+ ASSERT(a && b);
+ is_eq = v4f_eq_eps(a[0], b[0], eps);
+ FOR_EACH(i, 1, SOA4FX_DIMENSION__)
+ is_eq = v4f_and(is_eq, v4f_eq_eps(a[i], b[i], eps));
+ return is_eq;
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(max)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_max(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+static FINLINE v4f_T*
+SOA4FX_FUNC__(min)(v4f_T* dst, const v4f_T* a, const v4f_T* b)
+{
+ v4f_T tmp[SOA4FX_DIMENSION__];
+ int i;
+ ASSERT(dst && a && b);
+ FOR_EACH(i, 0, SOA4FX_DIMENSION__)
+ tmp[i] = v4f_min(a[i], b[i]);
+ return SOA4FX_FUNC__(set__)(dst, tmp);
+}
+
+#undef SIZEOF_SOA4FX__
+#undef SOA4FX_DIMENSION__
+#undef SOA4FX_FUNC__
diff --git a/src/sse/ssef.h b/src/sse/ssef.h
@@ -23,12 +23,8 @@
#include "sse_swz.h"
#include <rsys/math.h>
-#ifdef SIMD_SSE
- #include <xmmintrin.h>
-#endif
-#ifdef SIMD_SSE2
- #include <emmintrin.h>
-#endif
+#include <xmmintrin.h>
+#include <emmintrin.h>
typedef __m128 v4f_T;
#define V4F_AT__(Vec, Id) __builtin_ia32_vec_ext_v4sf(Vec, Id)
@@ -544,7 +540,7 @@ v4f_lt(const v4f_T v0, const v4f_T v1)
static FINLINE v4f_T
v4f_eq_eps(const v4f_T v0, const v4f_T v1, const v4f_T eps)
{
- return v4f_lt(v4f_abs(v4f_sub(v0, v1)), eps);
+ return v4f_le(v4f_abs(v4f_sub(v0, v1)), eps);
}
static FINLINE v4f_T
diff --git a/src/test_soa4f2.c b/src/test_soa4f2.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 2014 Vincent Forest (vaplv@free.fr)
+ *
+ * The RSIMD library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The RSIMD library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the RSIMD library. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "soa4f2.h"
+
+#define V4TRUE ~0, ~0, ~0, ~0
+#define V4FALSE 0, 0, 0, 0
+#define CHECK_V4MASK__(Mask, A, B, C, D) \
+ { \
+ const v4f_T mask__ = (Mask); \
+ CHECK(v4f_mask_x(mask__), (A)); \
+ CHECK(v4f_mask_y(mask__), (B)); \
+ CHECK(v4f_mask_z(mask__), (C)); \
+ CHECK(v4f_mask_w(mask__), (D)); \
+ } (void)0
+#define CHECK_V4MASK(Mask, Vec) CHECK_V4MASK__(Mask, Vec)
+
+#define CHECK_SOA4F2(V, A, B, C, D, E, F, G, H) \
+ { \
+ const v4f_T* v__ = (V); \
+ CHECK_V4MASK(v4f_eq(v__[0], v4f_set((A), (B), (C), (D))), V4TRUE); \
+ CHECK_V4MASK(v4f_eq(v__[1], v4f_set((E), (F), (G), (H))), V4TRUE); \
+ } (void)0
+
+int
+main(int argc, char** argv)
+{
+ v4f_T a[2], b[2], c[2], dst[2], f;
+ (void)argc, (void)argv;
+
+ CHECK(soa4f2_set(a, soa4f2_splat(c, v4f_set1(-1.f))), a);
+ CHECK_V4MASK(v4f_eq(a[0], v4f_set1(-1.f)), V4TRUE);
+ CHECK_V4MASK(v4f_eq(a[1], v4f_set1(-1.f)), V4TRUE);
+
+ CHECK(soa4f2(c, v4f_set(0.f, 1.f, 2.f, 3.f), v4f_set(5.f, 6.f, 7.f, 8.f)), c);
+ CHECK(soa4f2_set(a, c), a);
+ CHECK_V4MASK(v4f_eq(c[0], v4f_set(0.f, 1.f, 2.f, 3.f)), V4TRUE);
+ CHECK_V4MASK(v4f_eq(c[1], v4f_set(5.f, 6.f, 7.f, 8.f)), V4TRUE);
+ CHECK_V4MASK(v4f_eq(a[0], v4f_set(0.f, 1.f, 2.f, 3.f)), V4TRUE);
+ CHECK_V4MASK(v4f_eq(a[1], v4f_set(5.f, 6.f, 7.f, 8.f)), V4TRUE);
+
+ CHECK(soa4f2(a, v4f_set(-1.f, 2.f, 3.f,-4.f),v4f_set(5.f,-6.f,-7.f, 8.f)), a);
+ CHECK(soa4f2_minus(b, a), b);
+ CHECK_SOA4F2(b, 1.f,-2.f,-3.f, 4.f, -5.f, 6.f, 7.f,-8.f);
+
+ CHECK(soa4f2_addf(dst, a, v4f_set1(1.f)), dst);
+ CHECK_SOA4F2(dst, 0.f, 3.f, 4.f, -3.f, 6.f, -5.f, -6.f, 9.f);
+ CHECK(soa4f2_addf(dst, a, v4f_set(1.f, 2.f, 0.f, 3.f)), dst);
+ CHECK_SOA4F2(dst, 0.f, 4.f, 3.f, -1.f, 6.f, -4.f, -7.f, 11.f);
+ CHECK(soa4f2_add(dst, a, b), dst);
+ CHECK_SOA4F2(dst, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
+
+ CHECK(soa4f2_subf(dst, a, v4f_set1(1.f)), dst);
+ CHECK_SOA4F2(dst, -2.f, 1.f, 2.f, -5.f, 4.f, -7.f, -8.f, 7.f);
+ CHECK(soa4f2_subf(dst, a, v4f_set(1.f, 2.f, 0.f, 3.f)), dst);
+ CHECK_SOA4F2(dst, -2.f, 0.f, 3.f, -7.f, 4.f, -8.f, -7.f, 5.f);
+ CHECK(soa4f2_sub(dst, a, b), dst);
+ CHECK_SOA4F2(dst, -2.f, 4.f, 6.f, -8.f, 10.f, -12.f, -14.f, 16.f);
+
+ CHECK(soa4f2_mulf(dst, a, v4f_set1(2.f)), dst);
+ CHECK_SOA4F2(dst, -2.f, 4.f, 6.f, -8.f, 10.f, -12.f, -14.f, 16.f);
+ CHECK(soa4f2_mulf(dst, a, v4f_set(2.f, 3.f, 0.f, -1.f)), dst);
+ CHECK_SOA4F2(dst, -2.f, 6.f, 0.f, 4.f, 10.f, -18.f, 0.f, -8.f);
+ CHECK(soa4f2_mul(dst, a, b), dst);
+ CHECK_SOA4F2(dst, -1.f, -4.f, -9.f, -16.f, -25.f, -36.f, -49.f, -64.f);
+
+ CHECK(soa4f2_divf(dst, a, v4f_set1(2.f)), dst);
+ CHECK_SOA4F2(dst, -0.5f, 1.f, 1.5f, -2.f, 2.5f, -3.f, -3.5f, 4.f);
+ CHECK(soa4f2_divf(dst, a, v4f_set(2.f, 0.5f, 1.f, 4.f)), dst);
+ CHECK_SOA4F2(dst, -0.5f, 4.f, 3.f, -1.f, 2.5f, -12.f, -7.f, 2.f);
+ CHECK(soa4f2_div(dst, a, b), dst);
+ CHECK_SOA4F2(dst, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f);
+
+ soa4f2(a, v4f_set1(0.f), v4f_set1(1.f));
+ soa4f2(b, v4f_set1(1.f), v4f_set1(2.f));
+ CHECK(soa4f2_lerp(dst, a, b, v4f_set1(0.5f)), dst);
+ CHECK_SOA4F2(dst, 0.5f, 0.5f, 0.5f, 0.5f, 1.5f, 1.5f, 1.5f, 1.5f);
+ soa4f2(a, v4f_set(-1.f, 2.f, 3.f,-4.f), v4f_set(5.f,-6.f,-7.f, 8.f));
+ soa4f2_minus(b, a);
+ CHECK(soa4f2_lerp(dst, a, b, v4f_set(-0.5f, 1.f, 0.5f, 4.f)), dst);
+ CHECK_SOA4F2(dst, -1.f, -2.f, 0.f, 4.f, 5.f, 6.f, 0.f, -8.f);
+
+ f = soa4f2_sum(b);
+ CHECK_V4MASK(v4f_eq(f, v4f_set(-4.f, 4.f, 4.f, -4.f)), V4TRUE);
+ f = soa4f2_dot(a, b);
+ CHECK_V4MASK(v4f_eq(f, v4f_set(-26.f, -40.f, -58.f, -80.f)), V4TRUE);
+ f = soa4f2_len(a);
+ CHECK_V4MASK
+ (v4f_eq_eps(f, v4f_sqrt(soa4f2_dot(a, a)), v4f_set1(1.e-6f)), V4TRUE);
+
+ CHECK_V4MASK(soa4f2_is_normalized(b), V4FALSE);
+ f = soa4f2_normalize(dst, b);
+ CHECK_V4MASK(v4f_eq_eps(f, soa4f2_len(b), v4f_set1(1.e-6f)), V4TRUE);
+ CHECK_V4MASK(soa4f2_is_normalized(b), V4FALSE);
+ CHECK_V4MASK(soa4f2_is_normalized(dst), V4TRUE);
+ soa4f2_divf(b, b, f);
+ CHECK_V4MASK(v4f_eq_eps(dst[0], b[0], v4f_set1(1.e-6f)), V4TRUE);
+ CHECK_V4MASK(v4f_eq_eps(dst[1], b[1], v4f_set1(1.e-6f)), V4TRUE);
+
+ CHECK_V4MASK(soa4f2_eq(a, a), V4TRUE);
+ CHECK_V4MASK(soa4f2_eq(a, b), V4FALSE);
+ soa4f2(a, v4f_set(-1.f, 2.f, 3.f,-4.f), v4f_set(5.f,-6.f,-7.f, 8.f));
+ soa4f2(b, v4f_set(-1.f,-2.f, 5.f,-4.001f), v4f_set(5.f,-6.f, 7.f, 8.001f));
+ CHECK_V4MASK__(soa4f2_eq(a, b), ~0, 0, 0, 0);
+ CHECK_V4MASK__(soa4f2_eq_eps(a, b, v4f_set1(1.e-6f)), ~0, 0, 0, 0);
+ CHECK_V4MASK__(soa4f2_eq_eps(a, b, v4f_set(0.f,0.f,0.f,1.e-6f)),~0, 0, 0, 0);
+ CHECK_V4MASK__(soa4f2_eq_eps(a, b, v4f_set(0.f,0.f,0.f,1.e-2f)),~0, 0, 0,~0);
+
+ soa4f2(a, v4f_set(1.f, 2.f, 3.f,-1.f), v4f_set(-2.f, 0.f,-7.f, 0.f));
+ soa4f2(b, v4f_set(3.f, 2.f, 1.f,-2.f), v4f_set(1.f,-6.f, 0.5f, 2.f));
+ f = soa4f2_cross(a, b);
+ CHECK_V4MASK(v4f_eq(f, v4f_set(7.f, -12.f, 8.5f, -2.f)), V4TRUE);
+
+ CHECK(soa4f2_min(dst, a, b), dst);
+ CHECK_SOA4F2(dst, 1.f, 2.f, 1.f, -2.f, -2.f, -6.f, -7.f, 0.f);
+ CHECK(soa4f2_max(dst, a, b), dst);
+ CHECK_SOA4F2(dst, 3.f, 2.f, 3.f, -1.f, 1.f, 0.f, 0.5f, 2.f);
+
+ return 0;
+}