1343171Sdim//===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim// 9343171Sdim// This file implements a target parser to recognise AArch64 hardware features 10343171Sdim// such as FPU/CPU/ARCH and extension names. 11343171Sdim// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim 14343171Sdim#include "llvm/Support/AArch64TargetParser.h" 15343171Sdim#include "llvm/ADT/StringRef.h" 16343171Sdim#include "llvm/ADT/StringSwitch.h" 17343171Sdim#include <cctype> 18343171Sdim 19343171Sdimusing namespace llvm; 20343171Sdim 21343171Sdimstatic unsigned checkArchVersion(llvm::StringRef Arch) { 22343171Sdim if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) 23343171Sdim return (Arch[1] - 48); 24343171Sdim return 0; 25343171Sdim} 26343171Sdim 27343171Sdimunsigned AArch64::getDefaultFPU(StringRef CPU, AArch64::ArchKind AK) { 28343171Sdim if (CPU == "generic") 29343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].DefaultFPU; 30343171Sdim 31343171Sdim return StringSwitch<unsigned>(CPU) 32343171Sdim#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 33343171Sdim .Case(NAME, ARM::DEFAULT_FPU) 34343171Sdim#include "../../include/llvm/Support/AArch64TargetParser.def" 35343171Sdim .Default(ARM::FK_INVALID); 36343171Sdim} 37343171Sdim 38343171Sdimunsigned AArch64::getDefaultExtensions(StringRef CPU, AArch64::ArchKind AK) { 39343171Sdim if (CPU == "generic") 40343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions; 41343171Sdim 42343171Sdim return StringSwitch<unsigned>(CPU) 43343171Sdim#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 44343171Sdim .Case(NAME, AArch64ARCHNames[static_cast<unsigned>(ArchKind::ID)] \ 45343171Sdim .ArchBaseExtensions | \ 46343171Sdim DEFAULT_EXT) 47343171Sdim#include "../../include/llvm/Support/AArch64TargetParser.def" 48343171Sdim .Default(AArch64::AEK_INVALID); 49343171Sdim} 50343171Sdim 51343171SdimAArch64::ArchKind AArch64::getCPUArchKind(StringRef CPU) { 52343171Sdim if (CPU == "generic") 53343171Sdim return ArchKind::ARMV8A; 54343171Sdim 55343171Sdim return StringSwitch<AArch64::ArchKind>(CPU) 56343171Sdim#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ 57343171Sdim .Case(NAME, ArchKind::ID) 58343171Sdim#include "../../include/llvm/Support/AArch64TargetParser.def" 59343171Sdim .Default(ArchKind::INVALID); 60343171Sdim} 61343171Sdim 62343171Sdimbool AArch64::getExtensionFeatures(unsigned Extensions, 63343171Sdim std::vector<StringRef> &Features) { 64343171Sdim if (Extensions == AArch64::AEK_INVALID) 65343171Sdim return false; 66343171Sdim 67343171Sdim if (Extensions & AEK_FP) 68343171Sdim Features.push_back("+fp-armv8"); 69343171Sdim if (Extensions & AEK_SIMD) 70343171Sdim Features.push_back("+neon"); 71343171Sdim if (Extensions & AEK_CRC) 72343171Sdim Features.push_back("+crc"); 73343171Sdim if (Extensions & AEK_CRYPTO) 74343171Sdim Features.push_back("+crypto"); 75343171Sdim if (Extensions & AEK_DOTPROD) 76343171Sdim Features.push_back("+dotprod"); 77343171Sdim if (Extensions & AEK_FP16FML) 78343171Sdim Features.push_back("+fp16fml"); 79343171Sdim if (Extensions & AEK_FP16) 80343171Sdim Features.push_back("+fullfp16"); 81343171Sdim if (Extensions & AEK_PROFILE) 82343171Sdim Features.push_back("+spe"); 83343171Sdim if (Extensions & AEK_RAS) 84343171Sdim Features.push_back("+ras"); 85343171Sdim if (Extensions & AEK_LSE) 86343171Sdim Features.push_back("+lse"); 87343171Sdim if (Extensions & AEK_RDM) 88343171Sdim Features.push_back("+rdm"); 89343171Sdim if (Extensions & AEK_SVE) 90343171Sdim Features.push_back("+sve"); 91353358Sdim if (Extensions & AEK_SVE2) 92353358Sdim Features.push_back("+sve2"); 93353358Sdim if (Extensions & AEK_SVE2AES) 94353358Sdim Features.push_back("+sve2-aes"); 95353358Sdim if (Extensions & AEK_SVE2SM4) 96353358Sdim Features.push_back("+sve2-sm4"); 97353358Sdim if (Extensions & AEK_SVE2SHA3) 98353358Sdim Features.push_back("+sve2-sha3"); 99353358Sdim if (Extensions & AEK_SVE2BITPERM) 100353358Sdim Features.push_back("+sve2-bitperm"); 101343171Sdim if (Extensions & AEK_RCPC) 102343171Sdim Features.push_back("+rcpc"); 103343171Sdim 104343171Sdim return true; 105343171Sdim} 106343171Sdim 107343171Sdimbool AArch64::getArchFeatures(AArch64::ArchKind AK, 108343171Sdim std::vector<StringRef> &Features) { 109343171Sdim if (AK == ArchKind::ARMV8_1A) 110343171Sdim Features.push_back("+v8.1a"); 111343171Sdim if (AK == ArchKind::ARMV8_2A) 112343171Sdim Features.push_back("+v8.2a"); 113343171Sdim if (AK == ArchKind::ARMV8_3A) 114343171Sdim Features.push_back("+v8.3a"); 115343171Sdim if (AK == ArchKind::ARMV8_4A) 116343171Sdim Features.push_back("+v8.4a"); 117343171Sdim if (AK == ArchKind::ARMV8_5A) 118343171Sdim Features.push_back("+v8.5a"); 119343171Sdim 120343171Sdim return AK != ArchKind::INVALID; 121343171Sdim} 122343171Sdim 123343171SdimStringRef AArch64::getArchName(AArch64::ArchKind AK) { 124343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].getName(); 125343171Sdim} 126343171Sdim 127343171SdimStringRef AArch64::getCPUAttr(AArch64::ArchKind AK) { 128343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].getCPUAttr(); 129343171Sdim} 130343171Sdim 131343171SdimStringRef AArch64::getSubArch(AArch64::ArchKind AK) { 132343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].getSubArch(); 133343171Sdim} 134343171Sdim 135343171Sdimunsigned AArch64::getArchAttr(AArch64::ArchKind AK) { 136343171Sdim return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchAttr; 137343171Sdim} 138343171Sdim 139343171SdimStringRef AArch64::getArchExtName(unsigned ArchExtKind) { 140343171Sdim for (const auto &AE : AArch64ARCHExtNames) 141343171Sdim if (ArchExtKind == AE.ID) 142343171Sdim return AE.getName(); 143343171Sdim return StringRef(); 144343171Sdim} 145343171Sdim 146343171SdimStringRef AArch64::getArchExtFeature(StringRef ArchExt) { 147343171Sdim if (ArchExt.startswith("no")) { 148343171Sdim StringRef ArchExtBase(ArchExt.substr(2)); 149343171Sdim for (const auto &AE : AArch64ARCHExtNames) { 150343171Sdim if (AE.NegFeature && ArchExtBase == AE.getName()) 151343171Sdim return StringRef(AE.NegFeature); 152343171Sdim } 153343171Sdim } 154343171Sdim 155343171Sdim for (const auto &AE : AArch64ARCHExtNames) 156343171Sdim if (AE.Feature && ArchExt == AE.getName()) 157343171Sdim return StringRef(AE.Feature); 158343171Sdim return StringRef(); 159343171Sdim} 160343171Sdim 161343171SdimStringRef AArch64::getDefaultCPU(StringRef Arch) { 162343171Sdim ArchKind AK = parseArch(Arch); 163343171Sdim if (AK == ArchKind::INVALID) 164343171Sdim return StringRef(); 165343171Sdim 166343171Sdim // Look for multiple AKs to find the default for pair AK+Name. 167343171Sdim for (const auto &CPU : AArch64CPUNames) 168343171Sdim if (CPU.ArchID == AK && CPU.Default) 169343171Sdim return CPU.getName(); 170343171Sdim 171343171Sdim // If we can't find a default then target the architecture instead 172343171Sdim return "generic"; 173343171Sdim} 174343171Sdim 175343171Sdimvoid AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { 176343171Sdim for (const auto &Arch : AArch64CPUNames) { 177343171Sdim if (Arch.ArchID != ArchKind::INVALID) 178343171Sdim Values.push_back(Arch.getName()); 179343171Sdim } 180343171Sdim} 181343171Sdim 182343171Sdimbool AArch64::isX18ReservedByDefault(const Triple &TT) { 183343171Sdim return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || 184343171Sdim TT.isOSWindows(); 185343171Sdim} 186343171Sdim 187343171Sdim// Allows partial match, ex. "v8a" matches "armv8a". 188343171SdimAArch64::ArchKind AArch64::parseArch(StringRef Arch) { 189343171Sdim Arch = ARM::getCanonicalArchName(Arch); 190343171Sdim if (checkArchVersion(Arch) < 8) 191343171Sdim return ArchKind::INVALID; 192343171Sdim 193343171Sdim StringRef Syn = ARM::getArchSynonym(Arch); 194343171Sdim for (const auto A : AArch64ARCHNames) { 195343171Sdim if (A.getName().endswith(Syn)) 196343171Sdim return A.ID; 197343171Sdim } 198343171Sdim return ArchKind::INVALID; 199343171Sdim} 200343171Sdim 201343171SdimAArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) { 202343171Sdim for (const auto A : AArch64ARCHExtNames) { 203343171Sdim if (ArchExt == A.getName()) 204343171Sdim return static_cast<ArchExtKind>(A.ID); 205343171Sdim } 206343171Sdim return AArch64::AEK_INVALID; 207343171Sdim} 208343171Sdim 209343171SdimAArch64::ArchKind AArch64::parseCPUArch(StringRef CPU) { 210343171Sdim for (const auto C : AArch64CPUNames) { 211343171Sdim if (CPU == C.getName()) 212343171Sdim return C.ArchID; 213343171Sdim } 214343171Sdim return ArchKind::INVALID; 215343171Sdim} 216360784Sdim 217360784Sdim// Parse a branch protection specification, which has the form 218360784Sdim// standard | none | [bti,pac-ret[+b-key,+leaf]*] 219360784Sdim// Returns true on success, with individual elements of the specification 220360784Sdim// returned in `PBP`. Returns false in error, with `Err` containing 221360784Sdim// an erroneous part of the spec. 222360784Sdimbool AArch64::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, 223360784Sdim StringRef &Err) { 224360784Sdim PBP = {"none", "a_key", false}; 225360784Sdim if (Spec == "none") 226360784Sdim return true; // defaults are ok 227360784Sdim 228360784Sdim if (Spec == "standard") { 229360784Sdim PBP.Scope = "non-leaf"; 230360784Sdim PBP.BranchTargetEnforcement = true; 231360784Sdim return true; 232360784Sdim } 233360784Sdim 234360784Sdim SmallVector<StringRef, 4> Opts; 235360784Sdim Spec.split(Opts, "+"); 236360784Sdim for (int I = 0, E = Opts.size(); I != E; ++I) { 237360784Sdim StringRef Opt = Opts[I].trim(); 238360784Sdim if (Opt == "bti") { 239360784Sdim PBP.BranchTargetEnforcement = true; 240360784Sdim continue; 241360784Sdim } 242360784Sdim if (Opt == "pac-ret") { 243360784Sdim PBP.Scope = "non-leaf"; 244360784Sdim for (; I + 1 != E; ++I) { 245360784Sdim StringRef PACOpt = Opts[I + 1].trim(); 246360784Sdim if (PACOpt == "leaf") 247360784Sdim PBP.Scope = "all"; 248360784Sdim else if (PACOpt == "b-key") 249360784Sdim PBP.Key = "b_key"; 250360784Sdim else 251360784Sdim break; 252360784Sdim } 253360784Sdim continue; 254360784Sdim } 255360784Sdim if (Opt == "") 256360784Sdim Err = "<empty>"; 257360784Sdim else 258360784Sdim Err = Opt; 259360784Sdim return false; 260360784Sdim } 261360784Sdim 262360784Sdim return true; 263360784Sdim} 264