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