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 == 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 && Feature.starts_with('+')) { 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 TargetFeature == E.NegTargetFeature) 186 return E; 187 return {}; 188 } 189 190 std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 191 // Resolve aliases first. 192 Name = resolveCPUAlias(Name); 193 194 // Then find the CPU name. 195 for (const auto &C : CpuInfos) 196 if (Name == C.Name) 197 return C; 198 199 return {}; 200 } 201 202 void AArch64::PrintSupportedExtensions() { 203 outs() << "All available -march extensions for AArch64\n\n" 204 << " " << left_justify("Name", 20) 205 << left_justify("Architecture Feature(s)", 55) 206 << "Description\n"; 207 for (const auto &Ext : Extensions) { 208 // Extensions without a feature cannot be used with -march. 209 if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) { 210 outs() << " " 211 << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n", 212 Ext.UserVisibleName.str().c_str(), 213 Ext.ArchFeatureName.str().c_str(), 214 Ext.Description.str().c_str()); 215 } 216 } 217 } 218 219 void 220 AArch64::printEnabledExtensions(const std::set<StringRef> &EnabledFeatureNames) { 221 outs() << "Extensions enabled for the given AArch64 target\n\n" 222 << " " << left_justify("Architecture Feature(s)", 55) 223 << "Description\n"; 224 std::vector<ExtensionInfo> EnabledExtensionsInfo; 225 for (const auto &FeatureName : EnabledFeatureNames) { 226 std::string PosFeatureName = '+' + FeatureName.str(); 227 if (auto ExtInfo = targetFeatureToExtension(PosFeatureName)) 228 EnabledExtensionsInfo.push_back(*ExtInfo); 229 } 230 231 std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(), 232 [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) { 233 return Lhs.ArchFeatureName < Rhs.ArchFeatureName; 234 }); 235 236 for (const auto &Ext : EnabledExtensionsInfo) { 237 outs() << " " 238 << format("%-55s%s\n", 239 Ext.ArchFeatureName.str().c_str(), 240 Ext.Description.str().c_str()); 241 } 242 } 243 244 const llvm::AArch64::ExtensionInfo & 245 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 246 for (const auto &E : llvm::AArch64::Extensions) 247 if (E.ID == ExtID) 248 return E; 249 llvm_unreachable("Invalid extension ID"); 250 } 251 252 void AArch64::ExtensionSet::enable(ArchExtKind E) { 253 if (Enabled.test(E)) 254 return; 255 256 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n"); 257 258 Touched.set(E); 259 Enabled.set(E); 260 261 // Recursively enable all features that this one depends on. This handles all 262 // of the simple cases, where the behaviour doesn't depend on the base 263 // architecture version. 264 for (auto Dep : ExtensionDependencies) 265 if (E == Dep.Later) 266 enable(Dep.Earlier); 267 268 // Special cases for dependencies which vary depending on the base 269 // architecture version. 270 if (BaseArch) { 271 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 272 if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 273 !BaseArch->is_superset(ARMV9A)) 274 enable(AEK_FP16FML); 275 276 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 277 if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 278 enable(AEK_SHA3); 279 enable(AEK_SM4); 280 } 281 } 282 } 283 284 void AArch64::ExtensionSet::disable(ArchExtKind E) { 285 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 286 // where the latter two would not be enabled by +crypto. 287 if (E == AEK_CRYPTO) { 288 disable(AEK_AES); 289 disable(AEK_SHA2); 290 disable(AEK_SHA3); 291 disable(AEK_SM4); 292 } 293 294 // sve2-aes was historically associated with both FEAT_SVE2 and FEAT_SVE_AES, 295 // the latter is now associated with sve-aes and sve2-aes has become shorthand 296 // for +sve2+sve-aes. For backwards compatibility, when we disable sve2-aes we 297 // must also disable sve-aes. 298 if (E == AEK_SVE2AES) 299 disable(AEK_SVEAES); 300 301 // sve2-sm4 was historically associated with both FEAT_SVE2 and 302 // FEAT_SVE_SM4, the latter is now associated with sve-sm4 and sve2-sm4 has 303 // become shorthand for +sve2+sve-sm4. For backwards compatibility, when we 304 // disable sve2-sm4 we must also disable sve-sm4. 305 if (E == AEK_SVE2SM4) 306 disable(AEK_SVESM4); 307 308 // sve2-sha3 was historically associated with both FEAT_SVE2 and 309 // FEAT_SVE_SHA3, the latter is now associated with sve-sha3 and sve2-sha3 has 310 // become shorthand for +sve2+sve-sha3. For backwards compatibility, when we 311 // disable sve2-sha3 we must also disable sve-sha3. 312 if (E == AEK_SVE2SHA3) 313 disable(AEK_SVESHA3); 314 315 if (E == AEK_SVE2BITPERM){ 316 disable(AEK_SVEBITPERM); 317 disable(AEK_SVE2); 318 } 319 320 if (!Enabled.test(E)) 321 return; 322 323 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n"); 324 325 Touched.set(E); 326 Enabled.reset(E); 327 328 // Recursively disable all features that depends on this one. 329 for (auto Dep : ExtensionDependencies) 330 if (E == Dep.Earlier) 331 disable(Dep.Later); 332 } 333 334 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 335 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 336 BaseArch = &CPU.Arch; 337 338 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 339 for (const auto &E : Extensions) 340 if (CPUExtensions.test(E.ID)) 341 enable(E.ID); 342 } 343 344 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 345 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 346 BaseArch = &Arch; 347 348 for (const auto &E : Extensions) 349 if (Arch.DefaultExts.test(E.ID)) 350 enable(E.ID); 351 } 352 353 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier, 354 const bool AllowNoDashForm) { 355 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 356 357 size_t NChars = 0; 358 // The "no-feat" form is allowed in the target attribute but nowhere else. 359 if (AllowNoDashForm && Modifier.starts_with("no-")) 360 NChars = 3; 361 else if (Modifier.starts_with("no")) 362 NChars = 2; 363 bool IsNegated = NChars != 0; 364 StringRef ArchExt = Modifier.drop_front(NChars); 365 366 if (auto AE = parseArchExtension(ArchExt)) { 367 if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty()) 368 return false; 369 if (IsNegated) 370 disable(AE->ID); 371 else 372 enable(AE->ID); 373 return true; 374 } 375 return false; 376 } 377 378 void AArch64::ExtensionSet::reconstructFromParsedFeatures( 379 const std::vector<std::string> &Features, 380 std::vector<std::string> &NonExtensions) { 381 assert(Touched.none() && "Bitset already initialized"); 382 for (auto &F : Features) { 383 bool IsNegated = F[0] == '-'; 384 if (auto AE = targetFeatureToExtension(F)) { 385 Touched.set(AE->ID); 386 if (IsNegated) 387 Enabled.reset(AE->ID); 388 else 389 Enabled.set(AE->ID); 390 continue; 391 } 392 NonExtensions.push_back(F); 393 } 394 } 395 396 void AArch64::ExtensionSet::dump() const { 397 std::vector<StringRef> Features; 398 toLLVMFeatureList(Features); 399 for (StringRef F : Features) 400 llvm::outs() << F << " "; 401 llvm::outs() << "\n"; 402 } 403 404 const AArch64::ExtensionInfo & 405 AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) { 406 return lookupExtensionByID(ExtID); 407 } 408