Skip to content

Commit

Permalink
libFLAC/cpu.c : Simplify OS SSE support detection.
Browse files Browse the repository at this point in the history
Simplify the code that tries to detect whether OS supports SSE instructions.

a) Linux: "old" vs "new" sigaction

OBSOLETE_SIGCONTEXT_FLAVOR was disabled in Mar 2007 in commit 1ca3a44.
According to <http://unixhelp.ed.ac.uk/CGI/man-cgi?sigaction>: "Support for
SA_SIGINFO was added in Linux 2.2" (released in Jan 1999). If noone wants to
use FLAC with Linux kernel 2.0 then it's safe to delete this code.

b) MSVC: try/catch vs. sigill_handler

TRY_CATCH_FLAVOR was enabled in Jan 2009 in commit a832ef3. According to the
comment in cpu.c, "sigill_handler flavor resulted in several crash reports on
win32". Also this sigill_handler flavor is not thread-safe.

c) MinGW: fxsave/fxrestore vs. sigill_handler

The code was added Mar 2014 in commit 99d5154. It's better to use FXSR flavor
instead of sigill_handler flavor. The reasons are the same as for MSVC.

Patch-from: lvqcl <lvqcl.mail@gmail.com>
  • Loading branch information
erikd committed Jul 28, 2014
1 parent 02591f6 commit 6a28fac
Showing 1 changed file with 1 addition and 93 deletions.
94 changes: 1 addition & 93 deletions src/libFLAC/cpu.c
Expand Up @@ -125,52 +125,14 @@ static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
* 6 bytes extra in case our estimate is wrong
* 12 bytes puts us in the NOP "landing zone"
*/
# undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */
# ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
static void sigill_handler_sse_os(int signal, struct sigcontext sc)
{
(void)signal;
sc.eip += 3 + 3 + 6;
}
# else
# include <sys/ucontext.h>
static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
{
(void)signal, (void)si;
((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
}
# endif
# elif defined(_MSC_VER)
# include <windows.h>
# define USE_TRY_CATCH_FLAVOR /* sigill_handler flavor resulted in several crash reports on win32 */
# ifdef USE_TRY_CATCH_FLAVOR
# else
LONG WINAPI sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
{
if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
ep->ContextRecord->Eip += 3 + 3 + 6;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
# endif
# elif defined(_WIN32) && defined(__GNUC__)
# undef USE_FXSR_FLAVOR
# ifdef USE_FXSR_FLAVOR
/* not guaranteed to work on some unknown future Intel CPUs */
# else
/* exception handler is process-wide; not good for a library */
# include <windows.h>
LONG WINAPI sigill_handler_sse_os(EXCEPTION_POINTERS *ep); /* to suppress GCC warning */
LONG WINAPI sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
{
if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
ep->ContextRecord->Eip += 3 + 3 + 6;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
# endif
# endif
#endif

Expand Down Expand Up @@ -282,15 +244,11 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
#elif defined(__linux__)
int sse = 0;
struct sigaction sigill_save;
#ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR)
#else
struct sigaction sigill_sse;
sigill_sse.sa_sigaction = sigill_handler_sse_os;
__sigemptyset(&sigill_sse.sa_mask);
sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */
if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
#endif
{
/* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
/* see sigill_handler_sse_os() for an explanation of the following: */
Expand All @@ -317,7 +275,6 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
if(!sse)
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
#elif defined(_MSC_VER)
# ifdef USE_TRY_CATCH_FLAVOR
__try {
__asm {
xorps xmm0,xmm0
Expand All @@ -327,33 +284,7 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
}
# else
int sse = 0;
/* From MSDN: SetUnhandledExceptionFilter replaces the existing top-level exception filter for all threads in the calling process */
/* So sigill_handler_sse_os() is process-wide and affects other threads as well (not a good thing for a library in a multi-threaded process) */
LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
/* see GCC version above for explanation */
/* http://msdn.microsoft.com/en-us/library/4ks26t93.aspx */
/* http://www.codeproject.com/Articles/5267/Inline-Assembly-in-GCC-Vs-VC */
__asm {
xorps xmm0,xmm0
inc sse
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
SetUnhandledExceptionFilter(save);
if(!sse)
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
# endif
#elif defined(_WIN32) && defined(__GNUC__)
# ifdef USE_FXSR_FLAVOR
#elif defined(__GNUC__) /* MinGW goes here */
int sse = 0;
/* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */
/* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */
Expand All @@ -378,29 +309,6 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
}
if(!sse)
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
# else
int sse = 0;
LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
/* see MSVC version above for explanation */
asm volatile (
"xorps %%xmm0,%%xmm0\n\t"
"incl %0\n\t"
"nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop" /* SIGILL jump lands here if "inc" is 1 byte */
: "=r"(sse)
: "0"(sse)
);
SetUnhandledExceptionFilter(save);
if(!sse)
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
# endif
#else
/* no way to test, disable to be safe */
info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
Expand Down

0 comments on commit 6a28fac

Please sign in to comment.