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
57 #if defined(__linux__) || (defined(__FreeBSD__) && (__FreeBSD__ >= 12))
62 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
64 /* these are flags in EDX of CPUID AX=00000001 */
65 static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV
= 0x00008000;
66 static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX
= 0x00800000;
67 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE
= 0x02000000;
68 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2
= 0x04000000;
70 /* these are flags in ECX of CPUID AX=00000001 */
71 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3
= 0x00000001;
72 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3
= 0x00000200;
73 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41
= 0x00080000;
74 static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42
= 0x00100000;
75 static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE
= 0x08000000;
76 static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX
= 0x10000000;
77 static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA
= 0x00001000;
79 /* these are flags in EBX of CPUID AX=00000007 */
80 static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2
= 0x00000020;
85 #if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
86 return (uint32_t)_xgetbv(0);
87 #elif defined __GNUC__
89 __asm__
volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo
), "=d"(hi
) : "c" (0));
99 #if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
100 /* target CPU does have CPUID instruction */
102 #elif defined FLAC__HAS_NASM
103 return FLAC__cpu_have_cpuid_asm_ia32();
104 #elif defined __GNUC__ && defined HAVE_CPUID_H
105 if (__get_cpuid_max(0, 0) != 0)
109 #elif defined _MSC_VER
110 FLAC__uint32 flags1
, flags2
;
124 if (((flags1
^flags2
) & 0x200000) != 0)
134 cpuinfo_x86(FLAC__uint32 level
, FLAC__uint32
*eax
, FLAC__uint32
*ebx
, FLAC__uint32
*ecx
, FLAC__uint32
*edx
)
138 int ext
= level
& 0x80000000;
139 __cpuid(cpuinfo
, ext
);
140 if ((uint32_t)cpuinfo
[0] >= level
) {
141 #if FLAC__AVX_SUPPORTED
142 __cpuidex(cpuinfo
, level
, 0); /* for AVX2 detection */
144 __cpuid(cpuinfo
, level
); /* some old compilers don't support __cpuidex */
146 *eax
= cpuinfo
[0]; *ebx
= cpuinfo
[1]; *ecx
= cpuinfo
[2]; *edx
= cpuinfo
[3];
149 #elif defined __GNUC__ && defined HAVE_CPUID_H
150 FLAC__uint32 ext
= level
& 0x80000000;
151 __cpuid(ext
, *eax
, *ebx
, *ecx
, *edx
);
153 __cpuid_count(level
, 0, *eax
, *ebx
, *ecx
, *edx
);
156 #elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32
157 FLAC__cpu_info_asm_ia32(level
, eax
, ebx
, ecx
, edx
);
160 *eax
= *ebx
= *ecx
= *edx
= 0;
166 x86_cpu_info (FLAC__CPUInfo
*info
)
168 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
169 FLAC__bool x86_osxsave
= false;
170 FLAC__bool os_avx
= false;
171 FLAC__uint32 flags_eax
, flags_ebx
, flags_ecx
, flags_edx
;
173 info
->use_asm
= true; /* we assume a minimum of 80386 */
174 if (!cpu_have_cpuid())
177 cpuinfo_x86(0, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
178 info
->x86
.intel
= (flags_ebx
== 0x756E6547 && flags_edx
== 0x49656E69 && flags_ecx
== 0x6C65746E) ? true : false; /* GenuineIntel */
179 cpuinfo_x86(1, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
181 info
->x86
.cmov
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_CMOV
) ? true : false;
182 info
->x86
.mmx
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_MMX
) ? true : false;
183 info
->x86
.sse
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_SSE
) ? true : false;
184 info
->x86
.sse2
= (flags_edx
& FLAC__CPUINFO_X86_CPUID_SSE2
) ? true : false;
185 info
->x86
.sse3
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE3
) ? true : false;
186 info
->x86
.ssse3
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSSE3
) ? true : false;
187 info
->x86
.sse41
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE41
) ? true : false;
188 info
->x86
.sse42
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_SSE42
) ? true : false;
190 if (FLAC__AVX_SUPPORTED
) {
191 x86_osxsave
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_OSXSAVE
) ? true : false;
192 info
->x86
.avx
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_AVX
) ? true : false;
193 info
->x86
.fma
= (flags_ecx
& FLAC__CPUINFO_X86_CPUID_FMA
) ? true : false;
194 cpuinfo_x86(7, &flags_eax
, &flags_ebx
, &flags_ecx
, &flags_edx
);
195 info
->x86
.avx2
= (flags_ebx
& FLAC__CPUINFO_X86_CPUID_AVX2
) ? true : false;
198 #if defined FLAC__CPU_IA32
199 dfprintf(stderr
, "CPU info (IA-32):\n");
201 dfprintf(stderr
, "CPU info (x86-64):\n");
203 dfprintf(stderr
, " CMOV ....... %c\n", info
->x86
.cmov
? 'Y' : 'n');
204 dfprintf(stderr
, " MMX ........ %c\n", info
->x86
.mmx
? 'Y' : 'n');
205 dfprintf(stderr
, " SSE ........ %c\n", info
->x86
.sse
? 'Y' : 'n');
206 dfprintf(stderr
, " SSE2 ....... %c\n", info
->x86
.sse2
? 'Y' : 'n');
207 dfprintf(stderr
, " SSE3 ....... %c\n", info
->x86
.sse3
? 'Y' : 'n');
208 dfprintf(stderr
, " SSSE3 ...... %c\n", info
->x86
.ssse3
? 'Y' : 'n');
209 dfprintf(stderr
, " SSE41 ...... %c\n", info
->x86
.sse41
? 'Y' : 'n');
210 dfprintf(stderr
, " SSE42 ...... %c\n", info
->x86
.sse42
? 'Y' : 'n');
212 if (FLAC__AVX_SUPPORTED
) {
213 dfprintf(stderr
, " AVX ........ %c\n", info
->x86
.avx
? 'Y' : 'n');
214 dfprintf(stderr
, " FMA ........ %c\n", info
->x86
.fma
? 'Y' : 'n');
215 dfprintf(stderr
, " AVX2 ....... %c\n", info
->x86
.avx2
? 'Y' : 'n');
219 * now have to check for OS support of AVX instructions
221 if (FLAC__AVX_SUPPORTED
&& info
->x86
.avx
&& x86_osxsave
&& (cpu_xgetbv_x86() & 0x6) == 0x6) {
225 dfprintf(stderr
, " AVX OS sup . %c\n", info
->x86
.avx
? 'Y' : 'n');
228 /* no OS AVX support */
229 info
->x86
.avx
= false;
230 info
->x86
.avx2
= false;
231 info
->x86
.fma
= false;
234 info
->use_asm
= false;
239 ppc_cpu_info (FLAC__CPUInfo
*info
)
241 #if defined FLAC__CPU_PPC
242 #ifndef PPC_FEATURE2_ARCH_3_00
243 #define PPC_FEATURE2_ARCH_3_00 0x00800000
246 #ifndef PPC_FEATURE2_ARCH_2_07
247 #define PPC_FEATURE2_ARCH_2_07 0x80000000
251 if (getauxval(AT_HWCAP2
) & PPC_FEATURE2_ARCH_3_00
) {
252 info
->ppc
.arch_3_00
= true;
253 } else if (getauxval(AT_HWCAP2
) & PPC_FEATURE2_ARCH_2_07
) {
254 info
->ppc
.arch_2_07
= true;
256 #elif defined(__FreeBSD__) && (__FreeBSD__ >= 12)
258 /* elf_aux_info() appeared in FreeBSD 12.0 */
259 elf_aux_info(AT_HWCAP2
, &hwcaps
, sizeof(hwcaps
));
260 if (hwcaps
& PPC_FEATURE2_ARCH_3_00
) {
261 info
->ppc
.arch_3_00
= true;
262 } else if (hwcaps
& PPC_FEATURE2_ARCH_2_07
) {
263 info
->ppc
.arch_2_07
= true;
265 #elif defined(__APPLE__)
266 /* no Mac OS X version supports CPU with Power AVI v2.07 or better */
267 info
->ppc
.arch_2_07
= false;
268 info
->ppc
.arch_3_00
= false;
270 #error Unsupported platform! Please add support for reading ppc hwcaps.
274 info
->ppc
.arch_2_07
= false;
275 info
->ppc
.arch_3_00
= false;
279 void FLAC__cpu_info (FLAC__CPUInfo
*info
)
281 memset(info
, 0, sizeof(*info
));
283 #ifdef FLAC__CPU_IA32
284 info
->type
= FLAC__CPUINFO_TYPE_IA32
;
285 #elif defined FLAC__CPU_X86_64
286 info
->type
= FLAC__CPUINFO_TYPE_X86_64
;
287 #elif defined FLAC__CPU_PPC
288 info
->type
= FLAC__CPUINFO_TYPE_PPC
;
290 info
->type
= FLAC__CPUINFO_TYPE_UNKNOWN
;
293 switch (info
->type
) {
294 case FLAC__CPUINFO_TYPE_IA32
: /* fallthrough */
295 case FLAC__CPUINFO_TYPE_X86_64
:
298 case FLAC__CPUINFO_TYPE_PPC
:
302 info
->use_asm
= false;