util/bufferiszero: Simplify test_buffer_is_zero_next_accel

Because the three alternatives are monotonic, we don't need
to keep a couple of bitmasks, just identify the strongest
alternative at startup.

Generalize test_buffer_is_zero_next_accel and init_accel
by always defining an accel_table array.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-02-14 21:10:56 -10:00
parent 0100ce2b49
commit bf67aa3dd2

View File

@ -27,7 +27,6 @@
#include "host/cpuinfo.h" #include "host/cpuinfo.h"
typedef bool (*biz_accel_fn)(const void *, size_t); typedef bool (*biz_accel_fn)(const void *, size_t);
static biz_accel_fn buffer_is_zero_accel;
static bool buffer_is_zero_int_lt256(const void *buf, size_t len) static bool buffer_is_zero_int_lt256(const void *buf, size_t len)
{ {
@ -179,60 +178,35 @@ buffer_zero_avx2(const void *buf, size_t len)
} }
#endif /* CONFIG_AVX2_OPT */ #endif /* CONFIG_AVX2_OPT */
static unsigned __attribute__((noinline)) static biz_accel_fn const accel_table[] = {
select_accel_cpuinfo(unsigned info) buffer_is_zero_int_ge256,
{ buffer_zero_sse2,
/* Array is sorted in order of algorithm preference. */
static const struct {
unsigned bit;
biz_accel_fn fn;
} all[] = {
#ifdef CONFIG_AVX2_OPT #ifdef CONFIG_AVX2_OPT
{ CPUINFO_AVX2, buffer_zero_avx2 }, buffer_zero_avx2,
#endif #endif
{ CPUINFO_SSE2, buffer_zero_sse2 }, };
{ CPUINFO_ALWAYS, buffer_is_zero_int_ge256 },
};
for (unsigned i = 0; i < ARRAY_SIZE(all); ++i) { static unsigned best_accel(void)
if (info & all[i].bit) { {
buffer_is_zero_accel = all[i].fn; unsigned info = cpuinfo_init();
return all[i].bit;
} #ifdef CONFIG_AVX2_OPT
if (info & CPUINFO_AVX2) {
return 2;
} }
return 0; #endif
return info & CPUINFO_SSE2 ? 1 : 0;
} }
static unsigned used_accel;
static void __attribute__((constructor)) init_accel(void)
{
used_accel = select_accel_cpuinfo(cpuinfo_init());
}
#define INIT_ACCEL NULL
bool test_buffer_is_zero_next_accel(void)
{
/*
* Accumulate the accelerators that we've already tested, and
* remove them from the set to test this round. We'll get back
* a zero from select_accel_cpuinfo when there are no more.
*/
unsigned used = select_accel_cpuinfo(cpuinfo & ~used_accel);
used_accel |= used;
return used;
}
#else #else
bool test_buffer_is_zero_next_accel(void) #define best_accel() 0
{ static biz_accel_fn const accel_table[1] = {
return false; buffer_is_zero_int_ge256
} };
#define INIT_ACCEL buffer_is_zero_int_ge256
#endif #endif
static biz_accel_fn buffer_is_zero_accel = INIT_ACCEL; static biz_accel_fn buffer_is_zero_accel;
static unsigned accel_index;
bool buffer_is_zero_ool(const void *buf, size_t len) bool buffer_is_zero_ool(const void *buf, size_t len)
{ {
@ -257,3 +231,18 @@ bool buffer_is_zero_ge256(const void *buf, size_t len)
{ {
return buffer_is_zero_accel(buf, len); return buffer_is_zero_accel(buf, len);
} }
bool test_buffer_is_zero_next_accel(void)
{
if (accel_index != 0) {
buffer_is_zero_accel = accel_table[--accel_index];
return true;
}
return false;
}
static void __attribute__((constructor)) init_accel(void)
{
accel_index = best_accel();
buffer_is_zero_accel = accel_table[accel_index];
}