| //===- 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."); |