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