1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
|
//===-- 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/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/ARMTargetParserCommon.h"
#include "llvm/TargetParser/Triple.h"
#include <cctype>
#include <vector>
#define DEBUG_TYPE "target-parser"
using namespace llvm;
#define EMIT_FMV_INFO
#include "llvm/TargetParser/AArch64TargetParserDef.inc"
static unsigned checkArchVersion(llvm::StringRef Arch) {
if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
return (Arch[1] - 48);
return 0;
}
const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) {
// Note: this now takes cpu aliases into account
std::optional<CpuInfo> Cpu = parseCpu(CPU);
if (!Cpu)
return nullptr;
return &Cpu->Arch;
}
std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) {
for (const auto *A : AArch64::ArchInfos)
if (A->getSubArch() == SubArch)
return *A;
return {};
}
uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
uint64_t FeaturesMask = 0;
for (const StringRef &FeatureStr : FeatureStrs) {
if (auto Ext = parseFMVExtension(FeatureStr))
FeaturesMask |= (1ULL << Ext->Bit);
}
return FeaturesMask;
}
bool AArch64::getExtensionFeatures(
const AArch64::ExtensionBitset &InputExts,
std::vector<StringRef> &Features) {
for (const auto &E : Extensions)
/* INVALID and NONE have no feature name. */
if (InputExts.test(E.ID) && !E.PosTargetFeature.empty())
Features.push_back(E.PosTargetFeature);
return true;
}
StringRef AArch64::resolveCPUAlias(StringRef Name) {
for (const auto &A : CpuAliases)
if (A.AltName == Name)
return A.Name;
return Name;
}
StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
bool IsNegated = ArchExt.starts_with("no");
StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
if (auto AE = parseArchExtension(ArchExtBase)) {
assert(!(AE.has_value() && AE->NegTargetFeature.empty()));
return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature;
}
return StringRef();
}
void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
for (const auto &C : CpuInfos)
Values.push_back(C.Name);
for (const auto &Alias : CpuAliases)
// The apple-latest alias is backend only, do not expose it to clang's -mcpu.
if (Alias.AltName != "apple-latest")
Values.push_back(Alias.AltName);
llvm::sort(Values);
}
bool AArch64::isX18ReservedByDefault(const Triple &TT) {
return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
TT.isOSWindows() || TT.isOHOSFamily();
}
// Allows partial match, ex. "v8a" matches "armv8a".
const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
Arch = llvm::ARM::getCanonicalArchName(Arch);
if (checkArchVersion(Arch) < 8)
return {};
StringRef Syn = llvm::ARM::getArchSynonym(Arch);
for (const auto *A : ArchInfos) {
if (A->Name.ends_with(Syn))
return A;
}
return {};
}
std::optional<AArch64::ExtensionInfo>
AArch64::parseArchExtension(StringRef ArchExt) {
if (ArchExt.empty())
return {};
for (const auto &A : Extensions) {
if (ArchExt == A.UserVisibleName || ArchExt == A.Alias)
return A;
}
return {};
}
std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
// FIXME introduce general alias functionality, or remove this exception.
if (FMVExt == "rdma")
FMVExt = "rdm";
for (const auto &I : getFMVInfo()) {
if (FMVExt == I.Name)
return I;
}
return {};
}
std::optional<AArch64::ExtensionInfo>
AArch64::targetFeatureToExtension(StringRef TargetFeature) {
for (const auto &E : Extensions)
if (TargetFeature == E.PosTargetFeature)
return E;
return {};
}
std::optional<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;
return {};
}
void AArch64::PrintSupportedExtensions() {
outs() << "All available -march extensions for AArch64\n\n"
<< " " << left_justify("Name", 20)
<< left_justify("Architecture Feature(s)", 55)
<< "Description\n";
for (const auto &Ext : Extensions) {
// Extensions without a feature cannot be used with -march.
if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) {
outs() << " "
<< format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
Ext.UserVisibleName.str().c_str(),
Ext.ArchFeatureName.str().c_str(),
Ext.Description.str().c_str());
}
}
}
void
AArch64::printEnabledExtensions(const std::set<StringRef> &EnabledFeatureNames) {
outs() << "Extensions enabled for the given AArch64 target\n\n"
<< " " << left_justify("Architecture Feature(s)", 55)
<< "Description\n";
std::vector<ExtensionInfo> EnabledExtensionsInfo;
for (const auto &FeatureName : EnabledFeatureNames) {
std::string PosFeatureName = '+' + FeatureName.str();
if (auto ExtInfo = targetFeatureToExtension(PosFeatureName))
EnabledExtensionsInfo.push_back(*ExtInfo);
}
std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(),
[](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) {
return Lhs.ArchFeatureName < Rhs.ArchFeatureName;
});
for (const auto &Ext : EnabledExtensionsInfo) {
outs() << " "
<< format("%-55s%s\n",
Ext.ArchFeatureName.str().c_str(),
Ext.Description.str().c_str());
}
}
const llvm::AArch64::ExtensionInfo &
lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
for (const auto &E : llvm::AArch64::Extensions)
if (E.ID == ExtID)
return E;
llvm_unreachable("Invalid extension ID");
}
void AArch64::ExtensionSet::enable(ArchExtKind E) {
if (Enabled.test(E))
return;
LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n");
Touched.set(E);
Enabled.set(E);
// Recursively enable all features that this one depends on. This handles all
// of the simple cases, where the behaviour doesn't depend on the base
// architecture version.
for (auto Dep : ExtensionDependencies)
if (E == Dep.Later)
enable(Dep.Earlier);
// Special cases for dependencies which vary depending on the base
// architecture version.
if (BaseArch) {
// +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+
if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) &&
!BaseArch->is_superset(ARMV9A))
enable(AEK_FP16FML);
// For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4.
if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) {
enable(AEK_SHA3);
enable(AEK_SM4);
}
}
}
void AArch64::ExtensionSet::disable(ArchExtKind E) {
// -crypto always disables aes, sha2, sha3 and sm4, even for architectures
// where the latter two would not be enabled by +crypto.
if (E == AEK_CRYPTO) {
disable(AEK_AES);
disable(AEK_SHA2);
disable(AEK_SHA3);
disable(AEK_SM4);
}
if (!Enabled.test(E))
return;
LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n");
Touched.set(E);
Enabled.reset(E);
// Recursively disable all features that depends on this one.
for (auto Dep : ExtensionDependencies)
if (E == Dep.Earlier)
disable(Dep.Later);
}
void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) {
LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n");
BaseArch = &CPU.Arch;
AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions();
for (const auto &E : Extensions)
if (CPUExtensions.test(E.ID))
enable(E.ID);
}
void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) {
LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n");
BaseArch = &Arch;
for (const auto &E : Extensions)
if (Arch.DefaultExts.test(E.ID))
enable(E.ID);
}
bool AArch64::ExtensionSet::parseModifier(StringRef Modifier,
const bool AllowNoDashForm) {
LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n");
size_t NChars = 0;
// The "no-feat" form is allowed in the target attribute but nowhere else.
if (AllowNoDashForm && Modifier.starts_with("no-"))
NChars = 3;
else if (Modifier.starts_with("no"))
NChars = 2;
bool IsNegated = NChars != 0;
StringRef ArchExt = Modifier.drop_front(NChars);
if (auto AE = parseArchExtension(ArchExt)) {
if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty())
return false;
if (IsNegated)
disable(AE->ID);
else
enable(AE->ID);
return true;
}
return false;
}
void AArch64::ExtensionSet::reconstructFromParsedFeatures(
const std::vector<std::string> &Features,
std::vector<std::string> &NonExtensions) {
assert(Touched.none() && "Bitset already initialized");
for (auto &F : Features) {
bool IsNegated = F[0] == '-';
if (auto AE = targetFeatureToExtension(F)) {
Touched.set(AE->ID);
if (IsNegated)
Enabled.reset(AE->ID);
else
Enabled.set(AE->ID);
continue;
}
NonExtensions.push_back(F);
}
}
void AArch64::ExtensionSet::dump() const {
std::vector<StringRef> Features;
toLLVMFeatureList(Features);
for (StringRef F : Features)
llvm::outs() << F << " ";
llvm::outs() << "\n";
}
const AArch64::ExtensionInfo &
AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) {
return lookupExtensionByID(ExtID);
}
|