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
25using namespace llvm;
26
27/// Collect the full set of implied features for a SubtargetFeature.
28static void CollectImpliedFeatures(std::set<Record *> &SeenFeats, Record *Rec) {
29 assert(Rec->isSubClassOf("SubtargetFeature") &&
30 "Rec is not a SubtargetFeature");
31
32 SeenFeats.insert(x: Rec);
33 for (Record *Implied : Rec->getValueAsListOfDefs(FieldName: "Implies"))
34 CollectImpliedFeatures(SeenFeats, Rec: Implied);
35}
36
37static void CheckFeatureTree(Record *Root) {
38 std::set<Record *> SeenFeats;
39 CollectImpliedFeatures(SeenFeats, Rec: 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(FieldName: "DefaultExts");
44 std::set<Record *> DefaultExts{DefaultExtsVec.begin(), DefaultExtsVec.end()};
45 for (auto *Feat : SeenFeats) {
46 if (Feat->isSubClassOf(Name: "ExtensionWithMArch") && !DefaultExts.count(x: Feat))
47 PrintFatalError(ErrorLoc: Root->getLoc(),
48 Msg: "ExtensionWithMArch " + Feat->getName() +
49 " is implied (mandatory) as a SubtargetFeature, but "
50 "is not present in DefaultExts");
51 }
52}
53
54static 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(ClassName: "SubtargetFeature")) {
62 if (Rec->getValueAsString(FieldName: "FieldName") == FieldName) {
63 Set.insert(key: Rec->getValueAsString(FieldName: "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(ClassName: "Extension");
72 auto Alphabetical = [](Record *A, Record *B) -> bool {
73 const auto NameA = A->getValueAsString(FieldName: "Name");
74 const auto NameB = B->getValueAsString(FieldName: "Name");
75 return NameA.compare(RHS: NameB) < 0; // A lexographically less than B
76 };
77 std::sort(first: SortedExtensions.begin(), last: SortedExtensions.end(), comp: 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(Name: "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(FieldName: "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(FieldName: "ArchExtKindSpelling").upper();
124 OS << " ";
125 OS << "{\"" << Rec->getValueAsString(FieldName: "UserVisibleName") << "\"";
126 if (auto Alias = Rec->getValueAsString(FieldName: "UserVisibleAlias"); Alias.empty())
127 OS << ", {}";
128 else
129 OS << ", \"" << Alias << "\"";
130 OS << ", AArch64::" << AEK;
131 OS << ", \"" << Rec->getValueAsString(FieldName: "ArchFeatureName") << "\"";
132 OS << ", \"" << Rec->getValueAsString(FieldName: "Desc") << "\"";
133 OS << ", \"+" << Rec->getValueAsString(FieldName: "Name") << "\""; // posfeature
134 OS << ", \"-" << Rec->getValueAsString(FieldName: "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(ClassName: "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(FieldName: "Name") << "\"";
153 OS << ", " << Rec->getValueAsString(FieldName: "Bit");
154 OS << ", \"" << Rec->getValueAsString(FieldName: "BackendFeatures") << "\"";
155 OS << ", " << (uint64_t)Rec->getValueAsInt(FieldName: "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(FieldName: "ArchExtKindSpelling").upper();
169 for (const Record *I : Rec->getValueAsListOfDefs(FieldName: "Implies"))
170 if (auto EarlierAEK = I->getValueAsOptionalString(FieldName: "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(val: Major) + Profile.upper()
189 : "ARMV" + std::to_string(val: Major) + "_" +
190 std::to_string(val: Minor) + Profile.upper();
191 };
192
193 auto Architectures = RK.getAllDerivedDefinitionsIfDefined(ClassName: "Architecture64");
194 std::vector<std::string> CppSpellings;
195 for (const Record *Rec : Architectures) {
196 const int Major = Rec->getValueAsInt(FieldName: "Major");
197 const int Minor = Rec->getValueAsInt(FieldName: "Minor");
198 const std::string ProfileLower = Rec->getValueAsString(FieldName: "Profile").str();
199 const std::string ProfileUpper = Rec->getValueAsString(FieldName: "Profile").upper();
200
201 if (ProfileLower != "a" && ProfileLower != "r")
202 PrintFatalError(ErrorLoc: Rec->getLoc(),
203 Msg: "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(x: CppSpelling);
210
211 OS << llvm::format(Fmt: " VersionTuple{%d, %d},\n", Vals: Major, Vals: Minor);
212 OS << llvm::format(Fmt: " %sProfile,\n", Vals: ProfileUpper.c_str());
213
214 // Name as spelled for -march.
215 if (Minor == 0)
216 OS << llvm::format(Fmt: " \"armv%d-%s\",\n", Vals: Major, Vals: ProfileLower.c_str());
217 else
218 OS << llvm::format(Fmt: " \"armv%d.%d-%s\",\n", Vals: Major, Vals: Minor,
219 Vals: ProfileLower.c_str());
220
221 // SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
222 const auto TargetFeatureName = Rec->getValueAsString(FieldName: "Name");
223 OS << " \"+" << TargetFeatureName << "\",\n";
224
225 // Construct the list of default extensions
226 OS << " (AArch64::ExtensionBitset({";
227 for (auto *E : Rec->getValueAsListOfDefs(FieldName: "DefaultExts")) {
228 OS << "AArch64::" << E->getValueAsString(FieldName: "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(ClassName: "ProcessorModel"))
254 Processors.insert(key: Rec->getValueAsString(FieldName: "Name"));
255
256 llvm::StringSet<> Aliases;
257 for (const Record *Rec : RK.getAllDerivedDefinitions(ClassName: "ProcessorAlias")) {
258 auto Name = Rec->getValueAsString(FieldName: "Name");
259 auto Alias = Rec->getValueAsString(FieldName: "Alias");
260 if (!Processors.contains(key: Alias))
261 PrintFatalError(
262 Rec, Msg: "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");
263 if (Processors.contains(key: Name))
264 PrintFatalError(
265 Rec, Msg: "Alias '" + Name + "' duplicates an existing ProcessorModel");
266 if (!Aliases.insert(key: Name).second)
267 PrintFatalError(
268 Rec, Msg: "Alias '" + Name + "' duplicates an existing ProcessorAlias");
269
270 OS << llvm::formatv(Fmt: R"( { "{0}", "{1}" },)", Vals&: Name, Vals&: 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(ClassName: "ProcessorModel")) {
283 auto Name = Rec->getValueAsString(FieldName: "Name");
284 auto Features = Rec->getValueAsListOfDefs(FieldName: "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(Name: "HasV8_0aOps");
296 } else {
297 // Search for an Architecture64 in the list of features.
298 auto IsArch = [](Record *F) { return F->isSubClassOf(Name: "Architecture64"); };
299 auto ArchIter = llvm::find_if(Range&: Features, P: IsArch);
300 if (ArchIter == Features.end())
301 PrintFatalError(Rec, Msg: "Features must include an Architecture64.");
302 Arch = *ArchIter;
303
304 // Check there is only one Architecture in the list.
305 if (llvm::count_if(Range&: Features, P: IsArch) > 1)
306 PrintFatalError(Rec, Msg: "Features has multiple Architecture64 entries");
307 }
308
309 auto Major = Arch->getValueAsInt(FieldName: "Major");
310 auto Minor = Arch->getValueAsInt(FieldName: "Minor");
311 auto Profile = Arch->getValueAsString(FieldName: "Profile");
312 auto ArchInfo = ArchInfoName(Major, Minor, Profile);
313
314 CheckFeatureTree(Root: 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(FieldName: "Features"))
324 // Only process subclasses of Extension
325 if (E->isSubClassOf(Name: "Extension")) {
326 const auto AEK = E->getValueAsString(FieldName: "ArchExtKindSpelling").upper();
327 if (!SeenExts.insert(key: AEK).second)
328 PrintFatalError(Rec, Msg: "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
341static TableGen::Emitter::Opt
342 X("gen-arm-target-def", EmitARMTargetDef,
343 "Generate the ARM or AArch64 Architecture information header.");
344