llvm-project/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
2024-05-19 14:51:13 -07:00

185 lines
7.2 KiB
C++

//===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//
//
// 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 tablegen backend exports information about CPUs, FPUs, architectures,
// and features into a common format that can be used by both TargetParser and
// the ARM and AArch64 backends.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Format.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <cstdint>
#include <string>
using namespace llvm;
static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
// Look through all SubtargetFeature defs with the given FieldName, and
// collect the set of all Values that that FieldName is set to.
auto gatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {
llvm::StringSet<> Set;
for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {
if (Rec->getValueAsString("FieldName") == FieldName) {
Set.insert(Rec->getValueAsString("Value"));
}
}
return Set;
};
// Sort the extensions alphabetically, so they don't appear in tablegen order.
std::vector<Record *> SortedExtensions =
RK.getAllDerivedDefinitions("Extension");
auto Alphabetical = [](Record *A, Record *B) -> bool {
const auto MarchA = A->getValueAsString("MArchName");
const auto MarchB = B->getValueAsString("MArchName");
return MarchA.compare(MarchB) < 0; // A lexographically less than B
};
std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
// The ARMProcFamilyEnum values are initialised by SubtargetFeature defs
// which set the ARMProcFamily field. We can generate the enum from these defs
// which look like this:
//
// def ProcA5 : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",
// "Cortex-A5 ARM processors", []>;
OS << "#ifndef ARM_PROCESSOR_FAMILY\n"
<< "#define ARM_PROCESSOR_FAMILY(ENUM)\n"
<< "#endif\n\n";
const StringSet<> ARMProcFamilyVals =
gatherSubtargetFeatureFieldValues("ARMProcFamily");
for (const StringRef &Family : ARMProcFamilyVals.keys())
OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";
OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";
OS << "#ifndef ARM_ARCHITECTURE\n"
<< "#define ARM_ARCHITECTURE(ENUM)\n"
<< "#endif\n\n";
// This should correspond to instances of the Architecture tablegen class.
const StringSet<> ARMArchVals = gatherSubtargetFeatureFieldValues("ARMArch");
for (const StringRef &Arch : ARMArchVals.keys())
OS << "ARM_ARCHITECTURE(" << Arch << ")\n";
OS << "\n#undef ARM_ARCHITECTURE\n\n";
// Emit the ArchExtKind enum
OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"
<< "enum ArchExtKind : unsigned {\n"
<< " AEK_NONE = 1,\n";
for (const Record *Rec : SortedExtensions) {
auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
if (AEK != "AEK_NONE")
OS << " " << AEK << ",\n";
}
OS << " AEK_NUM_EXTENSIONS\n"
<< "};\n"
<< "#undef EMIT_ARCHEXTKIND_ENUM\n"
<< "#endif // EMIT_ARCHEXTKIND_ENUM\n";
// Emit information for each defined Extension; used to build ArmExtKind.
OS << "#ifdef EMIT_EXTENSIONS\n"
<< "inline constexpr ExtensionInfo Extensions[] = {\n";
for (const Record *Rec : SortedExtensions) {
auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
OS << " ";
OS << "{\"" << Rec->getValueAsString("MArchName") << "\"";
if (auto Alias = Rec->getValueAsString("MArchAlias"); Alias.empty())
OS << ", {}";
else
OS << ", \"" << Alias << "\"";
OS << ", AArch64::" << AEK;
if (AEK == "AEK_NONE") {
// HACK: don't emit posfeat/negfeat strings for FMVOnlyExtensions.
OS << ", {}, {}";
} else {
OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
}
OS << ", " << Rec->getValueAsString("FMVBit");
OS << ", \"" << Rec->getValueAsString("FMVDependencies") << "\"";
OS << ", " << (uint64_t)Rec->getValueAsInt("FMVPriority");
OS << "},\n";
};
OS << " {\"none\", {}, AArch64::AEK_NONE, {}, {}, FEAT_INIT, \"\", "
"ExtensionInfo::MaxFMVPriority},\n";
OS << "};\n"
<< "#undef EMIT_EXTENSIONS\n"
<< "#endif // EMIT_EXTENSIONS\n"
<< "\n";
// Emit architecture information
OS << "#ifdef EMIT_ARCHITECTURES\n";
auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");
std::vector<std::string> CppSpellings;
for (const Record *Rec : Architectures) {
const int Major = Rec->getValueAsInt("Major");
const int Minor = Rec->getValueAsInt("Minor");
const std::string ProfileLower = Rec->getValueAsString("Profile").str();
const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();
if (ProfileLower != "a" && ProfileLower != "r")
PrintFatalError(Rec->getLoc(),
"error: Profile must be one of 'a' or 'r', got '" +
ProfileLower + "'");
// Name of the object in C++
const std::string CppSpelling =
Minor == 0 ? "ARMV" + std::to_string(Major) + ProfileUpper.c_str()
: "ARMV" + std::to_string(Major) + "_" +
std::to_string(Minor) + ProfileUpper.c_str();
OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";
CppSpellings.push_back(CppSpelling);
OS << llvm::format(" VersionTuple{%d, %d},\n", Major, Minor);
OS << llvm::format(" %sProfile,\n", ProfileUpper.c_str());
// Name as spelled for -march.
if (Minor == 0)
OS << llvm::format(" \"armv%d-%s\",\n", Major, ProfileLower.c_str());
else
OS << llvm::format(" \"armv%d.%d-%s\",\n", Major, Minor,
ProfileLower.c_str());
// SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
const auto TargetFeatureName = Rec->getValueAsString("Name");
OS << " \"+" << TargetFeatureName << "\",\n";
// Construct the list of default extensions
OS << " (AArch64::ExtensionBitset({";
for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {
// Only process subclasses of Extension
OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()
<< ", ";
}
OS << "}))\n";
OS << "};\n";
}
OS << "\n"
<< "/// The set of all architectures\n"
<< "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()
<< "> ArchInfos = {\n";
for (StringRef CppSpelling : CppSpellings)
OS << " &" << CppSpelling << ",\n";
OS << "};\n";
OS << "#undef EMIT_ARCHITECTURES\n"
<< "#endif // EMIT_ARCHITECTURES\n"
<< "\n";
}
static TableGen::Emitter::Opt
X("gen-arm-target-def", EmitARMTargetDef,
"Generate the ARM or AArch64 Architecture information header.");