408 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements a target parser to recognise AArch64 hardware features10// 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 25using namespace llvm;26 27#define EMIT_FMV_INFO28#include "llvm/TargetParser/AArch64TargetParserDef.inc"29 30static 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 36const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) {37 // Note: this now takes cpu aliases into account38 std::optional<CpuInfo> Cpu = parseCpu(CPU);39 if (!Cpu)40 return nullptr;41 return &Cpu->Arch;42}43 44std::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 51std::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 58APInt 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 APInt PriorityMask = APInt::getZero(128);73 for (const FMVInfo &Info : getFMVInfo())74 if (Info.ID && FeatureBits.Enabled.test(*Info.ID))75 PriorityMask.setBit(Info.PriorityBit);76 77 return PriorityMask;78}79 80APInt 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 APInt FeaturesMask = APInt::getZero(128);90 for (const FMVInfo &Info : getFMVInfo())91 if (Info.ID && FeatureBits.Enabled.test(*Info.ID))92 FeaturesMask.setBit(Info.FeatureBit);93 94 return FeaturesMask;95}96 97bool 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 108StringRef AArch64::resolveCPUAlias(StringRef Name) {109 for (const auto &A : CpuAliases)110 if (A.AltName == Name)111 return A.Name;112 return Name;113}114 115StringRef 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 127void 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 139bool 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".145const 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 158std::optional<AArch64::ExtensionInfo>159AArch64::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 169std::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 181std::optional<AArch64::ExtensionInfo>182AArch64::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 190std::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 202void 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 219void220AArch64::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 244const llvm::AArch64::ExtensionInfo &245lookupExtensionByID(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 252void 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 all262 // of the simple cases, where the behaviour doesn't depend on the base263 // 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 base269 // 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 284void AArch64::ExtensionSet::disable(ArchExtKind E) {285 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures286 // 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 shorthand296 // for +sve2+sve-aes. For backwards compatibility, when we disable sve2-aes we297 // 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 and302 // FEAT_SVE_SM4, the latter is now associated with sve-sm4 and sve2-sm4 has303 // become shorthand for +sve2+sve-sm4. For backwards compatibility, when we304 // 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 and309 // FEAT_SVE_SHA3, the latter is now associated with sve-sha3 and sve2-sha3 has310 // become shorthand for +sve2+sve-sha3. For backwards compatibility, when we311 // 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 334void 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 344void 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 353bool 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 else372 enable(AE->ID);373 return true;374 }375 return false;376}377 378void 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 else389 Enabled.set(AE->ID);390 continue;391 }392 NonExtensions.push_back(F);393 }394}395 396void 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 404const AArch64::ExtensionInfo &405AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) {406 return lookupExtensionByID(ExtID);407}408