libFLAC/cpu.c : Refactor disabling SSE into a single function.
[flac.git] / src / libFLAC / cpu.c
1 /* libFLAC - Free Lossless Audio Codec library
2  * Copyright (C) 2001-2009  Josh Coalson
3  * Copyright (C) 2011-2013  Xiph.Org Foundation
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * - Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Xiph.org Foundation nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
36
37 #include "private/cpu.h"
38 #include <stdlib.h>
39 #include <stdio.h>
40
41 #if defined FLAC__CPU_IA32
42 # include <signal.h>
43
44 static void disable_sse(FLAC__CPUInfo *info)
45 {
46         info->ia32.fxsr = info->ia32.sse = info->ia32.sse2 = info->ia32.sse3 = info->ia32.ssse3 = info->ia32.sse41 = info->ia32.sse42 = false;
47 }
48 #elif defined FLAC__CPU_PPC
49 # if !defined FLAC__NO_ASM
50 #  if defined FLAC__SYS_DARWIN
51 #   include <sys/sysctl.h>
52 #   include <mach/mach.h>
53 #   include <mach/mach_host.h>
54 #   include <mach/host_info.h>
55 #   include <mach/machine.h>
56 #   ifndef CPU_SUBTYPE_POWERPC_970
57 #    define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
58 #   endif
59 #  else /* FLAC__SYS_DARWIN */
60
61 #   include <signal.h>
62 #   include <setjmp.h>
63
64 static sigjmp_buf jmpbuf;
65 static volatile sig_atomic_t canjump = 0;
66
67 static void sigill_handler (int sig)
68 {
69         if (!canjump) {
70                 signal (sig, SIG_DFL);
71                 raise (sig);
72         }
73         canjump = 0;
74         siglongjmp (jmpbuf, 1);
75 }
76 #  endif /* FLAC__SYS_DARWIN */
77 # endif /* FLAC__NO_ASM */
78 #endif /* FLAC__CPU_PPC */
79
80 #if defined (__NetBSD__) || defined(__OpenBSD__)
81 #include <sys/param.h>
82 #include <sys/sysctl.h>
83 #include <machine/cpu.h>
84 #endif
85
86 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
87 #include <sys/types.h>
88 #include <sys/sysctl.h>
89 #endif
90
91 #if defined(__APPLE__)
92 /* how to get sysctlbyname()? */
93 #endif
94
95 #ifdef FLAC__CPU_IA32
96 /* these are flags in EDX of CPUID AX=00000001 */
97 static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
98 static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
99 static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
100 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
101 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
102 #endif
103 /* these are flags in ECX of CPUID AX=00000001 */
104 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
105 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
106 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000;
107 static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000;
108 #ifdef FLAC__CPU_IA32
109 /* these are flags in EDX of CPUID AX=80000001 */
110 static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
111 static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
112 static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
113 #endif
114
115 /*
116  * Extra stuff needed for detection of OS support for SSE on IA-32
117  */
118 #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS
119 # if defined(__linux__)
120 /*
121  * If the OS doesn't support SSE, we will get here with a SIGILL.  We
122  * modify the return address to jump over the offending SSE instruction
123  * and also the operation following it that indicates the instruction
124  * executed successfully.  In this way we use no global variables and
125  * stay thread-safe.
126  *
127  * 3 + 3 + 6:
128  *   3 bytes for "xorps xmm0,xmm0"
129  *   3 bytes for estimate of how long the follwing "inc var" instruction is
130  *   6 bytes extra in case our estimate is wrong
131  * 12 bytes puts us in the NOP "landing zone"
132  */
133 #   include <sys/ucontext.h>
134         static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
135         {
136                 (void)signal, (void)si;
137                 ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
138         }
139 # elif defined(_MSC_VER)
140 #  include <windows.h>
141 # endif
142 #endif
143
144
145 void FLAC__cpu_info(FLAC__CPUInfo *info)
146 {
147 /*
148  * IA32-specific
149  */
150 #ifdef FLAC__CPU_IA32
151         info->type = FLAC__CPUINFO_TYPE_IA32;
152 #if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN)
153         info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
154 #ifdef FLAC__HAS_NASM
155         info->ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false;
156 #else
157         info->ia32.cpuid = FLAC__cpu_have_cpuid_x86()? true : false;
158 #endif
159         info->ia32.bswap = info->ia32.cpuid; /* CPUID => BSWAP since it came after */
160         info->ia32.cmov = false;
161         info->ia32.mmx = false;
162         info->ia32.fxsr = false;
163         info->ia32.sse = false;
164         info->ia32.sse2 = false;
165         info->ia32.sse3 = false;
166         info->ia32.ssse3 = false;
167         info->ia32.sse41 = false;
168         info->ia32.sse42 = false;
169         info->ia32._3dnow = false;
170         info->ia32.ext3dnow = false;
171         info->ia32.extmmx = false;
172         if(info->ia32.cpuid) {
173                 /* http://www.sandpile.org/x86/cpuid.htm */
174                 FLAC__uint32 flags_edx, flags_ecx;
175 #ifdef FLAC__HAS_NASM
176                 FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
177 #else
178                 FLAC__cpu_info_x86(&flags_edx, &flags_ecx);
179 #endif
180                 info->ia32.cmov  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
181                 info->ia32.mmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX  )? true : false;
182                 info->ia32.fxsr  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
183                 info->ia32.sse   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE  )? true : false;
184                 info->ia32.sse2  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
185                 info->ia32.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
186                 info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
187                 info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
188                 info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
189
190 #if defined FLAC__HAS_NASM && defined FLAC__USE_3DNOW
191                 flags_edx = FLAC__cpu_info_extended_amd_asm_ia32();
192                 info->ia32._3dnow   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW   )? true : false;
193                 info->ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
194                 info->ia32.extmmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX  )? true : false;
195 #else
196                 info->ia32._3dnow = info->ia32.ext3dnow = info->ia32.extmmx = false;
197 #endif
198
199 #ifdef DEBUG
200                 fprintf(stderr, "CPU info (IA-32):\n");
201                 fprintf(stderr, "  CPUID ...... %c\n", info->ia32.cpuid   ? 'Y' : 'n');
202                 fprintf(stderr, "  BSWAP ...... %c\n", info->ia32.bswap   ? 'Y' : 'n');
203                 fprintf(stderr, "  CMOV ....... %c\n", info->ia32.cmov    ? 'Y' : 'n');
204                 fprintf(stderr, "  MMX ........ %c\n", info->ia32.mmx     ? 'Y' : 'n');
205                 fprintf(stderr, "  FXSR ....... %c\n", info->ia32.fxsr    ? 'Y' : 'n');
206                 fprintf(stderr, "  SSE ........ %c\n", info->ia32.sse     ? 'Y' : 'n');
207                 fprintf(stderr, "  SSE2 ....... %c\n", info->ia32.sse2    ? 'Y' : 'n');
208                 fprintf(stderr, "  SSE3 ....... %c\n", info->ia32.sse3    ? 'Y' : 'n');
209                 fprintf(stderr, "  SSSE3 ...... %c\n", info->ia32.ssse3   ? 'Y' : 'n');
210                 fprintf(stderr, "  SSE41 ...... %c\n", info->ia32.sse41   ? 'Y' : 'n');
211                 fprintf(stderr, "  SSE42 ...... %c\n", info->ia32.sse42   ? 'Y' : 'n');
212                 fprintf(stderr, "  3DNow! ..... %c\n", info->ia32._3dnow  ? 'Y' : 'n');
213                 fprintf(stderr, "  3DNow!-ext . %c\n", info->ia32.ext3dnow? 'Y' : 'n');
214                 fprintf(stderr, "  3DNow!-MMX . %c\n", info->ia32.extmmx  ? 'Y' : 'n');
215 #endif
216
217                 /*
218                  * now have to check for OS support of SSE instructions
219                  */
220                 if(info->ia32.sse) {
221 #if defined FLAC__NO_SSE_OS
222                         /* assume user knows better than us; turn it off */
223                         disable_sse(info);
224 #elif defined FLAC__SSE_OS
225                         /* assume user knows better than us; leave as detected above */
226 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
227                         int sse = 0;
228                         size_t len;
229                         /* at least one of these must work: */
230                         len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
231                         len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse"   , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
232                         if(!sse)
233                                 disable_sse(info);
234 #elif defined(__NetBSD__) || defined (__OpenBSD__)
235 # if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
236                         int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
237                         size_t len = sizeof(val);
238                         if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
239                                 disable_sse(info);
240                         else { /* double-check SSE2 */
241                                 mib[1] = CPU_SSE2;
242                                 len = sizeof(val);
243                                 if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) {
244                                         disable_sse(info);
245                                         info->ia32.fxsr = info->ia32.sse = true;
246                                 }
247                         }
248 # else
249                         disable_sse(info);
250 # endif
251 #elif defined(__linux__)
252                         int sse = 0;
253                         struct sigaction sigill_save;
254                         struct sigaction sigill_sse;
255                         sigill_sse.sa_sigaction = sigill_handler_sse_os;
256                         __sigemptyset(&sigill_sse.sa_mask);
257                         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 */
258                         if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
259                         {
260                                 /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
261                                 /* see sigill_handler_sse_os() for an explanation of the following: */
262                                 asm volatile (
263                                         "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
264                                         "incl %0\n\t"             /* SIGILL handler will jump over this */
265                                         /* landing zone */
266                                         "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
267                                         "nop\n\t"
268                                         "nop\n\t"
269                                         "nop\n\t"
270                                         "nop\n\t"
271                                         "nop\n\t"
272                                         "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
273                                         "nop\n\t"
274                                         "nop"     /* SIGILL jump lands here if "inc" is 1 byte */
275                                         : "=r"(sse)
276                                         : "0"(sse)
277                                 );
278
279                                 sigaction(SIGILL, &sigill_save, NULL);
280                         }
281
282                         if(!sse)
283                                 disable_sse(info);
284 #elif defined(_MSC_VER)
285                         __try {
286                                 __asm {
287                                         xorps xmm0,xmm0
288                                 }
289                         }
290                         __except(EXCEPTION_EXECUTE_HANDLER) {
291                                 if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
292                                         disable_sse(info);
293                         }
294 #elif defined(__GNUC__) /* MinGW goes here */
295                         int sse = 0;
296                         /* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */
297                         /* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */
298                         if (info->ia32.fxsr) {
299                                 struct {
300                                         FLAC__uint32 buff[128];
301                                 } __attribute__((aligned(16))) fxsr;
302                                 FLAC__uint32 old_val, new_val;
303
304                                 asm volatile ("fxsave %0"  : "=m" (fxsr) : "m" (fxsr));
305                                 old_val = fxsr.buff[50];
306                                 fxsr.buff[50] ^= 0x0013c0de;                             /* change value in the buffer */
307                                 asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr));  /* try to change SSE register */
308                                 fxsr.buff[50] = old_val;                                 /* restore old value in the buffer */
309                                 asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr));  /* old value will be overwritten if SSE register was changed */
310                                 new_val = fxsr.buff[50];                                 /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */
311                                 fxsr.buff[50] = old_val;                                 /* again restore old value in the buffer */
312                                 asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr));  /* restore old values of registers */
313
314                                 if ((old_val^new_val) == 0x0013c0de)
315                                         sse = 1;
316                         }
317                         if(!sse)
318                                 disable_sse(info);
319 #else
320                         /* no way to test, disable to be safe */
321                         disable_sse(info);
322 #endif
323 #ifdef DEBUG
324                         fprintf(stderr, "  SSE OS sup . %c\n", info->ia32.sse     ? 'Y' : 'n');
325 #endif
326                 }
327                 else /* info->ia32.sse == false */
328                         disable_sse(info);
329         }
330 #else
331         info->use_asm = false;
332 #endif
333
334 /*
335  * x86-64-specific
336  */
337 #elif defined FLAC__CPU_X86_64
338         info->type = FLAC__CPUINFO_TYPE_X86_64;
339 #if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN
340         info->use_asm = true;
341         {
342                 /* http://www.sandpile.org/x86/cpuid.htm */
343                 FLAC__uint32 flags_edx, flags_ecx;
344                 FLAC__cpu_info_x86(&flags_edx, &flags_ecx);
345                 info->x86_64.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
346                 info->x86_64.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
347                 info->x86_64.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
348                 info->x86_64.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
349         }
350 #ifdef DEBUG
351         fprintf(stderr, "CPU info (x86-64):\n");
352         fprintf(stderr, "  SSE3 ....... %c\n", info->x86_64.sse3    ? 'Y' : 'n');
353         fprintf(stderr, "  SSSE3 ...... %c\n", info->x86_64.ssse3   ? 'Y' : 'n');
354         fprintf(stderr, "  SSE41 ...... %c\n", info->x86_64.sse41   ? 'Y' : 'n');
355         fprintf(stderr, "  SSE42 ...... %c\n", info->x86_64.sse42   ? 'Y' : 'n');
356 #endif
357
358 #else
359         info->use_asm = false;
360 #endif
361
362 /*
363  * PPC-specific
364  */
365 #elif defined FLAC__CPU_PPC
366         info->type = FLAC__CPUINFO_TYPE_PPC;
367 # if !defined FLAC__NO_ASM
368         info->use_asm = true;
369 #  ifdef FLAC__USE_ALTIVEC
370 #   if defined FLAC__SYS_DARWIN
371         {
372                 int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT };
373                 size_t len = sizeof(val);
374                 info->ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val);
375         }
376         {
377                 host_basic_info_data_t hostInfo;
378                 mach_msg_type_number_t infoCount;
379
380                 infoCount = HOST_BASIC_INFO_COUNT;
381                 host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
382
383                 info->ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
384         }
385 #   else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */
386         {
387                 /* no Darwin, do it the brute-force way */
388                 /* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */
389                 info->ppc.altivec = 0;
390                 info->ppc.ppc64 = 0;
391
392                 signal (SIGILL, sigill_handler);
393                 canjump = 0;
394                 if (!sigsetjmp (jmpbuf, 1)) {
395                         canjump = 1;
396
397                         asm volatile (
398                                 "mtspr 256, %0\n\t"
399                                 "vand %%v0, %%v0, %%v0"
400                                 :
401                                 : "r" (-1)
402                         );
403
404                         info->ppc.altivec = 1;
405                 }
406                 canjump = 0;
407                 if (!sigsetjmp (jmpbuf, 1)) {
408                         int x = 0;
409                         canjump = 1;
410
411                         /* PPC64 hardware implements the cntlzd instruction */
412                         asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) );
413
414                         info->ppc.ppc64 = 1;
415                 }
416                 signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */
417         }
418 #   endif
419 #  else /* !FLAC__USE_ALTIVEC */
420         info->ppc.altivec = 0;
421         info->ppc.ppc64 = 0;
422 #  endif
423 # else
424         info->use_asm = false;
425 # endif
426
427 /*
428  * unknown CPU
429  */
430 #else
431         info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
432         info->use_asm = false;
433 #endif
434 }
435
436 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
437
438 #if defined _MSC_VER
439 #include <intrin.h> /* for __cpuid() */
440 #elif defined __GNUC__ && defined HAVE_CPUID_H
441 #include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
442 #endif
443
444 FLAC__uint32 FLAC__cpu_have_cpuid_x86(void)
445 {
446 #ifdef FLAC__CPU_X86_64
447         return 1;
448 #else
449 # if defined _MSC_VER || defined __INTEL_COMPILER /* Do they support CPUs w/o CPUID support (or OSes that work on those CPUs)? */
450         FLAC__uint32 flags1, flags2;
451         __asm {
452                 pushfd
453                 pushfd
454                 pop             eax
455                 mov             flags1, eax
456                 xor             eax, 0x200000
457                 push    eax
458                 popfd
459                 pushfd
460                 pop             eax
461                 mov             flags2, eax
462                 popfd
463         }
464         if (((flags1^flags2) & 0x200000) != 0)
465                 return 1;
466         else
467                 return 0;
468 # elif defined __GNUC__ && defined HAVE_CPUID_H
469         if (__get_cpuid_max(0, 0) != 0)
470                 return 1;
471         else
472                 return 0;
473 # else
474         return 0;
475 # endif
476 #endif
477 }
478
479 void FLAC__cpu_info_x86(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx)
480 {
481 #if defined _MSC_VER || defined __INTEL_COMPILER
482         int cpuinfo[4];
483         __cpuid(cpuinfo, 0);
484         if(cpuinfo[0] < 1) {
485                 *flags_ecx = *flags_edx = 0;
486                 return;
487         }
488         __cpuid(cpuinfo, 1);
489         *flags_ecx = cpuinfo[2];
490         *flags_edx = cpuinfo[3];
491 #elif defined __GNUC__ && defined HAVE_CPUID_H
492         FLAC__uint32 flags_eax, flags_ebx;
493         if (0 == __get_cpuid(1, &flags_eax, &flags_ebx, flags_ecx, flags_edx))
494                 *flags_ecx = *flags_edx = 0;
495 #else
496         *flags_ecx = *flags_edx = 0;
497 #endif
498 }
499
500 #endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */