view src/impl/fallback.c @ 25:92156fe32755

impl/ppc/altivec: update to new implementation the signed average function is wrong; it needs to round up the number when only one of them is odd, but that doesn't necessarily seem to be true because altivec is weird, and that's what we need to emulate the quirks for. ugh. also the altivec backend uses the generic functions instead of fallbacks because it does indeed use the exact same memory structure as the generic implementation...
author Paper <paper@tflc.us>
date Sun, 24 Nov 2024 11:15:59 +0000
parents e49e70f7012f
children
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). This is likely true for AltiVec and NEON as well, but those
// aren't tested for now.

#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(vec_##sign##avg(varr1[i], varr2[i]), 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