1 // Copyright 2020 Google LLC
2 // SPDX-License-Identifier: Apache-2.0
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
16 #include "hwy/targets.h"
18 #include "hwy/detect_targets.h"
19 #include "hwy/tests/test_util-inl.h"
23 #define DECLARE_FUNCTION(TGT) \
25 /* Function argument is just to ensure/demonstrate they are possible. */ \
26 int64_t FakeFunction(int) { return HWY_##TGT; } \
29 DECLARE_FUNCTION(AVX3_SPR
)
30 DECLARE_FUNCTION(AVX3_ZEN4
)
31 DECLARE_FUNCTION(AVX3_DL
)
32 DECLARE_FUNCTION(AVX3
)
33 DECLARE_FUNCTION(AVX2
)
34 DECLARE_FUNCTION(SSE4
)
35 DECLARE_FUNCTION(SSSE3
)
36 DECLARE_FUNCTION(SSE2
)
38 DECLARE_FUNCTION(SVE2_128
)
39 DECLARE_FUNCTION(SVE_256
)
40 DECLARE_FUNCTION(SVE2
)
42 DECLARE_FUNCTION(NEON
)
43 DECLARE_FUNCTION(NEON_WITHOUT_AES
)
45 DECLARE_FUNCTION(PPC10
)
46 DECLARE_FUNCTION(PPC9
)
47 DECLARE_FUNCTION(PPC8
)
52 DECLARE_FUNCTION(WASM
)
53 DECLARE_FUNCTION(WASM_EMU256
)
57 DECLARE_FUNCTION(SCALAR
)
58 DECLARE_FUNCTION(EMU128
)
60 HWY_EXPORT(FakeFunction
);
62 void CallFunctionForTarget(int64_t target
, int line
) {
63 if ((HWY_TARGETS
& target
) == 0) return;
64 hwy::SetSupportedTargetsForTest(target
);
66 // Call Update() first to make &HWY_DYNAMIC_DISPATCH() return
67 // the pointer to the already cached function.
68 hwy::GetChosenTarget().Update(hwy::SupportedTargets());
70 EXPECT_EQ(target
, HWY_DYNAMIC_DISPATCH(FakeFunction
)(42)) << line
;
72 // Calling DeInit() will test that the initializer function
73 // also calls the right function.
74 hwy::GetChosenTarget().DeInit();
76 #if HWY_DISPATCH_WORKAROUND
77 EXPECT_EQ(HWY_STATIC_TARGET
, HWY_DYNAMIC_DISPATCH(FakeFunction
)(42)) << line
;
79 EXPECT_EQ(target
, HWY_DYNAMIC_DISPATCH(FakeFunction
)(42)) << line
;
82 // Second call uses the cached value from the previous call.
83 EXPECT_EQ(target
, HWY_DYNAMIC_DISPATCH(FakeFunction
)(42)) << line
;
86 void CheckFakeFunction() {
87 // When adding a target, also add to DECLARE_FUNCTION above.
88 CallFunctionForTarget(HWY_AVX3_SPR
, __LINE__
);
89 CallFunctionForTarget(HWY_AVX3_ZEN4
, __LINE__
);
90 CallFunctionForTarget(HWY_AVX3_DL
, __LINE__
);
91 CallFunctionForTarget(HWY_AVX3
, __LINE__
);
92 CallFunctionForTarget(HWY_AVX2
, __LINE__
);
93 CallFunctionForTarget(HWY_SSE4
, __LINE__
);
94 CallFunctionForTarget(HWY_SSSE3
, __LINE__
);
95 CallFunctionForTarget(HWY_SSE2
, __LINE__
);
97 CallFunctionForTarget(HWY_SVE2_128
, __LINE__
);
98 CallFunctionForTarget(HWY_SVE_256
, __LINE__
);
99 CallFunctionForTarget(HWY_SVE2
, __LINE__
);
100 CallFunctionForTarget(HWY_SVE
, __LINE__
);
101 CallFunctionForTarget(HWY_NEON
, __LINE__
);
102 CallFunctionForTarget(HWY_NEON_WITHOUT_AES
, __LINE__
);
104 CallFunctionForTarget(HWY_PPC10
, __LINE__
);
105 CallFunctionForTarget(HWY_PPC9
, __LINE__
);
106 CallFunctionForTarget(HWY_PPC8
, __LINE__
);
108 CallFunctionForTarget(HWY_WASM
, __LINE__
);
109 CallFunctionForTarget(HWY_WASM_EMU256
, __LINE__
);
111 CallFunctionForTarget(HWY_RVV
, __LINE__
);
112 // The tables only have space for either HWY_SCALAR or HWY_EMU128; the former
114 #if defined(HWY_COMPILE_ONLY_SCALAR) || HWY_BROKEN_EMU128
115 CallFunctionForTarget(HWY_SCALAR
, __LINE__
);
117 CallFunctionForTarget(HWY_EMU128
, __LINE__
);
125 class HwyTargetsTest
: public testing::Test
{
127 void TearDown() override
{
128 SetSupportedTargetsForTest(0);
129 DisableTargets(0); // Reset the mask.
133 // Test that the order in the HWY_EXPORT static array matches the expected
134 // value of the target bits. This is only checked for the targets that are
135 // enabled in the current compilation.
136 TEST_F(HwyTargetsTest
, ChosenTargetOrderTest
) { fake::CheckFakeFunction(); }
138 TEST_F(HwyTargetsTest
, DisabledTargetsTest
) {
139 DisableTargets(~0LL);
140 // Check that disabling everything at least leaves the static target.
141 HWY_ASSERT(HWY_STATIC_TARGET
== SupportedTargets());
143 DisableTargets(0); // Reset the mask.
144 const int64_t current_targets
= SupportedTargets();
145 const int64_t enabled_baseline
= static_cast<int64_t>(HWY_ENABLED_BASELINE
);
146 // Exclude these two because they are always returned by SupportedTargets.
147 const int64_t fallback
= HWY_SCALAR
| HWY_EMU128
;
148 if ((current_targets
& ~enabled_baseline
& ~fallback
) == 0) {
149 // We can't test anything else if the only compiled target is the baseline.
153 // Get the lowest bit in the mask (the best target) and disable that one.
154 const int64_t best_target
= current_targets
& (~current_targets
+ 1);
155 DisableTargets(best_target
);
157 // Check that the other targets are still enabled.
158 HWY_ASSERT((best_target
^ current_targets
) == SupportedTargets());
159 DisableTargets(0); // Reset the mask.