• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.67
/src/lib/utils/cpuid/cpuid_x86.cpp
1
/*
2
* Runtime CPU detection for x86
3
* (C) 2009,2010,2013,2017,2023 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/cpuid.h>
9

10
#include <botan/mem_ops.h>
11
#include <botan/internal/loadstor.h>
12

13
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
14

15
   #include <immintrin.h>
16

17
   #if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
18
      #include <intrin.h>
19
   #elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
20
      #include <ia32intrin.h>
21
   #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
22
      #include <cpuid.h>
23
   #endif
24

25
#endif
26

27
namespace Botan {
28

29
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
30

31
namespace {
32

33
void invoke_cpuid(uint32_t type, uint32_t out[4]) {
25,680✔
34
   #if defined(BOTAN_BUILD_COMPILER_IS_MSVC) || defined(BOTAN_BUILD_COMPILER_IS_INTEL)
35
   __cpuid((int*)out, type);
36

37
   #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
38
   __get_cpuid(type, out, out + 1, out + 2, out + 3);
51,360✔
39

40
   #elif defined(BOTAN_USE_GCC_INLINE_ASM)
41
   asm("cpuid\n\t" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "0"(type));
42

43
   #else
44
      #warning "No way of calling x86 cpuid instruction for this compiler"
45
   clear_mem(out, 4);
46
   #endif
47
}
48

49
BOTAN_FUNC_ISA("xsave") uint64_t xgetbv() { return _xgetbv(0); }
12,840✔
50

51
void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
12,840✔
52
   #if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
53
   __cpuidex((int*)out, type, level);
54

55
   #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
56
   __cpuid_count(type, level, out[0], out[1], out[2], out[3]);
12,840✔
57

58
   #elif defined(BOTAN_USE_GCC_INLINE_ASM)
59
   asm("cpuid\n\t" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "0"(type), "2"(level));
60

61
   #else
62
      #warning "No way of calling x86 cpuid instruction for this compiler"
63
   clear_mem(out, 4);
64
   #endif
65
}
66

67
}
68

69
uint32_t CPUID::CPUID_Data::detect_cpu_features() {
12,840✔
70
   uint32_t features_detected = 0;
12,840✔
71
   uint32_t cpuid[4] = {0};
12,840✔
72
   bool has_os_ymm_support = false;
12,840✔
73
   bool has_os_zmm_support = false;
12,840✔
74

75
   // CPUID 0: vendor identification, max sublevel
76
   invoke_cpuid(0, cpuid);
12,840✔
77

78
   const uint32_t max_supported_sublevel = cpuid[0];
12,840✔
79

80
   if(max_supported_sublevel >= 1) {
12,840✔
81
      // CPUID 1: feature bits
82
      invoke_cpuid(1, cpuid);
12,840✔
83
      const uint64_t flags0 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[3];
12,840✔
84

85
      enum x86_CPUID_1_bits : uint64_t {
12,840✔
86
         RDTSC = (1ULL << 4),
87
         SSE2 = (1ULL << 26),
88
         CLMUL = (1ULL << 33),
89
         SSSE3 = (1ULL << 41),
90
         AESNI = (1ULL << 57),
91
         OSXSAVE = (1ULL << 59),
92
         AVX = (1ULL << 60),
93
         RDRAND = (1ULL << 62)
94
      };
95

96
      if(flags0 & x86_CPUID_1_bits::RDTSC)
12,840✔
97
         features_detected |= CPUID::CPUID_RDTSC_BIT;
12,840✔
98
      if(flags0 & x86_CPUID_1_bits::SSE2)
12,840✔
99
         features_detected |= CPUID::CPUID_SSE2_BIT;
12,840✔
100
      if(flags0 & x86_CPUID_1_bits::CLMUL)
12,840✔
101
         features_detected |= CPUID::CPUID_CLMUL_BIT;
12,840✔
102
      if(flags0 & x86_CPUID_1_bits::SSSE3)
12,840✔
103
         features_detected |= CPUID::CPUID_SSSE3_BIT;
12,840✔
104
      if(flags0 & x86_CPUID_1_bits::AESNI)
12,840✔
105
         features_detected |= CPUID::CPUID_AESNI_BIT;
12,840✔
106
      if(flags0 & x86_CPUID_1_bits::RDRAND)
12,840✔
107
         features_detected |= CPUID::CPUID_RDRAND_BIT;
12,840✔
108

109
      if((flags0 & x86_CPUID_1_bits::AVX) && (flags0 & x86_CPUID_1_bits::OSXSAVE)) {
12,840✔
110
         const uint64_t xcr_flags = xgetbv();
12,840✔
111
         if((xcr_flags & 0x6) == 0x6) {
12,840✔
112
            has_os_ymm_support = true;
12,840✔
113
            has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
12,840✔
114
         }
115
      }
116
   }
117

118
   if(max_supported_sublevel >= 7) {
12,840✔
119
      clear_mem(cpuid, 4);
12,840✔
120
      invoke_cpuid_sublevel(7, 0, cpuid);
12,840✔
121

122
      enum x86_CPUID_7_bits : uint64_t {
12,840✔
123
         BMI1 = (1ULL << 3),
124
         AVX2 = (1ULL << 5),
125
         BMI2 = (1ULL << 8),
126
         AVX512_F = (1ULL << 16),
127
         AVX512_DQ = (1ULL << 17),
128
         RDSEED = (1ULL << 18),
129
         ADX = (1ULL << 19),
130
         AVX512_IFMA = (1ULL << 21),
131
         SHA = (1ULL << 29),
132
         AVX512_BW = (1ULL << 30),
133
         AVX512_VL = (1ULL << 31),
134
         AVX512_VBMI = (1ULL << 33),
135
         AVX512_VBMI2 = (1ULL << 38),
136
         AVX512_VAES = (1ULL << 41),
137
         AVX512_VCLMUL = (1ULL << 42),
138
         AVX512_VBITALG = (1ULL << 44),
139
      };
140

141
      const uint64_t flags7 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[1];
12,840✔
142

143
      if((flags7 & x86_CPUID_7_bits::AVX2) && has_os_ymm_support)
12,840✔
144
         features_detected |= CPUID::CPUID_AVX2_BIT;
12,840✔
145
      if(flags7 & x86_CPUID_7_bits::RDSEED)
12,840✔
146
         features_detected |= CPUID::CPUID_RDSEED_BIT;
12,840✔
147
      if(flags7 & x86_CPUID_7_bits::ADX)
12,840✔
148
         features_detected |= CPUID::CPUID_ADX_BIT;
12,840✔
149
      if(flags7 & x86_CPUID_7_bits::SHA)
12,840✔
150
         features_detected |= CPUID::CPUID_SHA_BIT;
×
151

152
      /*
153
      We only set the BMI bit if both BMI1 and BMI2 are supported, since
154
      typically we want to use both extensions in the same code.
155
      */
