Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
213799 views
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
25
using namespace llvm;
26
27
/// Collect the full set of implied features for a SubtargetFeature.
28
static 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(Rec);
34
for (const Record *Implied : Rec->getValueAsListOfDefs("Implies"))
35
collectImpliedFeatures(SeenFeats, Implied);
36
}
37
38
static void checkFeatureTree(const Record *Root) {
39
std::set<const Record *> SeenFeats;
40
collectImpliedFeatures(SeenFeats, 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("DefaultExts");
45
std::set<const Record *> DefaultExts{DefaultExtsVec.begin(),
46
DefaultExtsVec.end()};
47
for (const Record *Feat : SeenFeats) {
48
if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat))
49
PrintFatalError(Root->getLoc(),
50
"ExtensionWithMArch " + Feat->getName() +
51
" is implied (mandatory) as a SubtargetFeature, but "
52
"is not present in DefaultExts");
53
}
54
}
55
56
static 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("SubtargetFeature")) {
64
if (Rec->getValueAsString("FieldName") == FieldName) {
65
Set.insert(Rec->getValueAsString("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("Extension");
74
auto Alphabetical = [](const Record *A, const Record *B) -> bool {
75
const auto NameA = A->getValueAsString("Name");
76
const auto NameB = B->getValueAsString("Name");
77
return NameA.compare(NameB) < 0; // A lexographically less than B
78
};
79
sort(SortedExtensions, 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("UserVisibleName");
85
if (Name.empty())
86
Name = Rec->getValueAsString("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("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("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("ArchExtKindSpelling").upper();
135
OS << " ";
136
OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
137
if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
138
OS << ", {}";
139
else
140
OS << ", \"" << Alias << "\"";
141
OS << ", AArch64::" << AEK;
142
OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
143
OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
144
OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
145
OS << ", \"-" << Rec->getValueAsString("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("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
OS << " I.emplace_back(";
163
OS << "\"" << Rec->getValueAsString("Name") << "\"";
164
OS << ", " << Rec->getValueAsString("FeatureBit");
165
OS << ", " << Rec->getValueAsString("PriorityBit");
166
auto FeatName = Rec->getValueAsString("BackendFeature");
167
const Record *FeatRec = ExtensionMap[FeatName];
168
if (FeatRec)
169
OS << ", " << FeatRec->getValueAsString("ArchExtKindSpelling").upper();
170
else
171
OS << ", std::nullopt";
172
OS << ");\n";
173
};
174
OS << " return I;\n"
175
<< "}\n"
176
<< "#undef EMIT_FMV_INFO\n"
177
<< "#endif // EMIT_FMV_INFO\n"
178
<< "\n";
179
180
// Emit extension dependencies
181
OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"
182
<< "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";
183
for (const Record *Rec : SortedExtensions) {
184
auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
185
for (const Record *I : Rec->getValueAsListOfDefs("Implies"))
186
if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))
187
OS << " {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";
188
}
189
// FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied
190
// by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make
191
// FeatureRCPC_IMMO an Extension but that will expose it to the command line.
192
OS << " {AEK_RCPC, AEK_RCPC3},\n";
193
OS << "};\n"
194
<< "#undef EMIT_EXTENSION_DEPENDENCIES\n"
195
<< "#endif // EMIT_EXTENSION_DEPENDENCIES\n"
196
<< "\n";
197
198
// Emit architecture information
199
OS << "#ifdef EMIT_ARCHITECTURES\n";
200
201
// Return the C++ name of the of an ArchInfo object
202
auto ArchInfoName = [](int Major, int Minor,
203
StringRef Profile) -> std::string {
204
return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()
205
: "ARMV" + std::to_string(Major) + "_" +
206
std::to_string(Minor) + Profile.upper();
207
};
208
209
auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");
210
std::vector<std::string> CppSpellings;
211
for (const Record *Rec : Architectures) {
212
const int Major = Rec->getValueAsInt("Major");
213
const int Minor = Rec->getValueAsInt("Minor");
214
const std::string ProfileLower = Rec->getValueAsString("Profile").str();
215
const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();
216
217
if (ProfileLower != "a" && ProfileLower != "r")
218
PrintFatalError(Rec->getLoc(),
219
"error: Profile must be one of 'a' or 'r', got '" +
220
ProfileLower + "'");
221
222
// Name of the object in C++
223
const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);
224
OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";
225
CppSpellings.push_back(std::move(CppSpelling));
226
227
OS << llvm::format(" VersionTuple{%d, %d},\n", Major, Minor);
228
OS << llvm::format(" %sProfile,\n", ProfileUpper.c_str());
229
230
// Name as spelled for -march.
231
if (Minor == 0)
232
OS << llvm::format(" \"armv%d-%s\",\n", Major, ProfileLower.c_str());
233
else
234
OS << llvm::format(" \"armv%d.%d-%s\",\n", Major, Minor,
235
ProfileLower.c_str());
236
237
// SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
238
const auto TargetFeatureName = Rec->getValueAsString("Name");
239
OS << " \"+" << TargetFeatureName << "\",\n";
240
241
// Construct the list of default extensions
242
OS << " (AArch64::ExtensionBitset({";
243
for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {
244
OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()
245
<< ", ";
246
}
247
OS << "}))\n";
248
249
OS << "};\n";
250
}
251
252
OS << "\n"
253
<< "/// The set of all architectures\n"
254
<< "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()
255
<< "> ArchInfos = {\n";
256
for (StringRef CppSpelling : CppSpellings)
257
OS << " &" << CppSpelling << ",\n";
258
OS << "};\n";
259
260
OS << "#undef EMIT_ARCHITECTURES\n"
261
<< "#endif // EMIT_ARCHITECTURES\n"
262
<< "\n";
263
264
// Emit CPU Aliases
265
OS << "#ifdef EMIT_CPU_ALIAS\n"
266
<< "inline constexpr Alias CpuAliases[] = {\n";
267
268
llvm::StringSet<> Processors;
269
for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))
270
Processors.insert(Rec->getValueAsString("Name"));
271
272
llvm::StringSet<> Aliases;
273
for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {
274
auto Name = Rec->getValueAsString("Name");
275
auto Alias = Rec->getValueAsString("Alias");
276
if (!Processors.contains(Alias))
277
PrintFatalError(
278
Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");
279
if (Processors.contains(Name))
280
PrintFatalError(
281
Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");
282
if (!Aliases.insert(Name).second)
283
PrintFatalError(
284
Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");
285
286
OS << llvm::formatv(R"( { "{0}", "{1}" },)", Name, Alias) << '\n';
287
}
288
289
OS << "};\n"
290
<< "#undef EMIT_CPU_ALIAS\n"
291
<< "#endif // EMIT_CPU_ALIAS\n"
292
<< "\n";
293
294
// Emit CPU information
295
OS << "#ifdef EMIT_CPU_INFO\n"
296
<< "inline constexpr CpuInfo CpuInfos[] = {\n";
297
298
for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {
299
auto Name = Rec->getValueAsString("Name");
300
auto Features = Rec->getValueAsListOfDefs("Features");
301
302
// "apple-latest" is backend-only, should not be accepted by TargetParser.
303
if (Name == "apple-latest")
304
continue;
305
306
const Record *Arch;
307
if (Name == "generic") {
308
// "generic" is an exception. It does not have an architecture, and there
309
// are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.
310
// However, in TargetParser CPUInfo, it is written as 8.0-A.
311
Arch = RK.getDef("HasV8_0aOps");
312
} else {
313
// Search for an Architecture64 in the list of features.
314
auto IsArch = [](const Record *F) {
315
return F->isSubClassOf("Architecture64");
316
};
317
auto ArchIter = llvm::find_if(Features, IsArch);
318
if (ArchIter == Features.end())
319
PrintFatalError(Rec, "Features must include an Architecture64.");
320
Arch = *ArchIter;
321
322
// Check there is only one Architecture in the list.
323
if (llvm::count_if(Features, IsArch) > 1)
324
PrintFatalError(Rec, "Features has multiple Architecture64 entries");
325
}
326
327
auto Major = Arch->getValueAsInt("Major");
328
auto Minor = Arch->getValueAsInt("Minor");
329
auto Profile = Arch->getValueAsString("Profile");
330
auto ArchInfo = ArchInfoName(Major, Minor, Profile);
331
332
checkFeatureTree(Arch);
333
334
OS << " {\n"
335
<< " \"" << Name << "\",\n"
336
<< " " << ArchInfo << ",\n"
337
<< " AArch64::ExtensionBitset({\n";
338
339
// Keep track of extensions we have seen
340
StringSet<> SeenExts;
341
for (const Record *E : Rec->getValueAsListOfDefs("Features"))
342
// Only process subclasses of Extension
343
if (E->isSubClassOf("Extension")) {
344
const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();
345
if (!SeenExts.insert(AEK).second)
346
PrintFatalError(Rec, "feature already added: " + E->getName());
347
OS << " AArch64::" << AEK << ",\n";
348
}
349
OS << " })\n"
350
<< " },\n";
351
}
352
OS << "};\n";
353
354
OS << "#undef EMIT_CPU_INFO\n"
355
<< "#endif // EMIT_CPU_INFO\n"
356
<< "\n";
357
}
358
359
static TableGen::Emitter::Opt
360
X("gen-arm-target-def", emitARMTargetDef,
361
"Generate the ARM or AArch64 Architecture information header.");
362
363