1 #ifndef PROCESSOR_SUPPORT_H_
2 #define PROCESSOR_SUPPORT_H_
3 
4 // Utility class ProcessorSupport provides POPCNTenabled() to determine
5 // processor support for POPCNT instruction. It uses CPUID to
6 // retrieve the processor capabilities.
7 // for Intel ICC compiler __cpuid() is an intrinsic
8 // for Microsoft compiler __cpuid() is provided by #include <intrin.h>
9 // for GCC compiler __get_cpuid() is provided by #include <cpuid.h>
10 
11 // Intel compiler defines __GNUC__, so this is needed to disambiguate
12 
13 #if defined(__INTEL_COMPILER)
14 #   define USING_INTEL_COMPILER
15 #elif defined(__GNUC__)
16 #   define USING_GCC_COMPILER
17 #   include <cpuid.h>
18 #elif defined(_MSC_VER)
19 // __MSC_VER defined by Microsoft compiler
20 #define USING MSC_COMPILER
21 #endif
22 
23 struct regs_t {unsigned int EAX, EBX, ECX, EDX;};
24 #define BIT(n) ((1<<n))
25 
26 class ProcessorSupport {
27 
28 #ifdef POPCNT_CAPABILITY
29 
30 public:
ProcessorSupport()31     ProcessorSupport() { }
POPCNTenabled()32     bool POPCNTenabled()
33     {
34     // from: Intel® 64 and IA-32 Architectures Software Developer’s Manual, 325462-036US,March 2013
35     //Before an application attempts to use the POPCNT instruction, it must check that the
36     //processor supports SSE4.2
37     //"(if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT (if CPUID.01H:ECX.POPCNT[bit 23] = 1)"
38     //
39     // see p.272 of http://download.intel.com/products/processor/manual/253667.pdf available at
40     // http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
41     // Also http://en.wikipedia.org/wiki/SSE4 talks about available on Intel & AMD processors
42 
43     regs_t regs;
44 
45     try {
46 #if ( defined(USING_INTEL_COMPILER) || defined(USING_MSC_COMPILER) )
47         __cpuid((int *) &regs,0); // test if __cpuid() works, if not catch the exception
48         __cpuid((int *) &regs,0x1); // POPCNT bit is bit 23 in ECX
49 #elif defined(USING_GCC_COMPILER)
50         __get_cpuid(0x1, &regs.EAX, &regs.EBX, &regs.ECX, &regs.EDX);
51 #else
52         std::cerr << "ERROR: please define __cpuid() for this build.\n";
53         assert(0);
54 #endif
55         if( !( (regs.ECX & BIT(20)) && (regs.ECX & BIT(23)) ) ) return false;
56     }
57     catch (int e) {
58         return false;
59     }
60     return true;
61     }
62 
63 #endif // POPCNT_CAPABILITY
64 };
65 
66 #endif /*PROCESSOR_SUPPORT_H_*/
67