1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "hwy/targets.h"
16 
17 #include "hwy/tests/test_util-inl.h"
18 
19 namespace fake {
20 
21 #define DECLARE_FUNCTION(TGT)                        \
22   namespace N_##TGT {                                \
23     uint32_t FakeFunction(int) { return HWY_##TGT; } \
24   }
25 
26 DECLARE_FUNCTION(AVX3)
27 DECLARE_FUNCTION(AVX2)
28 DECLARE_FUNCTION(SSE4)
29 DECLARE_FUNCTION(NEON)
30 DECLARE_FUNCTION(PPC8)
31 DECLARE_FUNCTION(WASM)
32 DECLARE_FUNCTION(RVV)
33 DECLARE_FUNCTION(SCALAR)
34 
35 HWY_EXPORT(FakeFunction);
36 
CheckFakeFunction()37 void CheckFakeFunction() {
38 #define CHECK_ARRAY_ENTRY(TGT)                                              \
39   if ((HWY_TARGETS & HWY_##TGT) != 0) {                                     \
40     hwy::SetSupportedTargetsForTest(HWY_##TGT);                             \
41     /* Calling Update() first to make &HWY_DYNAMIC_DISPATCH() return */     \
42     /* the pointer to the already cached function. */                       \
43     hwy::chosen_target.Update();                                            \
44     EXPECT_EQ(uint32_t(HWY_##TGT), HWY_DYNAMIC_DISPATCH(FakeFunction)(42)); \
45     /* Calling DeInit() will test that the initializer function */          \
46     /* also calls the right function. */                                    \
47     hwy::chosen_target.DeInit();                                            \
48     EXPECT_EQ(uint32_t(HWY_##TGT), HWY_DYNAMIC_DISPATCH(FakeFunction)(42)); \
49     /* Second call uses the cached value from the previous call. */         \
50     EXPECT_EQ(uint32_t(HWY_##TGT), HWY_DYNAMIC_DISPATCH(FakeFunction)(42)); \
51   }
52   CHECK_ARRAY_ENTRY(AVX3)
53   CHECK_ARRAY_ENTRY(AVX2)
54   CHECK_ARRAY_ENTRY(SSE4)
55   CHECK_ARRAY_ENTRY(NEON)
56   CHECK_ARRAY_ENTRY(PPC8)
57   CHECK_ARRAY_ENTRY(WASM)
58   CHECK_ARRAY_ENTRY(RVV)
59   CHECK_ARRAY_ENTRY(SCALAR)
60 #undef CHECK_ARRAY_ENTRY
61 }
62 
63 }  // namespace fake
64 
65 namespace hwy {
66 
67 class HwyTargetsTest : public testing::Test {
68  protected:
TearDown()69   void TearDown() override {
70     SetSupportedTargetsForTest(0);
71     DisableTargets(0);  // Reset the mask.
72   }
73 };
74 
75 // Test that the order in the HWY_EXPORT static array matches the expected
76 // value of the target bits. This is only checked for the targets that are
77 // enabled in the current compilation.
TEST_F(HwyTargetsTest,ChosenTargetOrderTest)78 TEST_F(HwyTargetsTest, ChosenTargetOrderTest) { fake::CheckFakeFunction(); }
79 
TEST_F(HwyTargetsTest,DisabledTargetsTest)80 TEST_F(HwyTargetsTest, DisabledTargetsTest) {
81   DisableTargets(~0u);
82   // Check that the baseline can't be disabled.
83   HWY_ASSERT(HWY_ENABLED_BASELINE == SupportedTargets());
84 
85   DisableTargets(0);  // Reset the mask.
86   uint32_t current_targets = SupportedTargets();
87   if ((current_targets & ~HWY_ENABLED_BASELINE) == 0) {
88     // We can't test anything else if the only compiled target is the baseline.
89     return;
90   }
91   // Get the lowest bit in the mask (the best target) and disable that one.
92   uint32_t lowest_target = current_targets & (~current_targets + 1);
93   // The lowest target shouldn't be one in the baseline.
94   HWY_ASSERT((lowest_target & ~HWY_ENABLED_BASELINE) != 0);
95   DisableTargets(lowest_target);
96 
97   // Check that the other targets are still enabled.
98   HWY_ASSERT((lowest_target ^ current_targets) == SupportedTargets());
99   DisableTargets(0);  // Reset the mask.
100 }
101 
102 }  // namespace hwy
103