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::resolveExtAlias(StringRef Name) { 78 for (const auto &A : ExtAliases) 79 if (A.AltName == Name) 80 return A.Name; 81 return Name; 82 } 83 84 StringRef AArch64::getArchExtFeature(StringRef ArchExt) { 85 bool IsNegated = ArchExt.starts_with("no"); 86 StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt; 87 88 if (auto AE = parseArchExtension(ArchExtBase)) { 89 // Note: the returned string can be empty. 90 return IsNegated ? AE->NegFeature : AE->Feature; 91 } 92 93 return StringRef(); 94 } 95 96 void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 97 for (const auto &C : CpuInfos) 98 Values.push_back(C.Name); 99 100 for (const auto &Alias : CpuAliases) 101 Values.push_back(Alias.AltName); 102 } 103 104 bool AArch64::isX18ReservedByDefault(const Triple &TT) { 105 return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || 106 TT.isOSWindows() || TT.isOHOSFamily(); 107 } 108 109 // Allows partial match, ex. "v8a" matches "armv8a". 110 const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) { 111 Arch = llvm::ARM::getCanonicalArchName(Arch); 112 if (checkArchVersion(Arch) < 8) 113 return {}; 114 115 StringRef Syn = llvm::ARM::getArchSynonym(Arch); 116 for (const auto *A : ArchInfos) { 117 if (A->Name.ends_with(Syn)) 118 return A; 119 } 120 return {}; 121 } 122 123 std::optional<AArch64::ExtensionInfo> AArch64::parseArchExtension(StringRef ArchExt) { 124 // Resolve aliases first. 125 ArchExt = resolveExtAlias(ArchExt); 126 127 // Then find the Extension name. 128 for (const auto &A : Extensions) { 129 if (ArchExt == A.Name) 130 return A; 131 } 132 return {}; 133 } 134 135 std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 136 // Resolve aliases first. 137 Name = resolveCPUAlias(Name); 138 139 // Then find the CPU name. 140 for (const auto &C : CpuInfos) 141 if (Name == C.Name) 142 return C; 143 144 return {}; 145 } 146 147 void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) { 148 outs() << "All available -march extensions for AArch64\n\n" 149 << " " << left_justify("Name", 20) 150 << (DescMap.empty() ? "\n" : "Description\n"); 151 for (const auto &Ext : Extensions) { 152 // Extensions without a feature cannot be used with -march. 153 if (!Ext.Feature.empty()) { 154 std::string Description = DescMap[Ext.Name].str(); 155 outs() << " " 156 << format(Description.empty() ? "%s\n" : "%-20s%s\n", 157 Ext.Name.str().c_str(), Description.c_str()); 158 } 159 } 160 } 161 162 const llvm::AArch64::ExtensionInfo & 163 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 164 for (const auto &E : llvm::AArch64::Extensions) 165 if (E.ID == ExtID) 166 return E; 167 llvm_unreachable("Invalid extension ID"); 168 } 169 170 void AArch64::ExtensionSet::enable(ArchExtKind E) { 171 if (Enabled.test(E)) 172 return; 173 174 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n"); 175 176 Touched.set(E); 177 Enabled.set(E); 178 179 // Recursively enable all features that this one depends on. This handles all 180 // of the simple cases, where the behaviour doesn't depend on the base 181 // architecture version. 182 for (auto Dep : ExtensionDependencies) 183 if (E == Dep.Later) 184 enable(Dep.Earlier); 185 186 // Special cases for dependencies which vary depending on the base 187 // architecture version. 188 if (BaseArch) { 189 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 190 if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 191 !BaseArch->is_superset(ARMV9A)) 192 enable(AEK_FP16FML); 193 194 // For all architectures, +crypto enables +aes and +sha2. 195 if (E == AEK_CRYPTO) { 196 enable(AEK_AES); 197 enable(AEK_SHA2); 198 } 199 200 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 201 if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 202 enable(AEK_SHA3); 203 enable(AEK_SM4); 204 } 205 } 206 } 207 208 void AArch64::ExtensionSet::disable(ArchExtKind E) { 209 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 210 // where the latter two would not be enabled by +crypto. 211 if (E == AEK_CRYPTO) { 212 disable(AEK_AES); 213 disable(AEK_SHA2); 214 disable(AEK_SHA3); 215 disable(AEK_SM4); 216 } 217 218 if (!Enabled.test(E)) 219 return; 220 221 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n"); 222 223 Touched.set(E); 224 Enabled.reset(E); 225 226 // Recursively disable all features that depends on this one. 227 for (auto Dep : ExtensionDependencies) 228 if (E == Dep.Earlier) 229 disable(Dep.Later); 230 } 231 232 void AArch64::ExtensionSet::toLLVMFeatureList( 233 std::vector<StringRef> &Features) const { 234 if (BaseArch && !BaseArch->ArchFeature.empty()) 235 Features.push_back(BaseArch->ArchFeature); 236 237 for (const auto &E : Extensions) { 238 if (E.Feature.empty() || !Touched.test(E.ID)) 239 continue; 240 if (Enabled.test(E.ID)) 241 Features.push_back(E.Feature); 242 else 243 Features.push_back(E.NegFeature); 244 } 245 } 246 247 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 248 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 249 BaseArch = &CPU.Arch; 250 251 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 252 for (const auto &E : Extensions) 253 if (CPUExtensions.test(E.ID)) 254 enable(E.ID); 255 } 256 257 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 258 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 259 BaseArch = &Arch; 260 261 for (const auto &E : Extensions) 262 if (Arch.DefaultExts.test(E.ID)) 263 enable(E.ID); 264 } 265 266 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier) { 267 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 268 269 bool IsNegated = Modifier.starts_with("no"); 270 StringRef ArchExt = IsNegated ? Modifier.drop_front(2) : Modifier; 271 272 if (auto AE = parseArchExtension(ArchExt)) { 273 if (AE->Feature.empty() || AE->NegFeature.empty()) 274 return false; 275 if (IsNegated) 276 disable(AE->ID); 277 else 278 enable(AE->ID); 279 return true; 280 } 281 return false; 282 } 283