OSDN Git Service

[flac] Update FLAC to 1.3.3
[timidity41/timidity41.git] / FLAC / src / cpu.c
1 /* libFLAC - Free Lossless Audio Codec library
2  * Copyright (C) 2001-2009  Josh Coalson
3  * Copyright (C) 2011-2016  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 "share/compat.h"
39 #include <stdlib.h>
40 #include <string.h>
41
42 #if defined _MSC_VER
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() */
46 #endif
47
48 #ifndef NDEBUG
49 #include <stdio.h>
50 #define dfprintf fprintf
51 #else
52 /* This is bad practice, it should be a static void empty function */
53 #define dfprintf(file, format, ...)
54 #endif
55
56 #if defined FLAC__CPU_PPC
57 #include <sys/auxv.h>
58 #endif
59
60 #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
61
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;
67
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;
76
77 /* these are flags in EBX of CPUID AX=00000007 */
78 static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2    = 0x00000020;
79
80 static uint32_t
81 cpu_xgetbv_x86(void)
82 {
83 #if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
84         return (uint32_t)_xgetbv(0);
85 #elif defined __GNUC__
86         uint32_t lo, hi;
87         __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
88         return lo;
89 #else
90         return 0;
91 #endif
92 }
93
94 static uint32_t
95 cpu_have_cpuid(void)
96 {
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 */
99         return 1;
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)
104                 return 1;
105         else
106                 return 0;
107 #elif defined _MSC_VER
108         FLAC__uint32 flags1, flags2;
109         __asm {
110                 pushfd
111                 pushfd
112                 pop             eax
113                 mov             flags1, eax
114                 xor             eax, 0x200000
115                 push    eax
116                 popfd
117                 pushfd
118                 pop             eax
119                 mov             flags2, eax
120                 popfd
121         }
122         if (((flags1^flags2) & 0x200000) != 0)
123                 return 1;
124         else
125                 return 0;
126 #else
127         return 0;
128 #endif
129 }
130
131 static void
132 cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
133 {
134 #if defined _MSC_VER
135         int cpuinfo[4];
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 */
141 #else
142                 __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
143 #endif
144                 *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
145                 return;
146         }
147 #elif defined __GNUC__ && defined HAVE_CPUID_H
148         FLAC__uint32 ext = level & 0x80000000;
149         __cpuid(ext, *eax, *ebx, *ecx, *edx);
150         if (*eax >= level) {
151                 __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
152                 return;
153         }
154 #elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32
155         FLAC__cpu_info_asm_ia32(level, eax, ebx, ecx, edx);
156         return;
157 #endif
158         *eax = *ebx = *ecx = *edx = 0;
159 }
160
161 #endif
162
163 static void
164 x86_cpu_info (FLAC__CPUInfo *info)
165 {
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;
170
171         info->use_asm = true; /* we assume a minimum of 80386 */
172         if (!cpu_have_cpuid())
173                 return;
174
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);
178
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;
187
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;
194         }
195
196 #if defined FLAC__CPU_IA32
197         dfprintf(stderr, "CPU info (IA-32):\n");
198 #else
199         dfprintf(stderr, "CPU info (x86-64):\n");
200 #endif
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');
209
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');
214         }
215
216         /*
217          * now have to check for OS support of AVX instructions
218          */
219         if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
220                 os_avx = true;
221         }
222         if (os_avx) {
223                 dfprintf(stderr, "  AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
224         }
225         if (!os_avx) {
226                 /* no OS AVX support */
227                 info->x86.avx     = false;
228                 info->x86.avx2    = false;
229                 info->x86.fma     = false;
230         }
231 #else
232         info->use_asm = false;
233 #endif
234 }
235
236 static void
237 ppc_cpu_info (FLAC__CPUInfo *info)
238 {
239 #if defined FLAC__CPU_PPC
240 #ifndef PPC_FEATURE2_ARCH_3_00
241 #define PPC_FEATURE2_ARCH_3_00          0x00800000
242 #endif
243
244 #ifndef PPC_FEATURE2_ARCH_2_07
245 #define PPC_FEATURE2_ARCH_2_07          0x80000000
246 #endif
247
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;
252         }
253 #else
254         info->ppc.arch_2_07 = false;
255         info->ppc.arch_3_00 = false;
256 #endif
257 }
258
259 void FLAC__cpu_info (FLAC__CPUInfo *info)
260 {
261         memset(info, 0, sizeof(*info));
262
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;
269 #else
270         info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
271 #endif
272
273         switch (info->type) {
274         case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
275         case FLAC__CPUINFO_TYPE_X86_64:
276                 x86_cpu_info (info);
277                 break;
278         case FLAC__CPUINFO_TYPE_PPC:
279                 ppc_cpu_info (info);
280                 break;
281         default:
282                 info->use_asm = false;
283                 break;
284         }
285 }