1 /* libFLAC - Free Lossless Audio Codec library
2 * Copyright (C) 2001-2009 Josh Coalson
3 * Copyright (C) 2011-2016 Xiph.Org Foundation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
37 #include "private/cpu.h"
38 #include "share/compat.h"
43 #include <intrin.h> /* for __cpuid() and _xgetbv() */
44 #elif defined __GNUC__ && defined HAVE_CPUID_H
45 #include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
50 #define dfprintf fprintf
52 /* This is bad practice, it should be a static void empty function */
53 #define dfprintf(file, format, ...)
56 #if defined FLAC__CPU_PPC
60 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
62 /* these are flags in EDX of CPUID AX=00000001 */
63 static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV
= 0x00008000;
64 static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX
= 0x00800000;
65 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE
= 0x02000000;
66 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2
= 0x04000000;
68 /* these are flags in ECX of CPUID AX=00000001 */
69 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3
= 0x00000001;
70 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3
= 0x00000200;
71 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41
= 0x00080000;
72 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42
= 0x00100000;
73 static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE
= 0x08000000;
74 static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX
= 0x10000000;
75 static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA
= 0x00001000;
77 /* these are flags in EBX of CPUID AX=00000007 */
78 static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2
= 0x00000020;
83 #if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
84 return (uint32_t)_xgetbv(0);
85 #elif defined __GNUC__
87 __asm__
volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo
), "=d"(hi
) : "c" (0));
97 #if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
98 /* target CPU does have CPUID instruction */
100 #elif defined FLAC__HAS_NASM
101 return FLAC__cpu_have_cpuid_asm_ia32();
102 #elif defined __GNUC__ && defined HAVE_CPUID_H
103 if (__get_cpuid_max(0, 0) != 0)
107 #elif defined _MSC_VER
108 FLAC__uint32 flags1
, flags2
;
122 if (((flags1
^flags2
) & 0x200000) != 0)
132 cpuinfo_x86(FLAC__uint32 level
, FLAC__uint32
*eax
, FLAC__uint32
*ebx
, FLAC__uint32
*ecx
, FLAC__uint32
*edx
)
136 int ext
= level
& 0x80000000;
137 __cpuid(cpuinfo
, ext
);
138 if ((uint32_t)cpuinfo
[0] >= level
) {
139 #if FLAC__AVX_SUPPORTED
140 __cpuidex(cpuinfo
, level
, 0); /* for AVX2 detection */
142 __cpuid(cpuinfo
, level
); /* some old compilers don't support __cpuidex */
144 *eax
= cpuinfo
[0]; *ebx
= cpuinfo
[1]; *ecx
= cpuinfo
[2]; *edx
= cpuinfo
[3];
147 #elif defined __GNUC__ && defined HAVE_CPUID_H
148 FLAC__uint32 ext
= level
& 0x80000000;
149 __cpuid(ext
, *eax
, *ebx
, *ecx
, *edx
);
151 __cpuid_count(level
, 0, *eax
, *ebx
, *ecx
, *edx
);
154 #elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32
155 FLAC__cpu_info_asm_ia32(level
, eax
, ebx
, ecx
, edx
);
158 *eax
= *ebx
= *ecx
= *edx
= 0;
164 x86_cpu_info (FLAC__CPUInfo
*info
)
166 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
167 FLAC__bool x86_osxsave
= false;
168 FLAC__bool os_avx
= false;
169 FLAC__uint32 flags_eax
, flags_ebx
, flags_ecx
, flags_edx
;
171 info
->use_asm
= true; /* we assume a minimum of 80386 */
172 if (!cpu_have_cpuid())
175 cpuinfo_x86(0, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
176 info
->x86
.intel
= (flags_ebx
== 0x756E6547 && flags_edx
== 0x49656E69 && flags_ecx
== 0x6C65746E) ? true : false; /* GenuineIntel */
177 cpuinfo_x86(1, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
179 info
->x86
.cmov
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_CMOV
) ? true : false;
180 info
->x86
.mmx
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_MMX
) ? true : false;
181 info
->x86
.sse
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_SSE
) ? true : false;
182 info
->x86
.sse2
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_SSE2
) ? true : false;
183 info
->x86
.sse3
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE3
) ? true : false;
184 info
->x86
.ssse3
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSSE3
) ? true : false;
185 info
->x86
.sse41
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE41
) ? true : false;
186 info
->x86
.sse42
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE42
) ? true : false;
188 if (FLAC__AVX_SUPPORTED
) {
189 x86_osxsave
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_OSXSAVE
) ? true : false;
190 info
->x86
.avx
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_AVX
) ? true : false;
191 info
->x86
.fma
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_FMA
) ? true : false;
192 cpuinfo_x86(7, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
193 info
->x86
.avx2
= (flags_ebx
& FLAC__CPUINFO_X86_CPUID_AVX2
) ? true : false;
196 #if defined FLAC__CPU_IA32
197 dfprintf(stderr
, "CPU info (IA-32):\n");
199 dfprintf(stderr
, "CPU info (x86-64):\n");
201 dfprintf(stderr
, " CMOV ....... %c\n", info
->x86
.cmov
? 'Y' : 'n');
202 dfprintf(stderr
, " MMX ........ %c\n", info
->x86
.mmx
? 'Y' : 'n');
203 dfprintf(stderr
, " SSE ........ %c\n", info
->x86
.sse
? 'Y' : 'n');
204 dfprintf(stderr
, " SSE2 ....... %c\n", info
->x86
.sse2
? 'Y' : 'n');
205 dfprintf(stderr
, " SSE3 ....... %c\n", info
->x86
.sse3
? 'Y' : 'n');
206 dfprintf(stderr
, " SSSE3 ...... %c\n", info
->x86
.ssse3
? 'Y' : 'n');
207 dfprintf(stderr
, " SSE41 ...... %c\n", info
->x86
.sse41
? 'Y' : 'n');
208 dfprintf(stderr
, " SSE42 ...... %c\n", info
->x86
.sse42
? 'Y' : 'n');
210 if (FLAC__AVX_SUPPORTED
) {
211 dfprintf(stderr
, " AVX ........ %c\n", info
->x86
.avx
? 'Y' : 'n');
212 dfprintf(stderr
, " FMA ........ %c\n", info
->x86
.fma
? 'Y' : 'n');
213 dfprintf(stderr
, " AVX2 ....... %c\n", info
->x86
.avx2
? 'Y' : 'n');
217 * now have to check for OS support of AVX instructions
219 if (FLAC__AVX_SUPPORTED
&& info
->x86
.avx
&& x86_osxsave
&& (cpu_xgetbv_x86() & 0x6) == 0x6) {
223 dfprintf(stderr
, " AVX OS sup . %c\n", info
->x86
.avx
? 'Y' : 'n');
226 /* no OS AVX support */
227 info
->x86
.avx
= false;
228 info
->x86
.avx2
= false;
229 info
->x86
.fma
= false;
232 info
->use_asm
= false;
237 ppc_cpu_info (FLAC__CPUInfo
*info
)
239 #if defined FLAC__CPU_PPC
240 #ifndef PPC_FEATURE2_ARCH_3_00
241 #define PPC_FEATURE2_ARCH_3_00 0x00800000
244 #ifndef PPC_FEATURE2_ARCH_2_07
245 #define PPC_FEATURE2_ARCH_2_07 0x80000000
248 if (getauxval(AT_HWCAP2
) & PPC_FEATURE2_ARCH_3_00
) {
249 info
->ppc
.arch_3_00
= true;
250 } else if (getauxval(AT_HWCAP2
) & PPC_FEATURE2_ARCH_2_07
) {
251 info
->ppc
.arch_2_07
= true;
254 info
->ppc
.arch_2_07
= false;
255 info
->ppc
.arch_3_00
= false;
259 void FLAC__cpu_info (FLAC__CPUInfo
*info
)
261 memset(info
, 0, sizeof(*info
));
263 #ifdef FLAC__CPU_IA32
264 info
->type
= FLAC__CPUINFO_TYPE_IA32
;
265 #elif defined FLAC__CPU_X86_64
266 info
->type
= FLAC__CPUINFO_TYPE_X86_64
;
267 #elif defined FLAC__CPU_PPC
268 info
->type
= FLAC__CPUINFO_TYPE_PPC
;
270 info
->type
= FLAC__CPUINFO_TYPE_UNKNOWN
;
273 switch (info
->type
) {
274 case FLAC__CPUINFO_TYPE_IA32
: /* fallthrough */
275 case FLAC__CPUINFO_TYPE_X86_64
:
278 case FLAC__CPUINFO_TYPE_PPC
:
282 info
->use_asm
= false;