1 //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a target parser to recognise AArch64 hardware features 10 // such as FPU/CPU/ARCH and extension names. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/TargetParser/AArch64TargetParser.h" 15 #include "llvm/Support/Debug.h" 16 #include "llvm/Support/Format.h" 17 #include "llvm/Support/raw_ostream.h" 18 #include "llvm/TargetParser/ARMTargetParserCommon.h" 19 #include "llvm/TargetParser/Triple.h" 20 #include <cctype> 21 #include <vector> 22 23 #define DEBUG_TYPE "target-parser" 24 25 using namespace llvm; 26 27 #define EMIT_FMV_INFO 28 #include "llvm/TargetParser/AArch64TargetParserDef.inc" 29 30 static unsigned checkArchVersion(llvm::StringRef Arch) { 31 if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) 32 return (Arch[1] - 48); 33 return 0; 34 } 35 36 const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) { 37 // Note: this now takes cpu aliases into account 38 std::optional<CpuInfo> Cpu = parseCpu(CPU); 39 if (!Cpu) 40 return nullptr; 41 return &Cpu->Arch; 42 } 43 44 std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) { 45 for (const auto *A : AArch64::ArchInfos) 46 if (A->getSubArch() == SubArch) 47 return *A; 48 return {}; 49 } 50 51 std::optional<AArch64::FMVInfo> lookupFMVByID(AArch64::ArchExtKind ExtID) { 52 for (const AArch64::FMVInfo &Info : AArch64::getFMVInfo()) 53 if (Info.ID && *Info.ID == ExtID) 54 return Info; 55 return {}; 56 } 57 58 uint64_t AArch64::getFMVPriority(ArrayRef<StringRef> Features) { 59 // Transitively enable the Arch Extensions which correspond to each feature. 60 ExtensionSet FeatureBits; 61 for (const StringRef Feature : Features) { 62 std::optional<FMVInfo> FMV = parseFMVExtension(Feature); 63 if (!FMV) { 64 if (std::optional<ExtensionInfo> Info = targetFeatureToExtension(Feature)) 65 FMV = lookupFMVByID(Info->ID); 66 } 67 if (FMV && FMV->ID) 68 FeatureBits.enable(*FMV->ID); 69 } 70 71 // Construct a bitmask for all the transitively enabled Arch Extensions. 72 uint64_t PriorityMask = 0; 73 for (const FMVInfo &Info : getFMVInfo()) 74 if (Info.ID && FeatureBits.Enabled.test(*Info.ID)) 75 PriorityMask |= (1ULL << Info.PriorityBit); 76 77 return PriorityMask; 78 } 79 80 uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> Features) { 81 // Transitively enable the Arch Extensions which correspond to each feature. 82 ExtensionSet FeatureBits; 83 for (const StringRef Feature : Features) 84 if (std::optional<FMVInfo> Info = parseFMVExtension(Feature)) 85 if (Info->ID) 86 FeatureBits.enable(*Info->ID); 87 88 // Construct a bitmask for all the transitively enabled Arch Extensions. 89 uint64_t FeaturesMask = 0; 90 for (const FMVInfo &Info : getFMVInfo()) 91 if (Info.ID && FeatureBits.Enabled.test(*Info.ID)) 92 FeaturesMask |= (1ULL << Info.FeatureBit); 93 94 return FeaturesMask; 95 } 96 97 bool AArch64::getExtensionFeatures( 98 const AArch64::ExtensionBitset &InputExts, 99 std::vector<StringRef> &Features) { 100 for (const auto &E : Extensions) 101 /* INVALID and NONE have no feature name. */ 102 if (InputExts.test(E.ID) && !E.PosTargetFeature.empty()) 103 Features.push_back(E.PosTargetFeature); 104 105 return true; 106 } 107 108 StringRef AArch64::resolveCPUAlias(StringRef Name) { 109 for (const auto &A : CpuAliases) 110 if (A.AltName == Name) 111 return A.Name; 112 return Name; 113 } 114 115 StringRef AArch64::getArchExtFeature(StringRef ArchExt) { 116 bool IsNegated = ArchExt.starts_with("no"); 117 StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt; 118 119 if (auto AE = parseArchExtension(ArchExtBase)) { 120 assert(!(AE.has_value() && AE->NegTargetFeature.empty())); 121 return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature; 122 } 123 124 return StringRef(); 125 } 126 127 void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 128 for (const auto &C : CpuInfos) 129 Values.push_back(C.Name); 130 131 for (const auto &Alias : CpuAliases) 132 // The apple-latest alias is backend only, do not expose it to clang's -mcpu. 133 if (Alias.AltName != "apple-latest") 134 Values.push_back(Alias.AltName); 135 136 llvm::sort(Values); 137 } 138 139 bool AArch64::isX18ReservedByDefault(const Triple &TT) { 140 return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || 141 TT.isOSWindows() || TT.isOHOSFamily(); 142 } 143 144 // Allows partial match, ex. "v8a" matches "armv8a". 145 const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) { 146 Arch = llvm::ARM::getCanonicalArchName(Arch); 147 if (checkArchVersion(Arch) < 8) 148 return {}; 149 150 StringRef Syn = llvm::ARM::getArchSynonym(Arch); 151 for (const auto *A : ArchInfos) { 152 if (A->Name.ends_with(Syn)) 153 return A; 154 } 155 return {}; 156 } 157 158 std::optional<AArch64::ExtensionInfo> 159 AArch64::parseArchExtension(StringRef ArchExt) { 160 if (ArchExt.empty()) 161 return {}; 162 for (const auto &A : Extensions) { 163 if (ArchExt == A.UserVisibleName || ArchExt == A.Alias) 164 return A; 165 } 166 return {}; 167 } 168 169 std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) { 170 // FIXME introduce general alias functionality, or remove this exception. 171 if (FMVExt == "rdma") 172 FMVExt = "rdm"; 173 174 for (const auto &I : getFMVInfo()) { 175 if (FMVExt == I.Name) 176 return I; 177 } 178 return {}; 179 } 180 181 std::optional<AArch64::ExtensionInfo> 182 AArch64::targetFeatureToExtension(StringRef TargetFeature) { 183 for (const auto &E : Extensions) 184 if (TargetFeature == E.PosTargetFeature) 185 return E; 186 return {}; 187 } 188 189 std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 190 // Resolve aliases first. 191 Name = resolveCPUAlias(Name); 192 193 // Then find the CPU name. 194 for (const auto &C : CpuInfos) 195 if (Name == C.Name) 196 return C; 197 198 return {}; 199 } 200 201 void AArch64::PrintSupportedExtensions() { 202 outs() << "All available -march extensions for AArch64\n\n" 203 << " " << left_justify("Name", 20) 204 << left_justify("Architecture Feature(s)", 55) 205 << "Description\n"; 206 for (const auto &Ext : Extensions) { 207 // Extensions without a feature cannot be used with -march. 208 if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) { 209 outs() << " " 210 << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n", 211 Ext.UserVisibleName.str().c_str(), 212 Ext.ArchFeatureName.str().c_str(), 213 Ext.Description.str().c_str()); 214 } 215 } 216 } 217 218 void 219 AArch64::printEnabledExtensions(const std::set<StringRef> &EnabledFeatureNames) { 220 outs() << "Extensions enabled for the given AArch64 target\n\n" 221 << " " << left_justify("Architecture Feature(s)", 55) 222 << "Description\n"; 223 std::vector<ExtensionInfo> EnabledExtensionsInfo; 224 for (const auto &FeatureName : EnabledFeatureNames) { 225 std::string PosFeatureName = '+' + FeatureName.str(); 226 if (auto ExtInfo = targetFeatureToExtension(PosFeatureName)) 227 EnabledExtensionsInfo.push_back(*ExtInfo); 228 } 229 230 std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(), 231 [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) { 232 return Lhs.ArchFeatureName < Rhs.ArchFeatureName; 233 }); 234 235 for (const auto &Ext : EnabledExtensionsInfo) { 236 outs() << " " 237 << format("%-55s%s\n", 238 Ext.ArchFeatureName.str().c_str(), 239 Ext.Description.str().c_str()); 240 } 241 } 242 243 const llvm::AArch64::ExtensionInfo & 244 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 245 for (const auto &E : llvm::AArch64::Extensions) 246 if (E.ID == ExtID) 247 return E; 248 llvm_unreachable("Invalid extension ID"); 249 } 250 251 void AArch64::ExtensionSet::enable(ArchExtKind E) { 252 if (Enabled.test(E)) 253 return; 254 255 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n"); 256 257 Touched.set(E); 258 Enabled.set(E); 259 260 // Recursively enable all features that this one depends on. This handles all 261 // of the simple cases, where the behaviour doesn't depend on the base 262 // architecture version. 263 for (auto Dep : ExtensionDependencies) 264 if (E == Dep.Later) 265 enable(Dep.Earlier); 266 267 // Special cases for dependencies which vary depending on the base 268 // architecture version. 269 if (BaseArch) { 270 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 271 if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 272 !BaseArch->is_superset(ARMV9A)) 273 enable(AEK_FP16FML); 274 275 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 276 if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 277 enable(AEK_SHA3); 278 enable(AEK_SM4); 279 } 280 } 281 } 282 283 void AArch64::ExtensionSet::disable(ArchExtKind E) { 284 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 285 // where the latter two would not be enabled by +crypto. 286 if (E == AEK_CRYPTO) { 287 disable(AEK_AES); 288 disable(AEK_SHA2); 289 disable(AEK_SHA3); 290 disable(AEK_SM4); 291 } 292 293 // sve2-aes was historically associated with both FEAT_SVE2 and FEAT_SVE_AES, 294 // the latter is now associated with sve-aes and sve2-aes has become shorthand 295 // for +sve2+sve-aes. For backwards compatibility, when we disable sve2-aes we 296 // must also disable sve-aes. 297 if (E == AEK_SVE2AES) 298 disable(AEK_SVEAES); 299 300 if (E == AEK_SVE2BITPERM){ 301 disable(AEK_SVEBITPERM); 302 disable(AEK_SVE2); 303 } 304 305 if (!Enabled.test(E)) 306 return; 307 308 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n"); 309 310 Touched.set(E); 311 Enabled.reset(E); 312 313 // Recursively disable all features that depends on this one. 314 for (auto Dep : ExtensionDependencies) 315 if (E == Dep.Earlier) 316 disable(Dep.Later); 317 } 318 319 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 320 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 321 BaseArch = &CPU.Arch; 322 323 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 324 for (const auto &E : Extensions) 325 if (CPUExtensions.test(E.ID)) 326 enable(E.ID); 327 } 328 329 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 330 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 331 BaseArch = &Arch; 332 333 for (const auto &E : Extensions) 334 if (Arch.DefaultExts.test(E.ID)) 335 enable(E.ID); 336 } 337 338 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier, 339 const bool AllowNoDashForm) { 340 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 341 342 size_t NChars = 0; 343 // The "no-feat" form is allowed in the target attribute but nowhere else. 344 if (AllowNoDashForm && Modifier.starts_with("no-")) 345 NChars = 3; 346 else if (Modifier.starts_with("no")) 347 NChars = 2; 348 bool IsNegated = NChars != 0; 349 StringRef ArchExt = Modifier.drop_front(NChars); 350 351 if (auto AE = parseArchExtension(ArchExt)) { 352 if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty()) 353 return false; 354 if (IsNegated) 355 disable(AE->ID); 356 else 357 enable(AE->ID); 358 return true; 359 } 360 return false; 361 } 362 363 void AArch64::ExtensionSet::reconstructFromParsedFeatures( 364 const std::vector<std::string> &Features, 365 std::vector<std::string> &NonExtensions) { 366 assert(Touched.none() && "Bitset already initialized"); 367 for (auto &F : Features) { 368 bool IsNegated = F[0] == '-'; 369 if (auto AE = targetFeatureToExtension(F)) { 370 Touched.set(AE->ID); 371 if (IsNegated) 372 Enabled.reset(AE->ID); 373 else 374 Enabled.set(AE->ID); 375 continue; 376 } 377 NonExtensions.push_back(F); 378 } 379 } 380 381 void AArch64::ExtensionSet::dump() const { 382 std::vector<StringRef> Features; 383 toLLVMFeatureList(Features); 384 for (StringRef F : Features) 385 llvm::outs() << F << " "; 386 llvm::outs() << "\n"; 387 } 388 389 const AArch64::ExtensionInfo & 390 AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) { 391 return lookupExtensionByID(ExtID); 392 } 393