#include "hwy/targets.h"
#include <stdint.h>
#include "hwy/detect_targets.h"
#include "hwy/tests/hwy_gtest.h"
#include "hwy/tests/test_util-inl.h"
namespace fake {
namespace {
#define DECLARE_FUNCTION(TGT) \
namespace N_##TGT { \
\
HWY_MAYBE_UNUSED int64_t FakeFunction(int) { return HWY_##TGT; } \
template <typename T> \
int64_t FakeFunctionT(T) { \
return HWY_##TGT; \
} \
}
DECLARE_FUNCTION(AVX10_2)
DECLARE_FUNCTION(AVX3_SPR)
DECLARE_FUNCTION(AVX3_ZEN4)
DECLARE_FUNCTION(AVX3_DL)
DECLARE_FUNCTION(AVX3)
DECLARE_FUNCTION(AVX2)
DECLARE_FUNCTION(SSE4)
DECLARE_FUNCTION(SSSE3)
DECLARE_FUNCTION(SSE2)
DECLARE_FUNCTION(SVE2_128)
DECLARE_FUNCTION(SVE_256)
DECLARE_FUNCTION(SVE2)
DECLARE_FUNCTION(SVE)
DECLARE_FUNCTION(NEON_BF16)
DECLARE_FUNCTION(NEON)
DECLARE_FUNCTION(NEON_WITHOUT_AES)
DECLARE_FUNCTION(PPC10)
DECLARE_FUNCTION(PPC9)
DECLARE_FUNCTION(PPC8)
DECLARE_FUNCTION(Z15)
DECLARE_FUNCTION(Z14)
DECLARE_FUNCTION(WASM)
DECLARE_FUNCTION(WASM_EMU256)
DECLARE_FUNCTION(RVV)
DECLARE_FUNCTION(LASX)
DECLARE_FUNCTION(LSX)
DECLARE_FUNCTION(SCALAR)
DECLARE_FUNCTION(EMU128)
HWY_EXPORT(FakeFunction);
template <typename T>
int64_t FakeFunctionDispatcher(T value) {
HWY_EXPORT_T(FakeFunction1, FakeFunctionT<T>);
HWY_EXPORT_T(FakeFunction2, FakeFunctionT<bool>);
return hwy::AddWithWraparound(HWY_DYNAMIC_DISPATCH_T(FakeFunction1)(value),
HWY_DYNAMIC_DISPATCH_T(FakeFunction2)(true));
}
void CallFunctionForTarget(int64_t target, int ) {
if ((HWY_TARGETS & target) == 0) return;
hwy::SetSupportedTargetsForTest(target);
hwy::GetChosenTarget().Update(hwy::SupportedTargets());
HWY_ASSERT_EQ(target, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
const int64_t target_times_2 =
static_cast<int64_t>(static_cast<uint64_t>(target) * 2ULL);
HWY_ASSERT_EQ(target_times_2, FakeFunctionDispatcher<float>(1.0f));
HWY_ASSERT_EQ(target_times_2, FakeFunctionDispatcher<double>(1.0));
hwy::GetChosenTarget().DeInit();
const int64_t expected = target;
HWY_ASSERT_EQ(expected, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
HWY_ASSERT_EQ(target, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
}
void CheckFakeFunction() {
CallFunctionForTarget(HWY_AVX3_SPR, __LINE__);
CallFunctionForTarget(HWY_AVX3_ZEN4, __LINE__);
CallFunctionForTarget(HWY_AVX3_DL, __LINE__);
CallFunctionForTarget(HWY_AVX3, __LINE__);
CallFunctionForTarget(HWY_AVX2, __LINE__);
CallFunctionForTarget(HWY_SSE4, __LINE__);
CallFunctionForTarget(HWY_SSSE3, __LINE__);
CallFunctionForTarget(HWY_SSE2, __LINE__);
CallFunctionForTarget(HWY_SVE2_128, __LINE__);
CallFunctionForTarget(HWY_SVE_256, __LINE__);
CallFunctionForTarget(HWY_SVE2, __LINE__);
CallFunctionForTarget(HWY_SVE, __LINE__);
CallFunctionForTarget(HWY_NEON_BF16, __LINE__);
CallFunctionForTarget(HWY_NEON, __LINE__);
CallFunctionForTarget(HWY_NEON_WITHOUT_AES, __LINE__);
CallFunctionForTarget(HWY_PPC10, __LINE__);
CallFunctionForTarget(HWY_PPC9, __LINE__);
CallFunctionForTarget(HWY_PPC8, __LINE__);
CallFunctionForTarget(HWY_WASM, __LINE__);
CallFunctionForTarget(HWY_WASM_EMU256, __LINE__);
CallFunctionForTarget(HWY_RVV, __LINE__);
CallFunctionForTarget(HWY_LASX, __LINE__);
CallFunctionForTarget(HWY_LSX, __LINE__);
#if defined(HWY_COMPILE_ONLY_SCALAR) || HWY_BROKEN_EMU128
CallFunctionForTarget(HWY_SCALAR, __LINE__);
#else
CallFunctionForTarget(HWY_EMU128, __LINE__);
#endif
}
} }
namespace hwy {
namespace {
#if !HWY_TEST_STANDALONE
class HwyTargetsTest : public testing::Test {};
#endif
TEST(HwyTargetsTest, ChosenTargetOrderTest) { fake::CheckFakeFunction(); }
TEST(HwyTargetsTest, DisabledTargetsTest) {
SetSupportedTargetsForTest(0);
DisableTargets(~0LL);
HWY_ASSERT(HWY_STATIC_TARGET == SupportedTargets());
DisableTargets(0); const int64_t current_targets = SupportedTargets();
const int64_t enabled_baseline = static_cast<int64_t>(HWY_ENABLED_BASELINE);
const int64_t fallback = HWY_SCALAR | HWY_EMU128;
if ((current_targets & ~enabled_baseline & ~fallback) == 0) {
return;
}
const int64_t best_target = current_targets & (~current_targets + 1);
DisableTargets(best_target);
HWY_ASSERT((best_target ^ current_targets) == SupportedTargets());
DisableTargets(0); }
} }
HWY_TEST_MAIN();