• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/array_ref.h"
32 #include "base/stl_util.h"
33 
34 #include <cpu_features_macros.h>
35 
36 #ifdef CPU_FEATURES_ARCH_AARCH64
37 // This header can only be included on aarch64 targets,
38 // as determined by cpu_features own define.
39 #include <cpuinfo_aarch64.h>
40 #endif
41 
42 namespace art {
43 
44 using android::base::StringPrintf;
45 
FromVariant(const std::string & variant,std::string * error_msg)46 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
47     const std::string& variant, std::string* error_msg) {
48   // The CPU variant string is passed to ART through --instruction-set-variant option.
49   // During build, such setting is from TARGET_CPU_VARIANT in device BoardConfig.mk, for example:
50   //   TARGET_CPU_VARIANT := cortex-a75
51 
52   // Look for variants that need a fix for a53 erratum 835769.
53   static const char* arm64_variants_with_a53_835769_bug[] = {
54       // Pessimistically assume all generic CPUs are cortex-a53.
55       "default",
56       "generic",
57       "cortex-a53",
58       "cortex-a53.a57",
59       "cortex-a53.a72",
60       // Pessimistically assume following "big" cortex CPUs are paired with a cortex-a53.
61       "cortex-a57",
62       "cortex-a72",
63       "cortex-a73",
64   };
65 
66   static const char* arm64_variants_with_crc[] = {
67       "default",
68       "generic",
69       "cortex-a35",
70       "cortex-a53",
71       "cortex-a53.a57",
72       "cortex-a53.a72",
73       "cortex-a57",
74       "cortex-a72",
75       "cortex-a73",
76       "cortex-a55",
77       "cortex-a75",
78       "cortex-a76",
79       "exynos-m1",
80       "exynos-m2",
81       "exynos-m3",
82       "kryo",
83       "kryo385",
84       "kryo785",
85   };
86 
87   static const char* arm64_variants_with_lse[] = {
88       "cortex-a55",
89       "cortex-a75",
90       "cortex-a76",
91       "kryo385",
92       "kryo785",
93   };
94 
95   static const char* arm64_variants_with_fp16[] = {
96       "cortex-a55",
97       "cortex-a75",
98       "cortex-a76",
99       "kryo385",
100       "kryo785",
101   };
102 
103   static const char* arm64_variants_with_dotprod[] = {
104       "cortex-a55",
105       "cortex-a75",
106       "cortex-a76",
107   };
108 
109   bool needs_a53_835769_fix = FindVariantInArray(arm64_variants_with_a53_835769_bug,
110                                                  arraysize(arm64_variants_with_a53_835769_bug),
111                                                  variant);
112   // The variants that need a fix for 843419 are the same that need a fix for 835769.
113   bool needs_a53_843419_fix = needs_a53_835769_fix;
114 
115   bool has_crc = FindVariantInArray(arm64_variants_with_crc,
116                                     arraysize(arm64_variants_with_crc),
117                                     variant);
118 
119   bool has_lse = FindVariantInArray(arm64_variants_with_lse,
120                                     arraysize(arm64_variants_with_lse),
121                                     variant);
122 
123   bool has_fp16 = FindVariantInArray(arm64_variants_with_fp16,
124                                      arraysize(arm64_variants_with_fp16),
125                                      variant);
126 
127   bool has_dotprod = FindVariantInArray(arm64_variants_with_dotprod,
128                                         arraysize(arm64_variants_with_dotprod),
129                                         variant);
130 
131   // Currently there are no cpu variants which support SVE.
132   bool has_sve = false;
133 
134   if (!needs_a53_835769_fix) {
135     // Check to see if this is an expected variant. `other_arm64_known_variants` contains the
136     // variants which do *not* need a fix for a53 erratum 835769.
137     static const char* other_arm64_known_variants[] = {
138         "cortex-a35",
139         "cortex-a55",
140         "cortex-a75",
141         "cortex-a76",
142         "exynos-m1",
143         "exynos-m2",
144         "exynos-m3",
145         "kryo",
146         "kryo300",
147         "kryo385",
148         "kryo785",
149     };
150     if (!FindVariantInArray(
151             other_arm64_known_variants, arraysize(other_arm64_known_variants), variant)) {
152       std::ostringstream os;
153       os << "Unexpected CPU variant for Arm64: " << variant << ".\n"
154          << "Known variants that need a fix for a53 erratum 835769: "
155          << android::base::Join(ArrayRef<const char* const>(arm64_variants_with_a53_835769_bug),
156                                 ", ")
157          << ".\n"
158          << "Known variants that do not need a fix for a53 erratum 835769: "
159          << android::base::Join(ArrayRef<const char* const>(other_arm64_known_variants), ", ");
160       *error_msg = os.str();
161       return nullptr;
162     }
163   }
164 
165   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
166                                                                 needs_a53_843419_fix,
167                                                                 has_crc,
168                                                                 has_lse,
169                                                                 has_fp16,
170                                                                 has_dotprod,
171                                                                 has_sve));
172 }
173 
IntersectWithHwcap() const174 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::IntersectWithHwcap() const {
175   Arm64FeaturesUniquePtr hwcaps = Arm64InstructionSetFeatures::FromHwcap();
176   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(
177       fix_cortex_a53_835769_,
178       fix_cortex_a53_843419_,
179       has_crc_ && hwcaps->has_crc_,
180       has_lse_ && hwcaps->has_lse_,
181       has_fp16_ && hwcaps->has_fp16_,
182       has_dotprod_ && hwcaps->has_dotprod_,
183       has_sve_ && hwcaps->has_sve_));
184 }
185 
FromBitmap(uint32_t bitmap)186 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
187   bool is_a53 = (bitmap & kA53Bitfield) != 0;
188   bool has_crc = (bitmap & kCRCBitField) != 0;
189   bool has_lse = (bitmap & kLSEBitField) != 0;
190   bool has_fp16 = (bitmap & kFP16BitField) != 0;
191   bool has_dotprod = (bitmap & kDotProdBitField) != 0;
192   bool has_sve = (bitmap & kSVEBitField) != 0;
193   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53,
194                                                                 is_a53,
195                                                                 has_crc,
196                                                                 has_lse,
197                                                                 has_fp16,
198                                                                 has_dotprod,
199                                                                 has_sve));
200 }
201 
FromCppDefines()202 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCppDefines() {
203   // For more details about ARM feature macros, refer to
204   // Arm C Language Extensions Documentation (ACLE).
205   // https://developer.arm.com/docs/101028/latest
206   bool needs_a53_835769_fix = false;
207   bool needs_a53_843419_fix = needs_a53_835769_fix;
208   bool has_crc = false;
209   bool has_lse = false;
210   bool has_fp16 = false;
211   bool has_dotprod = false;
212   bool has_sve = false;
213 
214 #if defined (__ARM_FEATURE_CRC32)
215   has_crc = true;
216 #endif
217 
218 #if defined (__ARM_ARCH_8_1A__) || defined (__ARM_ARCH_8_2A__)
219   // There is no specific ACLE macro defined for ARMv8.1 LSE features.
220   has_lse = true;
221 #endif
222 
223 #if defined (__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) || defined (__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
224   has_fp16 = true;
225 #endif
226 
227 #if defined (__ARM_FEATURE_DOTPROD)
228   has_dotprod = true;
229 #endif
230 
231 #if defined (__ARM_FEATURE_SVE)
232   has_sve = true;
233 #endif
234 
235   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
236                                                                 needs_a53_843419_fix,
237                                                                 has_crc,
238                                                                 has_lse,
239                                                                 has_fp16,
240                                                                 has_dotprod,
241                                                                 has_sve));
242 }
243 
FromCpuInfo()244 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCpuInfo() {
245   UNIMPLEMENTED(WARNING);
246   return FromCppDefines();
247 }
248 
FromHwcap()249 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromHwcap() {
250   bool needs_a53_835769_fix = false;  // No HWCAP for this.
251   bool needs_a53_843419_fix = false;  // No HWCAP for this.
252   bool has_crc = false;
253   bool has_lse = false;
254   bool has_fp16 = false;
255   bool has_dotprod = false;
256   bool has_sve = false;
257 
258 #if defined(ART_TARGET_ANDROID) && defined(__aarch64__)
259   uint64_t hwcaps = getauxval(AT_HWCAP);
260   has_crc = hwcaps & HWCAP_CRC32 ? true : false;
261   has_lse = hwcaps & HWCAP_ATOMICS ? true : false;
262   has_fp16 = hwcaps & HWCAP_FPHP ? true : false;
263   has_dotprod = hwcaps & HWCAP_ASIMDDP ? true : false;
264   has_sve = hwcaps & HWCAP_SVE ? true : false;
265 #endif
266 
267   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
268                                                                 needs_a53_843419_fix,
269                                                                 has_crc,
270                                                                 has_lse,
271                                                                 has_fp16,
272                                                                 has_dotprod,
273                                                                 has_sve));
274 }
275 
FromAssembly()276 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromAssembly() {
277   UNIMPLEMENTED(WARNING);
278   return FromCppDefines();
279 }
280 
FromCpuFeatures()281 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCpuFeatures() {
282 #ifdef CPU_FEATURES_ARCH_AARCH64
283   auto features = cpu_features::GetAarch64Info().features;
284   return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(false,
285                                                                 false,
286                                                                 features.crc32,
287                                                                 features.atomics,
288                                                                 features.fphp,
289                                                                 features.asimddp,
290                                                                 features.sve));
291 #else
292   UNIMPLEMENTED(WARNING);
293   return FromCppDefines();
294 #endif
295 }
296 
Equals(const InstructionSetFeatures * other) const297 bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
298   if (InstructionSet::kArm64 != other->GetInstructionSet()) {
299     return false;
300   }
301   const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
302   return fix_cortex_a53_835769_ == other_as_arm64->fix_cortex_a53_835769_ &&
303       fix_cortex_a53_843419_ == other_as_arm64->fix_cortex_a53_843419_ &&
304       has_crc_ == other_as_arm64->has_crc_ &&
305       has_lse_ == other_as_arm64->has_lse_ &&
306       has_fp16_ == other_as_arm64->has_fp16_ &&
307       has_dotprod_ == other_as_arm64->has_dotprod_ &&
308       has_sve_ == other_as_arm64->has_sve_;
309 }
310 
HasAtLeast(const InstructionSetFeatures * other) const311 bool Arm64InstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
312   if (InstructionSet::kArm64 != other->GetInstructionSet()) {
313     return false;
314   }
315   // Currently 'default' feature is cortex-a53 with fixes 835769 and 843419.
316   // Newer CPUs are not required to have such features,
317   // so these two a53 fix features are not tested for HasAtLeast.
318   const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
319   return (has_crc_ || !other_as_arm64->has_crc_)
320       && (has_lse_ || !other_as_arm64->has_lse_)
321       && (has_fp16_ || !other_as_arm64->has_fp16_)
322       && (has_dotprod_ || !other_as_arm64->has_dotprod_)
323       && (has_sve_ || !other_as_arm64->has_sve_);
324 }
325 
AsBitmap() const326 uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
327   return (fix_cortex_a53_835769_ ? kA53Bitfield : 0)
328       | (has_crc_ ? kCRCBitField : 0)
329       | (has_lse_ ? kLSEBitField: 0)
330       | (has_fp16_ ? kFP16BitField: 0)
331       | (has_dotprod_ ? kDotProdBitField : 0)
332       | (has_sve_ ? kSVEBitField : 0);
333 }
334 
GetFeatureString() const335 std::string Arm64InstructionSetFeatures::GetFeatureString() const {
336   std::string result;
337   if (fix_cortex_a53_835769_) {
338     result += "a53";
339   } else {
340     result += "-a53";
341   }
342   if (has_crc_) {
343     result += ",crc";
344   } else {
345     result += ",-crc";
346   }
347   if (has_lse_) {
348     result += ",lse";
349   } else {
350     result += ",-lse";
351   }
352   if (has_fp16_) {
353     result += ",fp16";
354   } else {
355     result += ",-fp16";
356   }
357   if (has_dotprod_) {
358     result += ",dotprod";
359   } else {
360     result += ",-dotprod";
361   }
362   if (has_sve_) {
363     result += ",sve";
364   } else {
365     result += ",-sve";
366   }
367   return result;
368 }
369 
370 std::unique_ptr<const InstructionSetFeatures>
AddFeaturesFromSplitString(const std::vector<std::string> & features,std::string * error_msg) const371 Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
372     const std::vector<std::string>& features, std::string* error_msg) const {
373   // This 'features' string is from '--instruction-set-features=' option in ART.
374   // These ARMv8.x feature strings align with those introduced in other compilers:
375   // https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
376   // User can also use armv8.x-a to select group of features:
377   //   armv8.1-a is equivalent to crc,lse
378   //   armv8.2-a is equivalent to crc,lse,fp16
379   //   armv8.3-a is equivalent to crc,lse,fp16
380   //   armv8.4-a is equivalent to crc,lse,fp16,dotprod
381   // For detailed optional & mandatory features support in armv8.x-a,
382   // please refer to section 'A1.7 ARMv8 architecture extensions' in
383   // ARM Architecture Reference Manual ARMv8 document:
384   // https://developer.arm.com/products/architecture/cpu-architecture/a-profile/docs/ddi0487/latest/
385   // arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile/
386   bool is_a53 = fix_cortex_a53_835769_;
387   bool has_crc = has_crc_;
388   bool has_lse = has_lse_;
389   bool has_fp16 = has_fp16_;
390   bool has_dotprod = has_dotprod_;
391   bool has_sve = has_sve_;
392   for (const std::string& feature : features) {
393     DCHECK_EQ(android::base::Trim(feature), feature)
394         << "Feature name is not trimmed: '" << feature << "'";
395     if (feature == "a53") {
396       is_a53 = true;
397     } else if (feature == "-a53") {
398       is_a53 = false;
399     } else if (feature == "crc") {
400       has_crc = true;
401     } else if (feature == "-crc") {
402       has_crc = false;
403     } else if (feature == "lse") {
404       has_lse = true;
405     } else if (feature == "-lse") {
406       has_lse = false;
407     } else if (feature == "fp16") {
408       has_fp16 = true;
409     } else if (feature == "-fp16") {
410       has_fp16 = false;
411     } else if (feature == "dotprod") {
412       has_dotprod = true;
413     } else if (feature == "-dotprod") {
414       has_dotprod = false;
415     } else if (feature == "sve") {
416       has_sve = true;
417     } else if (feature == "-sve") {
418       has_sve = false;
419     } else if (feature == "armv8.1-a") {
420       has_crc = true;
421       has_lse = true;
422     } else if (feature == "armv8.2-a") {
423       has_crc = true;
424       has_lse = true;
425       has_fp16 = true;
426     } else if (feature == "armv8.3-a") {
427       has_crc = true;
428       has_lse = true;
429       has_fp16 = true;
430     } else if (feature == "armv8.4-a") {
431       has_crc = true;
432       has_lse = true;
433       has_fp16 = true;
434       has_dotprod = true;
435     } else {
436       *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
437       return nullptr;
438     }
439   }
440   return std::unique_ptr<const InstructionSetFeatures>(
441       new Arm64InstructionSetFeatures(is_a53,  // erratum 835769
442                                       is_a53,  // erratum 843419
443                                       has_crc,
444                                       has_lse,
445                                       has_fp16,
446                                       has_dotprod,
447                                       has_sve));
448 }
449 
450 std::unique_ptr<const InstructionSetFeatures>
AddRuntimeDetectedFeatures(const InstructionSetFeatures * features) const451 Arm64InstructionSetFeatures::AddRuntimeDetectedFeatures(
452     const InstructionSetFeatures *features) const {
453   const Arm64InstructionSetFeatures *arm64_features = features->AsArm64InstructionSetFeatures();
454   return std::unique_ptr<const InstructionSetFeatures>(
455       new Arm64InstructionSetFeatures(fix_cortex_a53_835769_,
456                                       fix_cortex_a53_843419_,
457                                       arm64_features->has_crc_,
458                                       arm64_features->has_lse_,
459                                       arm64_features->has_fp16_,
460                                       arm64_features->has_dotprod_,
461                                       arm64_features->has_sve_));
462 }
463 
464 }  // namespace art
465