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