1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "instruction_set_features_arm64.h"
18
19 #if defined(ART_TARGET_ANDROID) && defined(__aarch64__)
20 #include <asm/hwcap.h>
21 #include <sys/auxv.h>
22 #endif
23
24 #include <fstream>
25 #include <sstream>
26
27 #include <android-base/logging.h>
28 #include <android-base/stringprintf.h>
29 #include <android-base/strings.h>
30
31 #include "base/stl_util.h"
32
33 namespace art {
34
35 using android::base::StringPrintf;
36
FromVariant(const std::string & variant,std::string * error_msg)37 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
38 const std::string& variant, std::string* error_msg) {
39 // The CPU variant string is passed to ART through --instruction-set-variant option.
40 // During build, such setting is from TARGET_CPU_VARIANT in device BoardConfig.mk, for example:
41 // TARGET_CPU_VARIANT := cortex-a75
42
43 // Look for variants that need a fix for a53 erratum 835769.
44 static const char* arm64_variants_with_a53_835769_bug[] = {
45 // Pessimistically assume all generic CPUs are cortex-a53.
46 "default",
47 "generic",
48 "cortex-a53",
49 "cortex-a53.a57",
50 "cortex-a53.a72",
51 // Pessimistically assume following "big" cortex CPUs are paired with a cortex-a53.
52 "cortex-a57",
53 "cortex-a72",
54 "cortex-a73",
55 };
56
57 static const char* arm64_variants_with_crc[] = {
58 "default",
59 "generic",
60 "cortex-a35",
61 "cortex-a53",
62 "cortex-a53.a57",
63 "cortex-a53.a72",
64 "cortex-a57",
65 "cortex-a72",
66 "cortex-a73",
67 "cortex-a55",
68 "cortex-a75",
69 "cortex-a76",
70 "exynos-m1",
71 "exynos-m2",
72 "exynos-m3",
73 "kryo",
74 "kryo385",
75 };
76
77 static const char* arm64_variants_with_lse[] = {
78 "cortex-a55",
79 "cortex-a75",
80 "cortex-a76",
81 "kryo385",
82 };
83
84 static const char* arm64_variants_with_fp16[] = {
85 "cortex-a55",
86 "cortex-a75",
87 "cortex-a76",
88 "kryo385",
89 };
90
91 static const char* arm64_variants_with_dotprod[] = {
92 "cortex-a55",
93 "cortex-a75",
94 "cortex-a76",
95 };
96
97 bool needs_a53_835769_fix = FindVariantInArray(arm64_variants_with_a53_835769_bug,
98 arraysize(arm64_variants_with_a53_835769_bug),
99 variant);
100 // The variants that need a fix for 843419 are the same that need a fix for 835769.
101 bool needs_a53_843419_fix = needs_a53_835769_fix;
102
103 bool has_crc = FindVariantInArray(arm64_variants_with_crc,
104 arraysize(arm64_variants_with_crc),
105 variant);
106
107 bool has_lse = FindVariantInArray(arm64_variants_with_lse,
108 arraysize(arm64_variants_with_lse),
109 variant);
110
111 bool has_fp16 = FindVariantInArray(arm64_variants_with_fp16,
112 arraysize(arm64_variants_with_fp16),
113 variant);
114
115 bool has_dotprod = FindVariantInArray(arm64_variants_with_dotprod,
116 arraysize(arm64_variants_with_dotprod),
117 variant);
118
119 // Currently there are no cpu variants which support SVE.
120 bool has_sve = false;
121
122 if (!needs_a53_835769_fix) {
123 // Check to see if this is an expected variant.
124 static const char* arm64_known_variants[] = {
125 "cortex-a35",
126 "cortex-a55",
127 "cortex-a75",
128 "cortex-a76",
129 "exynos-m1",
130 "exynos-m2",
131 "exynos-m3",
132 "kryo",
133 "kryo300",
134 "kryo385",
135 };
136 if (!FindVariantInArray(arm64_known_variants, arraysize(arm64_known_variants), variant)) {
137 std::ostringstream os;
138 os << "Unexpected CPU variant for Arm64: " << variant;
139 *error_msg = os.str();
140 return nullptr;
141 }
142 }
143
144 return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
145 needs_a53_843419_fix,
146 has_crc,
147 has_lse,
148 has_fp16,
149 has_dotprod,
150 has_sve));
151 }
152
FromBitmap(uint32_t bitmap)153 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
154 bool is_a53 = (bitmap & kA53Bitfield) != 0;
155 bool has_crc = (bitmap & kCRCBitField) != 0;
156 bool has_lse = (bitmap & kLSEBitField) != 0;
157 bool has_fp16 = (bitmap & kFP16BitField) != 0;
158 bool has_dotprod = (bitmap & kDotProdBitField) != 0;
159 bool has_sve = (bitmap & kSVEBitField) != 0;
160 return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53,
161 is_a53,
162 has_crc,
163 has_lse,
164 has_fp16,
165 has_dotprod,
166 has_sve));
167 }
168
FromCppDefines()169 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCppDefines() {
170 // For more details about ARM feature macros, refer to
171 // Arm C Language Extensions Documentation (ACLE).
172 // https://developer.arm.com/docs/101028/latest
173 bool needs_a53_835769_fix = false;
174 bool needs_a53_843419_fix = needs_a53_835769_fix;
175 bool has_crc = false;
176 bool has_lse = false;
177 bool has_fp16 = false;
178 bool has_dotprod = false;
179 bool has_sve = false;
180
181 #if defined (__ARM_FEATURE_CRC32)
182 has_crc = true;
183 #endif
184
185 #if defined (__ARM_ARCH_8_1A__) || defined (__ARM_ARCH_8_2A__)
186 // There is no specific ACLE macro defined for ARMv8.1 LSE features.
187 has_lse = true;
188 #endif
189
190 #if defined (__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) || defined (__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
191 has_fp16 = true;
192 #endif
193
194 #if defined (__ARM_FEATURE_DOTPROD)
195 has_dotprod = true;
196 #endif
197
198 #if defined (__ARM_FEATURE_SVE)
199 has_sve = true;
200 #endif
201
202 return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
203 needs_a53_843419_fix,
204 has_crc,
205 has_lse,
206 has_fp16,
207 has_dotprod,
208 has_sve));
209 }
210
FromCpuInfo()211 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCpuInfo() {
212 UNIMPLEMENTED(WARNING);
213 return FromCppDefines();
214 }
215
FromHwcap()216 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromHwcap() {
217 bool needs_a53_835769_fix = false; // No HWCAP for this.
218 bool needs_a53_843419_fix = false; // No HWCAP for this.
219 bool has_crc = false;
220 bool has_lse = false;
221 bool has_fp16 = false;
222 bool has_dotprod = false;
223 bool has_sve = false;
224
225 #if defined(ART_TARGET_ANDROID) && defined(__aarch64__)
226 uint64_t hwcaps = getauxval(AT_HWCAP);
227 has_crc = hwcaps & HWCAP_CRC32 ? true : false;
228 has_lse = hwcaps & HWCAP_ATOMICS ? true : false;
229 has_fp16 = hwcaps & HWCAP_FPHP ? true : false;
230 has_dotprod = hwcaps & HWCAP_ASIMDDP ? true : false;
231 has_sve = hwcaps & HWCAP_SVE ? true : false;
232 #endif
233
234 return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
235 needs_a53_843419_fix,
236 has_crc,
237 has_lse,
238 has_fp16,
239 has_dotprod,
240 has_sve));
241 }
242
FromAssembly()243 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromAssembly() {
244 UNIMPLEMENTED(WARNING);
245 return FromCppDefines();
246 }
247
Equals(const InstructionSetFeatures * other) const248 bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
249 if (InstructionSet::kArm64 != other->GetInstructionSet()) {
250 return false;
251 }
252 const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
253 return fix_cortex_a53_835769_ == other_as_arm64->fix_cortex_a53_835769_ &&
254 fix_cortex_a53_843419_ == other_as_arm64->fix_cortex_a53_843419_ &&
255 has_crc_ == other_as_arm64->has_crc_ &&
256 has_lse_ == other_as_arm64->has_lse_ &&
257 has_fp16_ == other_as_arm64->has_fp16_ &&
258 has_dotprod_ == other_as_arm64->has_dotprod_ &&
259 has_sve_ == other_as_arm64->has_sve_;
260 }
261
HasAtLeast(const InstructionSetFeatures * other) const262 bool Arm64InstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
263 if (InstructionSet::kArm64 != other->GetInstructionSet()) {
264 return false;
265 }
266 // Currently 'default' feature is cortex-a53 with fixes 835769 and 843419.
267 // Newer CPUs are not required to have such features,
268 // so these two a53 fix features are not tested for HasAtLeast.
269 const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
270 return (has_crc_ || !other_as_arm64->has_crc_)
271 && (has_lse_ || !other_as_arm64->has_lse_)
272 && (has_fp16_ || !other_as_arm64->has_fp16_)
273 && (has_dotprod_ || !other_as_arm64->has_dotprod_)
274 && (has_sve_ || !other_as_arm64->has_sve_);
275 }
276
AsBitmap() const277 uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
278 return (fix_cortex_a53_835769_ ? kA53Bitfield : 0)
279 | (has_crc_ ? kCRCBitField : 0)
280 | (has_lse_ ? kLSEBitField: 0)
281 | (has_fp16_ ? kFP16BitField: 0)
282 | (has_dotprod_ ? kDotProdBitField : 0)
283 | (has_sve_ ? kSVEBitField : 0);
284 }
285
GetFeatureString() const286 std::string Arm64InstructionSetFeatures::GetFeatureString() const {
287 std::string result;
288 if (fix_cortex_a53_835769_) {
289 result += "a53";
290 } else {
291 result += "-a53";
292 }
293 if (has_crc_) {
294 result += ",crc";
295 } else {
296 result += ",-crc";
297 }
298 if (has_lse_) {
299 result += ",lse";
300 } else {
301 result += ",-lse";
302 }
303 if (has_fp16_) {
304 result += ",fp16";
305 } else {
306 result += ",-fp16";
307 }
308 if (has_dotprod_) {
309 result += ",dotprod";
310 } else {
311 result += ",-dotprod";
312 }
313 if (has_sve_) {
314 result += ",sve";
315 } else {
316 result += ",-sve";
317 }
318 return result;
319 }
320
321 std::unique_ptr<const InstructionSetFeatures>
AddFeaturesFromSplitString(const std::vector<std::string> & features,std::string * error_msg) const322 Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
323 const std::vector<std::string>& features, std::string* error_msg) const {
324 // This 'features' string is from '--instruction-set-features=' option in ART.
325 // These ARMv8.x feature strings align with those introduced in other compilers:
326 // https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
327 // User can also use armv8.x-a to select group of features:
328 // armv8.1-a is equivalent to crc,lse
329 // armv8.2-a is equivalent to crc,lse,fp16
330 // armv8.3-a is equivalent to crc,lse,fp16
331 // armv8.4-a is equivalent to crc,lse,fp16,dotprod
332 // For detailed optional & mandatory features support in armv8.x-a,
333 // please refer to section 'A1.7 ARMv8 architecture extensions' in
334 // ARM Architecture Reference Manual ARMv8 document:
335 // https://developer.arm.com/products/architecture/cpu-architecture/a-profile/docs/ddi0487/latest/
336 // arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile/
337 bool is_a53 = fix_cortex_a53_835769_;
338 bool has_crc = has_crc_;
339 bool has_lse = has_lse_;
340 bool has_fp16 = has_fp16_;
341 bool has_dotprod = has_dotprod_;
342 bool has_sve = has_sve_;
343 for (const std::string& feature : features) {
344 DCHECK_EQ(android::base::Trim(feature), feature)
345 << "Feature name is not trimmed: '" << feature << "'";
346 if (feature == "a53") {
347 is_a53 = true;
348 } else if (feature == "-a53") {
349 is_a53 = false;
350 } else if (feature == "crc") {
351 has_crc = true;
352 } else if (feature == "-crc") {
353 has_crc = false;
354 } else if (feature == "lse") {
355 has_lse = true;
356 } else if (feature == "-lse") {
357 has_lse = false;
358 } else if (feature == "fp16") {
359 has_fp16 = true;
360 } else if (feature == "-fp16") {
361 has_fp16 = false;
362 } else if (feature == "dotprod") {
363 has_dotprod = true;
364 } else if (feature == "-dotprod") {
365 has_dotprod = false;
366 } else if (feature == "sve") {
367 has_sve = true;
368 } else if (feature == "-sve") {
369 has_sve = false;
370 } else if (feature == "armv8.1-a") {
371 has_crc = true;
372 has_lse = true;
373 } else if (feature == "armv8.2-a") {
374 has_crc = true;
375 has_lse = true;
376 has_fp16 = true;
377 } else if (feature == "armv8.3-a") {
378 has_crc = true;
379 has_lse = true;
380 has_fp16 = true;
381 } else if (feature == "armv8.4-a") {
382 has_crc = true;
383 has_lse = true;
384 has_fp16 = true;
385 has_dotprod = true;
386 } else {
387 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
388 return nullptr;
389 }
390 }
391 return std::unique_ptr<const InstructionSetFeatures>(
392 new Arm64InstructionSetFeatures(is_a53, // erratum 835769
393 is_a53, // erratum 843419
394 has_crc,
395 has_lse,
396 has_fp16,
397 has_dotprod,
398 has_sve));
399 }
400
401 std::unique_ptr<const InstructionSetFeatures>
AddRuntimeDetectedFeatures(const InstructionSetFeatures * features) const402 Arm64InstructionSetFeatures::AddRuntimeDetectedFeatures(
403 const InstructionSetFeatures *features) const {
404 const Arm64InstructionSetFeatures *arm64_features = features->AsArm64InstructionSetFeatures();
405 return std::unique_ptr<const InstructionSetFeatures>(
406 new Arm64InstructionSetFeatures(fix_cortex_a53_835769_,
407 fix_cortex_a53_843419_,
408 arm64_features->has_crc_,
409 arm64_features->has_lse_,
410 arm64_features->has_fp16_,
411 arm64_features->has_dotprod_,
412 arm64_features->has_sve_));
413 }
414
415 } // namespace art
416