merged patches from Chris Csanady and John Steele Scott, better checking for altivec...
[platform/upstream/flac.git] / src / libFLAC / cpu.c
1 /* libFLAC - Free Lossless Audio Codec library
2  * Copyright (C) 2001,2002,2003,2004  Josh Coalson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the Xiph.org Foundation nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "private/cpu.h"
33 #include <stdlib.h>
34 #include <stdio.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #if defined FLAC__CPU_PPC
41 #if !defined FLAC__NO_ASM
42 #if defined FLAC__SYS_DARWIN
43 #include <sys/sysctl.h>
44 #include <mach/mach.h>
45 #include <mach/mach_host.h>
46 #include <mach/host_info.h>
47 #include <mach/machine.h>
48 #ifndef CPU_SUBTYPE_POWERPC_970
49 #define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
50 #endif
51 #else /* FLAC__SYS_DARWIN */
52 #include <signal.h>
53 #include <setjmp.h>
54
55 static sigjmp_buf jmpbuf;
56 static volatile sig_atomic_t canjump = 0;
57
58 static void sigill_handler (int sig)
59 {
60         if (!canjump) {
61                 signal (sig, SIG_DFL);
62                 raise (sig);
63         }
64         canjump = 0;
65         siglongjmp (jmpbuf, 1);
66 }
67 #endif /* FLAC__SYS_DARWIN */
68 #endif /* FLAC__NO_ASM */
69 #endif /* FLAC__CPU_PPC */
70
71 const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
72 const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
73 const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
74 const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
75 const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
76
77 const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
78 const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
79 const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
80
81
82 void FLAC__cpu_info(FLAC__CPUInfo *info)
83 {
84 #ifdef FLAC__CPU_IA32
85         info->type = FLAC__CPUINFO_TYPE_IA32;
86 #if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
87         info->use_asm = true;
88         {
89                 unsigned cpuid = FLAC__cpu_info_asm_ia32();
90                 info->data.ia32.cmov = (cpuid & FLAC__CPUINFO_IA32_CPUID_CMOV)? true : false;
91                 info->data.ia32.mmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_MMX)? true : false;
92                 info->data.ia32.fxsr = (cpuid & FLAC__CPUINFO_IA32_CPUID_FXSR)? true : false;
93                 info->data.ia32.sse = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE)? true : false;
94                 info->data.ia32.sse2 = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE2)? true : false;
95
96 #ifndef FLAC__SSE_OS
97                 info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
98 #endif
99
100 #ifdef FLAC__USE_3DNOW
101                 cpuid = FLAC__cpu_info_extended_amd_asm_ia32();
102                 info->data.ia32._3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW)? true : false;
103                 info->data.ia32.ext3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
104                 info->data.ia32.extmmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX)? true : false;
105 #else
106                 info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
107 #endif
108         }
109 #else
110         info->use_asm = false;
111 #endif
112 #elif defined FLAC__CPU_PPC
113         info->type = FLAC__CPUINFO_TYPE_PPC;
114 #if !defined FLAC__NO_ASM
115         info->use_asm = true;
116 #ifdef FLAC__USE_ALTIVEC
117 #if defined FLAC__SYS_DARWIN
118         {
119                 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
120                 int result = 0;
121                 size_t length = sizeof(result);
122                 int error = sysctl(selectors, 2, &result, &length, 0, 0);
123
124                 info->data.ppc.altivec = error==0 ? result!=0 : 0;
125         }
126         {
127                 host_basic_info_data_t hostInfo;
128                 mach_msg_type_number_t infoCount;
129
130                 infoCount = HOST_BASIC_INFO_COUNT;
131                 host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
132
133                 info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
134         }
135 #else /* FLAC__SYS_DARWIN */
136         {
137                 /* no Darwin, do it the brute-force way */
138                 /* this is borrowed from MPlayer from the libmpeg2 library */
139                 info->data.ppc.altivec = 0;
140                 info->data.ppc.ppc64 = 0;
141
142                 signal (SIGILL, sigill_handler);
143                 if (!sigsetjmp (jmpbuf, 1)) {
144                         canjump = 1;
145
146                         asm volatile (
147                                 "mtspr 256, %0\n\t"
148                                 "vand %%v0, %%v0, %%v0"
149                                 :
150                                 : "r" (-1)
151                         );
152
153                         info->data.ppc.altivec = 1;
154                 }
155                 canjump = 0;
156                 if (!sigsetjmp (jmpbuf, 1)) {
157                         int x = 0;
158                         canjump = 1;
159
160                         /* PPC64 hardware implements the cntlzd instruction */
161                         asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) );
162
163                         info->data.ppc.ppc64 = 1;
164                 }
165                 signal (SIGILL, SIG_DFL);
166         }
167 #endif /* FLAC__SYS_DARWIN */
168 #else /* FLAC__USE_ALTIVEC */
169         info->data.ppc.altivec = 0;
170         info->data.ppc.ppc64 = 0;
171 #endif /* FLAC__USE_ALTIVEC */
172 #else /* FLAC__NO_ASM */
173         info->use_asm = false;
174 #endif /* FLAC__NO_ASM */
175 #else
176         info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
177         info->use_asm = false;
178 #endif
179 }