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 | |
19 | using namespace llvm; |
20 | |
21 | using FeatureMapTy = DenseMap<const Record *, unsigned>; |
22 | using ConstRecVec = std::vector<const Record *>; |
23 | |
24 | TargetFeaturesEmitter::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 | |
34 | FeatureMapTy 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 | |
67 | void 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 | |
85 | void 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 | |
123 | void 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 | |
149 | void 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 | |
173 | static TableGen::Emitter::OptClass<TargetFeaturesEmitter> |
174 | X("gen-target-features" , "Generate subtarget enumerations" ); |
175 | |