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