view src/impl/fallback.c @ 23:e26874655738

*: huge refactor, new major release (hahaha) I keep finding things that are broken... The problem NOW was that vec would unintentionally build some functions with extended instruction sets, which is Bad and would mean that for all intents and purposes the CPU detection was completely broken. Now vec is no longer header only either. Boohoo. However this gives a lot more flexibility to vec since we no longer want or need to care about C++ crap. The NEON and Altivec implementations have not been updated which means they won't compile hence why they're commented out in the cmake build file.
author Paper <paper@tflc.us>
date Sun, 24 Nov 2024 02:52:40 -0500
parents
children e49e70f7012f
line wrap: on
line source

#include "vec/impl/fallback.h"

#include <string.h>

// Fallback implementations - this is what an implementation should use if it
// doesn't support a specific function *and* the actual representation in
// memory is unknown or yields incorrect results from the generic functions.
// This is *extremely* unlikely; for x86 the layout is exactly the same in
// memory as the generic functions (i.e. it is literally stored as an array of
// integers).
//
// These functions can probably be removed if every current implementation is
// found to have the same 

#define VEC_FALLBACK_OPERATION(op, sign, csign, bits, size) \
	do { \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr1); \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr2); \
	\
		v##sign##int##bits##x##size##_store_aligned(vec1, varr1); \
		v##sign##int##bits##x##size##_store_aligned(vec2, varr2); \
	\
		for (int i = 0; i < size; i++) varr1[i] = (op); \
	\
		return v##sign##int##bits##x##size##_load_aligned(varr1); \
	} while (0)

#define VEC_FALLBACK_CMP(op, sign, csign, bits, size) \
	VEC_FALLBACK_OPERATION((varr1[i] op varr2[i]) ? VEC_UINT##bits##_MAX : 0, sign, csign, bits, size)

#define VEC_FALLBACK_SHIFT(op, sign, csign, bits, size) \
	do { \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(varr1); \
		VUINT##bits##x##size##_ALIGNED_ARRAY(varr2); \
	\
		v##sign##int##bits##x##size##_store_aligned(vec1, varr1); \
		vuint##bits##x##size##_store_aligned(vec2, varr2); \
	\
		for (int i = 0; i < size; i++) varr1[i] = (op); \
	\
		return v##sign##int##bits##x##size##_load_aligned(varr1); \
	} while (0)

#define VEC_DEFINE_FALLBACK_OPERATIONS_SIGN(sign, csign, bits, size) \
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_splat(vec_##sign##int##bits x) \
	{ \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
		for (int i = 0; i < size; i++) arr[i] = x; \
		return v##sign##int##bits##x##size##_load_aligned(arr); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_load(const vec_##sign##int##bits in[size]) \
	{ \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
		memcpy(arr, in, sizeof(vec_##sign##int##bits) * size); \
		return v##sign##int##bits##x##size##_load_aligned(arr); \
	} \
	\
	void v##sign##int##bits##x##size##_fallback_store(v##sign##int##bits##x##size vec, vec_##sign##int##bits out[size]) \
	{ \
		V##csign##INT##bits##x##size##_ALIGNED_ARRAY(arr); \
		v##sign##int##bits##x##size##_store_aligned(vec, arr); \
		memcpy(out, arr, sizeof(vec_##sign##int##bits) * size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_add(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] + varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_sub(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] - varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_mul(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] * varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_div(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr2[i] ? (varr1[i] / varr2[i]) : 0, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_avg(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION((varr1[i] + varr2[i] + 1) / 2, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_and(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] & varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_or(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] | varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_xor(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_OPERATION(varr1[i] ^ varr2[i], sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_not(v##sign##int##bits##x##size vec) \
	{ \
		return v##sign##int##bits##x##size##_xor(vec, v##sign##int##bits##x##size##_splat((vec_##sign##int##bits)VEC_UINT##bits##_MAX)); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmplt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_CMP(<, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmple(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_CMP(<=, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpeq(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_CMP(==, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpge(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_CMP(>=, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_cmpgt(v##sign##int##bits##x##size vec1, v##sign##int##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_CMP(>, sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_lshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_SHIFT(vec_##sign##lshift(varr1[i], varr2[i]), sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_rshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_SHIFT(vec_##sign##rshift(varr1[i], varr2[i]), sign, csign, bits, size); \
	} \
	\
	v##sign##int##bits##x##size v##sign##int##bits##x##size##_fallback_lrshift(v##sign##int##bits##x##size vec1, vuint##bits##x##size vec2) \
	{ \
		VEC_FALLBACK_SHIFT(vec_lrshift((vec_uint##bits)varr1[i], varr2[i]), sign, csign, bits, size); \
	}

#define VEC_DEFINE_FALLBACK_OPERATIONS(bits, size) \
	VEC_DEFINE_FALLBACK_OPERATIONS_SIGN( ,  , bits, size) \
	VEC_DEFINE_FALLBACK_OPERATIONS_SIGN(u, U, bits, size)

// 16-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 2)

// 32-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 4)
VEC_DEFINE_FALLBACK_OPERATIONS(16, 2)

// 64-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 8)
VEC_DEFINE_FALLBACK_OPERATIONS(16, 4)
VEC_DEFINE_FALLBACK_OPERATIONS(32, 2)

// 128-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 16)
VEC_DEFINE_FALLBACK_OPERATIONS(16, 8)
VEC_DEFINE_FALLBACK_OPERATIONS(32, 4)
VEC_DEFINE_FALLBACK_OPERATIONS(64, 2)

// 256-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 32)
VEC_DEFINE_FALLBACK_OPERATIONS(16, 16)
VEC_DEFINE_FALLBACK_OPERATIONS(32, 8)
VEC_DEFINE_FALLBACK_OPERATIONS(64, 4)

// 512-bit
VEC_DEFINE_FALLBACK_OPERATIONS(8, 64)
VEC_DEFINE_FALLBACK_OPERATIONS(16, 32)
VEC_DEFINE_FALLBACK_OPERATIONS(32, 16)
VEC_DEFINE_FALLBACK_OPERATIONS(64, 8)

#undef VEC_FALLBACK_OPERATION
#undef VEC_FALLBACK_CMP
#undef VEC_FALLBACK_SHIFT
#undef VEC_DEFINE_FALLBACK_OPERATIONS
#undef VEC_DEFINE_FALLBACK_OPERATIONS_SIGN