1 module xbyak_cpuid; 2 import std.stdio; 3 4 alias uint64 = ulong; 5 enum Type : uint64 { 6 NONE = 0, 7 tMMX = 1 << 0, //mmx(), //amdMmx() 8 tMMX2 = 1 << 1, 9 tCMOV = 1 << 2, //hasCmov() 10 tSSE = 1 << 3, //sse() 11 tSSE2 = 1 << 4, //sse2() 12 tSSE3 = 1 << 5, //sse3() 13 tSSSE3 = 1 << 6, //ssse3() 14 tSSE41 = 1 << 7, //sse41() 15 tSSE42 = 1 << 8, //sse42() 16 tPOPCNT = 1 << 9, //hasPopcnt() 17 tAESNI = 1 << 10, //aes() 18 tSSE5 = 1 << 11, //?? 19 tOSXSAVE = 1 << 12, //OSXSAVE_BIT 20 tPCLMULQDQ = 1 << 13, //hasPclmulqdq() 21 tAVX = 1 << 14, //avx() 22 tFMA = 1 << 15, //fma() 23 24 t3DN = 1 << 16, //amd3dnow() 25 tE3DN = 1 << 17, //amd3dnowExt() 26 tSSE4a = 1 << 18, //sse4a() 27 tRDTSCP = 1 << 19, //RDTSCP_BIT 28 tAVX2 = 1 << 20, //avx2() 29 tBMI1 = 1 << 21, //andn, bextr, blsi, blsmsk, blsr, tzcnt //BMI1_BIT 30 tBMI2 = 1 << 22, //bzhi, mulx, pdep, pext, rorx, sarx, shlx, shrx //BMI2_BIT 31 tLZCNT = 1 << 23, //hasLzcnt() 32 33 tINTEL = 1 << 24, 34 tAMD = 1 << 25, 35 36 tENHANCED_REP = 1 << 26, //enhanced rep movsb/stosb //ERMS_BIT 37 tRDRAND = 1 << 27, //hasRdrand() 38 tADX = 1 << 28, //adcx, adox //EAX=7 bit<<19 39 tRDSEED = 1 << 29, //rdseed //hasRdseed() 40 tSMAP = 1 << 30, //stac //EAX=7 bit<<20 41 tHLE = 1 << 31, //xacquire, xrelease, xtest //hle() 42 tRTM = uint64(1) << 32, //xbegin, xend, xabort //rtm() 43 tF16C = uint64(1) << 33, //vcvtph2ps, vcvtps2ph //fp16c() 44 tMOVBE = uint64(1) << 34 //mobve //bit<22 45 } 46 47 class CpuId { 48 uint64 type_; 49 uint get32bitAsBE(string x) 50 { 51 return (x[0] | (x[1] << 8) | (x[2] << 16) | (x[3] << 24)); 52 } 53 54 uint mask(int n) 55 { 56 return ((1U << n) - 1); 57 } 58 59 void setFamily() 60 { 61 uint[4] data; 62 63 data = getCpuid(1); 64 stepping = data[0] & mask(4); 65 model = (data[0] >> 4) & mask(4); 66 family = (data[0] >> 8) & mask(4); 67 // type = (data[0] >> 12) & mask(2); 68 extModel = (data[0] >> 16) & mask(4); 69 extFamily = (data[0] >> 20) & mask(8); 70 if (family == 0x0f) { 71 displayFamily = family + extFamily; 72 }else { 73 displayFamily = family; 74 } 75 if ((family == 6) || (family == 0x0f)) { 76 displayModel = (extModel << 4) + model; 77 }else { 78 displayModel = model; 79 } 80 } 81 82 public: 83 int model; 84 int family; 85 int stepping; 86 int extModel; 87 int extFamily; 88 int displayFamily; // family + extFamily 89 int displayModel; // model + extModel 90 91 uint[4] getCpuid(uint eaxIn) 92 { 93 uint d1, d2, d3, d4; 94 asm 95 { 96 mov EAX, eaxIn; 97 cpuid; 98 mov d1, EAX; 99 mov d2, EBX; 100 mov d3, ECX; 101 mov d4, EDX; 102 } 103 return [d1, d2, d3, d4]; 104 } 105 106 uint[4] getCpuidEx(uint eaxIn, uint ecxIn) 107 { 108 uint d1, d2, d3, d4; 109 asm 110 { 111 mov EAX, eaxIn; 112 mov ECX, ecxIn; 113 cpuid; 114 mov d1, EAX; 115 mov d2, EBX; 116 mov d3, ECX; 117 mov d4, EDX; 118 } 119 return [d1, d2, d3, d4]; 120 } 121 122 uint64 getXfeature() 123 { 124 uint d, a; 125 asm 126 { 127 mov ECX, 0; 128 xgetbv; 129 mov d, EDX; 130 mov a, EAX; 131 } 132 return (cast(uint64) d << 32 | a); 133 } 134 135 this() 136 { 137 type_ = Type.NONE; 138 uint[4] data; 139 data = getCpuid(0); 140 uint maxNum = data[0]; 141 string intel = "ntel"; 142 string amd = "cAMD"; 143 if (data[2] == get32bitAsBE(amd)) { 144 type_ |= Type.tAMD; 145 data = getCpuid(0x80000001); 146 if (data[3] & (1U << 31)) { 147 type_ |= Type.t3DN; 148 } 149 if (data[3] & (1U << 15)) { 150 type_ |= Type.tCMOV; 151 } 152 if (data[3] & (1U << 30)) { 153 type_ |= Type.tE3DN; 154 } 155 if (data[3] & (1U << 22)) { 156 type_ |= Type.tMMX2; 157 } 158 if (data[3] & (1U << 27)) { 159 type_ |= Type.tRDTSCP; 160 } 161 } 162 if (data[2] == get32bitAsBE(intel)) { 163 type_ |= Type.tINTEL; 164 data = getCpuid(0x80000001); 165 if (data[3] & (1U << 27)) { 166 type_ |= Type.tRDTSCP; 167 } 168 if (data[2] & (1U << 5)) { 169 type_ |= Type.tLZCNT; 170 } 171 } 172 data = getCpuid(1); 173 if (data[2] & (1U << 0)) { 174 type_ |= Type.tSSE3; 175 } 176 if (data[2] & (1U << 9)) { 177 type_ |= Type.tSSSE3; 178 } 179 if (data[2] & (1U << 19)) { 180 type_ |= Type.tSSE41; 181 } 182 if (data[2] & (1U << 20)) { 183 type_ |= Type.tSSE42; 184 } 185 if (data[2] & (1U << 22)) { 186 type_ |= Type.tMOVBE; 187 } 188 if (data[2] & (1U << 23)) { 189 type_ |= Type.tPOPCNT; 190 } 191 if (data[2] & (1U << 25)) { 192 type_ |= Type.tAESNI; 193 } 194 if (data[2] & (1U << 1)) { 195 type_ |= Type.tPCLMULQDQ; 196 } 197 if (data[2] & (1U << 27)) { 198 type_ |= Type.tOSXSAVE; 199 } 200 if (data[2] & (1U << 30)) { 201 type_ |= Type.tRDRAND; 202 } 203 if (data[2] & (1U << 29)) { 204 type_ |= Type.tF16C; 205 } 206 207 if (data[3] & (1U << 15)) { 208 type_ |= Type.tCMOV; 209 } 210 if (data[3] & (1U << 23)) { 211 type_ |= Type.tMMX; 212 } 213 if (data[3] & (1U << 25)) { 214 type_ |= Type.tMMX2 | Type.tSSE; 215 } 216 if (data[3] & (1U << 26)) { 217 type_ |= Type.tSSE2; 218 } 219 220 if (type_ & Type.tOSXSAVE) { 221 // check XFEATURE_ENABLED_MASK[2:1] = '11b' 222 uint64 bv = getXfeature(); 223 if ((bv & 6) == 6) { 224 if (data[2] & (1U << 28)) { 225 type_ |= Type.tAVX; 226 } 227 if (data[2] & (1U << 12)) { 228 type_ |= Type.tFMA; 229 } 230 } 231 } 232 if (maxNum >= 7) { 233 data = getCpuidEx(7, 0); 234 if (type_ & Type.tAVX && data[1] & 0x20) { 235 type_ |= Type.tAVX2; 236 } 237 if (data[1] & (1U << 3)) { 238 type_ |= Type.tBMI1; 239 } 240 if (data[1] & (1U << 8)) { 241 type_ |= Type.tBMI2; 242 } 243 if (data[1] & (1U << 9)) { 244 type_ |= Type.tENHANCED_REP; 245 } 246 if (data[1] & (1U << 18)) { 247 type_ |= Type.tRDSEED; 248 } 249 if (data[1] & (1U << 19)) { 250 type_ |= Type.tADX; 251 } 252 if (data[1] & (1U << 20)) { 253 type_ |= Type.tSMAP; 254 } 255 if (data[1] & (1U << 4)) { 256 type_ |= Type.tHLE; 257 } 258 if (data[1] & (1U << 11)) { 259 type_ |= Type.tRTM; 260 } 261 } 262 setFamily(); 263 } 264 void putFamily() 265 { 266 writefln("family=%d, model=%X, stepping=%X, extFamily=%d, extModel=%X", family, model, stepping, extFamily, extModel); 267 writefln("display:family=%X, model=%X", displayFamily, displayModel); 268 } 269 270 bool has(Type type) 271 { 272 return ((type & type_) != 0); 273 } 274 }