#include "hashtree.h"
#include <assert.h>
#ifdef __x86_64__
#include <cpuid.h>
#endif
#ifdef __aarch64__
#ifndef __APPLE__
#include <sys/auxv.h>
#include <asm/hwcap.h>
#endif
#endif
static void init_and_hash(unsigned char *output, const unsigned char *input, uint64_t count);
static hashtree_hash_fcn hash_ptr = init_and_hash;
static hashtree_hash_fcn hashtree_detect() {
#ifdef __x86_64__
uint32_t a = 0, b = 0, c = 0, d = 0;
__get_cpuid_count(7, 0, &a, &b, &c, &d);
if (b & bit_SHA) {
return &hashtree_sha256_shani_x2;
}
if ((b & bit_AVX512F) && (b & bit_AVX512VL)) {
return &hashtree_sha256_avx512_x16;
}
if (b & bit_AVX2) {
return &hashtree_sha256_avx2_x8;
}
__get_cpuid_count(1, 0, &a, &b, &c, &d);
if (c & bit_AVX) {
return &hashtree_sha256_avx_x4;
}
if (c & bit_AVX) {
return &hashtree_sha256_sse_x1;
}
return (hashtree_hash_fcn)0;
#endif
#ifdef __aarch64__
#ifdef __APPLE__
return &hashtree_sha256_sha_x1;
#else
long hwcaps = getauxval(AT_HWCAP);
if (hwcaps & HWCAP_SHA2) {
return &hashtree_sha256_sha_x1;
}
if (hwcaps & HWCAP_ASIMD) {
return &hashtree_sha256_neon_x4;
}
return (hashtree_hash_fcn)0;
#endif
#endif
}
int hashtree_init(hashtree_hash_fcn override) {
if (override) {
hash_ptr = override;
} else {
hash_ptr = hashtree_detect();
}
return !!hash_ptr;
}
void hashtree_hash(unsigned char *output, const unsigned char *input, uint64_t count) {
(*hash_ptr)(output, input, count);
}
static void init_and_hash(unsigned char *output, const unsigned char *input, uint64_t count) {
hash_ptr = hashtree_detect();
assert(hash_ptr);
hashtree_hash(output, input, count);
}