A set of windows utf8 patches fromJanne Hyvärinen <cse@sci.fi>.
[platform/upstream/flac.git] / src / libFLAC / cpu.c
index 2ead063..47f5d58 100644 (file)
@@ -1,5 +1,5 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009  Josh Coalson
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -86,15 +86,19 @@ static void sigill_handler (int sig)
 /* how to get sysctlbyname()? */
 #endif
 
-const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
-
-const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
-const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
+/* these are flags in EDX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
+/* these are flags in ECX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
+/* these are flags in EDX of CPUID AX=80000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
 
 
 /*
@@ -132,7 +136,7 @@ const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
 #  endif
 # elif defined(_MSC_VER)
 #  include <windows.h>
-#  undef USE_TRY_CATCH_FLAVOR /* #define this to use the try/catch method for catching illegal opcode exception */
+#  define USE_TRY_CATCH_FLAVOR /* sigill_handler flavor resulted in several crash reports on win32 */
 #  ifdef USE_TRY_CATCH_FLAVOR
 #  else
        LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
@@ -156,31 +160,63 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
 #ifdef FLAC__CPU_IA32
        info->type = FLAC__CPUINFO_TYPE_IA32;
 #if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
-       info->use_asm = true;
-       {
-               unsigned cpuid = FLAC__cpu_info_asm_ia32();
-               info->data.ia32.cmov = (cpuid & FLAC__CPUINFO_IA32_CPUID_CMOV)? true : false;
-               info->data.ia32.mmx  = (cpuid & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false;
-               info->data.ia32.fxsr = (cpuid & FLAC__CPUINFO_IA32_CPUID_FXSR)? true : false;
-               info->data.ia32.sse  = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false;
-               info->data.ia32.sse2 = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE2)? true : false;
+       info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
+       info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false;
+       info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */
+       info->data.ia32.cmov = false;
+       info->data.ia32.mmx = false;
+       info->data.ia32.fxsr = false;
+       info->data.ia32.sse = false;
+       info->data.ia32.sse2 = false;
+       info->data.ia32.sse3 = false;
+       info->data.ia32.ssse3 = false;
+       info->data.ia32._3dnow = false;
+       info->data.ia32.ext3dnow = false;
+       info->data.ia32.extmmx = false;
+       if(info->data.ia32.cpuid) {
+               /* http://www.sandpile.org/ia32/cpuid.htm */
+               FLAC__uint32 flags_edx, flags_ecx;
+               FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
+               info->data.ia32.cmov  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
+               info->data.ia32.mmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX  )? true : false;
+               info->data.ia32.fxsr  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
+               info->data.ia32.sse   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE  )? true : false;
+               info->data.ia32.sse2  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
+               info->data.ia32.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
+               info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
 
 #ifdef FLAC__USE_3DNOW
-               cpuid = FLAC__cpu_info_extended_amd_asm_ia32();
-               info->data.ia32._3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW)? true : false;
-               info->data.ia32.ext3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
-               info->data.ia32.extmmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX)? true : false;
+               flags_edx = FLAC__cpu_info_extended_amd_asm_ia32();
+               info->data.ia32._3dnow   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW   )? true : false;
+               info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
+               info->data.ia32.extmmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX  )? true : false;
 #else
                info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
 #endif
 
+#ifdef DEBUG
+               fprintf(stderr, "CPU info (IA-32):\n");
+               fprintf(stderr, "  CPUID ...... %c\n", info->data.ia32.cpuid   ? 'Y' : 'n');
+               fprintf(stderr, "  BSWAP ...... %c\n", info->data.ia32.bswap   ? 'Y' : 'n');
+               fprintf(stderr, "  CMOV ....... %c\n", info->data.ia32.cmov    ? 'Y' : 'n');
+               fprintf(stderr, "  MMX ........ %c\n", info->data.ia32.mmx     ? 'Y' : 'n');
+               fprintf(stderr, "  FXSR ....... %c\n", info->data.ia32.fxsr    ? 'Y' : 'n');
+               fprintf(stderr, "  SSE ........ %c\n", info->data.ia32.sse     ? 'Y' : 'n');
+               fprintf(stderr, "  SSE2 ....... %c\n", info->data.ia32.sse2    ? 'Y' : 'n');
+               fprintf(stderr, "  SSE3 ....... %c\n", info->data.ia32.sse3    ? 'Y' : 'n');
+               fprintf(stderr, "  SSSE3 ...... %c\n", info->data.ia32.ssse3   ? 'Y' : 'n');
+               fprintf(stderr, "  3DNow! ..... %c\n", info->data.ia32._3dnow  ? 'Y' : 'n');
+               fprintf(stderr, "  3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n');
+               fprintf(stderr, "  3DNow!-MMX . %c\n", info->data.ia32.extmmx  ? 'Y' : 'n');
+#endif
+
                /*
                 * now have to check for OS support of SSE/SSE2
                 */
                if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) {
 #if defined FLAC__NO_SSE_OS
                        /* assume user knows better than us; turn it off */
-                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
 #elif defined FLAC__SSE_OS
                        /* assume user knows better than us; leave as detected above */
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
@@ -190,21 +226,21 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
                        len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
                        len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse"   , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
                        if(!sse)
-                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
 #elif defined(__NetBSD__) || defined (__OpenBSD__)
 # if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
                        int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
                        size_t len = sizeof(val);
                        if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
-                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
                        else { /* double-check SSE2 */
                                mib[1] = CPU_SSE2;
                                len = sizeof(val);
                                if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
-                                       info->data.ia32.sse2 = false;
+                                       info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
                        }
 # else
-                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
 # endif
 #elif defined(__linux__)
                        int sse = 0;
@@ -243,7 +279,7 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
                        }
 
                        if(!sse)
-                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
 #elif defined(_MSC_VER)
 # ifdef USE_TRY_CATCH_FLAVOR
                        _try {
@@ -260,16 +296,15 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
                        }
                        _except(EXCEPTION_EXECUTE_HANDLER) {
                                if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
-                                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
                        }
 # else
                        int sse = 0;
                        LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
                        /* see GCC version above for explanation */
-                       //@@@@@@ http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx
-                       //@@@@@@ http://www.daniweb.com/techtalkforums/thread8072.html
-                       //@@@@@@ http://www.codeproject.com/cpp/gccasm.asp
-                       //@@@@@@ http://www.hick.org/~mmiller/msvc_inline_asm.html
+                       /*  http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx */
+                       /*  http://www.codeproject.com/cpp/gccasm.asp */
+                       /*  http://www.hick.org/~mmiller/msvc_inline_asm.html */
                        __asm {
 #  if _MSC_VER <= 1200
                                /* VC6 assembler doesn't know SSE, have to emit bytecode instead */
@@ -292,13 +327,16 @@ void FLAC__cpu_info(FLAC__CPUInfo *info)
                        }
                        SetUnhandledExceptionFilter(save);
                        if(!sse)
-                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
-fprintf(stderr,"\n@@@@@@ SSE OS=%d %d\n",sse?1:0,sse);
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
 # endif
 #else
                        /* no way to test, disable to be safe */
-                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#endif
+#ifdef DEBUG
+               fprintf(stderr, "  SSE OS sup . %c\n", info->data.ia32.sse     ? 'Y' : 'n');
 #endif
+
                }
        }
 #else