|
1 /* Copyright (c) 2010 Xiph.Org Foundation |
|
2 * Copyright (c) 2013 Parrot */ |
|
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 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
16 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
17 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
18 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
|
19 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
20 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
22 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
24 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
26 */ |
|
27 |
|
28 /* Original code from libtheora modified to suit to Opus */ |
|
29 |
|
30 #ifdef HAVE_CONFIG_H |
|
31 #include "config.h" |
|
32 #endif |
|
33 |
|
34 #ifdef OPUS_HAVE_RTCD |
|
35 |
|
36 #include "armcpu.h" |
|
37 #include "cpu_support.h" |
|
38 #include "os_support.h" |
|
39 #include "opus_types.h" |
|
40 |
|
41 #define OPUS_CPU_ARM_V4 (1) |
|
42 #define OPUS_CPU_ARM_EDSP (1<<1) |
|
43 #define OPUS_CPU_ARM_MEDIA (1<<2) |
|
44 #define OPUS_CPU_ARM_NEON (1<<3) |
|
45 |
|
46 #if defined(_MSC_VER) |
|
47 /*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/ |
|
48 # define WIN32_LEAN_AND_MEAN |
|
49 # define WIN32_EXTRA_LEAN |
|
50 # include <windows.h> |
|
51 |
|
52 static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ |
|
53 opus_uint32 flags; |
|
54 flags=0; |
|
55 /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit |
|
56 * instructions via their assembled hex code. |
|
57 * All of these instructions should be essentially nops. */ |
|
58 # if defined(OPUS_ARM_MAY_HAVE_EDSP) |
|
59 __try{ |
|
60 /*PLD [r13]*/ |
|
61 __emit(0xF5DDF000); |
|
62 flags|=OPUS_CPU_ARM_EDSP; |
|
63 } |
|
64 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ |
|
65 /*Ignore exception.*/ |
|
66 } |
|
67 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) |
|
68 __try{ |
|
69 /*SHADD8 r3,r3,r3*/ |
|
70 __emit(0xE6333F93); |
|
71 flags|=OPUS_CPU_ARM_MEDIA; |
|
72 } |
|
73 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ |
|
74 /*Ignore exception.*/ |
|
75 } |
|
76 # if defined(OPUS_ARM_MAY_HAVE_NEON) |
|
77 __try{ |
|
78 /*VORR q0,q0,q0*/ |
|
79 __emit(0xF2200150); |
|
80 flags|=OPUS_CPU_ARM_NEON; |
|
81 } |
|
82 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ |
|
83 /*Ignore exception.*/ |
|
84 } |
|
85 # endif |
|
86 # endif |
|
87 # endif |
|
88 return flags; |
|
89 } |
|
90 |
|
91 #elif defined(__linux__) |
|
92 /* Linux based */ |
|
93 opus_uint32 opus_cpu_capabilities(void) |
|
94 { |
|
95 opus_uint32 flags = 0; |
|
96 FILE *cpuinfo; |
|
97 |
|
98 /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on |
|
99 * Android */ |
|
100 cpuinfo = fopen("/proc/cpuinfo", "r"); |
|
101 |
|
102 if(cpuinfo != NULL) |
|
103 { |
|
104 /* 512 should be enough for anybody (it's even enough for all the flags that |
|
105 * x86 has accumulated... so far). */ |
|
106 char buf[512]; |
|
107 |
|
108 while(fgets(buf, 512, cpuinfo) != NULL) |
|
109 { |
|
110 # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_NEON) |
|
111 /* Search for edsp and neon flag */ |
|
112 if(memcmp(buf, "Features", 8) == 0) |
|
113 { |
|
114 char *p; |
|
115 # if defined(OPUS_ARM_MAY_HAVE_EDSP) |
|
116 p = strstr(buf, " edsp"); |
|
117 if(p != NULL && (p[5] == ' ' || p[5] == '\n')) |
|
118 flags |= OPUS_CPU_ARM_EDSP; |
|
119 # endif |
|
120 |
|
121 # if defined(OPUS_ARM_MAY_HAVE_NEON) |
|
122 p = strstr(buf, " neon"); |
|
123 if(p != NULL && (p[5] == ' ' || p[5] == '\n')) |
|
124 flags |= OPUS_CPU_ARM_NEON; |
|
125 # endif |
|
126 } |
|
127 # endif |
|
128 |
|
129 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) |
|
130 /* Search for media capabilities (>= ARMv6) */ |
|
131 if(memcmp(buf, "CPU architecture:", 17) == 0) |
|
132 { |
|
133 int version; |
|
134 version = atoi(buf+17); |
|
135 |
|
136 if(version >= 6) |
|
137 flags |= OPUS_CPU_ARM_MEDIA; |
|
138 } |
|
139 # endif |
|
140 } |
|
141 |
|
142 fclose(cpuinfo); |
|
143 } |
|
144 return flags; |
|
145 } |
|
146 #else |
|
147 /* The feature registers which can tell us what the processor supports are |
|
148 * accessible in priveleged modes only, so we can't have a general user-space |
|
149 * detection method like on x86.*/ |
|
150 # error "Configured to use ARM asm but no CPU detection method available for " \ |
|
151 "your platform. Reconfigure with --disable-rtcd (or send patches)." |
|
152 #endif |
|
153 |
|
154 int opus_select_arch(void) |
|
155 { |
|
156 opus_uint32 flags = opus_cpu_capabilities(); |
|
157 int arch = 0; |
|
158 |
|
159 if(!(flags & OPUS_CPU_ARM_EDSP)) |
|
160 return arch; |
|
161 arch++; |
|
162 |
|
163 if(!(flags & OPUS_CPU_ARM_MEDIA)) |
|
164 return arch; |
|
165 arch++; |
|
166 |
|
167 if(!(flags & OPUS_CPU_ARM_NEON)) |
|
168 return arch; |
|
169 arch++; |
|
170 |
|
171 return arch; |
|
172 } |
|
173 |
|
174 #endif |