1 //===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//
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
7 //===----------------------------------------------------------------------===//
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.
13 //===----------------------------------------------------------------------===//
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"
28 /// Collect the full set of implied features for a SubtargetFeature.
29 static void collectImpliedFeatures(std::set
<const Record
*> &SeenFeats
,
31 assert(Rec
->isSubClassOf("SubtargetFeature") &&
32 "Rec is not a SubtargetFeature");
34 SeenFeats
.insert(Rec
);
35 for (const Record
*Implied
: Rec
->getValueAsListOfDefs("Implies"))
36 collectImpliedFeatures(SeenFeats
, Implied
);
39 static void checkFeatureTree(const Record
*Root
) {
40 std::set
<const Record
*> SeenFeats
;
41 collectImpliedFeatures(SeenFeats
, Root
);
43 // Check that each of the mandatory (implied) features which is an
44 // ExtensionWithMArch is also enabled by default.
45 auto DefaultExtsVec
= Root
->getValueAsListOfDefs("DefaultExts");
46 std::set
<const Record
*> DefaultExts
{DefaultExtsVec
.begin(),
47 DefaultExtsVec
.end()};
48 for (const Record
*Feat
: SeenFeats
) {
49 if (Feat
->isSubClassOf("ExtensionWithMArch") && !DefaultExts
.count(Feat
))
50 PrintFatalError(Root
->getLoc(),
51 "ExtensionWithMArch " + Feat
->getName() +
52 " is implied (mandatory) as a SubtargetFeature, but "
53 "is not present in DefaultExts");
57 static void emitARMTargetDef(const RecordKeeper
&RK
, raw_ostream
&OS
) {
58 OS
<< "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
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("SubtargetFeature")) {
65 if (Rec
->getValueAsString("FieldName") == FieldName
) {
66 Set
.insert(Rec
->getValueAsString("Value"));
72 // Sort the extensions alphabetically, so they don't appear in tablegen order.
73 std::vector
<const Record
*> SortedExtensions
=
74 RK
.getAllDerivedDefinitions("Extension");
75 auto Alphabetical
= [](const Record
*A
, const Record
*B
) -> bool {
76 const auto NameA
= A
->getValueAsString("Name");
77 const auto NameB
= B
->getValueAsString("Name");
78 return NameA
.compare(NameB
) < 0; // A lexographically less than B
80 sort(SortedExtensions
, Alphabetical
);
82 // Cache Extension records for quick lookup.
83 DenseMap
<StringRef
, const Record
*> ExtensionMap
;
84 for (const Record
*Rec
: SortedExtensions
) {
85 auto Name
= Rec
->getValueAsString("UserVisibleName");
87 Name
= Rec
->getValueAsString("Name");
88 ExtensionMap
[Name
] = Rec
;
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:
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"
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";
106 OS
<< "#ifndef ARM_ARCHITECTURE\n"
107 << "#define ARM_ARCHITECTURE(ENUM)\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";
115 // Currently only AArch64 (not ARM) is handled beyond this point.
116 if (!RK
.getClass("Architecture64"))
119 // Emit the ArchExtKind enum
120 OS
<< "#ifdef EMIT_ARCHEXTKIND_ENUM\n"
121 << "enum ArchExtKind : unsigned {\n";
122 for (const Record
*Rec
: SortedExtensions
) {
123 auto AEK
= Rec
->getValueAsString("ArchExtKindSpelling").upper();
124 OS
<< " " << AEK
<< ",\n";
126 OS
<< " AEK_NUM_EXTENSIONS\n"
128 << "#undef EMIT_ARCHEXTKIND_ENUM\n"
129 << "#endif // EMIT_ARCHEXTKIND_ENUM\n";
131 // Emit information for each defined Extension; used to build ArmExtKind.
132 OS
<< "#ifdef EMIT_EXTENSIONS\n"
133 << "inline constexpr ExtensionInfo Extensions[] = {\n";
134 for (const Record
*Rec
: SortedExtensions
) {
135 auto AEK
= Rec
->getValueAsString("ArchExtKindSpelling").upper();
137 OS
<< "{\"" << Rec
->getValueAsString("UserVisibleName") << "\"";
138 if (auto Alias
= Rec
->getValueAsString("UserVisibleAlias"); Alias
.empty())
141 OS
<< ", \"" << Alias
<< "\"";
142 OS
<< ", AArch64::" << AEK
;
143 OS
<< ", \"" << Rec
->getValueAsString("ArchFeatureName") << "\"";
144 OS
<< ", \"" << Rec
->getValueAsString("Desc") << "\"";
145 OS
<< ", \"+" << Rec
->getValueAsString("Name") << "\""; // posfeature
146 OS
<< ", \"-" << Rec
->getValueAsString("Name") << "\""; // negfeature
150 << "#undef EMIT_EXTENSIONS\n"
151 << "#endif // EMIT_EXTENSIONS\n"
154 // Emit FMV information
155 auto FMVExts
= RK
.getAllDerivedDefinitionsIfDefined("FMVExtension");
156 OS
<< "#ifdef EMIT_FMV_INFO\n"
157 << "const std::vector<llvm::AArch64::FMVInfo>& "
158 "llvm::AArch64::getFMVInfo() {\n"
159 << " static std::vector<FMVInfo> I;\n"
160 << " if(I.size()) return I;\n"
161 << " I.reserve(" << FMVExts
.size() << ");\n";
162 for (const Record
*Rec
: FMVExts
) {
163 OS
<< " I.emplace_back(";
164 OS
<< "\"" << Rec
->getValueAsString("Name") << "\"";
165 OS
<< ", " << Rec
->getValueAsString("Bit");
166 auto FeatName
= Rec
->getValueAsString("BackendFeature");
167 const Record
*FeatRec
= ExtensionMap
[FeatName
];
169 OS
<< ", " << FeatRec
->getValueAsString("ArchExtKindSpelling").upper();
171 OS
<< ", std::nullopt";
172 OS
<< ", " << (uint64_t)Rec
->getValueAsInt("Priority");
177 << "#undef EMIT_FMV_INFO\n"
178 << "#endif // EMIT_FMV_INFO\n"
181 // Emit extension dependencies
182 OS
<< "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"
183 << "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";
184 for (const Record
*Rec
: SortedExtensions
) {
185 auto LaterAEK
= Rec
->getValueAsString("ArchExtKindSpelling").upper();
186 for (const Record
*I
: Rec
->getValueAsListOfDefs("Implies"))
187 if (auto EarlierAEK
= I
->getValueAsOptionalString("ArchExtKindSpelling"))
188 OS
<< " {" << EarlierAEK
->upper() << ", " << LaterAEK
<< "},\n";
190 // FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied
191 // by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make
192 // FeatureRCPC_IMMO an Extension but that will expose it to the command line.
193 OS
<< " {AEK_RCPC, AEK_RCPC3},\n";
195 << "#undef EMIT_EXTENSION_DEPENDENCIES\n"
196 << "#endif // EMIT_EXTENSION_DEPENDENCIES\n"
199 // Emit architecture information
200 OS
<< "#ifdef EMIT_ARCHITECTURES\n";
202 // Return the C++ name of the of an ArchInfo object
203 auto ArchInfoName
= [](int Major
, int Minor
,
204 StringRef Profile
) -> std::string
{
205 return Minor
== 0 ? "ARMV" + std::to_string(Major
) + Profile
.upper()
206 : "ARMV" + std::to_string(Major
) + "_" +
207 std::to_string(Minor
) + Profile
.upper();
210 auto Architectures
= RK
.getAllDerivedDefinitionsIfDefined("Architecture64");
211 std::vector
<std::string
> CppSpellings
;
212 for (const Record
*Rec
: Architectures
) {
213 const int Major
= Rec
->getValueAsInt("Major");
214 const int Minor
= Rec
->getValueAsInt("Minor");
215 const std::string ProfileLower
= Rec
->getValueAsString("Profile").str();
216 const std::string ProfileUpper
= Rec
->getValueAsString("Profile").upper();
218 if (ProfileLower
!= "a" && ProfileLower
!= "r")
219 PrintFatalError(Rec
->getLoc(),
220 "error: Profile must be one of 'a' or 'r', got '" +
223 // Name of the object in C++
224 const std::string CppSpelling
= ArchInfoName(Major
, Minor
, ProfileUpper
);
225 OS
<< "inline constexpr ArchInfo " << CppSpelling
<< " = {\n";
226 CppSpellings
.push_back(CppSpelling
);
228 OS
<< llvm::format(" VersionTuple{%d, %d},\n", Major
, Minor
);
229 OS
<< llvm::format(" %sProfile,\n", ProfileUpper
.c_str());
231 // Name as spelled for -march.
233 OS
<< llvm::format(" \"armv%d-%s\",\n", Major
, ProfileLower
.c_str());
235 OS
<< llvm::format(" \"armv%d.%d-%s\",\n", Major
, Minor
,
236 ProfileLower
.c_str());
238 // SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
239 const auto TargetFeatureName
= Rec
->getValueAsString("Name");
240 OS
<< " \"+" << TargetFeatureName
<< "\",\n";
242 // Construct the list of default extensions
243 OS
<< " (AArch64::ExtensionBitset({";
244 for (auto *E
: Rec
->getValueAsListOfDefs("DefaultExts")) {
245 OS
<< "AArch64::" << E
->getValueAsString("ArchExtKindSpelling").upper()
254 << "/// The set of all architectures\n"
255 << "static constexpr std::array<const ArchInfo *, " << CppSpellings
.size()
256 << "> ArchInfos = {\n";
257 for (StringRef CppSpelling
: CppSpellings
)
258 OS
<< " &" << CppSpelling
<< ",\n";
261 OS
<< "#undef EMIT_ARCHITECTURES\n"
262 << "#endif // EMIT_ARCHITECTURES\n"
266 OS
<< "#ifdef EMIT_CPU_ALIAS\n"
267 << "inline constexpr Alias CpuAliases[] = {\n";
269 llvm::StringSet
<> Processors
;
270 for (const Record
*Rec
: RK
.getAllDerivedDefinitions("ProcessorModel"))
271 Processors
.insert(Rec
->getValueAsString("Name"));
273 llvm::StringSet
<> Aliases
;
274 for (const Record
*Rec
: RK
.getAllDerivedDefinitions("ProcessorAlias")) {
275 auto Name
= Rec
->getValueAsString("Name");
276 auto Alias
= Rec
->getValueAsString("Alias");
277 if (!Processors
.contains(Alias
))
279 Rec
, "Alias '" + Name
+ "' references a non-existent ProcessorModel '" + Alias
+ "'");
280 if (Processors
.contains(Name
))
282 Rec
, "Alias '" + Name
+ "' duplicates an existing ProcessorModel");
283 if (!Aliases
.insert(Name
).second
)
285 Rec
, "Alias '" + Name
+ "' duplicates an existing ProcessorAlias");
287 OS
<< llvm::formatv(R
"( { "{0}", "{1}" },)", Name
, Alias
) << '\n';
291 << "#undef EMIT_CPU_ALIAS\n"
292 << "#endif // EMIT_CPU_ALIAS\n"
295 // Emit CPU information
296 OS
<< "#ifdef EMIT_CPU_INFO\n"
297 << "inline constexpr CpuInfo CpuInfos[] = {\n";
299 for (const Record
*Rec
: RK
.getAllDerivedDefinitions("ProcessorModel")) {
300 auto Name
= Rec
->getValueAsString("Name");
301 auto Features
= Rec
->getValueAsListOfDefs("Features");
303 // "apple-latest" is backend-only, should not be accepted by TargetParser.
304 if (Name
== "apple-latest")
308 if (Name
== "generic") {
309 // "generic" is an exception. It does not have an architecture, and there
310 // are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.
311 // However, in TargetParser CPUInfo, it is written as 8.0-A.
312 Arch
= RK
.getDef("HasV8_0aOps");
314 // Search for an Architecture64 in the list of features.
315 auto IsArch
= [](const Record
*F
) {
316 return F
->isSubClassOf("Architecture64");
318 auto ArchIter
= llvm::find_if(Features
, IsArch
);
319 if (ArchIter
== Features
.end())
320 PrintFatalError(Rec
, "Features must include an Architecture64.");
323 // Check there is only one Architecture in the list.
324 if (llvm::count_if(Features
, IsArch
) > 1)
325 PrintFatalError(Rec
, "Features has multiple Architecture64 entries");
328 auto Major
= Arch
->getValueAsInt("Major");
329 auto Minor
= Arch
->getValueAsInt("Minor");
330 auto Profile
= Arch
->getValueAsString("Profile");
331 auto ArchInfo
= ArchInfoName(Major
, Minor
, Profile
);
333 checkFeatureTree(Arch
);
336 << " \"" << Name
<< "\",\n"
337 << " " << ArchInfo
<< ",\n"
338 << " AArch64::ExtensionBitset({\n";
340 // Keep track of extensions we have seen
341 StringSet
<> SeenExts
;
342 for (const Record
*E
: Rec
->getValueAsListOfDefs("Features"))
343 // Only process subclasses of Extension
344 if (E
->isSubClassOf("Extension")) {
345 const auto AEK
= E
->getValueAsString("ArchExtKindSpelling").upper();
346 if (!SeenExts
.insert(AEK
).second
)
347 PrintFatalError(Rec
, "feature already added: " + E
->getName());
348 OS
<< " AArch64::" << AEK
<< ",\n";
355 OS
<< "#undef EMIT_CPU_INFO\n"
356 << "#endif // EMIT_CPU_INFO\n"
360 static TableGen::Emitter::Opt
361 X("gen-arm-target-def", emitARMTargetDef
,
362 "Generate the ARM or AArch64 Architecture information header.");