packages feed

reedsolomon-0.0.1.0: cbits/reedsolomon_dispatch.c

#include <stddef.h>
#include <cpuid.h>

#include "config.h"
#include "reedsolomon.h"

#ifndef bit_AVX2
# define bit_AVX2       (1 << 5)
#endif

#define unlikely(x)     __builtin_expect(!!(x), 0)

#define LOG(s)                          \
        do {                            \
                access(s, F_OK);        \
        } while(0)

#if HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE
# define ALWAYS_INLINE __attribute__((always_inline))
#else
# define ALWAYS_INLINE
#endif

static inline ALWAYS_INLINE int __get_cpuid_count(
        const unsigned int level,
        const unsigned int count,
        unsigned int *eax,
        unsigned int *ebx,
        unsigned int *ecx,
        unsigned int *edx) {
        unsigned int ext = level & 0x80000000;

        if((unsigned int)__get_cpuid_max(ext, 0) < level) {
                return 0;
        }

        __cpuid_count(level, count, *eax, *ebx, *ecx, *edx);
        return 1;
}

#if RS_HAVE_AVX2
# define IFUNC_AVX2(n, result)                                                                          \
        do {                                                                                            \
                int avx2_rc = 0;                                                                        \
                struct {                                                                                \
                        unsigned int eax, ebx, ecx, edx;                                                \
                } cpuid7 = { 0, 0, 0, 0 };                                                              \
                                                                                                        \
                avx2_rc = __get_cpuid_count(7, 0, &cpuid7.eax, &cpuid7.ebx, &cpuid7.ecx, &cpuid7.edx);  \
                                                                                                        \
                if(avx2_rc != 0 && (cpuid7.ebx & bit_AVX2) != 0) {                                      \
                        LOG("reedsolomon: using " #n "_avx2");                                          \
                        result = n ## _avx2;                                                            \
                }                                                                                       \
        } while(0)
#else
# define IFUNC_AVX2(n, result)
#endif

#define IFUNC(n, proto)                                                                         \
        static proto n ## _ifunc(void) {                                                        \
                struct {                                                                        \
                        unsigned int eax, ebx, ecx, edx;                                        \
                } cpuid1 = { 0, 0, 0, 0 };                                                      \
                int rc = 0;                                                                     \
                proto func = NULL;                                                              \
                                                                                                \
                rc = __get_cpuid(1, &cpuid1.eax, &cpuid1.ebx, &cpuid1.ecx, &cpuid1.edx);        \
                if(rc == 0) {                                                                   \
                        LOG("reedsolomon: cpuid failed, using " #n "_generic");                 \
                        func = n ## _generic;                                                   \
                }                                                                               \
                else {                                                                          \
                        IFUNC_AVX2(n, func);                                                    \
                        if(func == NULL) {                                                      \
                                if((cpuid1.ecx & bit_SSSE3) != 0) {                             \
                                        LOG("reedsolomon: using " #n "_ssse3");                 \
                                        func = n ## _ssse3;                                     \
                                }                                                               \
                                else if((cpuid1.edx & bit_SSE2) != 0) {                         \
                                        LOG("reedsolomon: using " #n "_sse2");                  \
                                        func = n ## _sse2;                                      \
                                }                                                               \
                                else {                                                          \
                                        LOG("reedsolomon: using " #n "_generic");               \
                                        func = n ## _generic;                                   \
                                }                                                               \
                        }                                                                       \
                }                                                                               \
                                                                                                \
                return func;                                                                    \
        }

typedef PROTO_RETURN(*gal_mul_proto)(PROTO_ARGS);
typedef PROTO_RETURN(*gal_mul_xor_proto)(PROTO_ARGS);

IFUNC(reedsolomon_gal_mul, gal_mul_proto)
IFUNC(reedsolomon_gal_mul_xor, gal_mul_xor_proto)

#ifdef HAVE_FUNC_ATTRIBUTE_IFUNC
PROTO(reedsolomon_gal_mul)
        __attribute__((ifunc("reedsolomon_gal_mul_ifunc")));

PROTO(reedsolomon_gal_mul_xor)
        __attribute__((ifunc("reedsolomon_gal_mul_xor_ifunc")));
#else
PROTO(reedsolomon_gal_mul) {
        static gal_mul_proto impl = NULL;

        if(unlikely(impl == NULL)) {
                impl = reedsolomon_gal_mul_ifunc();
        }

        return impl(low, high, in, out, len);
}

PROTO(reedsolomon_gal_mul_xor) {
        static gal_mul_xor_proto impl = NULL;

        if(unlikely(impl == NULL)) {
                impl = reedsolomon_gal_mul_xor_ifunc();
        }

        return impl(low, high, in, out, len);
}
#endif