1 /**************************************************************************** 2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 ****************************************************************************/ 23 24 #pragma once 25 26 #include <iostream> 27 #include <vector> 28 #include <bitset> 29 #include <array> 30 #include <string> 31 #include <algorithm> 32 33 // Clang for Windows does supply an intrin.h with __cpuid intrinsics, however... 34 // It seems to not realize that a write to "b" (ebx) will kill the value in rbx. 35 // This attempts to use the "native" clang / gcc intrinsics instead of the windows 36 // compatible ones. 37 #if defined(_MSC_VER) && !defined(__clang__) 38 #include <intrin.h> 39 #else 40 #include <string.h> 41 #include <cpuid.h> 42 #endif 43 44 class InstructionSet 45 { 46 public: 47 InstructionSet() : CPU_Rep() {}; 48 49 // getters 50 std::string Vendor(void) { return CPU_Rep.vendor_; } 51 std::string Brand(void) { return CPU_Rep.brand_; } 52 53 bool SSE3(void) { return CPU_Rep.f_1_ECX_[0]; } 54 bool PCLMULQDQ(void) { return CPU_Rep.f_1_ECX_[1]; } 55 bool MONITOR(void) { return CPU_Rep.f_1_ECX_[3]; } 56 bool SSSE3(void) { return CPU_Rep.f_1_ECX_[9]; } 57 bool FMA(void) { return CPU_Rep.f_1_ECX_[12]; } 58 bool CMPXCHG16B(void) { return CPU_Rep.f_1_ECX_[13]; } 59 bool SSE41(void) { return CPU_Rep.f_1_ECX_[19]; } 60 bool SSE42(void) { return CPU_Rep.f_1_ECX_[20]; } 61 bool MOVBE(void) { return CPU_Rep.f_1_ECX_[22]; } 62 bool POPCNT(void) { return CPU_Rep.f_1_ECX_[23]; } 63 bool AES(void) { return CPU_Rep.f_1_ECX_[25]; } 64 bool XSAVE(void) { return CPU_Rep.f_1_ECX_[26]; } 65 bool OSXSAVE(void) { return CPU_Rep.f_1_ECX_[27]; } 66 bool RDRAND(void) { return CPU_Rep.f_1_ECX_[30]; } 67 68 bool MSR(void) { return CPU_Rep.f_1_EDX_[5]; } 69 bool CX8(void) { return CPU_Rep.f_1_EDX_[8]; } 70 bool SEP(void) { return CPU_Rep.f_1_EDX_[11]; } 71 bool CMOV(void) { return CPU_Rep.f_1_EDX_[15]; } 72 bool CLFSH(void) { return CPU_Rep.f_1_EDX_[19]; } 73 bool MMX(void) { return CPU_Rep.f_1_EDX_[23]; } 74 bool FXSR(void) { return CPU_Rep.f_1_EDX_[24]; } 75 bool SSE(void) { return CPU_Rep.f_1_EDX_[25]; } 76 bool SSE2(void) { return CPU_Rep.f_1_EDX_[26]; } 77 78 bool FSGSBASE(void) { return CPU_Rep.f_7_EBX_[0]; } 79 bool BMI1(void) { return CPU_Rep.f_7_EBX_[3]; } 80 bool HLE(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4]; } 81 bool BMI2(void) { return CPU_Rep.f_7_EBX_[8]; } 82 bool ERMS(void) { return CPU_Rep.f_7_EBX_[9]; } 83 bool INVPCID(void) { return CPU_Rep.f_7_EBX_[10]; } 84 bool RTM(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11]; } 85 bool RDSEED(void) { return CPU_Rep.f_7_EBX_[18]; } 86 bool ADX(void) { return CPU_Rep.f_7_EBX_[19]; } 87 bool SHA(void) { return CPU_Rep.f_7_EBX_[29]; } 88 89 bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; } 90 91 bool LAHF(void) { return CPU_Rep.f_81_ECX_[0]; } 92 bool LZCNT(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5]; } 93 bool ABM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5]; } 94 bool SSE4a(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6]; } 95 bool XOP(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11]; } 96 bool TBM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21]; } 97 98 bool SYSCALL(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11]; } 99 bool MMXEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22]; } 100 bool RDTSCP(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27]; } 101 bool _3DNOWEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30]; } 102 bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; } 103 104 bool AVX(void) { return CPU_Rep.f_1_ECX_[28]; } 105 bool F16C(void) { return CPU_Rep.f_1_ECX_[29]; } 106 bool AVX2(void) { return CPU_Rep.f_7_EBX_[5]; } 107 bool AVX512F(void) { return CPU_Rep.f_7_EBX_[16]; } 108 bool AVX512PF(void) { return CPU_Rep.f_7_EBX_[26]; } 109 bool AVX512ER(void) { return CPU_Rep.f_7_EBX_[27]; } 110 bool AVX512CD(void) { return CPU_Rep.f_7_EBX_[28]; } 111 112 private: 113 class InstructionSet_Internal 114 { 115 public: 116 InstructionSet_Internal() 117 : nIds_{ 0 }, 118 nExIds_{ 0 }, 119 isIntel_{ false }, 120 isAMD_{ false }, 121 f_1_ECX_{ 0 }, 122 f_1_EDX_{ 0 }, 123 f_7_EBX_{ 0 }, 124 f_7_ECX_{ 0 }, 125 f_81_ECX_{ 0 }, 126 f_81_EDX_{ 0 }, 127 data_{}, 128 extdata_{} 129 { 130 //int cpuInfo[4] = {-1}; 131 std::array<int, 4> cpui; 132 133 // Calling __cpuid with 0x0 as the function_id argument 134 // gets the number of the highest valid function ID. 135 #if defined(_MSC_VER) && !defined(__clang__) 136 __cpuid(cpui.data(), 0); 137 nIds_ = cpui[0]; 138 #else 139 nIds_ = __get_cpuid_max(0, NULL); 140 #endif 141 142 for (int i = 0; i <= nIds_; ++i) 143 { 144 #if defined(_MSC_VER) && !defined(__clang__) 145 __cpuidex(cpui.data(), i, 0); 146 #else 147 int *data = cpui.data(); 148 __cpuid_count(i, 0, data[0], data[1], data[2], data[3]); 149 #endif 150 data_.push_back(cpui); 151 } 152 153 // Capture vendor string 154 char vendor[0x20]; 155 memset(vendor, 0, sizeof(vendor)); 156 *reinterpret_cast<int*>(vendor) = data_[0][1]; 157 *reinterpret_cast<int*>(vendor + 4) = data_[0][3]; 158 *reinterpret_cast<int*>(vendor + 8) = data_[0][2]; 159 vendor_ = vendor; 160 if (vendor_ == "GenuineIntel") 161 { 162 isIntel_ = true; 163 } 164 else if (vendor_ == "AuthenticAMD") 165 { 166 isAMD_ = true; 167 } 168 169 // load bitset with flags for function 0x00000001 170 if (nIds_ >= 1) 171 { 172 f_1_ECX_ = data_[1][2]; 173 f_1_EDX_ = data_[1][3]; 174 } 175 176 // load bitset with flags for function 0x00000007 177 if (nIds_ >= 7) 178 { 179 f_7_EBX_ = data_[7][1]; 180 f_7_ECX_ = data_[7][2]; 181 } 182 183 // Calling __cpuid with 0x80000000 as the function_id argument 184 // gets the number of the highest valid extended ID. 185 #if defined(_MSC_VER) && !defined(__clang__) 186 __cpuid(cpui.data(), 0x80000000); 187 nExIds_ = cpui[0]; 188 #else 189 nExIds_ = __get_cpuid_max(0x80000000, NULL); 190 #endif 191 192 char brand[0x40]; 193 memset(brand, 0, sizeof(brand)); 194 195 for (unsigned i = 0x80000000; i <= nExIds_; ++i) 196 { 197 #if defined(_MSC_VER) && !defined(__clang__) 198 __cpuidex(cpui.data(), i, 0); 199 #else 200 int *data = cpui.data(); 201 __cpuid_count(i, 0, data[0], data[1], data[2], data[3]); 202 #endif 203 extdata_.push_back(cpui); 204 } 205 206 // load bitset with flags for function 0x80000001 207 if (nExIds_ >= 0x80000001) 208 { 209 f_81_ECX_ = extdata_[1][2]; 210 f_81_EDX_ = extdata_[1][3]; 211 } 212 213 // Interpret CPU brand string if reported 214 if (nExIds_ >= 0x80000004) 215 { 216 memcpy(brand, extdata_[2].data(), sizeof(cpui)); 217 memcpy(brand + 16, extdata_[3].data(), sizeof(cpui)); 218 memcpy(brand + 32, extdata_[4].data(), sizeof(cpui)); 219 brand_ = brand; 220 } 221 }; 222 223 int nIds_; 224 unsigned nExIds_; 225 std::string vendor_; 226 std::string brand_; 227 bool isIntel_; 228 bool isAMD_; 229 std::bitset<32> f_1_ECX_; 230 std::bitset<32> f_1_EDX_; 231 std::bitset<32> f_7_EBX_; 232 std::bitset<32> f_7_ECX_; 233 std::bitset<32> f_81_ECX_; 234 std::bitset<32> f_81_EDX_; 235 std::vector<std::array<int, 4>> data_; 236 std::vector<std::array<int, 4>> extdata_; 237 }; 238 const InstructionSet_Internal CPU_Rep; 239 }; 240