PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/cpu.c

https://github.com/plasm-language/pyplasm
C | 494 lines | 379 code | 34 blank | 81 comment | 73 complexity | 3083caaf62beb76061958c598aaf5388 MD5 | raw file
  1. /* libFLAC - Free Lossless Audio Codec library
  2. * Copyright (C) 2001-2009 Josh Coalson
  3. * Copyright (C) 2011-2014 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. #ifdef HAVE_CONFIG_H
  33. # include <config.h>
  34. #endif
  35. #include "include/private/cpu.h"
  36. #if 0
  37. #include <stdlib.h>
  38. #include <memory.h>
  39. #include <stdio.h>
  40. #endif
  41. #if defined FLAC__CPU_IA32
  42. # include <signal.h>
  43. static void disable_sse(FLAC__CPUInfo *info)
  44. {
  45. info->ia32.sse = false;
  46. info->ia32.sse2 = false;
  47. info->ia32.sse3 = false;
  48. info->ia32.ssse3 = false;
  49. info->ia32.sse41 = false;
  50. info->ia32.sse42 = false;
  51. }
  52. static void disable_avx(FLAC__CPUInfo *info)
  53. {
  54. info->ia32.avx = false;
  55. info->ia32.avx2 = false;
  56. info->ia32.fma = false;
  57. }
  58. #elif defined FLAC__CPU_X86_64
  59. static void disable_avx(FLAC__CPUInfo *info)
  60. {
  61. info->x86.avx = false;
  62. info->x86.avx2 = false;
  63. info->x86.fma = false;
  64. }
  65. #endif
  66. #if defined (__NetBSD__) || defined(__OpenBSD__)
  67. #include <sys/param.h>
  68. #include <sys/sysctl.h>
  69. #include <machine/cpu.h>
  70. #endif
  71. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  72. #include <sys/types.h>
  73. #include <sys/sysctl.h>
  74. #endif
  75. #if defined(__APPLE__)
  76. /* how to get sysctlbyname()? */
  77. #endif
  78. #ifdef FLAC__CPU_IA32
  79. /* these are flags in EDX of CPUID AX=00000001 */
  80. static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
  81. static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
  82. static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
  83. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
  84. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
  85. #endif
  86. /* these are flags in ECX of CPUID AX=00000001 */
  87. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
  88. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
  89. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000;
  90. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000;
  91. #if defined FLAC__AVX_SUPPORTED
  92. /* these are flags in ECX of CPUID AX=00000001 */
  93. static const unsigned FLAC__CPUINFO_IA32_CPUID_OSXSAVE = 0x08000000;
  94. static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX = 0x10000000;
  95. static const unsigned FLAC__CPUINFO_IA32_CPUID_FMA = 0x00001000;
  96. /* these are flags in EBX of CPUID AX=00000007 */
  97. static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX2 = 0x00000020;
  98. #endif
  99. /*
  100. * Extra stuff needed for detection of OS support for SSE on IA-32
  101. */
  102. #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
  103. # if defined(__linux__)
  104. /*
  105. * If the OS doesn't support SSE, we will get here with a SIGILL. We
  106. * modify the return address to jump over the offending SSE instruction
  107. * and also the operation following it that indicates the instruction
  108. * executed successfully. In this way we use no global variables and
  109. * stay thread-safe.
  110. *
  111. * 3 + 3 + 6:
  112. * 3 bytes for "xorps xmm0,xmm0"
  113. * 3 bytes for estimate of how long the follwing "inc var" instruction is
  114. * 6 bytes extra in case our estimate is wrong
  115. * 12 bytes puts us in the NOP "landing zone"
  116. */
  117. # include <sys/ucontext.h>
  118. static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
  119. {
  120. (void)signal, (void)si;
  121. ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
  122. }
  123. # elif defined(_MSC_VER)
  124. # include <windows.h>
  125. # endif
  126. #endif
  127. void FLAC__cpu_info(FLAC__CPUInfo *info)
  128. {
  129. /*
  130. * IA32-specific
  131. */
  132. #ifdef FLAC__CPU_IA32
  133. FLAC__bool ia32_fxsr = false;
  134. FLAC__bool ia32_osxsave = false;
  135. (void) ia32_fxsr; (void) ia32_osxsave; /* to avoid warnings about unused variables */
  136. memset(info, 0, sizeof(*info));
  137. info->type = FLAC__CPUINFO_TYPE_IA32;
  138. #if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN)
  139. info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
  140. #ifdef FLAC__HAS_X86INTRIN
  141. if(!FLAC__cpu_have_cpuid_x86())
  142. return;
  143. #else
  144. if(!FLAC__cpu_have_cpuid_asm_ia32())
  145. return;
  146. #endif
  147. {
  148. /* http://www.sandpile.org/x86/cpuid.htm */
  149. #ifdef FLAC__HAS_X86INTRIN
  150. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  151. FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  152. #else
  153. FLAC__uint32 flags_ecx, flags_edx;
  154. FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
  155. #endif
  156. info->ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
  157. info->ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false;
  158. ia32_fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
  159. info->ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false;
  160. info->ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
  161. info->ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
  162. info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
  163. info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
  164. info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
  165. #if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED
  166. ia32_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false;
  167. info->ia32.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false;
  168. info->ia32.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false;
  169. FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  170. info->ia32.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false;
  171. #endif
  172. }
  173. #ifdef DEBUG
  174. fprintf(stderr, "CPU info (IA-32):\n");
  175. fprintf(stderr, " CMOV ....... %c\n", info->ia32.cmov ? 'Y' : 'n');
  176. fprintf(stderr, " MMX ........ %c\n", info->ia32.mmx ? 'Y' : 'n');
  177. fprintf(stderr, " SSE ........ %c\n", info->ia32.sse ? 'Y' : 'n');
  178. fprintf(stderr, " SSE2 ....... %c\n", info->ia32.sse2 ? 'Y' : 'n');
  179. fprintf(stderr, " SSE3 ....... %c\n", info->ia32.sse3 ? 'Y' : 'n');
  180. fprintf(stderr, " SSSE3 ...... %c\n", info->ia32.ssse3 ? 'Y' : 'n');
  181. fprintf(stderr, " SSE41 ...... %c\n", info->ia32.sse41 ? 'Y' : 'n');
  182. fprintf(stderr, " SSE42 ...... %c\n", info->ia32.sse42 ? 'Y' : 'n');
  183. # if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED
  184. fprintf(stderr, " AVX ........ %c\n", info->ia32.avx ? 'Y' : 'n');
  185. fprintf(stderr, " FMA ........ %c\n", info->ia32.fma ? 'Y' : 'n');
  186. fprintf(stderr, " AVX2 ....... %c\n", info->ia32.avx2 ? 'Y' : 'n');
  187. # endif
  188. #endif
  189. /*
  190. * now have to check for OS support of SSE instructions
  191. */
  192. if(info->ia32.sse) {
  193. #if defined FLAC__NO_SSE_OS
  194. /* assume user knows better than us; turn it off */
  195. disable_sse(info);
  196. #elif defined FLAC__SSE_OS
  197. /* assume user knows better than us; leave as detected above */
  198. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
  199. int sse = 0;
  200. size_t len;
  201. /* at least one of these must work: */
  202. len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
  203. len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
  204. if(!sse)
  205. disable_sse(info);
  206. #elif defined(__NetBSD__) || defined (__OpenBSD__)
  207. # if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
  208. int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
  209. size_t len = sizeof(val);
  210. if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
  211. disable_sse(info);
  212. else { /* double-check SSE2 */
  213. mib[1] = CPU_SSE2;
  214. len = sizeof(val);
  215. if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) {
  216. disable_sse(info);
  217. info->ia32.sse = true;
  218. }
  219. }
  220. # else
  221. disable_sse(info);
  222. # endif
  223. #elif defined(__linux__)
  224. int sse = 0;
  225. struct sigaction sigill_save;
  226. struct sigaction sigill_sse;
  227. sigill_sse.sa_sigaction = sigill_handler_sse_os;
  228. #ifdef __ANDROID__
  229. sigemptyset (&sigill_sse.sa_mask);
  230. #else
  231. __sigemptyset(&sigill_sse.sa_mask);
  232. #endif
  233. 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 */
  234. if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
  235. {
  236. /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
  237. /* see sigill_handler_sse_os() for an explanation of the following: */
  238. asm volatile (
  239. "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
  240. "incl %0\n\t" /* SIGILL handler will jump over this */
  241. /* landing zone */
  242. "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
  243. "nop\n\t"
  244. "nop\n\t"
  245. "nop\n\t"
  246. "nop\n\t"
  247. "nop\n\t"
  248. "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
  249. "nop\n\t"
  250. "nop" /* SIGILL jump lands here if "inc" is 1 byte */
  251. : "=r"(sse)
  252. : "0"(sse)
  253. );
  254. sigaction(SIGILL, &sigill_save, NULL);
  255. }
  256. if(!sse)
  257. disable_sse(info);
  258. #elif defined(_MSC_VER)
  259. __try {
  260. __asm {
  261. xorps xmm0,xmm0
  262. }
  263. }
  264. __except(EXCEPTION_EXECUTE_HANDLER) {
  265. if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
  266. disable_sse(info);
  267. }
  268. #elif defined(__GNUC__) /* MinGW goes here */
  269. int sse = 0;
  270. /* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */
  271. /* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */
  272. if (ia32_fxsr) {
  273. struct {
  274. FLAC__uint32 buff[128];
  275. } __attribute__((aligned(16))) fxsr;
  276. FLAC__uint32 old_val, new_val;
  277. asm volatile ("fxsave %0" : "=m" (fxsr) : "m" (fxsr));
  278. old_val = fxsr.buff[50];
  279. fxsr.buff[50] ^= 0x0013c0de; /* change value in the buffer */
  280. asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* try to change SSE register */
  281. fxsr.buff[50] = old_val; /* restore old value in the buffer */
  282. asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr)); /* old value will be overwritten if SSE register was changed */
  283. new_val = fxsr.buff[50]; /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */
  284. fxsr.buff[50] = old_val; /* again restore old value in the buffer */
  285. asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* restore old values of registers */
  286. if ((old_val^new_val) == 0x0013c0de)
  287. sse = 1;
  288. }
  289. if(!sse)
  290. disable_sse(info);
  291. #else
  292. /* no way to test, disable to be safe */
  293. disable_sse(info);
  294. #endif
  295. #ifdef DEBUG
  296. fprintf(stderr, " SSE OS sup . %c\n", info->ia32.sse ? 'Y' : 'n');
  297. #endif
  298. }
  299. else /* info->ia32.sse == false */
  300. disable_sse(info);
  301. /*
  302. * now have to check for OS support of AVX instructions
  303. */
  304. if(info->ia32.avx && ia32_osxsave) {
  305. FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86();
  306. if ((ecr & 0x6) != 0x6)
  307. disable_avx(info);
  308. #ifdef DEBUG
  309. fprintf(stderr, " AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n');
  310. #endif
  311. }
  312. else /* no OS AVX support*/
  313. disable_avx(info);
  314. #else
  315. info->use_asm = false;
  316. #endif
  317. /*
  318. * x86-64-specific
  319. */
  320. #elif defined FLAC__CPU_X86_64
  321. FLAC__bool x86_osxsave = false;
  322. (void) x86_osxsave; /* to avoid warnings about unused variables */
  323. memset(info, 0, sizeof(*info));
  324. info->type = FLAC__CPUINFO_TYPE_X86_64;
  325. #if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN
  326. info->use_asm = true;
  327. {
  328. /* http://www.sandpile.org/x86/cpuid.htm */
  329. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  330. FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  331. info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
  332. info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
  333. info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
  334. info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
  335. #if defined FLAC__AVX_SUPPORTED
  336. x86_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false;
  337. info->x86.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false;
  338. info->x86.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false;
  339. FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  340. info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false;
  341. #endif
  342. }
  343. #ifdef DEBUG
  344. fprintf(stderr, "CPU info (x86-64):\n");
  345. fprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n');
  346. fprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
  347. fprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
  348. fprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
  349. # if defined FLAC__AVX_SUPPORTED
  350. fprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n');
  351. fprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n');
  352. fprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n');
  353. # endif
  354. #endif
  355. /*
  356. * now have to check for OS support of AVX instructions
  357. */
  358. if(info->x86.avx && x86_osxsave) {
  359. FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86();
  360. if ((ecr & 0x6) != 0x6)
  361. disable_avx(info);
  362. #ifdef DEBUG
  363. fprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
  364. #endif
  365. }
  366. else /* no OS AVX support*/
  367. disable_avx(info);
  368. #else
  369. info->use_asm = false;
  370. #endif
  371. /*
  372. * unknown CPU
  373. */
  374. #else
  375. info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
  376. info->use_asm = false;
  377. #endif
  378. }
  379. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
  380. #if defined _MSC_VER
  381. #include <intrin.h> /* for __cpuid() and _xgetbv() */
  382. #elif defined __GNUC__ && defined HAVE_CPUID_H
  383. #include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
  384. #endif
  385. FLAC__uint32 FLAC__cpu_have_cpuid_x86(void)
  386. {
  387. #ifdef FLAC__CPU_X86_64
  388. return 1;
  389. #else
  390. # if defined _MSC_VER || defined __INTEL_COMPILER /* Do they support CPUs w/o CPUID support (or OSes that work on those CPUs)? */
  391. FLAC__uint32 flags1, flags2;
  392. __asm {
  393. pushfd
  394. pushfd
  395. pop eax
  396. mov flags1, eax
  397. xor eax, 0x200000
  398. push eax
  399. popfd
  400. pushfd
  401. pop eax
  402. mov flags2, eax
  403. popfd
  404. }
  405. if (((flags1^flags2) & 0x200000) != 0)
  406. return 1;
  407. else
  408. return 0;
  409. # elif defined __GNUC__ && defined HAVE_CPUID_H
  410. if (__get_cpuid_max(0, 0) != 0)
  411. return 1;
  412. else
  413. return 0;
  414. # else
  415. return 0;
  416. # endif
  417. #endif
  418. }
  419. void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
  420. {
  421. (void) level;
  422. #if defined _MSC_VER || defined __INTEL_COMPILER
  423. int cpuinfo[4];
  424. int ext = level & 0x80000000;
  425. __cpuid(cpuinfo, ext);
  426. if((unsigned)cpuinfo[0] < level) {
  427. *eax = *ebx = *ecx = *edx = 0;
  428. return;
  429. }
  430. #if defined FLAC__AVX_SUPPORTED
  431. __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
  432. #else
  433. __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
  434. #endif
  435. *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
  436. #elif defined __GNUC__ && defined HAVE_CPUID_H
  437. FLAC__uint32 ext = level & 0x80000000;
  438. __cpuid(ext, *eax, *ebx, *ecx, *edx);
  439. if (*eax < level) {
  440. *eax = *ebx = *ecx = *edx = 0;
  441. return;
  442. }
  443. __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
  444. #else
  445. *eax = *ebx = *ecx = *edx = 0;
  446. #endif
  447. }
  448. FLAC__uint32 FLAC__cpu_xgetbv_x86(void)
  449. {
  450. #if (defined _MSC_VER || defined __INTEL_COMPILER) && defined FLAC__AVX_SUPPORTED
  451. return (FLAC__uint32)_xgetbv(0);
  452. #elif defined __GNUC__
  453. FLAC__uint32 lo, hi;
  454. asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
  455. return lo;
  456. #else
  457. return 0;
  458. #endif
  459. }
  460. #endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */