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 44class InstructionSet 45{ 46public: 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 112private: 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