120 lines
4.8 KiB
C++
120 lines
4.8 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/TableGen/Record.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
#include <cstdint>
|
|
|
|
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";
|
|
}
|
|
|
|
static TableGen::Emitter::Opt
|
|
X("gen-arm-target-def", EmitARMTargetDef,
|
|
"Generate the ARM or AArch64 Architecture information header.");
|