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