|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* compile-time and runtime tests for whether to use various ARM extensions */ |
|
6 |
|
7 #include "mozilla/NullPtr.h" |
|
8 |
|
9 #include "arm.h" |
|
10 |
|
11 #if defined(MOZILLA_ARM_HAVE_CPUID_DETECTION) |
|
12 namespace { |
|
13 |
|
14 // arm.h has parallel #ifs which declare MOZILLA_ARM_HAVE_CPUID_DETECTION. |
|
15 // We don't check it here so that we get compile errors if it's defined, but |
|
16 // we don't compile one of these detection methods. The detection code here is |
|
17 // based on the CPU detection in libtheora. |
|
18 |
|
19 # if defined(_MSC_VER) |
|
20 //For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION. |
|
21 # define WIN32_LEAN_AND_MEAN |
|
22 # define WIN32_EXTRA_LEAN |
|
23 # include <windows.h> |
|
24 |
|
25 # if !defined(MOZILLA_PRESUME_EDSP) |
|
26 static bool |
|
27 check_edsp(void) |
|
28 { |
|
29 # if defined(MOZILLA_MAY_SUPPORT_EDSP) |
|
30 __try |
|
31 { |
|
32 //PLD [r13] |
|
33 __emit(0xF5DDF000); |
|
34 return true; |
|
35 } |
|
36 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) |
|
37 { |
|
38 //Ignore exception. |
|
39 } |
|
40 # endif |
|
41 return false; |
|
42 } |
|
43 # endif // !MOZILLA_PRESUME_EDSP |
|
44 |
|
45 # if !defined(MOZILLA_PRESUME_ARMV6) |
|
46 static bool |
|
47 check_armv6(void) |
|
48 { |
|
49 # if defined(MOZILLA_MAY_SUPPORT_ARMV6) |
|
50 __try |
|
51 { |
|
52 //SHADD8 r3,r3,r3 |
|
53 __emit(0xE6333F93); |
|
54 return true; |
|
55 } |
|
56 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) |
|
57 { |
|
58 //Ignore exception. |
|
59 } |
|
60 # endif |
|
61 return false; |
|
62 } |
|
63 # endif // !MOZILLA_PRESUME_ARMV6 |
|
64 |
|
65 # if !defined(MOZILLA_PRESUME_ARMV7) |
|
66 static bool |
|
67 check_armv7(void) |
|
68 { |
|
69 # if defined(MOZILLA_MAY_SUPPORT_ARMV7) |
|
70 __try |
|
71 { |
|
72 // ARMv7 DMB (Data Memory Barrier) for stores (DMB.ST) |
|
73 // The Data Memory Barrier existed before ARMv7 as a |
|
74 // cp15 operation, but ARMv7 introduced a dedicated |
|
75 // instruction, DMB. |
|
76 emit(0xF57FF05E); |
|
77 return true; |
|
78 } |
|
79 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) |
|
80 { |
|
81 //Ignore exception. |
|
82 } |
|
83 # endif |
|
84 return false; |
|
85 } |
|
86 # endif // !MOZILLA_PRESUME_ARMV7 |
|
87 |
|
88 # if !defined(MOZILLA_PRESUME_NEON) |
|
89 static bool |
|
90 check_neon(void) |
|
91 { |
|
92 # if defined(MOZILLA_MAY_SUPPORT_NEON) |
|
93 __try |
|
94 { |
|
95 //VORR q0,q0,q0 |
|
96 __emit(0xF2200150); |
|
97 return true; |
|
98 } |
|
99 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) |
|
100 { |
|
101 //Ignore exception. |
|
102 } |
|
103 # endif |
|
104 return false; |
|
105 } |
|
106 # endif // !MOZILLA_PRESUME_NEON |
|
107 |
|
108 # elif defined(__linux__) || defined(ANDROID) |
|
109 # include <stdio.h> |
|
110 # include <stdlib.h> |
|
111 # include <string.h> |
|
112 |
|
113 enum{ |
|
114 MOZILLA_HAS_EDSP_FLAG=1, |
|
115 MOZILLA_HAS_ARMV6_FLAG=2, |
|
116 MOZILLA_HAS_ARMV7_FLAG=4, |
|
117 MOZILLA_HAS_NEON_FLAG=8 |
|
118 }; |
|
119 |
|
120 static unsigned |
|
121 get_arm_cpu_flags(void) |
|
122 { |
|
123 unsigned flags; |
|
124 FILE *fin; |
|
125 bool armv6_processor = false; |
|
126 flags = 0; |
|
127 /*Reading /proc/self/auxv would be easier, but that doesn't work reliably on |
|
128 Android. This also means that detection will fail in Scratchbox, which is |
|
129 desirable, as NEON does not work in the qemu shipped with the Maemo 5 SDK. |
|
130 I don't know if /proc/self/auxv would do any better in that case, anyway, |
|
131 or if it would return random flags from the host CPU.*/ |
|
132 fin = fopen ("/proc/cpuinfo","r"); |
|
133 if (fin != nullptr) |
|
134 { |
|
135 /*512 should be enough for anybody (it's even enough for all the flags that |
|
136 x86 has accumulated... so far).*/ |
|
137 char buf[512]; |
|
138 while (fgets(buf, 511, fin) != nullptr) |
|
139 { |
|
140 if (memcmp(buf, "Features", 8) == 0) |
|
141 { |
|
142 char *p; |
|
143 p = strstr(buf, " edsp"); |
|
144 if (p != nullptr && (p[5] == ' ' || p[5] == '\n')) |
|
145 flags |= MOZILLA_HAS_EDSP_FLAG; |
|
146 p = strstr(buf, " neon"); |
|
147 if( p != nullptr && (p[5] == ' ' || p[5] == '\n')) |
|
148 flags |= MOZILLA_HAS_NEON_FLAG; |
|
149 } |
|
150 if (memcmp(buf, "CPU architecture:", 17) == 0) |
|
151 { |
|
152 int version; |
|
153 version = atoi(buf + 17); |
|
154 if (version >= 6) |
|
155 flags |= MOZILLA_HAS_ARMV6_FLAG; |
|
156 if (version >= 7) |
|
157 flags |= MOZILLA_HAS_ARMV7_FLAG; |
|
158 } |
|
159 /* media/webrtc/trunk/src/system_wrappers/source/cpu_features_arm.c |
|
160 * Unfortunately, it seems that certain ARMv6-based CPUs |
|
161 * report an incorrect architecture number of 7! |
|
162 * |
|
163 * We try to correct this by looking at the 'elf_format' |
|
164 * field reported by the 'Processor' field, which is of the |
|
165 * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for |
|
166 * an ARMv6-one. |
|
167 */ |
|
168 if (memcmp(buf, "Processor\t:", 11) == 0) { |
|
169 if (strstr(buf, "(v6l)") != 0) { |
|
170 armv6_processor = true; |
|
171 } |
|
172 } |
|
173 } |
|
174 fclose(fin); |
|
175 } |
|
176 if (armv6_processor) { |
|
177 // ARMv6 pretending to be ARMv7? clear flag |
|
178 if (flags & MOZILLA_HAS_ARMV7_FLAG) { |
|
179 flags &= ~MOZILLA_HAS_ARMV7_FLAG; |
|
180 } |
|
181 } |
|
182 return flags; |
|
183 } |
|
184 |
|
185 // Cache a local copy so we only have to read /proc/cpuinfo once. |
|
186 static unsigned arm_cpu_flags = get_arm_cpu_flags(); |
|
187 |
|
188 # if !defined(MOZILLA_PRESUME_EDSP) |
|
189 static bool |
|
190 check_edsp(void) |
|
191 { |
|
192 return (arm_cpu_flags & MOZILLA_HAS_EDSP_FLAG) != 0; |
|
193 } |
|
194 # endif |
|
195 |
|
196 # if !defined(MOZILLA_PRESUME_ARMV6) |
|
197 static bool |
|
198 check_armv6(void) |
|
199 { |
|
200 return (arm_cpu_flags & MOZILLA_HAS_ARMV6_FLAG) != 0; |
|
201 } |
|
202 # endif |
|
203 |
|
204 # if !defined(MOZILLA_PRESUME_ARMV7) |
|
205 static bool |
|
206 check_armv7(void) |
|
207 { |
|
208 return (arm_cpu_flags & MOZILLA_HAS_ARMV7_FLAG) != 0; |
|
209 } |
|
210 # endif |
|
211 |
|
212 # if !defined(MOZILLA_PRESUME_NEON) |
|
213 static bool |
|
214 check_neon(void) |
|
215 { |
|
216 return (arm_cpu_flags & MOZILLA_HAS_NEON_FLAG) != 0; |
|
217 } |
|
218 # endif |
|
219 |
|
220 # endif // defined(__linux__) || defined(ANDROID) |
|
221 |
|
222 } |
|
223 |
|
224 namespace mozilla { |
|
225 namespace arm_private { |
|
226 # if !defined(MOZILLA_PRESUME_EDSP) |
|
227 bool edsp_enabled = check_edsp(); |
|
228 # endif |
|
229 # if !defined(MOZILLA_PRESUME_ARMV6) |
|
230 bool armv6_enabled = check_armv6(); |
|
231 # endif |
|
232 # if !defined(MOZILLA_PRESUME_ARMV7) |
|
233 bool armv7_enabled = check_armv7(); |
|
234 # endif |
|
235 # if !defined(MOZILLA_PRESUME_NEON) |
|
236 bool neon_enabled = check_neon(); |
|
237 # endif |
|
238 } // namespace arm_private |
|
239 } // namespace mozilla |
|
240 |
|
241 #endif // MOZILLA_ARM_HAVE_CPUID_DETECTION |