tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

targets_test.cc (6760B)


      1 // Copyright 2020 Google LLC
      2 // SPDX-License-Identifier: Apache-2.0
      3 //
      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
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     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.
     15 
     16 #include "hwy/targets.h"
     17 
     18 #include <stdint.h>
     19 
     20 #include "hwy/detect_targets.h"
     21 #include "hwy/tests/hwy_gtest.h"
     22 #include "hwy/tests/test_util-inl.h"
     23 
     24 // Simulate another project having its own namespace.
     25 namespace fake {
     26 namespace {
     27 
     28 #define DECLARE_FUNCTION(TGT)                                                \
     29  namespace N_##TGT {                                                        \
     30    /* Function argument is just to ensure/demonstrate they are possible. */ \
     31    HWY_MAYBE_UNUSED int64_t FakeFunction(int) { return HWY_##TGT; }         \
     32    template <typename T>                                                    \
     33    int64_t FakeFunctionT(T) {                                               \
     34      return HWY_##TGT;                                                      \
     35    }                                                                        \
     36  }
     37 
     38 DECLARE_FUNCTION(AVX10_2)
     39 DECLARE_FUNCTION(AVX3_SPR)
     40 DECLARE_FUNCTION(AVX3_ZEN4)
     41 DECLARE_FUNCTION(AVX3_DL)
     42 DECLARE_FUNCTION(AVX3)
     43 DECLARE_FUNCTION(AVX2)
     44 DECLARE_FUNCTION(SSE4)
     45 DECLARE_FUNCTION(SSSE3)
     46 DECLARE_FUNCTION(SSE2)
     47 
     48 DECLARE_FUNCTION(SVE2_128)
     49 DECLARE_FUNCTION(SVE_256)
     50 DECLARE_FUNCTION(SVE2)
     51 DECLARE_FUNCTION(SVE)
     52 DECLARE_FUNCTION(NEON_BF16)
     53 DECLARE_FUNCTION(NEON)
     54 DECLARE_FUNCTION(NEON_WITHOUT_AES)
     55 
     56 DECLARE_FUNCTION(PPC10)
     57 DECLARE_FUNCTION(PPC9)
     58 DECLARE_FUNCTION(PPC8)
     59 
     60 DECLARE_FUNCTION(Z15)
     61 DECLARE_FUNCTION(Z14)
     62 
     63 DECLARE_FUNCTION(WASM)
     64 DECLARE_FUNCTION(WASM_EMU256)
     65 
     66 DECLARE_FUNCTION(RVV)
     67 
     68 DECLARE_FUNCTION(LASX)
     69 DECLARE_FUNCTION(LSX)
     70 
     71 DECLARE_FUNCTION(SCALAR)
     72 DECLARE_FUNCTION(EMU128)
     73 
     74 HWY_EXPORT(FakeFunction);
     75 
     76 template <typename T>
     77 int64_t FakeFunctionDispatcher(T value) {
     78  // Note that when calling templated code on arbitrary types, the dispatch
     79  // table must be defined inside another template function.
     80  HWY_EXPORT_T(FakeFunction1, FakeFunctionT<T>);
     81  HWY_EXPORT_T(FakeFunction2, FakeFunctionT<bool>);
     82  // Verify two EXPORT_T within a function are possible.
     83  return hwy::AddWithWraparound(HWY_DYNAMIC_DISPATCH_T(FakeFunction1)(value),
     84                                HWY_DYNAMIC_DISPATCH_T(FakeFunction2)(true));
     85 }
     86 
     87 void CallFunctionForTarget(int64_t target, int /*line*/) {
     88  if ((HWY_TARGETS & target) == 0) return;
     89  hwy::SetSupportedTargetsForTest(target);
     90 
     91  // Call Update() first to make &HWY_DYNAMIC_DISPATCH() return
     92  // the pointer to the already cached function.
     93  hwy::GetChosenTarget().Update(hwy::SupportedTargets());
     94 
     95  HWY_ASSERT_EQ(target, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
     96 
     97  // * 2 because we call two functions and add their target result together.
     98  const int64_t target_times_2 =
     99      static_cast<int64_t>(static_cast<uint64_t>(target) * 2ULL);
    100  HWY_ASSERT_EQ(target_times_2, FakeFunctionDispatcher<float>(1.0f));
    101  HWY_ASSERT_EQ(target_times_2, FakeFunctionDispatcher<double>(1.0));
    102 
    103  // Calling DeInit() will test that the initializer function
    104  // also calls the right function.
    105  hwy::GetChosenTarget().DeInit();
    106 
    107  const int64_t expected = target;
    108  HWY_ASSERT_EQ(expected, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
    109 
    110  // Second call uses the cached value from the previous call.
    111  HWY_ASSERT_EQ(target, HWY_DYNAMIC_DISPATCH(FakeFunction)(42));
    112 }
    113 
    114 void CheckFakeFunction() {
    115  // When adding a target, also add to DECLARE_FUNCTION above.
    116  CallFunctionForTarget(HWY_AVX3_SPR, __LINE__);
    117  CallFunctionForTarget(HWY_AVX3_ZEN4, __LINE__);
    118  CallFunctionForTarget(HWY_AVX3_DL, __LINE__);
    119  CallFunctionForTarget(HWY_AVX3, __LINE__);
    120  CallFunctionForTarget(HWY_AVX2, __LINE__);
    121  CallFunctionForTarget(HWY_SSE4, __LINE__);
    122  CallFunctionForTarget(HWY_SSSE3, __LINE__);
    123  CallFunctionForTarget(HWY_SSE2, __LINE__);
    124 
    125  CallFunctionForTarget(HWY_SVE2_128, __LINE__);
    126  CallFunctionForTarget(HWY_SVE_256, __LINE__);
    127  CallFunctionForTarget(HWY_SVE2, __LINE__);
    128  CallFunctionForTarget(HWY_SVE, __LINE__);
    129  CallFunctionForTarget(HWY_NEON_BF16, __LINE__);
    130  CallFunctionForTarget(HWY_NEON, __LINE__);
    131  CallFunctionForTarget(HWY_NEON_WITHOUT_AES, __LINE__);
    132 
    133  CallFunctionForTarget(HWY_PPC10, __LINE__);
    134  CallFunctionForTarget(HWY_PPC9, __LINE__);
    135  CallFunctionForTarget(HWY_PPC8, __LINE__);
    136 
    137  CallFunctionForTarget(HWY_WASM, __LINE__);
    138  CallFunctionForTarget(HWY_WASM_EMU256, __LINE__);
    139 
    140  CallFunctionForTarget(HWY_RVV, __LINE__);
    141 
    142  CallFunctionForTarget(HWY_LASX, __LINE__);
    143  CallFunctionForTarget(HWY_LSX, __LINE__);
    144 
    145  // The tables only have space for either HWY_SCALAR or HWY_EMU128; the former
    146  // is opt-in only.
    147 #if defined(HWY_COMPILE_ONLY_SCALAR) || HWY_BROKEN_EMU128
    148  CallFunctionForTarget(HWY_SCALAR, __LINE__);
    149 #else
    150  CallFunctionForTarget(HWY_EMU128, __LINE__);
    151 #endif
    152 }
    153 
    154 }  // namespace
    155 }  // namespace fake
    156 
    157 namespace hwy {
    158 namespace {
    159 
    160 #if !HWY_TEST_STANDALONE
    161 class HwyTargetsTest : public testing::Test {};
    162 #endif
    163 
    164 // Test that the order in the HWY_EXPORT static array matches the expected
    165 // value of the target bits. This is only checked for the targets that are
    166 // enabled in the current compilation.
    167 TEST(HwyTargetsTest, ChosenTargetOrderTest) { fake::CheckFakeFunction(); }
    168 
    169 TEST(HwyTargetsTest, DisabledTargetsTest) {
    170  SetSupportedTargetsForTest(0);
    171  DisableTargets(~0LL);
    172  // Check that disabling everything at least leaves the static target.
    173  HWY_ASSERT(HWY_STATIC_TARGET == SupportedTargets());
    174 
    175  DisableTargets(0);  // Reset the mask.
    176  const int64_t current_targets = SupportedTargets();
    177  const int64_t enabled_baseline = static_cast<int64_t>(HWY_ENABLED_BASELINE);
    178  // Exclude these two because they are always returned by SupportedTargets.
    179  const int64_t fallback = HWY_SCALAR | HWY_EMU128;
    180  if ((current_targets & ~enabled_baseline & ~fallback) == 0) {
    181    // We can't test anything else if the only compiled target is the baseline.
    182    return;
    183  }
    184 
    185  // Get the lowest bit in the mask (the best target) and disable that one.
    186  const int64_t best_target = current_targets & (~current_targets + 1);
    187  DisableTargets(best_target);
    188 
    189  // Check that the other targets are still enabled.
    190  HWY_ASSERT((best_target ^ current_targets) == SupportedTargets());
    191  DisableTargets(0);  // Reset the mask.
    192 }
    193 
    194 }  // namespace
    195 }  // namespace hwy
    196 
    197 HWY_TEST_MAIN();