Coverage Report

Created: 2025-11-24 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/highwayhash/highwayhash/instruction_sets.h
Line
Count
Source
1
// Copyright 2017 Google Inc. All Rights Reserved.
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
#ifndef HIGHWAYHASH_INSTRUCTION_SETS_H_
16
#define HIGHWAYHASH_INSTRUCTION_SETS_H_
17
18
// Calls the best specialization of a template supported by the current CPU.
19
//
20
// Usage: for each dispatch site, declare a Functor template with a 'Target'
21
// argument, add a source file defining its operator() and instantiating
22
// Functor<HH_TARGET>, add a cc_library_for_targets rule for that source file,
23
// and call InstructionSets::Run<Functor>(/*args*/).
24
25
#include <utility>  // std::forward
26
27
#include "highwayhash/arch_specific.h"  // HH_TARGET_*
28
#include "highwayhash/compiler_specific.h"
29
30
namespace highwayhash {
31
32
// Detects TargetBits and calls specializations of a user-defined functor.
33
class InstructionSets {
34
 public:
35
// Returns bit array of HH_TARGET_* supported by the current CPU.
36
// The HH_TARGET_Portable bit is guaranteed to be set.
37
#if HH_ARCH_X64
38
  static TargetBits Supported();
39
#elif HH_ARCH_PPC
40
  static HH_INLINE TargetBits Supported() {
41
    return HH_TARGET_VSX | HH_TARGET_Portable;
42
  }
43
#elif HH_ARCH_NEON
44
  static HH_INLINE TargetBits Supported() {
45
    return HH_TARGET_NEON | HH_TARGET_Portable;
46
  }
47
#else
48
  static HH_INLINE TargetBits Supported() { return HH_TARGET_Portable; }
49
#endif
50
51
  // Chooses the best available "Target" for the current CPU, runs the
52
  // corresponding Func<Target>::operator()(args) and returns that Target
53
  // (a single bit). The overhead of dispatching is low, about 4 cycles, but
54
  // this should only be called infrequently (e.g. hoisting it out of loops).
55
  template <template <TargetBits> class Func, typename... Args>
56
49
  static HH_INLINE TargetBits Run(Args&&... args) {
57
49
#if HH_ARCH_X64
58
49
    const TargetBits supported = Supported();
59
49
    if (supported & HH_TARGET_AVX2) {
60
49
      Func<HH_TARGET_AVX2>()(std::forward<Args>(args)...);
61
49
      return HH_TARGET_AVX2;
62
49
    }
63
0
    if (supported & HH_TARGET_SSE41) {
64
0
      Func<HH_TARGET_SSE41>()(std::forward<Args>(args)...);
65
0
      return HH_TARGET_SSE41;
66
0
    }
67
#elif HH_ARCH_PPC
68
    const TargetBits supported = Supported();
69
    if (supported & HH_TARGET_VSX) {
70
      Func<HH_TARGET_VSX>()(std::forward<Args>(args)...);
71
      return HH_TARGET_VSX;
72
    }
73
#elif HH_ARCH_NEON
74
    const TargetBits supported = Supported();
75
    if (supported & HH_TARGET_NEON) {
76
      Func<HH_TARGET_NEON>()(std::forward<Args>(args)...);
77
      return HH_TARGET_NEON;
78
    }
79
#endif
80
81
    // No matching HH_ARCH or no supported HH_TARGET:
82
0
    Func<HH_TARGET_Portable>()(std::forward<Args>(args)...);
83
0
    return HH_TARGET_Portable;
84
0
  }
85
86
  // Calls Func<Target>::operator()(args) for all Target supported by the
87
  // current CPU, and returns their HH_TARGET_* bits.
88
  template <template <TargetBits> class Func, typename... Args>
89
  static HH_INLINE TargetBits RunAll(Args&&... args) {
90
    const TargetBits supported = Supported();
91
92
#if HH_ARCH_X64
93
    if (supported & HH_TARGET_AVX2) {
94
      Func<HH_TARGET_AVX2>()(std::forward<Args>(args)...);
95
    }
96
    if (supported & HH_TARGET_SSE41) {
97
      Func<HH_TARGET_SSE41>()(std::forward<Args>(args)...);
98
    }
99
#elif HH_ARCH_PPC
100
    if (supported & HH_TARGET_VSX) {
101
      Func<HH_TARGET_VSX>()(std::forward<Args>(args)...);
102
    }
103
104
#elif HH_ARCH_NEON
105
    if (supported & HH_TARGET_NEON) {
106
      Func<HH_TARGET_NEON>()(std::forward<Args>(args)...);
107
    }
108
#endif
109
110
    Func<HH_TARGET_Portable>()(std::forward<Args>(args)...);
111
112
    return supported;  // i.e. all that were run
113
  }
114
};
115
116
}  // namespace highwayhash
117
118
#endif  // HIGHWAYHASH_INSTRUCTION_SETS_H_