156
      if((flags7 & x86_CPUID_7_bits::BMI1) && (flags7 & x86_CPUID_7_bits::BMI2)) {
12,840✔
157
         features_detected |= CPUID::CPUID_BMI_BIT;
12,840✔
158
      }
159

160
      if((flags7 & x86_CPUID_7_bits::AVX512_F) && has_os_zmm_support) {
12,840✔
161
         const uint64_t AVX512_PROFILE_FLAGS = x86_CPUID_7_bits::AVX512_F | x86_CPUID_7_bits::AVX512_DQ |
12,840✔
162
                                               x86_CPUID_7_bits::AVX512_IFMA | x86_CPUID_7_bits::AVX512_BW |
163
                                               x86_CPUID_7_bits::AVX512_VL | x86_CPUID_7_bits::AVX512_VBMI |
164
                                               x86_CPUID_7_bits::AVX512_VBMI2 | x86_CPUID_7_bits::AVX512_VBITALG;
165

166
         /*
167
         We only enable AVX512 support if all of the above flags are available
168

169
         This is more than we strictly need for most uses, however it also has
170
         the effect of preventing execution of AVX512 codepaths on cores that
171
         have serious downclocking problems when AVX512 code executes,
172
         especially Intel Skylake.
173

174
         VBMI2/VBITALG are the key flags here as they restrict us to Intel Ice
175
         Lake/Rocket Lake, or AMD Zen4, all of which do not have penalties for
176
         executing AVX512.
177

178
         There is nothing stopping some future processor from supporting the
179
         above flags and having AVX512 penalties, but maybe you should not have
180
         bought such a processor.
181
         */
182
         if((flags7 & AVX512_PROFILE_FLAGS) == AVX512_PROFILE_FLAGS) {
12,840✔
183
            features_detected |= CPUID::CPUID_AVX512_BIT;
×
184

185
            if(flags7 & x86_CPUID_7_bits::AVX512_VAES)
×
186
               features_detected |= CPUID::CPUID_AVX512_AES_BIT;
×
187
            if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL)
×
188
               features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
×
189
         }
190
      }
191
   }
192

193
   /*
194
   * If we don't have access to CPUID, we can still safely assume that
195
   * any x86-64 processor has SSE2 and RDTSC
196
   */
197
   #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
198
   if(features_detected == 0) {
12,840✔
199
      features_detected |= CPUID::CPUID_SSE2_BIT;
×
200
      features_detected |= CPUID::CPUID_RDTSC_BIT;
×
201
   }
202
   #endif
203

204
   return features_detected;
12,840✔
205
}
206

207
#endif
208

209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc