1 // sse_simd.cpp - written and placed in the public domain by
2 // Jeffrey Walton, Uri Blumenthal and Marcel Raad.
3 //
4 // This source file uses intrinsics to gain access to SSE for CPU
5 // feature testing. A separate source file is needed because additional
6 // CXXFLAGS are required to enable the appropriate instructions set in
7 // some build configurations.
8
9 #include "pch.h"
10 #include "config.h"
11 #include "cpu.h"
12
13 // Needed by MIPS for definition of NULL
14 #include "stdcpp.h"
15
16 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
17 # include <signal.h>
18 # include <setjmp.h>
19 #endif
20
21 #ifndef EXCEPTION_EXECUTE_HANDLER
22 # define EXCEPTION_EXECUTE_HANDLER 1
23 #endif
24
25 // Needed by SunCC and MSVC
26 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
27 # if !defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) && !CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_SSE2_INTRIN_AVAILABLE
28 # include <emmintrin.h>
29 # endif
30 #endif
31
32 // Squash MS LNK4221 and libtool warnings
33 extern const char SSE_SIMD_FNAME[] = __FILE__;
34
NAMESPACE_BEGIN(CryptoPP)35 NAMESPACE_BEGIN(CryptoPP)
36
37 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
38 extern "C" {
39 typedef void (*SigHandler)(int);
40 }
41
42 extern "C"
43 {
44 static jmp_buf s_jmpNoSSE2;
SigIllHandler(int)45 static void SigIllHandler(int)
46 {
47 longjmp(s_jmpNoSSE2, 1);
48 }
49 }
50 #endif // CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
51
CPU_ProbeSSE2()52 bool CPU_ProbeSSE2()
53 {
54 // Apple switched to Intel desktops in 2005/2006 using
55 // Core2 Duo's, which provides SSE2 and above.
56 #if CRYPTOPP_BOOL_X64 || defined(__APPLE__)
57 return true;
58 #elif defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
59 return false;
60 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
61 __try
62 {
63 # if CRYPTOPP_SSE2_ASM_AVAILABLE
64 AS2(por xmm0, xmm0) // executing SSE2 instruction
65 # elif CRYPTOPP_SSE2_INTRIN_AVAILABLE
66 __m128i x = _mm_setzero_si128();
67 return _mm_cvtsi128_si32(x) == 0;
68 # endif
69 }
70 // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
71 __except (EXCEPTION_EXECUTE_HANDLER)
72 {
73 return false;
74 }
75 return true;
76 #else
77 // longjmp and clobber warnings. Volatile is required.
78 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
79 volatile bool result = true;
80
81 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
82 if (oldHandler == SIG_ERR)
83 return false;
84
85 # ifndef __MINGW32__
86 volatile sigset_t oldMask;
87 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
88 {
89 signal(SIGILL, oldHandler);
90 return false;
91 }
92 # endif
93
94 if (setjmp(s_jmpNoSSE2))
95 result = false;
96 else
97 {
98 # if CRYPTOPP_SSE2_ASM_AVAILABLE
99 __asm __volatile ("por %xmm0, %xmm0");
100 # elif CRYPTOPP_SSE2_INTRIN_AVAILABLE
101 __m128i x = _mm_setzero_si128();
102 result = _mm_cvtsi128_si32(x) == 0;
103 # endif
104 }
105
106 # ifndef __MINGW32__
107 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
108 # endif
109
110 signal(SIGILL, oldHandler);
111 return result;
112 #endif
113 }
114
115 NAMESPACE_END
116