1 // cpu.cpp - written and placed in the public domain by Wei Dai
5 #ifndef CRYPTOPP_IMPORTS
16 #ifdef CRYPTOPP_MSVC6PP_OR_LATER
17 #include <emmintrin.h>
20 NAMESPACE_BEGIN(CryptoPP)
22 #ifdef CRYPTOPP_X86_ASM_AVAILABLE
25 typedef void (*SigHandler)(int);
27 static jmp_buf s_jmpNoCPUID;
28 static void SigIllHandlerCPUID(int)
30 longjmp(s_jmpNoCPUID, 1);
34 bool CpuId(word32 input, word32 *output)
56 SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
57 if (oldHandler == SIG_ERR)
61 if (setjmp(s_jmpNoCPUID))
67 // save ebx in case -fPIC is being used
69 "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
71 "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
73 : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
78 signal(SIGILL, oldHandler);
84 static jmp_buf s_jmpNoSSE2;
85 static void SigIllHandlerSSE2(int)
87 longjmp(s_jmpNoSSE2, 1);
91 #elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
93 bool CpuId(word32 input, word32 *output)
95 __cpuid((int *)output, input);
101 #ifdef CRYPTOPP_CPUID_AVAILABLE
103 static bool TrySSE2()
105 #if CRYPTOPP_BOOL_X64
107 #elif defined(_MSC_VER)
110 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
111 AS2(por xmm0, xmm0) // executing SSE2 instruction
112 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
113 __mm128i x = _mm_setzero_si128();
114 return _mm_cvtsi128_si32(x) == 0;
122 #elif defined(__GNUC__)
123 SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
124 if (oldHandler == SIG_ERR)
128 if (setjmp(s_jmpNoSSE2))
132 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
133 __asm __volatile ("por %xmm0, %xmm0");
134 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
135 __mm128i x = _mm_setzero_si128();
136 result = _mm_cvtsi128_si32(x) == 0;
140 signal(SIGILL, oldHandler);
147 bool g_x86DetectionDone = false;
148 bool g_hasISSE = false, g_hasSSE2 = false, g_hasSSSE3 = false, g_hasMMX = false, g_isP4 = false;
149 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
151 void DetectX86Features()
153 word32 cpuid[4], cpuid1[4];
154 if (!CpuId(0, cpuid))
156 if (!CpuId(1, cpuid1))
159 g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
160 if ((cpuid1[3] & (1 << 26)) != 0)
161 g_hasSSE2 = TrySSE2();
162 g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
164 if ((cpuid1[3] & (1 << 25)) != 0)
169 CpuId(0x080000000, cpuid2);
170 if (cpuid2[0] >= 0x080000001)
172 CpuId(0x080000001, cpuid2);
173 g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
177 std::swap(cpuid[2], cpuid[3]);
178 if (memcmp(cpuid+1, "GenuineIntel", 12) == 0)
180 g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
181 g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
183 else if (memcmp(cpuid+1, "AuthenticAMD", 12) == 0)
185 CpuId(0x80000005, cpuid);
186 g_cacheLineSize = GETBYTE(cpuid[2], 0);
189 if (!g_cacheLineSize)
190 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
192 g_x86DetectionDone = true;