source: trunk/lib/x86_CPU_detect.h @ 2145

Last change on this file since 2145 was 413, checked in by cameron, 9 years ago

Fix _M_X64 for Win64

File size: 4.9 KB
Line 
1/*  x86_CPU_detect.h:  Run-Time Detection of x86 and x86_64 SIMD features.
2 
3    Copyright (C) 2010, Robert D. Cameron
4    Licensed under Academic Free License version 3.0.
5
6    You may freely #include this file in software that is public
7    domain or licensed under any open source or other license.
8
9    This file defines the following functions which perform
10    runtime tests to see if particular SIMD or other acceleration
11    features are supported on x86 and x86-64 architectures.
12    The functions return 0 if a feature is not supported, a nonzero value,
13    otherwise.
14
15    CPU_has_MMX()
16    CPU_has_SSE()
17    CPU_has_SSE2()
18    CPU_has_SSE3()
19    CPU_has_SSSE3()
20    CPU_has_SSE41()
21    CPU_has_SSE42()
22    CPU_has_AVX()
23    CPU_has_POPCOUNT()
24
25    The CPUID instruction is used to determine these features,
26    taking advantage of the appropriate __cpuid compiler intrinsic
27    available with GCC and MSVC compilers.
28
29    Principal objective:  Dynamic detection of SIMD processor
30    capabilities is required when software is to be compiled
31    to produce a binary that is compatible with a range of
32    processors, including:
33     (a) some processors with no SIMD capabilities,
34     (b) some processors with a particular restricted subset
35         of SIMD capabilities (e.g., SSE but not SSE2), and
36     (c) some processors with the full set of desired SIMD
37         capabilities.
38
39    Compilation note:  The detection code must run successfully on
40    processors having no SIMD capabilities.  Therefore, this module must
41    be compiled without any compiler flags such as -msse2 or the like.
42*/
43
44#ifndef X86_CPU_DETECT_H
45#define X86_CPU_DETECT_H
46
47/*  These routines are for the Intel/AMD x86 (32-bit) and x86-64 (64-bit)
48    architectures.  Ensure that we are compiling for one of these
49    architectures.  Define common macros x86_32 and x86_64 based on
50    known compiler-specific macros for these architectures.
51    See http://predef.sourceforge.net/prearch.html
52*/
53
54#if defined(__x86_64__) || defined(_M_X64)
55#define x86_64 1
56#elif defined(__i386__) || defined(_M_IX86) || defined(__i386) || defined(__THW_INTEL__)
57#define x86_32 1
58#endif
59
60#if defined(x86_32) || defined(x86_64)
61
62enum CPUid_reg {
63  reg_eax = 0, 
64  reg_ebx = 1, 
65  reg_ecx = 2, 
66  reg_edx = 3
67};
68
69#ifdef _MSC_VER
70#include <intrin.h>
71static inline int check_CPUid1_feature(enum CPUid_reg reg, int CPUid_bit) {
72  int CPUinfo[4];
73  __cpuid(CPUinfo, 1);
74  return CPUinfo[reg] & CPUid_bit;
75}
76#endif
77
78#ifdef __GNUC__
79#include <cpuid.h>
80static inline int check_CPUid1_feature(enum CPUid_reg reg, int CPUid_bit) {
81  unsigned int CPUinfo[4];
82  if (__get_cpuid(1, &CPUinfo[reg_eax], &CPUinfo[reg_ebx], &CPUinfo[reg_ecx], &CPUinfo[reg_edx]))
83    return CPUinfo[reg] & CPUid_bit;
84  else return 0;
85}
86#endif
87
88
89#define MMX_CPUid_feature_register reg_edx
90#define MMX_CPUid_feature_bit (1 << 23)
91
92#define SSE_CPUid_feature_register reg_edx
93#define SSE_CPUid_feature_bit (1 << 25)
94
95#define SSE2_CPUid_feature_register reg_edx
96#define SSE2_CPUid_feature_bit (1 << 26)
97
98#define SSE3_CPUid_feature_register reg_ecx
99#define SSE3_CPUid_feature_bit (1 << 0)
100
101#define SSSE3_CPUid_feature_register reg_ecx
102#define SSSE3_CPUid_feature_bit (1 << 9)
103
104#define SSE41_CPUid_feature_register reg_ecx
105#define SSE41_CPUid_feature_bit (1 << 19)
106
107#define SSE42_CPUid_feature_register reg_ecx
108#define SSE42_CPUid_feature_bit (1 << 20)
109
110#define AVX_CPUid_feature_register reg_ecx
111#define AVX_CPUid_feature_bit (1 << 28)
112
113#define POPCOUNT_CPUid_feature_register reg_ecx
114#define POPCOUNT_CPUid_feature_bit (1 << 23)
115
116
117static inline int CPU_has_MMX() {
118#ifdef x86_64
119  return MMX_CPUid_feature_bit;  /*  MMX always available on x86_64 */
120#else
121  return check_CPUid1_feature(MMX_CPUid_feature_register, MMX_CPUid_feature_bit);
122#endif
123}
124static inline int CPU_has_SSE() {
125#ifdef x86_64
126  return SSE_CPUid_feature_bit;  /*  SSE always available on x86_64 */
127#else
128  return check_CPUid1_feature(SSE_CPUid_feature_register, SSE_CPUid_feature_bit);
129#endif
130}
131static inline int CPU_has_SSE2() {
132#ifdef x86_64
133  return SSE2_CPUid_feature_bit;  /*  SSE2 always available on x86_64 */
134#else
135  return check_CPUid1_feature(SSE2_CPUid_feature_register, SSE2_CPUid_feature_bit);
136#endif
137}
138
139static inline int CPU_has_SSE3() {
140  return check_CPUid1_feature(SSE3_CPUid_feature_register, SSE3_CPUid_feature_bit);
141}
142
143static inline int CPU_has_SSSE3() {
144  return check_CPUid1_feature(SSSE3_CPUid_feature_register, SSSE3_CPUid_feature_bit);
145}
146
147static inline int CPU_has_SSE41() {
148  return check_CPUid1_feature(SSE41_CPUid_feature_register, SSE41_CPUid_feature_bit);
149}
150
151static inline int CPU_has_SSE42() {
152  return check_CPUid1_feature(SSE42_CPUid_feature_register, SSE42_CPUid_feature_bit);
153}
154
155static inline int CPU_has_AVX() {
156  return check_CPUid1_feature(AVX_CPUid_feature_register, AVX_CPUid_feature_bit);
157}
158
159static inline int CPU_has_POPCOUNT() {
160  return check_CPUid1_feature(POPCOUNT_CPUid_feature_register, POPCOUNT_CPUid_feature_bit);
161}
162
163#endif
164#endif
Note: See TracBrowser for help on using the repository browser.