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(x: Rec); |
34 | for (const Record *Implied : Rec->getValueAsListOfDefs(FieldName: "Implies" )) |
35 | collectImpliedFeatures(SeenFeats, Rec: Implied); |
36 | } |
37 | |
38 | static 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 | |
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(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 | OS << " I.emplace_back(" ; |
163 | OS << "\"" << Rec->getValueAsString(FieldName: "Name" ) << "\"" ; |
164 | OS << ", " << Rec->getValueAsString(FieldName: "FeatureBit" ); |
165 | OS << ", " << Rec->getValueAsString(FieldName: "PriorityBit" ); |
166 | auto FeatName = Rec->getValueAsString(FieldName: "BackendFeature" ); |
167 | const Record *FeatRec = ExtensionMap[FeatName]; |
168 | if (FeatRec) |
169 | OS << ", " << FeatRec->getValueAsString(FieldName: "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(FieldName: "ArchExtKindSpelling" ).upper(); |
185 | for (const Record *I : Rec->getValueAsListOfDefs(FieldName: "Implies" )) |
186 | if (auto EarlierAEK = I->getValueAsOptionalString(FieldName: "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(val: Major) + Profile.upper() |
205 | : "ARMV" + std::to_string(val: Major) + "_" + |
206 | std::to_string(val: Minor) + Profile.upper(); |
207 | }; |
208 | |
209 | auto Architectures = RK.getAllDerivedDefinitionsIfDefined(ClassName: "Architecture64" ); |
210 | std::vector<std::string> CppSpellings; |
211 | for (const Record *Rec : Architectures) { |
212 | const int Major = Rec->getValueAsInt(FieldName: "Major" ); |
213 | const int Minor = Rec->getValueAsInt(FieldName: "Minor" ); |
214 | const std::string ProfileLower = Rec->getValueAsString(FieldName: "Profile" ).str(); |
215 | const std::string ProfileUpper = Rec->getValueAsString(FieldName: "Profile" ).upper(); |
216 | |
217 | if (ProfileLower != "a" && ProfileLower != "r" ) |
218 | PrintFatalError(ErrorLoc: Rec->getLoc(), |
219 | Msg: "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(x: std::move(CppSpelling)); |
226 | |
227 | OS << llvm::format(Fmt: " VersionTuple{%d, %d},\n" , Vals: Major, Vals: Minor); |
228 | OS << llvm::format(Fmt: " %sProfile,\n" , Vals: ProfileUpper.c_str()); |
229 | |
230 | // Name as spelled for -march. |
231 | if (Minor == 0) |
232 | OS << llvm::format(Fmt: " \"armv%d-%s\",\n" , Vals: Major, Vals: ProfileLower.c_str()); |
233 | else |
234 | OS << llvm::format(Fmt: " \"armv%d.%d-%s\",\n" , Vals: Major, Vals: Minor, |
235 | Vals: ProfileLower.c_str()); |
236 | |
237 | // SubtargetFeature::Name, used for -target-feature. Here the "+" is added. |
238 | const auto TargetFeatureName = Rec->getValueAsString(FieldName: "Name" ); |
239 | OS << " \"+" << TargetFeatureName << "\",\n" ; |
240 | |
241 | // Construct the list of default extensions |
242 | OS << " (AArch64::ExtensionBitset({" ; |
243 | for (auto *E : Rec->getValueAsListOfDefs(FieldName: "DefaultExts" )) { |
244 | OS << "AArch64::" << E->getValueAsString(FieldName: "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(ClassName: "ProcessorModel" )) |
270 | Processors.insert(key: Rec->getValueAsString(FieldName: "Name" )); |
271 | |
272 | llvm::StringSet<> Aliases; |
273 | for (const Record *Rec : RK.getAllDerivedDefinitions(ClassName: "ProcessorAlias" )) { |
274 | auto Name = Rec->getValueAsString(FieldName: "Name" ); |
275 | auto Alias = Rec->getValueAsString(FieldName: "Alias" ); |
276 | if (!Processors.contains(key: Alias)) |
277 | PrintFatalError( |
278 | Rec, Msg: "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'" ); |
279 | if (Processors.contains(key: Name)) |
280 | PrintFatalError( |
281 | Rec, Msg: "Alias '" + Name + "' duplicates an existing ProcessorModel" ); |
282 | if (!Aliases.insert(key: Name).second) |
283 | PrintFatalError( |
284 | Rec, Msg: "Alias '" + Name + "' duplicates an existing ProcessorAlias" ); |
285 | |
286 | OS << llvm::formatv(Fmt: R"( { "{0}", "{1}" },)" , Vals&: Name, Vals&: 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(ClassName: "ProcessorModel" )) { |
299 | auto Name = Rec->getValueAsString(FieldName: "Name" ); |
300 | auto Features = Rec->getValueAsListOfDefs(FieldName: "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(Name: "HasV8_0aOps" ); |
312 | } else { |
313 | // Search for an Architecture64 in the list of features. |
314 | auto IsArch = [](const Record *F) { |
315 | return F->isSubClassOf(Name: "Architecture64" ); |
316 | }; |
317 | auto ArchIter = llvm::find_if(Range&: Features, P: IsArch); |
318 | if (ArchIter == Features.end()) |
319 | PrintFatalError(Rec, Msg: "Features must include an Architecture64." ); |
320 | Arch = *ArchIter; |
321 | |
322 | // Check there is only one Architecture in the list. |
323 | if (llvm::count_if(Range&: Features, P: IsArch) > 1) |
324 | PrintFatalError(Rec, Msg: "Features has multiple Architecture64 entries" ); |
325 | } |
326 | |
327 | auto Major = Arch->getValueAsInt(FieldName: "Major" ); |
328 | auto Minor = Arch->getValueAsInt(FieldName: "Minor" ); |
329 | auto Profile = Arch->getValueAsString(FieldName: "Profile" ); |
330 | auto ArchInfo = ArchInfoName(Major, Minor, Profile); |
331 | |
332 | checkFeatureTree(Root: 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(FieldName: "Features" )) |
342 | // Only process subclasses of Extension |
343 | if (E->isSubClassOf(Name: "Extension" )) { |
344 | const auto AEK = E->getValueAsString(FieldName: "ArchExtKindSpelling" ).upper(); |
345 | if (!SeenExts.insert(key: AEK).second) |
346 | PrintFatalError(Rec, Msg: "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 | |