xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/ARMTargetDefEmitter.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
1 //===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend exports information about CPUs, FPUs, architectures,
10 // and features into a common format that can be used by both TargetParser and
11 // the ARM and AArch64 backends.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/ADT/StringSet.h"
16 #include "llvm/Support/Format.h"
17 #include "llvm/Support/FormatVariadic.h"
18 #include "llvm/TableGen/Error.h"
19 #include "llvm/TableGen/Record.h"
20 #include "llvm/TableGen/TableGenBackend.h"
21 #include <cstdint>
22 #include <set>
23 #include <string>
24 
25 using namespace llvm;
26 
27 /// Collect the full set of implied features for a SubtargetFeature.
28 static void CollectImpliedFeatures(std::set<Record *> &SeenFeats, Record *Rec) {
29   assert(Rec->isSubClassOf("SubtargetFeature") &&
30          "Rec is not a SubtargetFeature");
31 
32   SeenFeats.insert(Rec);
33   for (Record *Implied : Rec->getValueAsListOfDefs("Implies"))
34     CollectImpliedFeatures(SeenFeats, Implied);
35 }
36 
37 static void CheckFeatureTree(Record *Root) {
38   std::set<Record *> SeenFeats;
39   CollectImpliedFeatures(SeenFeats, Root);
40 
41   // Check that each of the mandatory (implied) features which is an
42   // ExtensionWithMArch is also enabled by default.
43   auto DefaultExtsVec = Root->getValueAsListOfDefs("DefaultExts");
44   std::set<Record *> DefaultExts{DefaultExtsVec.begin(), DefaultExtsVec.end()};
45   for (auto *Feat : SeenFeats) {
46     if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat))
47       PrintFatalError(Root->getLoc(),
48                       "ExtensionWithMArch " + Feat->getName() +
49                           " is implied (mandatory) as a SubtargetFeature, but "
50                           "is not present in DefaultExts");
51   }
52 }
53 
54 static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
55   OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
56 
57   // Look through all SubtargetFeature defs with the given FieldName, and
58   // collect the set of all Values that that FieldName is set to.
59   auto gatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {
60     llvm::StringSet<> Set;
61     for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {
62       if (Rec->getValueAsString("FieldName") == FieldName) {
63         Set.insert(Rec->getValueAsString("Value"));
64       }
65     }
66     return Set;
67   };
68 
69   // Sort the extensions alphabetically, so they don't appear in tablegen order.
70   std::vector<Record *> SortedExtensions =
71       RK.getAllDerivedDefinitions("Extension");
72   auto Alphabetical = [](Record *A, Record *B) -> bool {
73     const auto NameA = A->getValueAsString("Name");
74     const auto NameB = B->getValueAsString("Name");
75     return NameA.compare(NameB) < 0; // A lexographically less than B
76   };
77   std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
78 
79   // The ARMProcFamilyEnum values are initialised by SubtargetFeature defs
80   // which set the ARMProcFamily field. We can generate the enum from these defs
81   // which look like this:
82   //
83   // def ProcA5      : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",
84   //                                    "Cortex-A5 ARM processors", []>;
85   OS << "#ifndef ARM_PROCESSOR_FAMILY\n"
86      << "#define ARM_PROCESSOR_FAMILY(ENUM)\n"
87      << "#endif\n\n";
88   const StringSet<> ARMProcFamilyVals =
89       gatherSubtargetFeatureFieldValues("ARMProcFamily");
90   for (const StringRef &Family : ARMProcFamilyVals.keys())
91     OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";
92   OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";
93 
94   OS << "#ifndef ARM_ARCHITECTURE\n"
95      << "#define ARM_ARCHITECTURE(ENUM)\n"
96      << "#endif\n\n";
97   // This should correspond to instances of the Architecture tablegen class.
98   const StringSet<> ARMArchVals = gatherSubtargetFeatureFieldValues("ARMArch");
99   for (const StringRef &Arch : ARMArchVals.keys())
100     OS << "ARM_ARCHITECTURE(" << Arch << ")\n";
101   OS << "\n#undef ARM_ARCHITECTURE\n\n";
102 
103   // Currently only AArch64 (not ARM) is handled beyond this point.
104   if (!RK.getClass("Architecture64"))
105     return;
106 
107   // Emit the ArchExtKind enum
108   OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"
109      << "enum ArchExtKind : unsigned {\n";
110   for (const Record *Rec : SortedExtensions) {
111     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
112     OS << "  " << AEK << ",\n";
113   }
114   OS << "  AEK_NUM_EXTENSIONS\n"
115      << "};\n"
116      << "#undef EMIT_ARCHEXTKIND_ENUM\n"
117      << "#endif // EMIT_ARCHEXTKIND_ENUM\n";
118 
119   // Emit information for each defined Extension; used to build ArmExtKind.
120   OS << "#ifdef EMIT_EXTENSIONS\n"
121      << "inline constexpr ExtensionInfo Extensions[] = {\n";
122   for (const Record *Rec : SortedExtensions) {
123     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
124     OS << "  ";
125     OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
126     if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
127       OS << ", {}";
128     else
129       OS << ", \"" << Alias << "\"";
130     OS << ", AArch64::" << AEK;
131     OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
132     OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
133     OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
134     OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
135     OS << "},\n";
136   };
137   OS << "};\n"
138      << "#undef EMIT_EXTENSIONS\n"
139      << "#endif // EMIT_EXTENSIONS\n"
140      << "\n";
141 
142   // Emit FMV information
143   auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");
144   OS << "#ifdef EMIT_FMV_INFO\n"
145      << "const std::vector<llvm::AArch64::FMVInfo>& "
146         "llvm::AArch64::getFMVInfo() {\n"
147      << "  static std::vector<FMVInfo> I;\n"
148      << "  if(I.size()) return I;\n"
149      << "  I.reserve(" << FMVExts.size() << ");\n";
150   for (const Record *Rec : FMVExts) {
151     OS << "  I.emplace_back(";
152     OS << "\"" << Rec->getValueAsString("Name") << "\"";
153     OS << ", " << Rec->getValueAsString("Bit");
154     OS << ", \"" << Rec->getValueAsString("BackendFeatures") << "\"";
155     OS << ", " << (uint64_t)Rec->getValueAsInt("Priority");
156     OS << ");\n";
157   };
158   OS << "  return I;\n"
159      << "}\n"
160      << "#undef EMIT_FMV_INFO\n"
161      << "#endif // EMIT_FMV_INFO\n"
162      << "\n";
163 
164   // Emit extension dependencies
165   OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"
166      << "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";
167   for (const Record *Rec : SortedExtensions) {
168     auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
169     for (const Record *I : Rec->getValueAsListOfDefs("Implies"))
170       if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))
171         OS << "  {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";
172   }
173   // FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied
174   // by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make
175   // FeatureRCPC_IMMO an Extension but that will expose it to the command line.
176   OS << "  {AEK_RCPC, AEK_RCPC3},\n";
177   OS << "};\n"
178      << "#undef EMIT_EXTENSION_DEPENDENCIES\n"
179      << "#endif // EMIT_EXTENSION_DEPENDENCIES\n"
180      << "\n";
181 
182   // Emit architecture information
183   OS << "#ifdef EMIT_ARCHITECTURES\n";
184 
185   // Return the C++ name of the of an ArchInfo object
186   auto ArchInfoName = [](int Major, int Minor,
187                          StringRef Profile) -> std::string {
188     return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()
189                       : "ARMV" + std::to_string(Major) + "_" +
190                             std::to_string(Minor) + Profile.upper();
191   };
192 
193   auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");
194   std::vector<std::string> CppSpellings;
195   for (const Record *Rec : Architectures) {
196     const int Major = Rec->getValueAsInt("Major");
197     const int Minor = Rec->getValueAsInt("Minor");
198     const std::string ProfileLower = Rec->getValueAsString("Profile").str();
199     const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();
200 
201     if (ProfileLower != "a" && ProfileLower != "r")
202       PrintFatalError(Rec->getLoc(),
203                       "error: Profile must be one of 'a' or 'r', got '" +
204                           ProfileLower + "'");
205 
206     // Name of the object in C++
207     const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);
208     OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";
209     CppSpellings.push_back(CppSpelling);
210 
211     OS << llvm::format("  VersionTuple{%d, %d},\n", Major, Minor);
212     OS << llvm::format("  %sProfile,\n", ProfileUpper.c_str());
213 
214     // Name as spelled for -march.
215     if (Minor == 0)
216       OS << llvm::format("  \"armv%d-%s\",\n", Major, ProfileLower.c_str());
217     else
218       OS << llvm::format("  \"armv%d.%d-%s\",\n", Major, Minor,
219                          ProfileLower.c_str());
220 
221     // SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
222     const auto TargetFeatureName = Rec->getValueAsString("Name");
223     OS << "  \"+" << TargetFeatureName << "\",\n";
224 
225     // Construct the list of default extensions
226     OS << "  (AArch64::ExtensionBitset({";
227     for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {
228       OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()
229          << ", ";
230     }
231     OS << "}))\n";
232 
233     OS << "};\n";
234   }
235 
236   OS << "\n"
237      << "/// The set of all architectures\n"
238      << "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()
239      << "> ArchInfos = {\n";
240   for (StringRef CppSpelling : CppSpellings)
241     OS << "  &" << CppSpelling << ",\n";
242   OS << "};\n";
243 
244   OS << "#undef EMIT_ARCHITECTURES\n"
245      << "#endif // EMIT_ARCHITECTURES\n"
246      << "\n";
247 
248   // Emit CPU Aliases
249   OS << "#ifdef EMIT_CPU_ALIAS\n"
250      << "inline constexpr Alias CpuAliases[] = {\n";
251 
252   llvm::StringSet<> Processors;
253   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))
254     Processors.insert(Rec->getValueAsString("Name"));
255 
256   llvm::StringSet<> Aliases;
257   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {
258     auto Name = Rec->getValueAsString("Name");
259     auto Alias = Rec->getValueAsString("Alias");
260     if (!Processors.contains(Alias))
261       PrintFatalError(
262           Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");
263     if (Processors.contains(Name))
264       PrintFatalError(
265           Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");
266     if (!Aliases.insert(Name).second)
267       PrintFatalError(
268           Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");
269 
270     OS << llvm::formatv(R"(  { "{0}", "{1}" },)", Name, Alias) << '\n';
271   }
272 
273   OS << "};\n"
274      << "#undef EMIT_CPU_ALIAS\n"
275      << "#endif // EMIT_CPU_ALIAS\n"
276      << "\n";
277 
278   // Emit CPU information
279   OS << "#ifdef EMIT_CPU_INFO\n"
280      << "inline constexpr CpuInfo CpuInfos[] = {\n";
281 
282   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {
283     auto Name = Rec->getValueAsString("Name");
284     auto Features = Rec->getValueAsListOfDefs("Features");
285 
286     // "apple-latest" is backend-only, should not be accepted by TargetParser.
287     if (Name == "apple-latest")
288       continue;
289 
290     Record *Arch;
291     if (Name == "generic") {
292       // "generic" is an exception. It does not have an architecture, and there
293       // are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.
294       // However, in TargetParser CPUInfo, it is written as 8.0-A.
295       Arch = RK.getDef("HasV8_0aOps");
296     } else {
297       // Search for an Architecture64 in the list of features.
298       auto IsArch = [](Record *F) { return F->isSubClassOf("Architecture64"); };
299       auto ArchIter = llvm::find_if(Features, IsArch);
300       if (ArchIter == Features.end())
301         PrintFatalError(Rec, "Features must include an Architecture64.");
302       Arch = *ArchIter;
303 
304       // Check there is only one Architecture in the list.
305       if (llvm::count_if(Features, IsArch) > 1)
306         PrintFatalError(Rec, "Features has multiple Architecture64 entries");
307     }
308 
309     auto Major = Arch->getValueAsInt("Major");
310     auto Minor = Arch->getValueAsInt("Minor");
311     auto Profile = Arch->getValueAsString("Profile");
312     auto ArchInfo = ArchInfoName(Major, Minor, Profile);
313 
314     CheckFeatureTree(Arch);
315 
316     OS << "  {\n"
317        << "    \"" << Name << "\",\n"
318        << "    " << ArchInfo << ",\n"
319        << "    AArch64::ExtensionBitset({\n";
320 
321     // Keep track of extensions we have seen
322     StringSet<> SeenExts;
323     for (auto *E : Rec->getValueAsListOfDefs("Features"))
324       // Only process subclasses of Extension
325       if (E->isSubClassOf("Extension")) {
326         const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();
327         if (!SeenExts.insert(AEK).second)
328           PrintFatalError(Rec, "feature already added: " + E->getName());
329         OS << "      AArch64::" << AEK << ",\n";
330       }
331     OS << "    })\n"
332        << "  },\n";
333   }
334   OS << "};\n";
335 
336   OS << "#undef EMIT_CPU_INFO\n"
337      << "#endif // EMIT_CPU_INFO\n"
338      << "\n";
339 }
340 
341 static TableGen::Emitter::Opt
342     X("gen-arm-target-def", EmitARMTargetDef,
343       "Generate the ARM or AArch64 Architecture information header.");
344