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;