Bugfix: avoid sub-cent change (lost in fees) whenever possible
[bitcoin.git] / cryptopp / cpu.cpp
blob3e46804212b546d7d998a3901e6d10b1989772b4
1 // cpu.cpp - written and placed in the public domain by Wei Dai
3 #include "pch.h"
5 #ifndef CRYPTOPP_IMPORTS
7 #include "cpu.h"
8 #include "misc.h"
9 #include <algorithm>
11 #ifdef __GNUC__
12 #include <signal.h>
13 #include <setjmp.h>
14 #endif
16 #ifdef CRYPTOPP_MSVC6PP_OR_LATER
17 #include <emmintrin.h>
18 #endif
20 NAMESPACE_BEGIN(CryptoPP)
22 #ifdef CRYPTOPP_X86_ASM_AVAILABLE
24 #ifndef _MSC_VER
25 typedef void (*SigHandler)(int);
27 static jmp_buf s_jmpNoCPUID;
28 static void SigIllHandlerCPUID(int)
30 longjmp(s_jmpNoCPUID, 1);
32 #endif
34 bool CpuId(word32 input, word32 *output)
36 #ifdef _MSC_VER
37 __try
39 __asm
41 mov eax, input
42 cpuid
43 mov edi, output
44 mov [edi], eax
45 mov [edi+4], ebx
46 mov [edi+8], ecx
47 mov [edi+12], edx
50 __except (1)
52 return false;
54 return true;
55 #else
56 SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
57 if (oldHandler == SIG_ERR)
58 return false;
60 bool result = true;
61 if (setjmp(s_jmpNoCPUID))
62 result = false;
63 else
65 __asm__
67 // save ebx in case -fPIC is being used
68 #if CRYPTOPP_BOOL_X86
69 "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
70 #else
71 "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
72 #endif
73 : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
74 : "a" (input)
78 signal(SIGILL, oldHandler);
79 return result;
80 #endif
83 #ifndef _MSC_VER
84 static jmp_buf s_jmpNoSSE2;
85 static void SigIllHandlerSSE2(int)
87 longjmp(s_jmpNoSSE2, 1);
89 #endif
91 #elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
93 bool CpuId(word32 input, word32 *output)
95 __cpuid((int *)output, input);
96 return true;
99 #endif
101 #ifdef CRYPTOPP_CPUID_AVAILABLE
103 static bool TrySSE2()
105 #if CRYPTOPP_BOOL_X64
106 return true;
107 #elif defined(_MSC_VER)
108 __try
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;
115 #endif
117 __except (1)
119 return false;
121 return true;
122 #elif defined(__GNUC__)
123 SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
124 if (oldHandler == SIG_ERR)
125 return false;
127 bool result = true;
128 if (setjmp(s_jmpNoSSE2))
129 result = false;
130 else
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;
137 #endif
140 signal(SIGILL, oldHandler);
141 return result;
142 #else
143 return false;
144 #endif
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))
155 return;
156 if (!CpuId(1, cpuid1))
157 return;
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)
165 g_hasISSE = true;
166 else
168 word32 cpuid2[4];
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;
195 #endif
197 NAMESPACE_END
199 #endif