|
|
|
@@ -240,42 +240,7 @@ void FLAC__cpu_info(FLAC__CPUInfo *info) |
|
|
|
disable_sse(info);
|
|
|
|
# endif
|
|
|
|
#elif defined(__linux__)
|
|
|
|
int sse = 0;
|
|
|
|
struct sigaction sigill_save;
|
|
|
|
struct sigaction sigill_sse;
|
|
|
|
sigill_sse.sa_sigaction = sigill_handler_sse_os;
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
sigemptyset (&sigill_sse.sa_mask);
|
|
|
|
#else
|
|
|
|
__sigemptyset(&sigill_sse.sa_mask);
|
|
|
|
#endif
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
/* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
|
|
|
|
/* see sigill_handler_sse_os() for an explanation of the following: */
|
|
|
|
asm volatile (
|
|
|
|
"xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
|
|
|
|
"incl %0\n\t" /* SIGILL handler will jump over this */
|
|
|
|
/* landing zone */
|
|
|
|
"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" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
|
|
|
|
"nop\n\t"
|
|
|
|
"nop" /* SIGILL jump lands here if "inc" is 1 byte */
|
|
|
|
: "=r"(sse)
|
|
|
|
: "0"(sse)
|
|
|
|
);
|
|
|
|
|
|
|
|
sigaction(SIGILL, &sigill_save, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!sse)
|
|
|
|
disable_sse(info);
|
|
|
|
int sse = 1;
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__try {
|
|
|
|
__asm {
|
|
|
|
@@ -287,30 +252,7 @@ void FLAC__cpu_info(FLAC__CPUInfo *info) |
|
|
|
disable_sse(info);
|
|
|
|
}
|
|
|
|
#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) */
|
|
|
|
if (ia32_fxsr) {
|
|
|
|
struct {
|
|
|
|
FLAC__uint32 buff[128];
|
|
|
|
} __attribute__((aligned(16))) fxsr;
|
|
|
|
FLAC__uint32 old_val, new_val;
|
|
|
|
|
|
|
|
asm volatile ("fxsave %0" : "=m" (fxsr) : "m" (fxsr));
|
|
|
|
old_val = fxsr.buff[50];
|
|
|
|
fxsr.buff[50] ^= 0x0013c0de; /* change value in the buffer */
|
|
|
|
asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* try to change SSE register */
|
|
|
|
fxsr.buff[50] = old_val; /* restore old value in the buffer */
|
|
|
|
asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr)); /* old value will be overwritten if SSE register was changed */
|
|
|
|
new_val = fxsr.buff[50]; /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */
|
|
|
|
fxsr.buff[50] = old_val; /* again restore old value in the buffer */
|
|
|
|
asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* restore old values of registers */
|
|
|
|
|
|
|
|
if ((old_val^new_val) == 0x0013c0de)
|
|
|
|
sse = 1;
|
|
|
|
}
|
|
|
|
if(!sse)
|
|
|
|
disable_sse(info);
|
|
|
|
int sse = 1;
|
|
|
|
#else
|
|
|
|
/* no way to test, disable to be safe */
|
|
|
|
disable_sse(info);
|
|
|
|
|