diff src/impl/x86/mmx.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 e49e70f7012f
children bf6ad516f1e6
line wrap: on
line diff
--- a/src/impl/x86/mmx.c	Mon Nov 25 00:33:02 2024 -0500
+++ b/src/impl/x86/mmx.c	Thu Apr 24 00:54:02 2025 -0400
@@ -24,46 +24,67 @@
 
 #include "vec/vec.h"
 #include "vec/impl/x86/mmx.h"
-#include "vec/impl/generic.h"
 
 #include <mmintrin.h>
 #include <string.h>
 
-#define VEC_MMX_OPERATION_8x8(op, sign) \
-	do { \
-		/* unpack and multiply */ \
-		union v##sign##int8x8_impl_data *vec1d = (union v##sign##int8x8_impl_data *)&vec1; \
-		union v##sign##int8x8_impl_data *vec2d = (union v##sign##int8x8_impl_data *)&vec2; \
-	\
-		__m64 dst_even = _mm_##op##_pi16(vec1d->mmx, vec2d->mmx); \
-		__m64 dst_odd = _mm_##op##_pi16(_mm_srli_pi16(vec1d->mmx, 8), _mm_srli_pi16(vec2d->mmx, 8)); \
-	\
-		/* repack */ \
-		vec1d->mmx = _mm_or_si64( \
-			_mm_slli_pi16(dst_odd, 8), \
-			_mm_srli_pi16(_mm_slli_pi16(dst_even, 8), 8) \
-		); \
-		return vec1d->vec; \
-	} while (0)
+/* ------------------------------------------------------------------------ */
 
-// shared between MMX variations
-#define VEC_MMX_MUL_8x8(sign) \
-	VEC_MMX_OPERATION_8x8(mullo, sign)
-
+#define VEC_MMX_MUL_8x8(sign) /* nothing */
 #define VEC_MMX_MUL_16x4(sign) \
-	do { \
+	VEC_FUNC_IMPL v##sign##int16x4 v##sign##int16x4_mmx_mul(v##sign##int16x4 vec1, v##sign##int16x4 vec2) \
+	{ \
 		union v##sign##int16x4_impl_data *vec1d = (union v##sign##int16x4_impl_data *)&vec1; \
 		union vuint16x4_impl_data *vec2d = (union vuint16x4_impl_data *)&vec2; \
 	\
 		vec1d->mmx = _mm_mullo_pi16(vec1d->mmx, vec2d->mmx); \
 		return vec1d->vec; \
-	} while (0)
+	}
+#define VEC_MMX_MUL_32x2(sign) /* nothing */
+
+#define VEC_MMX_STRUCT_MUL_8x8(sign) NULL
+#define VEC_MMX_STRUCT_MUL_16x4(sign) v##sign##int16x4_mmx_mul
+#define VEC_MMX_STRUCT_MUL_32x8(sign) NULL
+
+/* ------------------------------------------------------------------------ */
+/* comparison */
 
-#define VEC_MMX_MUL_32x2(sign) \
-	/* TODO implement this for real */ \
-	do { \
-		return v##sign##int32x2_generic_mul(vec1, vec2); \
-	} while (0)
+/* helper funcs */
+#define VEC_xMMX_CMP(name, op, sign, bits, size, first, second, VARS, TRANS1, TRANS2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_##name(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	{ \
+		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
+		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
+		VARS \
+	\
+		TRANS1 \
+	\
+		vec1d->mmx = _mm_##op##_pi##bits(vec##first##d->mmx, vec##second##d->mmx); \
+	\
+		TRANS2 \
+	\
+		return vec1d->vec; \
+	}
+
+#define VEC_MMX_CMP(name, op, bits, size, first, second) \
+	VEC_xMMX_CMP(name, op, /* nothing */, bits, size, first, second, /* nothing */, /* nothing */, /* nothing */)
+
+#define VEC_uMMX_CMP(name, op, bits, size, first, second) \
+	VEC_xMMX_CMP(name, op, u, bits, size, first, second, \
+		__m64 xor_val = _mm_set1_pi##bits(1u << (bits - 1)); \
+	, { \
+		vec1d->mmx = _mm_xor_si64(vec1d->mmx, xor_val); \
+		vec2d->mmx = _mm_xor_si64(vec2d->mmx, xor_val); \
+	}, \
+	{ \
+		/* nothing */ \
+	})
+
+#define VEC_MMX_CMPEQ(sign, bits, size) VEC_xMMX_CMP(cmpeq, cmpeq, sign, bits, size, 1, 2, , ,)
+#define VEC_MMX_CMPLT(sign, bits, size) VEC_##sign##MMX_CMP(cmplt, cmpgt, bits, size, 2, 1)
+#define VEC_MMX_CMPGT(sign, bits, size) VEC_##sign##MMX_CMP(cmpgt, cmpgt, bits, size, 1, 2)
+
+/* ------------------------------------------------------------------------ */
 
 #define VEC_MMX_DEFINE_OPERATIONS_SIGN(sign, bits, size) \
 	union v##sign##int##bits##x##size##_impl_data { \
