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 22 #define DEBUG_TYPE "target-parser" 23 24 using namespace llvm; 25 26 static unsigned checkArchVersion(llvm::StringRef Arch) { 27 if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) 28 return (Arch[1] - 48); 29 return 0; 30 } 31 32 const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) { 33 if (CPU == "generic") 34 return &ARMV8A; 35 36 // Note: this now takes cpu aliases into account 37 std::optional<CpuInfo> Cpu = parseCpu(CPU); 38 if (!Cpu) 39 return nullptr; 40 return &Cpu->Arch; 41 } 42 43 std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) { 44 for (const auto *A : AArch64::ArchInfos) 45 if (A->getSubArch() == SubArch) 46 return *A; 47 return {}; 48 } 49 50 uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { 51 uint64_t FeaturesMask = 0; 52 for (const StringRef &FeatureStr : FeatureStrs) { 53 if (auto Ext = parseArchExtension(FeatureStr)) 54 FeaturesMask |= (1ULL << Ext->CPUFeature); 55 } 56 return FeaturesMask; 57 } 58 59 bool AArch64::getExtensionFeatures( 60 const AArch64::ExtensionBitset &InputExts, 61 std::vector<StringRef> &Features) { 62 for (const auto &E : Extensions) 63 /* INVALID and NONE have no feature name. */ 64 if (InputExts.test(E.ID) && !E.Feature.empty()) 65 Features.push_back(E.Feature); 66 67 return true; 68 } 69 70 StringRef AArch64::resolveCPUAlias(StringRef Name) { 71 for (const auto &A : CpuAliases) 72 if (A.AltName == Name) 73 return A.Name; 74 return Name; 75 } 76 77 StringRef AArch64::getArchExtFeature(StringRef ArchExt) { 78 bool IsNegated = ArchExt.starts_with("no"); 79 StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt; 80 81 if (auto AE = parseArchExtension(ArchExtBase)) { 82 // Note: the returned string can be empty. 83 return IsNegated ? AE->NegFeature : AE->Feature; 84 } 85 86 return StringRef(); 87 } 88 89 void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 90 for (const auto &C : CpuInfos) 91 Values.push_back(C.Name); 92 93 for (const auto &Alias : CpuAliases) 94 Values.push_back(Alias.AltName); 95 } 96 97 bool AArch64::isX18ReservedByDefault(const Triple &TT) { 98 return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || 99 TT.isOSWindows() || TT.isOHOSFamily(); 100 } 101 102 // Allows partial match, ex. "v8a" matches "armv8a". 103 const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) { 104 Arch = llvm::ARM::getCanonicalArchName(Arch); 105 if (checkArchVersion(Arch) < 8) 106 return {}; 107 108 StringRef Syn = llvm::ARM::getArchSynonym(Arch); 109 for (const auto *A : ArchInfos) { 110 if (A->Name.ends_with(Syn)) 111 return A; 112 } 113 return {}; 114 } 115 116 std::optional<AArch64::ExtensionInfo> 117 AArch64::parseArchExtension(StringRef ArchExt) { 118 for (const auto &A : Extensions) { 119 if (ArchExt == A.Name || ArchExt == A.Alias) 120 return A; 121 } 122 return {}; 123 } 124 125 std::optional<AArch64::ExtensionInfo> 126 AArch64::targetFeatureToExtension(StringRef TargetFeature) { 127 for (const auto &E : Extensions) 128 if (TargetFeature == E.Feature) 129 return E; 130 return {}; 131 } 132 133 std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 134 // Resolve aliases first. 135 Name = resolveCPUAlias(Name); 136 137 // Then find the CPU name. 138 for (const auto &C : CpuInfos) 139 if (Name == C.Name) 140 return C; 141 142 return {}; 143 } 144 145 void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) { 146 outs() << "All available -march extensions for AArch64\n\n" 147 << " " << left_justify("Name", 20) 148 << (DescMap.empty() ? "\n" : "Description\n"); 149 for (const auto &Ext : Extensions) { 150 // Extensions without a feature cannot be used with -march. 151 if (!Ext.Feature.empty()) { 152 std::string Description = DescMap[Ext.Name].str(); 153 outs() << " " 154 << format(Description.empty() ? "%s\n" : "%-20s%s\n", 155 Ext.Name.str().c_str(), Description.c_str()); 156 } 157 } 158 } 159 160 const llvm::AArch64::ExtensionInfo & 161 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 162 for (const auto &E : llvm::AArch64::Extensions) 163 if (E.ID == ExtID) 164 return E; 165 llvm_unreachable("Invalid extension ID"); 166 } 167 168 void AArch64::ExtensionSet::enable(ArchExtKind E) { 169 if (Enabled.test(E)) 170 return; 171 172 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n"); 173 174 Touched.set(E); 175 Enabled.set(E); 176 177 // Recursively enable all features that this one depends on. This handles all 178 // of the simple cases, where the behaviour doesn't depend on the base 179 // architecture version. 180 for (auto Dep : ExtensionDependencies) 181 if (E == Dep.Later) 182 enable(Dep.Earlier); 183 184 // Special cases for dependencies which vary depending on the base 185 // architecture version. 186 if (BaseArch) { 187 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 188 if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 189 !BaseArch->is_superset(ARMV9A)) 190 enable(AEK_FP16FML); 191 192 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 193 if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 194 enable(AEK_SHA3); 195 enable(AEK_SM4); 196 } 197 } 198 } 199 200 void AArch64::ExtensionSet::disable(ArchExtKind E) { 201 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 202 // where the latter two would not be enabled by +crypto. 203 if (E == AEK_CRYPTO) { 204 disable(AEK_AES); 205 disable(AEK_SHA2); 206 disable(AEK_SHA3); 207 disable(AEK_SM4); 208 } 209 210 if (!Enabled.test(E)) 211 return; 212 213 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n"); 214 215 Touched.set(E); 216 Enabled.reset(E); 217 218 // Recursively disable all features that depends on this one. 219 for (auto Dep : ExtensionDependencies) 220 if (E == Dep.Earlier) 221 disable(Dep.Later); 222 } 223 224 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 225 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 226 BaseArch = &CPU.Arch; 227 228 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 229 for (const auto &E : Extensions) 230 if (CPUExtensions.test(E.ID)) 231 enable(E.ID); 232 } 233 234 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 235 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 236 BaseArch = &Arch; 237 238 for (const auto &E : Extensions) 239 if (Arch.DefaultExts.test(E.ID)) 240 enable(E.ID); 241 } 242 243 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier, 244 const bool AllowNoDashForm) { 245 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 246 247 size_t NChars = 0; 248 // The "no-feat" form is allowed in the target attribute but nowhere else. 249 if (AllowNoDashForm && Modifier.starts_with("no-")) 250 NChars = 3; 251 else if (Modifier.starts_with("no")) 252 NChars = 2; 253 bool IsNegated = NChars != 0; 254 StringRef ArchExt = Modifier.drop_front(NChars); 255 256 if (auto AE = parseArchExtension(ArchExt)) { 257 if (AE->Feature.empty() || AE->NegFeature.empty()) 258 return false; 259 if (IsNegated) 260 disable(AE->ID); 261 else 262 enable(AE->ID); 263 return true; 264 } 265 return false; 266 } 267 268 void AArch64::ExtensionSet::reconstructFromParsedFeatures( 269 const std::vector<std::string> &Features) { 270 assert(Touched.none() && "Bitset already initialized"); 271 for (auto &F : Features) { 272 bool IsNegated = F[0] == '-'; 273 if (auto AE = targetFeatureToExtension(F)) { 274 Touched.set(AE->ID); 275 if (IsNegated) 276 Enabled.reset(AE->ID); 277 else 278 Enabled.set(AE->ID); 279 } 280 } 281 } 282 283 const AArch64::ExtensionInfo & 284 AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) { 285 return lookupExtensionByID(ExtID); 286 } 287