1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2019-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 /**
10  *  This file provides portable implementation of CPUID functions:
11  *
12  *  void __cpuid(int info[4], int function_id);
13  *  void __cpuidex(int info[4], int function_id, int subfunction_id);
14  *  int __get_cpuid(unsigned level, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx);
15  */
16 
17 #ifndef UFO_PORTABLE_CPUID_H
18 #define UFO_PORTABLE_CPUID_H
19 
20 #if defined(_MSC_VER) || defined(_WIN32)
21 
22     #if defined (_WIN64) && defined (_In_)
23         // NOTE: <math.h> is not necessary here.
24         // This is only an ugly workaround for a VS2008 bug that causes the compilation
25         // issue on 64-bit DEBUG configuration.
26         // Including "math.h" before "intrin.h" helps to get rid of the following warning:
27         // warning C4985: 'ceil': attributes not present on previous declaration.
28         #include <math.h>
29         #include <smmintrin.h>
30     #else
31         #include <intrin.h>
32     #endif
33 
34     #if (_MSC_VER >= 1500)
35         #pragma intrinsic (__cpuid)
36     #endif
37 
38     #if defined(__cplusplus) && (_MSC_VER >= 1900)
39         // __get_cpuid as lambda
40         #define __get_cpuid(_level, _peax, _pebx, _pecx, _pedx) \
41             [](unsigned level, unsigned *peax, unsigned *pebx, unsigned *pecx, unsigned *pedx) { \
42                 int tmp[4] = { 0 }; \
43                 __cpuid(tmp, level); \
44                 *(peax) = static_cast<unsigned>(tmp[0]); \
45                 *(pebx) = static_cast<unsigned>(tmp[1]); \
46                 *(pecx) = static_cast<unsigned>(tmp[2]); \
47                 *(pedx) = static_cast<unsigned>(tmp[3]); \
48                 return 1; \
49             } (_level, _peax, _pebx, _pecx, _pedx)
50     #else
51         static __forceinline
__get_cpuid(unsigned level,unsigned * peax,unsigned * pebx,unsigned * pecx,unsigned * pedx)52         int __get_cpuid(unsigned level, unsigned *peax, unsigned *pebx, unsigned *pecx, unsigned *pedx)
53         {
54             int tmp[4] = { 0 };
55             __cpuid(tmp, level);
56             *(peax) = (unsigned)tmp[0];
57             *(pebx) = (unsigned)tmp[1];
58             *(pecx) = (unsigned)tmp[2];
59             *(pedx) = (unsigned)tmp[3];
60             return 1;
61         }
62     #endif
63 
64 #elif defined (__GNUC__) || defined(__clang__)
65 
66     #include <cpuid.h>
67     #undef __cpuid // drop internal definition from cpuid.h
68 
69     #define __cpuid(info, function) \
70         (void)__get_cpuid((function), \
71                           (unsigned *)(info)+0, (unsigned *)(info)+1, \
72                           (unsigned *)(info)+2, (unsigned *)(info)+3)
73 
74     #define __cpuidex(info, function, sub_function) \
75         do { \
76             __cpuid_count((function), (sub_function), (info)[0], (info)[1], (info)[2], (info)[3]); \
77         } while(0)
78 #else
79 
80     #error "FIXME unknown compiler"
81 
82 #endif
83 
84 #endif /* UFO_PORTABLE_CPUID_H */
85