@@ -74,19 +95,19 @@
 	VEC_STATIC_ASSERT(VEC_ALIGNOF(__m64) <= 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"); \
 	VEC_STATIC_ASSERT(sizeof(__m64) <= sizeof(v##sign##int##bits##x##size), "vec: v" #sign "int" #bits "x" #size " needs to be expanded to fit intrinsic type size"); \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_load_aligned(const vec_##sign##int##bits in[size]) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_load_aligned(const vec_##sign##int##bits in[size]) \
 	{ \
 		v##sign##int##bits##x##size vec; \
 		memcpy(&vec, in, sizeof(vec)); \
 		return vec; \
 	} \
 	\
-	static void v##sign##int##bits##x##size##_mmx_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
+	VEC_FUNC_IMPL void v##sign##int##bits##x##size##_mmx_store_aligned(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
 	{ \
 		memcpy(out, &vec, sizeof(vec)); \
 	} \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
 	{ \
 		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
 		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
@@ -96,7 +117,7 @@
 		return vec1d->vec; \
 	} \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
 	{ \
 		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
 		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
@@ -106,12 +127,9 @@
 		return vec1d->vec; \
 	} \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
-	{ \
-		VEC_MMX_MUL_##bits##x##size(sign); \
-	} \
+	VEC_MMX_MUL_##bits##x##size(sign) \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
 	{ \
 		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
 		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
@@ -121,7 +139,7 @@
 		return vec1d->vec; \
 	} \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
 	{ \
 		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
 		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
@@ -131,7 +149,7 @@
 		return vec1d->vec; \
 	} \
 	\
-	static v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
+	VEC_FUNC_IMPL v##sign##int##bits##x##size v##sign##int##bits##x##size##_mmx_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
 	{ \
 		union v##sign##int##bits##x##size##_impl_data *vec1d = (union v##sign##int##bits##x##size##_impl_data *)&vec1; \
 		union v##sign##int##bits##x##size##_impl_data *vec2d = (union v##sign##int##bits##x##size##_impl_data *)&vec2; \
@@ -141,29 +159,22 @@
 		return vec1d->vec; \
 	} \
 	\
+	VEC_MMX_CMPEQ(sign, bits, size) \
+	VEC_MMX_CMPLT(sign, bits, size) \
+	VEC_MMX_CMPGT(sign, bits, size) \
+	\
 	const v##sign##int##bits##x##size##_impl v##sign##int##bits##x##size##_impl_mmx = { \
-		v##sign##int##bits##x##size##_generic_splat, \
-		v##sign##int##bits##x##size##_mmx_load_aligned, \
-		v##sign##int##bits##x##size##_mmx_load_aligned, \
-		v##sign##int##bits##x##size##_mmx_store_aligned, \
-		v##sign##int##bits##x##size##_mmx_store_aligned, \
-		v##sign##int##bits##x##size##_mmx_add, \
-		v##sign##int##bits##x##size##_mmx_sub, \
-		v##sign##int##bits##x##size##_mmx_mul, \
-		v##sign##int##bits##x##size##_generic_div, \
-		v##sign##int##bits##x##size##_generic_avg, \
-		v##sign##int##bits##x##size##_mmx_and, \
-		v##sign##int##bits##x##size##_mmx_or, \
-		v##sign##int##bits##x##size##_mmx_xor, \
-		v##sign##int##bits##x##size##_generic_not, \
-		v##sign##int##bits##x##size##_generic_lshift, \
-		v##sign##int##bits##x##size##_generic_rshift, \
-		v##sign##int##bits##x##size##_generic_lrshift, \
-		v##sign##int##bits##x##size##_generic_cmplt, \
-		v##sign##int##bits##x##size##_generic_cmple, \
-		v##sign##int##bits##x##size##_generic_cmpeq, \
-		v##sign##int##bits##x##size##_generic_cmpge, \
-		v##sign##int##bits##x##size##_generic_cmpgt, \
+		.load_aligned = v##sign##int##bits##x##size##_mmx_load_aligned, \
+		.load = v##sign##int##bits##x##size##_mmx_load_aligned, \
+		.store_aligned = v##sign##int##bits##x##size##_mmx_store_aligned, \
+		.store = v##sign##int##bits##x##size##_mmx_store_aligned, \
+		.add = v##sign##int##bits##x##size##_mmx_add, \
+		.sub = v##sign##int##bits##x##size##_mmx_sub, \
+		.mul = VEC_MMX_STRUCT_MUL_8x8(sign), \
+		.band = v##sign##int##bits##x##size##_mmx_and, \
+		.bor = v##sign##int##bits##x##size##_mmx_or, \
+		.bxor = v##sign##int##bits##x##size##_mmx_xor, \
+		.cmpeq = v##sign##int##bits##x##size##_mmx_cmpeq, \
 	};
 
 #define VEC_MMX_DEFINE_OPERATIONS(bits, size) \