1//===- TargetFeaturesEmitter.cpp - Generate CPU Target feature ----===//
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 cpu target features
10// and cpu sub-type.
11//
12//===----------------------------------------------------------------------===//
13
14#include "TargetFeaturesEmitter.h"
15#include "llvm/TableGen/Error.h"
16#include "llvm/TableGen/TableGenBackend.h"
17#include "llvm/TargetParser/SubtargetFeature.h"
18
19using namespace llvm;
20
21using FeatureMapTy = DenseMap<const Record *, unsigned>;
22using ConstRecVec = std::vector<const Record *>;
23
24TargetFeaturesEmitter::TargetFeaturesEmitter(const RecordKeeper &R)
25 : Records(R) {
26 ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions(ClassName: "Target");
27 if (Targets.size() == 0)
28 PrintFatalError(Msg: "No 'Target' subclasses defined!");
29 if (Targets.size() != 1)
30 PrintFatalError(Msg: "Multiple subclasses of Target defined!");
31 Target = Targets[0]->getName();
32}
33
34FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {
35 ArrayRef<const Record *> DefList =
36 Records.getAllDerivedDefinitions(ClassName: "SubtargetFeature");
37
38 unsigned N = DefList.size();
39 if (N == 0)
40 return FeatureMapTy();
41
42 if (N + 1 > MAX_SUBTARGET_FEATURES)
43 PrintFatalError(
44 Msg: "Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
45
46 OS << "namespace " << Target << " {\n";
47
48 OS << "enum {\n";
49
50 FeatureMapTy FeatureMap;
51 for (unsigned I = 0; I < N; ++I) {
52 const Record *Def = DefList[I];
53 // Print the Feature Name.
54 OS << " " << Def->getName() << " = " << I << ",\n";
55
56 FeatureMap[Def] = I;
57 }
58
59 OS << " " << "NumSubtargetFeatures = " << N << "\n";
60
61 // Close enumeration and namespace
62 OS << "};\n";
63 OS << "} // end namespace " << Target << "\n";
64 return FeatureMap;
65}
66
67void TargetFeaturesEmitter::printFeatureMask(
68 raw_ostream &OS, ArrayRef<const Record *> FeatureList,
69 const FeatureMapTy &FeatureMap) {
70 std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
71 for (const Record *Feature : FeatureList) {
72 unsigned Bit = FeatureMap.lookup(Val: Feature);
73 Mask[Bit / 64] |= 1ULL << (Bit % 64);
74 }
75
76 OS << "{ { { ";
77 for (unsigned I = 0; I != Mask.size(); ++I) {
78 OS << "0x";
79 OS.write_hex(N: Mask[I]);
80 OS << "ULL, ";
81 }
82 OS << "} } }";
83}
84
85void TargetFeaturesEmitter::printFeatureKeyValues(
86 raw_ostream &OS, const FeatureMapTy &FeatureMap) {
87 std::vector<const Record *> FeatureList =
88 Records.getAllDerivedDefinitions(ClassName: "SubtargetFeature");
89
90 // Remove features with empty name.
91 llvm::erase_if(C&: FeatureList, P: [](const Record *Rec) {
92 return Rec->getValueAsString(FieldName: "Name").empty();
93 });
94
95 if (FeatureList.empty())
96 return;
97
98 llvm::sort(C&: FeatureList, Comp: LessRecordFieldName());
99
100 // Begin feature table.
101 OS << "// Sorted (by key) array of values for CPU features.\n"
102 << "extern const llvm::BasicSubtargetFeatureKV " << "Basic" << Target
103 << "FeatureKV[] = {\n";
104
105 for (const Record *Feature : FeatureList) {
106 StringRef Name = Feature->getName();
107 StringRef ValueName = Feature->getValueAsString(FieldName: "Name");
108
109 OS << " { " << "\"" << ValueName << "\", " << Target << "::" << Name
110 << ", ";
111
112 ConstRecVec ImpliesList = Feature->getValueAsListOfDefs(FieldName: "Implies");
113
114 printFeatureMask(OS, FeatureList: ImpliesList, FeatureMap);
115
116 OS << " },\n";
117 }
118
119 // End feature table.
120 OS << "};\n";
121}
122
123void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS,
124 const FeatureMapTy &FeatureMap) {
125 // Gather and sort processor information
126 std::vector<const Record *> ProcessorList =
127 Records.getAllDerivedDefinitions(ClassName: "Processor");
128 llvm::sort(C&: ProcessorList, Comp: LessRecordFieldName());
129
130 // Begin processor table.
131 OS << "// Sorted (by key) array of values for CPU subtype.\n"
132 << "extern const llvm::BasicSubtargetSubTypeKV " << "Basic" << Target
133 << "SubTypeKV[] = {\n";
134
135 for (const Record *Processor : ProcessorList) {
136 StringRef Name = Processor->getValueAsString(FieldName: "Name");
137 ConstRecVec FeatureList = Processor->getValueAsListOfDefs(FieldName: "Features");
138
139 OS << " { " << "\"" << Name << "\", ";
140
141 printFeatureMask(OS, FeatureList, FeatureMap);
142 OS << " },\n";
143 }
144
145 // End processor table.
146 OS << "};\n";
147}
148
149void TargetFeaturesEmitter::run(raw_ostream &OS) {
150 OS << "// Autogenerated by TargetFeatureEmitter.cpp\n\n";
151
152 OS << "\n#ifdef GET_SUBTARGETFEATURES_ENUM\n";
153 OS << "#undef GET_SUBTARGETFEATURES_ENUM\n\n";
154
155 OS << "namespace llvm {\n";
156 auto FeatureMap = enumeration(OS);
157 OS << "} // end namespace llvm\n\n";
158 OS << "#endif // GET_SUBTARGETFEATURES_ENUM\n\n";
159
160 OS << "\n#ifdef GET_SUBTARGETFEATURES_KV\n";
161 OS << "#undef GET_SUBTARGETFEATURES_KV\n\n";
162
163 OS << "namespace llvm {\n";
164 printFeatureKeyValues(OS, FeatureMap);
165 OS << "\n";
166
167 printCPUKeyValues(OS, FeatureMap);
168 OS << "\n";
169 OS << "} // end namespace llvm\n\n";
170 OS << "#endif // GET_SUBTARGETFEATURES_KV\n\n";
171}
172
173static TableGen::Emitter::OptClass<TargetFeaturesEmitter>
174 X("gen-target-features", "Generate subtarget enumerations");
175