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

randombit / botan / 5158104404

02 Jun 2023 06:12PM UTC coverage: 91.734% (-0.007%) from 91.741%
5158104404

push

github

randombit
Merge GH #3571 Add a CI job for quick clang-tidy checks

76186 of 83051 relevant lines covered (91.73%)

11692721.55 hits per line

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

83.33
/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,682✔
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,364✔
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,841✔
50

51
void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
12,841✔
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,841✔
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
}  // namespace
68

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

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

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

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

85
      enum x86_CPUID_1_bits : uint64_t {
12,841✔
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,841✔
97
         features_detected |= CPUID::CPUID_RDTSC_BIT;
12,841✔
98
      }
99
      if(flags0 & x86_CPUID_1_bits::SSE2) {
12,841✔
100
         features_detected |= CPUID::CPUID_SSE2_BIT;
12,841✔
101
      }
102
      if(flags0 & x86_CPUID_1_bits::CLMUL) {
12,841✔
103
         features_detected |= CPUID::CPUID_CLMUL_BIT;
12,841✔
104
      }
105
      if(flags0 & x86_CPUID_1_bits::SSSE3) {
12,841✔
106
         features_detected |= CPUID::CPUID_SSSE3_BIT;
12,841✔
107
      }
108
      if(flags0 & x86_CPUID_1_bits::AESNI) {
12,841✔
109
         features_detected |= CPUID::CPUID_AESNI_BIT;
12,841✔
110
      }
111
      if(flags0 & x86_CPUID_1_bits::RDRAND) {
12,841✔
112
         features_detected |= CPUID::CPUID_RDRAND_BIT;
12,841✔
113
      }
114

115
      if((flags0 & x86_CPUID_1_bits::AVX) && (flags0 & x86_CPUID_1_bits::OSXSAVE)) {
12,841✔
116
         const uint64_t xcr_flags = xgetbv();
12,841✔
117
         if((xcr_flags & 0x6) == 0x6) {
12,841✔
118
            has_os_ymm_support = true;
12,841✔
119
            has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
12,841✔
120
         }
121
      }
122
   }
123

124
   if(max_supported_sublevel >= 7) {
12,841✔
125
      clear_mem(cpuid, 4);
12,841✔
126
      invoke_cpuid_sublevel(7, 0, cpuid);
12,841✔
127

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

147
      const uint64_t flags7 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[1];
12,841✔
148

149
      if((flags7 & x86_CPUID_7_bits::AVX2) && has_os_ymm_support) {
12,841✔
150
         features_detected |= CPUID::CPUID_AVX2_BIT;
12,841✔
151
      }
152
      if(flags7 & x86_CPUID_7_bits::RDSEED) {
12,841✔
153
         features_detected |= CPUID::CPUID_RDSEED_BIT;
12,841✔
154
      }
155
      if(flags7 & x86_CPUID_7_bits::ADX) {
12,841✔
156
         features_detected |= CPUID::CPUID_ADX_BIT;
12,841✔
157
      }
158
      if(flags7 & x86_CPUID_7_bits::SHA) {
12,841✔
159
         features_detected |= CPUID::CPUID_SHA_BIT;
×
160
      }
161

162
      /*
163
      We only set the BMI bit if both BMI1 and BMI2 are supported, since
164
      typically we want to use both extensions in the same code.
165
      */
166
      if((flags7 & x86_CPUID_7_bits::BMI1) && (flags7 & x86_CPUID_7_bits::BMI2)) {
12,841✔
167
         features_detected |= CPUID::CPUID_BMI_BIT;
12,841✔
168
      }
169

170
      if((flags7 & x86_CPUID_7_bits::AVX512_F) && has_os_zmm_support) {
12,841✔
171
         const uint64_t AVX512_PROFILE_FLAGS = x86_CPUID_7_bits::AVX512_F | x86_CPUID_7_bits::AVX512_DQ |
×
172
                                               x86_CPUID_7_bits::AVX512_IFMA | x86_CPUID_7_bits::AVX512_BW |
173
                                               x86_CPUID_7_bits::AVX512_VL | x86_CPUID_7_bits::AVX512_VBMI |
174
                                               x86_CPUID_7_bits::AVX512_VBMI2 | x86_CPUID_7_bits::AVX512_VBITALG;
175

176
         /*
177
         We only enable AVX512 support if all of the above flags are available
178

179
         This is more than we strictly need for most uses, however it also has
180
         the effect of preventing execution of AVX512 codepaths on cores that
181
         have serious downclocking problems when AVX512 code executes,
182
         especially Intel Skylake.
183

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

188
         There is nothing stopping some future processor from supporting the
189
         above flags and having AVX512 penalties, but maybe you should not have
190
         bought such a processor.
191
         */
192
         if((flags7 & AVX512_PROFILE_FLAGS) == AVX512_PROFILE_FLAGS) {
×
193
            features_detected |= CPUID::CPUID_AVX512_BIT;
×
194

195
            if(flags7 & x86_CPUID_7_bits::AVX512_VAES) {
×
196
               features_detected |= CPUID::CPUID_AVX512_AES_BIT;
×
197
            }
198
            if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL) {
×
199
               features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
×
200
            }
201
         }
202
      }
203
   }
204

205
   /*
206
   * If we don't have access to CPUID, we can still safely assume that
207
   * any x86-64 processor has SSE2 and RDTSC
208
   */
209
   #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
210
   if(features_detected == 0) {
12,841✔
211
      features_detected |= CPUID::CPUID_SSE2_BIT;
×
212
      features_detected |= CPUID::CPUID_RDTSC_BIT;
×
213
   }
214
   #endif
215

216
   return features_detected;
12,841✔
217
}
218

219
#endif
220

221
}  // namespace Botan
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

© 2025 Coveralls, Inc