1bdd1243dSDimitry Andric //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // This file implements a target parser to recognise AArch64 hardware features 10bdd1243dSDimitry Andric // such as FPU/CPU/ARCH and extension names. 11bdd1243dSDimitry Andric // 12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 13bdd1243dSDimitry Andric 14bdd1243dSDimitry Andric #include "llvm/TargetParser/AArch64TargetParser.h" 15*7a6dacacSDimitry Andric #include "llvm/Support/Debug.h" 165f757f3fSDimitry Andric #include "llvm/Support/Format.h" 175f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h" 18bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParserCommon.h" 19bdd1243dSDimitry Andric #include "llvm/TargetParser/Triple.h" 20bdd1243dSDimitry Andric #include <cctype> 21bdd1243dSDimitry Andric 22*7a6dacacSDimitry Andric #define DEBUG_TYPE "target-parser" 23*7a6dacacSDimitry Andric 24bdd1243dSDimitry Andric using namespace llvm; 25bdd1243dSDimitry Andric 26bdd1243dSDimitry Andric static unsigned checkArchVersion(llvm::StringRef Arch) { 27bdd1243dSDimitry Andric if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) 28bdd1243dSDimitry Andric return (Arch[1] - 48); 29bdd1243dSDimitry Andric return 0; 30bdd1243dSDimitry Andric } 31bdd1243dSDimitry Andric 32*7a6dacacSDimitry Andric const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) { 33bdd1243dSDimitry Andric if (CPU == "generic") 34*7a6dacacSDimitry Andric return &ARMV8A; 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric // Note: this now takes cpu aliases into account 3706c3fb27SDimitry Andric std::optional<CpuInfo> Cpu = parseCpu(CPU); 3806c3fb27SDimitry Andric if (!Cpu) 39*7a6dacacSDimitry Andric return nullptr; 40*7a6dacacSDimitry Andric return &Cpu->Arch; 41bdd1243dSDimitry Andric } 42bdd1243dSDimitry Andric 4306c3fb27SDimitry Andric std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) { 44bdd1243dSDimitry Andric for (const auto *A : AArch64::ArchInfos) 45bdd1243dSDimitry Andric if (A->getSubArch() == SubArch) 46bdd1243dSDimitry Andric return *A; 4706c3fb27SDimitry Andric return {}; 48bdd1243dSDimitry Andric } 49bdd1243dSDimitry Andric 50bdd1243dSDimitry Andric uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { 51bdd1243dSDimitry Andric uint64_t FeaturesMask = 0; 52bdd1243dSDimitry Andric for (const StringRef &FeatureStr : FeatureStrs) { 53*7a6dacacSDimitry Andric if (auto Ext = parseArchExtension(FeatureStr)) 54*7a6dacacSDimitry Andric FeaturesMask |= (1ULL << Ext->CPUFeature); 55bdd1243dSDimitry Andric } 56bdd1243dSDimitry Andric return FeaturesMask; 57bdd1243dSDimitry Andric } 58bdd1243dSDimitry Andric 595f757f3fSDimitry Andric bool AArch64::getExtensionFeatures( 605f757f3fSDimitry Andric const AArch64::ExtensionBitset &InputExts, 61bdd1243dSDimitry Andric std::vector<StringRef> &Features) { 62bdd1243dSDimitry Andric for (const auto &E : Extensions) 63bdd1243dSDimitry Andric /* INVALID and NONE have no feature name. */ 645f757f3fSDimitry Andric if (InputExts.test(E.ID) && !E.Feature.empty()) 65bdd1243dSDimitry Andric Features.push_back(E.Feature); 66bdd1243dSDimitry Andric 67bdd1243dSDimitry Andric return true; 68bdd1243dSDimitry Andric } 69bdd1243dSDimitry Andric 70bdd1243dSDimitry Andric StringRef AArch64::resolveCPUAlias(StringRef Name) { 71bdd1243dSDimitry Andric for (const auto &A : CpuAliases) 72bdd1243dSDimitry Andric if (A.Alias == Name) 73bdd1243dSDimitry Andric return A.Name; 74bdd1243dSDimitry Andric return Name; 75bdd1243dSDimitry Andric } 76bdd1243dSDimitry Andric 77bdd1243dSDimitry Andric StringRef AArch64::getArchExtFeature(StringRef ArchExt) { 78*7a6dacacSDimitry Andric bool IsNegated = ArchExt.starts_with("no"); 79*7a6dacacSDimitry Andric StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt; 80*7a6dacacSDimitry Andric 81*7a6dacacSDimitry Andric if (auto AE = parseArchExtension(ArchExtBase)) { 82*7a6dacacSDimitry Andric // Note: the returned string can be empty. 83*7a6dacacSDimitry Andric return IsNegated ? AE->NegFeature : AE->Feature; 84bdd1243dSDimitry Andric } 85bdd1243dSDimitry Andric 86bdd1243dSDimitry Andric return StringRef(); 87bdd1243dSDimitry Andric } 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 90bdd1243dSDimitry Andric for (const auto &C : CpuInfos) 91bdd1243dSDimitry Andric Values.push_back(C.Name); 92bdd1243dSDimitry Andric 93bdd1243dSDimitry Andric for (const auto &Alias : CpuAliases) 94bdd1243dSDimitry Andric Values.push_back(Alias.Alias); 95bdd1243dSDimitry Andric } 96bdd1243dSDimitry Andric 97bdd1243dSDimitry Andric bool AArch64::isX18ReservedByDefault(const Triple &TT) { 98bdd1243dSDimitry Andric return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || 9906c3fb27SDimitry Andric TT.isOSWindows() || TT.isOHOSFamily(); 100bdd1243dSDimitry Andric } 101bdd1243dSDimitry Andric 102bdd1243dSDimitry Andric // Allows partial match, ex. "v8a" matches "armv8a". 103*7a6dacacSDimitry Andric const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) { 104bdd1243dSDimitry Andric Arch = llvm::ARM::getCanonicalArchName(Arch); 105bdd1243dSDimitry Andric if (checkArchVersion(Arch) < 8) 10606c3fb27SDimitry Andric return {}; 107bdd1243dSDimitry Andric 108bdd1243dSDimitry Andric StringRef Syn = llvm::ARM::getArchSynonym(Arch); 109bdd1243dSDimitry Andric for (const auto *A : ArchInfos) { 1105f757f3fSDimitry Andric if (A->Name.ends_with(Syn)) 111*7a6dacacSDimitry Andric return A; 112bdd1243dSDimitry Andric } 11306c3fb27SDimitry Andric return {}; 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric 11606c3fb27SDimitry Andric std::optional<AArch64::ExtensionInfo> AArch64::parseArchExtension(StringRef ArchExt) { 117bdd1243dSDimitry Andric for (const auto &A : Extensions) { 118bdd1243dSDimitry Andric if (ArchExt == A.Name) 11906c3fb27SDimitry Andric return A; 120bdd1243dSDimitry Andric } 12106c3fb27SDimitry Andric return {}; 122bdd1243dSDimitry Andric } 123bdd1243dSDimitry Andric 12406c3fb27SDimitry Andric std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) { 125bdd1243dSDimitry Andric // Resolve aliases first. 126bdd1243dSDimitry Andric Name = resolveCPUAlias(Name); 127bdd1243dSDimitry Andric 128bdd1243dSDimitry Andric // Then find the CPU name. 129bdd1243dSDimitry Andric for (const auto &C : CpuInfos) 130bdd1243dSDimitry Andric if (Name == C.Name) 131bdd1243dSDimitry Andric return C; 132bdd1243dSDimitry Andric 13306c3fb27SDimitry Andric return {}; 134bdd1243dSDimitry Andric } 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) { 1375f757f3fSDimitry Andric outs() << "All available -march extensions for AArch64\n\n" 1385f757f3fSDimitry Andric << " " << left_justify("Name", 20) 1395f757f3fSDimitry Andric << (DescMap.empty() ? "\n" : "Description\n"); 1405f757f3fSDimitry Andric for (const auto &Ext : Extensions) { 1415f757f3fSDimitry Andric // Extensions without a feature cannot be used with -march. 1425f757f3fSDimitry Andric if (!Ext.Feature.empty()) { 1435f757f3fSDimitry Andric std::string Description = DescMap[Ext.Name].str(); 1445f757f3fSDimitry Andric outs() << " " 1455f757f3fSDimitry Andric << format(Description.empty() ? "%s\n" : "%-20s%s\n", 1465f757f3fSDimitry Andric Ext.Name.str().c_str(), Description.c_str()); 1475f757f3fSDimitry Andric } 1485f757f3fSDimitry Andric } 1495f757f3fSDimitry Andric } 150*7a6dacacSDimitry Andric 151*7a6dacacSDimitry Andric const llvm::AArch64::ExtensionInfo & 152*7a6dacacSDimitry Andric lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) { 153*7a6dacacSDimitry Andric for (const auto &E : llvm::AArch64::Extensions) 154*7a6dacacSDimitry Andric if (E.ID == ExtID) 155*7a6dacacSDimitry Andric return E; 156*7a6dacacSDimitry Andric llvm_unreachable("Invalid extension ID"); 157*7a6dacacSDimitry Andric } 158*7a6dacacSDimitry Andric 159*7a6dacacSDimitry Andric void AArch64::ExtensionSet::enable(ArchExtKind E) { 160*7a6dacacSDimitry Andric if (Enabled.test(E)) 161*7a6dacacSDimitry Andric return; 162*7a6dacacSDimitry Andric 163*7a6dacacSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n"); 164*7a6dacacSDimitry Andric 165*7a6dacacSDimitry Andric Touched.set(E); 166*7a6dacacSDimitry Andric Enabled.set(E); 167*7a6dacacSDimitry Andric 168*7a6dacacSDimitry Andric // Recursively enable all features that this one depends on. This handles all 169*7a6dacacSDimitry Andric // of the simple cases, where the behaviour doesn't depend on the base 170*7a6dacacSDimitry Andric // architecture version. 171*7a6dacacSDimitry Andric for (auto Dep : ExtensionDependencies) 172*7a6dacacSDimitry Andric if (E == Dep.Later) 173*7a6dacacSDimitry Andric enable(Dep.Earlier); 174*7a6dacacSDimitry Andric 175*7a6dacacSDimitry Andric // Special cases for dependencies which vary depending on the base 176*7a6dacacSDimitry Andric // architecture version. 177*7a6dacacSDimitry Andric if (BaseArch) { 178*7a6dacacSDimitry Andric // +sve implies +f32mm if the base architecture is v8.6A+ or v9.1A+ 179*7a6dacacSDimitry Andric // It isn't the case in general that sve implies both f64mm and f32mm 180*7a6dacacSDimitry Andric if (E == AEK_SVE && BaseArch->is_superset(ARMV8_6A)) 181*7a6dacacSDimitry Andric enable(AEK_F32MM); 182*7a6dacacSDimitry Andric 183*7a6dacacSDimitry Andric // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+ 184*7a6dacacSDimitry Andric if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) && 185*7a6dacacSDimitry Andric !BaseArch->is_superset(ARMV9A)) 186*7a6dacacSDimitry Andric enable(AEK_FP16FML); 187*7a6dacacSDimitry Andric 188*7a6dacacSDimitry Andric // For all architectures, +crypto enables +aes and +sha2. 189*7a6dacacSDimitry Andric if (E == AEK_CRYPTO) { 190*7a6dacacSDimitry Andric enable(AEK_AES); 191*7a6dacacSDimitry Andric enable(AEK_SHA2); 192*7a6dacacSDimitry Andric } 193*7a6dacacSDimitry Andric 194*7a6dacacSDimitry Andric // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4. 195*7a6dacacSDimitry Andric if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) { 196*7a6dacacSDimitry Andric enable(AEK_SHA3); 197*7a6dacacSDimitry Andric enable(AEK_SM4); 198*7a6dacacSDimitry Andric } 199*7a6dacacSDimitry Andric } 200*7a6dacacSDimitry Andric } 201*7a6dacacSDimitry Andric 202*7a6dacacSDimitry Andric void AArch64::ExtensionSet::disable(ArchExtKind E) { 203*7a6dacacSDimitry Andric // -crypto always disables aes, sha2, sha3 and sm4, even for architectures 204*7a6dacacSDimitry Andric // where the latter two would not be enabled by +crypto. 205*7a6dacacSDimitry Andric if (E == AEK_CRYPTO) { 206*7a6dacacSDimitry Andric disable(AEK_AES); 207*7a6dacacSDimitry Andric disable(AEK_SHA2); 208*7a6dacacSDimitry Andric disable(AEK_SHA3); 209*7a6dacacSDimitry Andric disable(AEK_SM4); 210*7a6dacacSDimitry Andric } 211*7a6dacacSDimitry Andric 212*7a6dacacSDimitry Andric if (!Enabled.test(E)) 213*7a6dacacSDimitry Andric return; 214*7a6dacacSDimitry Andric 215*7a6dacacSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n"); 216*7a6dacacSDimitry Andric 217*7a6dacacSDimitry Andric Touched.set(E); 218*7a6dacacSDimitry Andric Enabled.reset(E); 219*7a6dacacSDimitry Andric 220*7a6dacacSDimitry Andric // Recursively disable all features that depends on this one. 221*7a6dacacSDimitry Andric for (auto Dep : ExtensionDependencies) 222*7a6dacacSDimitry Andric if (E == Dep.Earlier) 223*7a6dacacSDimitry Andric disable(Dep.Later); 224*7a6dacacSDimitry Andric } 225*7a6dacacSDimitry Andric 226*7a6dacacSDimitry Andric void AArch64::ExtensionSet::toLLVMFeatureList( 227*7a6dacacSDimitry Andric std::vector<StringRef> &Features) const { 228*7a6dacacSDimitry Andric if (BaseArch && !BaseArch->ArchFeature.empty()) 229*7a6dacacSDimitry Andric Features.push_back(BaseArch->ArchFeature); 230*7a6dacacSDimitry Andric 231*7a6dacacSDimitry Andric for (const auto &E : Extensions) { 232*7a6dacacSDimitry Andric if (E.Feature.empty() || !Touched.test(E.ID)) 233*7a6dacacSDimitry Andric continue; 234*7a6dacacSDimitry Andric if (Enabled.test(E.ID)) 235*7a6dacacSDimitry Andric Features.push_back(E.Feature); 236*7a6dacacSDimitry Andric else 237*7a6dacacSDimitry Andric Features.push_back(E.NegFeature); 238*7a6dacacSDimitry Andric } 239*7a6dacacSDimitry Andric } 240*7a6dacacSDimitry Andric 241*7a6dacacSDimitry Andric void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) { 242*7a6dacacSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n"); 243*7a6dacacSDimitry Andric BaseArch = &CPU.Arch; 244*7a6dacacSDimitry Andric 245*7a6dacacSDimitry Andric AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions(); 246*7a6dacacSDimitry Andric for (const auto &E : Extensions) 247*7a6dacacSDimitry Andric if (CPUExtensions.test(E.ID)) 248*7a6dacacSDimitry Andric enable(E.ID); 249*7a6dacacSDimitry Andric } 250*7a6dacacSDimitry Andric 251*7a6dacacSDimitry Andric void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) { 252*7a6dacacSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n"); 253*7a6dacacSDimitry Andric BaseArch = &Arch; 254*7a6dacacSDimitry Andric 255*7a6dacacSDimitry Andric for (const auto &E : Extensions) 256*7a6dacacSDimitry Andric if (Arch.DefaultExts.test(E.ID)) 257*7a6dacacSDimitry Andric enable(E.ID); 258*7a6dacacSDimitry Andric } 259*7a6dacacSDimitry Andric 260*7a6dacacSDimitry Andric bool AArch64::ExtensionSet::parseModifier(StringRef Modifier) { 261*7a6dacacSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n"); 262*7a6dacacSDimitry Andric 263*7a6dacacSDimitry Andric // Negative modifiers, with the syntax "no<feat>" 264*7a6dacacSDimitry Andric if (Modifier.starts_with("no")) { 265*7a6dacacSDimitry Andric StringRef ModifierBase(Modifier.substr(2)); 266*7a6dacacSDimitry Andric for (const auto &AE : Extensions) { 267*7a6dacacSDimitry Andric if (!AE.NegFeature.empty() && ModifierBase == AE.Name) { 268*7a6dacacSDimitry Andric disable(AE.ID); 269*7a6dacacSDimitry Andric return true; 270*7a6dacacSDimitry Andric } 271*7a6dacacSDimitry Andric } 272*7a6dacacSDimitry Andric } 273*7a6dacacSDimitry Andric 274*7a6dacacSDimitry Andric // Positive modifiers 275*7a6dacacSDimitry Andric for (const auto &AE : Extensions) { 276*7a6dacacSDimitry Andric if (!AE.Feature.empty() && Modifier == AE.Name) { 277*7a6dacacSDimitry Andric enable(AE.ID); 278*7a6dacacSDimitry Andric return true; 279*7a6dacacSDimitry Andric } 280*7a6dacacSDimitry Andric } 281*7a6dacacSDimitry Andric 282*7a6dacacSDimitry Andric return false; 283*7a6dacacSDimitry Andric } 284