brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 7e35832 Raw
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