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 | |
25 | using namespace llvm; |
26 | |
27 | /// Collect the full set of implied features for a SubtargetFeature. |
28 | static 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 | |
37 | static 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 | |
54 | static 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 | |
341 | static TableGen::Emitter::Opt |
342 | X("gen-arm-target-def" , EmitARMTargetDef, |
343 | "Generate the ARM or AArch64 Architecture information header." ); |
344 | |