1*3117ece4Schristos /* 2*3117ece4Schristos * Copyright (c) Meta Platforms, Inc. and affiliates. 3*3117ece4Schristos * All rights reserved. 4*3117ece4Schristos * 5*3117ece4Schristos * This source code is licensed under both the BSD-style license (found in the 6*3117ece4Schristos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*3117ece4Schristos * in the COPYING file in the root directory of this source tree). 8*3117ece4Schristos * You may select, at your option, one of the above-listed licenses. 9*3117ece4Schristos */ 10*3117ece4Schristos 11*3117ece4Schristos #ifndef ZSTD_COMMON_CPU_H 12*3117ece4Schristos #define ZSTD_COMMON_CPU_H 13*3117ece4Schristos 14*3117ece4Schristos /** 15*3117ece4Schristos * Implementation taken from folly/CpuId.h 16*3117ece4Schristos * https://github.com/facebook/folly/blob/master/folly/CpuId.h 17*3117ece4Schristos */ 18*3117ece4Schristos 19*3117ece4Schristos #include "mem.h" 20*3117ece4Schristos 21*3117ece4Schristos #ifdef _MSC_VER 22*3117ece4Schristos #include <intrin.h> 23*3117ece4Schristos #endif 24*3117ece4Schristos 25*3117ece4Schristos typedef struct { 26*3117ece4Schristos U32 f1c; 27*3117ece4Schristos U32 f1d; 28*3117ece4Schristos U32 f7b; 29*3117ece4Schristos U32 f7c; 30*3117ece4Schristos } ZSTD_cpuid_t; 31*3117ece4Schristos 32*3117ece4Schristos MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { 33*3117ece4Schristos U32 f1c = 0; 34*3117ece4Schristos U32 f1d = 0; 35*3117ece4Schristos U32 f7b = 0; 36*3117ece4Schristos U32 f7c = 0; 37*3117ece4Schristos #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) 38*3117ece4Schristos #if !defined(__clang__) 39*3117ece4Schristos int reg[4]; 40*3117ece4Schristos __cpuid((int*)reg, 0); 41*3117ece4Schristos { 42*3117ece4Schristos int const n = reg[0]; 43*3117ece4Schristos if (n >= 1) { 44*3117ece4Schristos __cpuid((int*)reg, 1); 45*3117ece4Schristos f1c = (U32)reg[2]; 46*3117ece4Schristos f1d = (U32)reg[3]; 47*3117ece4Schristos } 48*3117ece4Schristos if (n >= 7) { 49*3117ece4Schristos __cpuidex((int*)reg, 7, 0); 50*3117ece4Schristos f7b = (U32)reg[1]; 51*3117ece4Schristos f7c = (U32)reg[2]; 52*3117ece4Schristos } 53*3117ece4Schristos } 54*3117ece4Schristos #else 55*3117ece4Schristos /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in 56*3117ece4Schristos * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs 57*3117ece4Schristos * to due to being a reserved register. So in that case, do the `cpuid` 58*3117ece4Schristos * ourselves. Clang supports inline assembly anyway. 59*3117ece4Schristos */ 60*3117ece4Schristos U32 n; 61*3117ece4Schristos __asm__( 62*3117ece4Schristos "pushq %%rbx\n\t" 63*3117ece4Schristos "cpuid\n\t" 64*3117ece4Schristos "popq %%rbx\n\t" 65*3117ece4Schristos : "=a"(n) 66*3117ece4Schristos : "a"(0) 67*3117ece4Schristos : "rcx", "rdx"); 68*3117ece4Schristos if (n >= 1) { 69*3117ece4Schristos U32 f1a; 70*3117ece4Schristos __asm__( 71*3117ece4Schristos "pushq %%rbx\n\t" 72*3117ece4Schristos "cpuid\n\t" 73*3117ece4Schristos "popq %%rbx\n\t" 74*3117ece4Schristos : "=a"(f1a), "=c"(f1c), "=d"(f1d) 75*3117ece4Schristos : "a"(1) 76*3117ece4Schristos :); 77*3117ece4Schristos } 78*3117ece4Schristos if (n >= 7) { 79*3117ece4Schristos __asm__( 80*3117ece4Schristos "pushq %%rbx\n\t" 81*3117ece4Schristos "cpuid\n\t" 82*3117ece4Schristos "movq %%rbx, %%rax\n\t" 83*3117ece4Schristos "popq %%rbx" 84*3117ece4Schristos : "=a"(f7b), "=c"(f7c) 85*3117ece4Schristos : "a"(7), "c"(0) 86*3117ece4Schristos : "rdx"); 87*3117ece4Schristos } 88*3117ece4Schristos #endif 89*3117ece4Schristos #elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) 90*3117ece4Schristos /* The following block like the normal cpuid branch below, but gcc 91*3117ece4Schristos * reserves ebx for use of its pic register so we must specially 92*3117ece4Schristos * handle the save and restore to avoid clobbering the register 93*3117ece4Schristos */ 94*3117ece4Schristos U32 n; 95*3117ece4Schristos __asm__( 96*3117ece4Schristos "pushl %%ebx\n\t" 97*3117ece4Schristos "cpuid\n\t" 98*3117ece4Schristos "popl %%ebx\n\t" 99*3117ece4Schristos : "=a"(n) 100*3117ece4Schristos : "a"(0) 101*3117ece4Schristos : "ecx", "edx"); 102*3117ece4Schristos if (n >= 1) { 103*3117ece4Schristos U32 f1a; 104*3117ece4Schristos __asm__( 105*3117ece4Schristos "pushl %%ebx\n\t" 106*3117ece4Schristos "cpuid\n\t" 107*3117ece4Schristos "popl %%ebx\n\t" 108*3117ece4Schristos : "=a"(f1a), "=c"(f1c), "=d"(f1d) 109*3117ece4Schristos : "a"(1)); 110*3117ece4Schristos } 111*3117ece4Schristos if (n >= 7) { 112*3117ece4Schristos __asm__( 113*3117ece4Schristos "pushl %%ebx\n\t" 114*3117ece4Schristos "cpuid\n\t" 115*3117ece4Schristos "movl %%ebx, %%eax\n\t" 116*3117ece4Schristos "popl %%ebx" 117*3117ece4Schristos : "=a"(f7b), "=c"(f7c) 118*3117ece4Schristos : "a"(7), "c"(0) 119*3117ece4Schristos : "edx"); 120*3117ece4Schristos } 121*3117ece4Schristos #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) 122*3117ece4Schristos U32 n; 123*3117ece4Schristos __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); 124*3117ece4Schristos if (n >= 1) { 125*3117ece4Schristos U32 f1a; 126*3117ece4Schristos __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); 127*3117ece4Schristos } 128*3117ece4Schristos if (n >= 7) { 129*3117ece4Schristos U32 f7a; 130*3117ece4Schristos __asm__("cpuid" 131*3117ece4Schristos : "=a"(f7a), "=b"(f7b), "=c"(f7c) 132*3117ece4Schristos : "a"(7), "c"(0) 133*3117ece4Schristos : "edx"); 134*3117ece4Schristos } 135*3117ece4Schristos #endif 136*3117ece4Schristos { 137*3117ece4Schristos ZSTD_cpuid_t cpuid; 138*3117ece4Schristos cpuid.f1c = f1c; 139*3117ece4Schristos cpuid.f1d = f1d; 140*3117ece4Schristos cpuid.f7b = f7b; 141*3117ece4Schristos cpuid.f7c = f7c; 142*3117ece4Schristos return cpuid; 143*3117ece4Schristos } 144*3117ece4Schristos } 145*3117ece4Schristos 146*3117ece4Schristos #define X(name, r, bit) \ 147*3117ece4Schristos MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ 148*3117ece4Schristos return ((cpuid.r) & (1U << bit)) != 0; \ 149*3117ece4Schristos } 150*3117ece4Schristos 151*3117ece4Schristos /* cpuid(1): Processor Info and Feature Bits. */ 152*3117ece4Schristos #define C(name, bit) X(name, f1c, bit) 153*3117ece4Schristos C(sse3, 0) 154*3117ece4Schristos C(pclmuldq, 1) 155*3117ece4Schristos C(dtes64, 2) 156*3117ece4Schristos C(monitor, 3) 157*3117ece4Schristos C(dscpl, 4) 158*3117ece4Schristos C(vmx, 5) 159*3117ece4Schristos C(smx, 6) 160*3117ece4Schristos C(eist, 7) 161*3117ece4Schristos C(tm2, 8) 162*3117ece4Schristos C(ssse3, 9) 163*3117ece4Schristos C(cnxtid, 10) 164*3117ece4Schristos C(fma, 12) 165*3117ece4Schristos C(cx16, 13) 166*3117ece4Schristos C(xtpr, 14) 167*3117ece4Schristos C(pdcm, 15) 168*3117ece4Schristos C(pcid, 17) 169*3117ece4Schristos C(dca, 18) 170*3117ece4Schristos C(sse41, 19) 171*3117ece4Schristos C(sse42, 20) 172*3117ece4Schristos C(x2apic, 21) 173*3117ece4Schristos C(movbe, 22) 174*3117ece4Schristos C(popcnt, 23) 175*3117ece4Schristos C(tscdeadline, 24) 176*3117ece4Schristos C(aes, 25) 177*3117ece4Schristos C(xsave, 26) 178*3117ece4Schristos C(osxsave, 27) 179*3117ece4Schristos C(avx, 28) 180*3117ece4Schristos C(f16c, 29) 181*3117ece4Schristos C(rdrand, 30) 182*3117ece4Schristos #undef C 183*3117ece4Schristos #define D(name, bit) X(name, f1d, bit) 184*3117ece4Schristos D(fpu, 0) 185*3117ece4Schristos D(vme, 1) 186*3117ece4Schristos D(de, 2) 187*3117ece4Schristos D(pse, 3) 188*3117ece4Schristos D(tsc, 4) 189*3117ece4Schristos D(msr, 5) 190*3117ece4Schristos D(pae, 6) 191*3117ece4Schristos D(mce, 7) 192*3117ece4Schristos D(cx8, 8) 193*3117ece4Schristos D(apic, 9) 194*3117ece4Schristos D(sep, 11) 195*3117ece4Schristos D(mtrr, 12) 196*3117ece4Schristos D(pge, 13) 197*3117ece4Schristos D(mca, 14) 198*3117ece4Schristos D(cmov, 15) 199*3117ece4Schristos D(pat, 16) 200*3117ece4Schristos D(pse36, 17) 201*3117ece4Schristos D(psn, 18) 202*3117ece4Schristos D(clfsh, 19) 203*3117ece4Schristos D(ds, 21) 204*3117ece4Schristos D(acpi, 22) 205*3117ece4Schristos D(mmx, 23) 206*3117ece4Schristos D(fxsr, 24) 207*3117ece4Schristos D(sse, 25) 208*3117ece4Schristos D(sse2, 26) 209*3117ece4Schristos D(ss, 27) 210*3117ece4Schristos D(htt, 28) 211*3117ece4Schristos D(tm, 29) 212*3117ece4Schristos D(pbe, 31) 213*3117ece4Schristos #undef D 214*3117ece4Schristos 215*3117ece4Schristos /* cpuid(7): Extended Features. */ 216*3117ece4Schristos #define B(name, bit) X(name, f7b, bit) 217*3117ece4Schristos B(bmi1, 3) 218*3117ece4Schristos B(hle, 4) 219*3117ece4Schristos B(avx2, 5) 220*3117ece4Schristos B(smep, 7) 221*3117ece4Schristos B(bmi2, 8) 222*3117ece4Schristos B(erms, 9) 223*3117ece4Schristos B(invpcid, 10) 224*3117ece4Schristos B(rtm, 11) 225*3117ece4Schristos B(mpx, 14) 226*3117ece4Schristos B(avx512f, 16) 227*3117ece4Schristos B(avx512dq, 17) 228*3117ece4Schristos B(rdseed, 18) 229*3117ece4Schristos B(adx, 19) 230*3117ece4Schristos B(smap, 20) 231*3117ece4Schristos B(avx512ifma, 21) 232*3117ece4Schristos B(pcommit, 22) 233*3117ece4Schristos B(clflushopt, 23) 234*3117ece4Schristos B(clwb, 24) 235*3117ece4Schristos B(avx512pf, 26) 236*3117ece4Schristos B(avx512er, 27) 237*3117ece4Schristos B(avx512cd, 28) 238*3117ece4Schristos B(sha, 29) 239*3117ece4Schristos B(avx512bw, 30) 240*3117ece4Schristos B(avx512vl, 31) 241*3117ece4Schristos #undef B 242*3117ece4Schristos #define C(name, bit) X(name, f7c, bit) 243*3117ece4Schristos C(prefetchwt1, 0) 244*3117ece4Schristos C(avx512vbmi, 1) 245*3117ece4Schristos #undef C 246*3117ece4Schristos 247*3117ece4Schristos #undef X 248*3117ece4Schristos 249*3117ece4Schristos #endif /* ZSTD_COMMON_CPU_H */ 250