| //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements a target parser to recognise AArch64 hardware features |
| // such as FPU/CPU/ARCH and extension names. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/TargetParser/AArch64TargetParser.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/TargetParser/ARMTargetParserCommon.h" |
| #include "llvm/TargetParser/Triple.h" |
| #include <cctype> |
| |
| using namespace llvm; |
| |
| static unsigned checkArchVersion(llvm::StringRef Arch) { |
| if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1])) |
| return (Arch[1] - 48); |
| return 0; |
| } |
| |
| uint64_t AArch64::getDefaultExtensions(StringRef CPU, |
| const AArch64::ArchInfo &AI) { |
| if (CPU == "generic") |
| return AI.DefaultExts; |
| |
| // Note: this now takes cpu aliases into account |
| const CpuInfo &Cpu = parseCpu(CPU); |
| return Cpu.Arch.DefaultExts | Cpu.DefaultExtensions; |
| } |
| |
| void AArch64::getFeatureOption(StringRef Name, std::string &Feature) { |
| for (const auto &E : llvm::AArch64::Extensions) { |
| if (Name == E.Name) { |
| Feature = E.Feature; |
| return; |
| } |
| } |
| Feature = Name.str(); |
| } |
| |
| const AArch64::ArchInfo &AArch64::getArchForCpu(StringRef CPU) { |
| if (CPU == "generic") |
| return ARMV8A; |
| |
| // Note: this now takes cpu aliases into account |
| const CpuInfo &Cpu = parseCpu(CPU); |
| return Cpu.Arch; |
| } |
| |
| const AArch64::ArchInfo &AArch64::ArchInfo::findBySubArch(StringRef SubArch) { |
| for (const auto *A : AArch64::ArchInfos) |
| if (A->getSubArch() == SubArch) |
| return *A; |
| return AArch64::INVALID; |
| } |
| |
| uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { |
| uint64_t FeaturesMask = 0; |
| for (const StringRef &FeatureStr : FeatureStrs) { |
| for (const auto &E : llvm::AArch64::Extensions) |
| if (FeatureStr == E.Name) { |
| FeaturesMask |= (1ULL << E.CPUFeature); |
| break; |
| } |
| } |
| return FeaturesMask; |
| } |
| |
| bool AArch64::getExtensionFeatures(uint64_t InputExts, |
| std::vector<StringRef> &Features) { |
| if (InputExts == AArch64::AEK_INVALID) |
| return false; |
| |
| for (const auto &E : Extensions) |
| /* INVALID and NONE have no feature name. */ |
| if ((InputExts & E.ID) && !E.Feature.empty()) |
| Features.push_back(E.Feature); |
| |
| return true; |
| } |
| |
| StringRef AArch64::resolveCPUAlias(StringRef Name) { |
| for (const auto &A : CpuAliases) |
| if (A.Alias == Name) |
| return A.Name; |
| return Name; |
| } |
| |
| StringRef AArch64::getArchExtFeature(StringRef ArchExt) { |
| if (ArchExt.startswith("no")) { |
| StringRef ArchExtBase(ArchExt.substr(2)); |
| for (const auto &AE : Extensions) { |
| if (!AE.NegFeature.empty() && ArchExtBase == AE.Name) |
| return AE.NegFeature; |
| } |
| } |
| |
| for (const auto &AE : Extensions) |
| if (!AE.Feature.empty() && ArchExt == AE.Name) |
| return AE.Feature; |
| return StringRef(); |
| } |
| |
| void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { |
| for (const auto &C : CpuInfos) |
| if (C.Arch != INVALID) |
| Values.push_back(C.Name); |
| |
| for (const auto &Alias : CpuAliases) |
| Values.push_back(Alias.Alias); |
| } |
| |
| bool AArch64::isX18ReservedByDefault(const Triple &TT) { |
| return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() || |
| TT.isOSWindows(); |
| } |
| |
| // Allows partial match, ex. "v8a" matches "armv8a". |
| const AArch64::ArchInfo &AArch64::parseArch(StringRef Arch) { |
| Arch = llvm::ARM::getCanonicalArchName(Arch); |
| if (checkArchVersion(Arch) < 8) |
| return AArch64::INVALID; |
| |
| StringRef Syn = llvm::ARM::getArchSynonym(Arch); |
| for (const auto *A : ArchInfos) { |
| if (A->Name.endswith(Syn)) |
| return *A; |
| } |
| return AArch64::INVALID; |
| } |
| |
| AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) { |
| for (const auto &A : Extensions) { |
| if (ArchExt == A.Name) |
| return static_cast<ArchExtKind>(A.ID); |
| } |
| return AArch64::AEK_INVALID; |
| } |
| |
| const AArch64::CpuInfo &AArch64::parseCpu(StringRef Name) { |
| // Resolve aliases first. |
| Name = resolveCPUAlias(Name); |
| |
| // Then find the CPU name. |
| for (const auto &C : CpuInfos) |
| if (Name == C.Name) |
| return C; |
| |
| // "generic" returns invalid. |
| assert(Name != "invalid" && "Unexpected recursion."); |
| return parseCpu("invalid"); |
| } |