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.Alias == 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.Alias); 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> AArch64::parseArchExtension(StringRef ArchExt) { 117 for (const auto &A : Extensions) { 118 if (ArchExt == A.Name) 119 return A; 120 } 121 return {}; 122 } 123 124 std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 125 // Resolve aliases first. 126 Name = resolveCPUAlias(Name); 127 128 // Then find the CPU name. 129 for (const auto &C : CpuInfos) 130 if (Name == C.Name) 131 return C; 132 133 return {}; 134 } 135 136 void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) { 137 outs() << "All available -march extensions for AArch64\n\n" 138 << " " << left_justify("Name", 20) 139 << (DescMap.empty() ? "\n" : "Description\n"); 140 for (const auto &Ext : Extensions) { 141 // Extensions without a feature cannot be used with -march. 142 if (!Ext.Feature.empty()) { 143 std::string Description = DescMap[Ext.Name].str(); 144 outs() << " " 145 << format(Description.empty() ? "%s\n" : "%-20s%s\n", 146 Ext.Name.str().c_str(), Description.c_str()); 147 } 148 } 149 } 150 151 const llvm::AArch64::ExtensionInfo & 152 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 153 for (const auto &E : llvm::AArch64::Extensions) 154 if (E.ID == ExtID) 155 return E; 156 llvm_unreachable("Invalid extension ID"); 157 } 158 159 void AArch64::ExtensionSet::enable(ArchExtKind E) { 160 if (Enabled.test(E)) 161 return; 162 163 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n"); 164 165 Touched.set(E); 166 Enabled.set(E); 167 168 // Recursively enable all features that this one depends on. This handles all 169 // of the simple cases, where the behaviour doesn't depend on the base 170 // architecture version. 171 for (auto Dep : ExtensionDependencies) 172 if (E == Dep.Later) 173 enable(Dep.Earlier); 174 175 // Special cases for dependencies which vary depending on the base 176 // architecture version. 177 if (BaseArch) { 178 // +sve implies +f32mm if the base architecture is v8.6A+ or v9.1A+ 179 // It isn't the case in general that sve implies both f64mm and f32mm 180 if (E == AEK_SVE && BaseArch->is_superset(ARMV8_6A)) 181 enable(AEK_F32MM); 182 183 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 184 if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 185 !BaseArch->is_superset(ARMV9A)) 186 enable(AEK_FP16FML); 187 188 // For all architectures, +crypto enables +aes and +sha2. 189 if (E == AEK_CRYPTO) { 190 enable(AEK_AES); 191 enable(AEK_SHA2); 192 } 193 194 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 195 if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 196 enable(AEK_SHA3); 197 enable(AEK_SM4); 198 } 199 } 200 } 201 202 void AArch64::ExtensionSet::disable(ArchExtKind E) { 203 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 204 // where the latter two would not be enabled by +crypto. 205 if (E == AEK_CRYPTO) { 206 disable(AEK_AES); 207 disable(AEK_SHA2); 208 disable(AEK_SHA3); 209 disable(AEK_SM4); 210 } 211 212 if (!Enabled.test(E)) 213 return; 214 215 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n"); 216 217 Touched.set(E); 218 Enabled.reset(E); 219 220 // Recursively disable all features that depends on this one. 221 for (auto Dep : ExtensionDependencies) 222 if (E == Dep.Earlier) 223 disable(Dep.Later); 224 } 225 226 void AArch64::ExtensionSet::toLLVMFeatureList( 227 std::vector<StringRef> &Features) const { 228 if (BaseArch && !BaseArch->ArchFeature.empty()) 229 Features.push_back(BaseArch->ArchFeature); 230 231 for (const auto &E : Extensions) { 232 if (E.Feature.empty() || !Touched.test(E.ID)) 233 continue; 234 if (Enabled.test(E.ID)) 235 Features.push_back(E.Feature); 236 else 237 Features.push_back(E.NegFeature); 238 } 239 } 240 241 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 242 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 243 BaseArch = &CPU.Arch; 244 245 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 246 for (const auto &E : Extensions) 247 if (CPUExtensions.test(E.ID)) 248 enable(E.ID); 249 } 250 251 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 252 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 253 BaseArch = &Arch; 254 255 for (const auto &E : Extensions) 256 if (Arch.DefaultExts.test(E.ID)) 257 enable(E.ID); 258 } 259 260 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier) { 261 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 262 263 // Negative modifiers, with the syntax "no<feat>" 264 if (Modifier.starts_with("no")) { 265 StringRef ModifierBase(Modifier.substr(2)); 266 for (const auto &AE : Extensions) { 267 if (!AE.NegFeature.empty() && ModifierBase == AE.Name) { 268 disable(AE.ID); 269 return true; 270 } 271 } 272 } 273 274 // Positive modifiers 275 for (const auto &AE : Extensions) { 276 if (!AE.Feature.empty() && Modifier == AE.Name) { 277 enable(AE.ID); 278 return true; 279 } 280 } 281 282 return false; 283 } 284