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/CodeGenHelpers.h"
16#include "llvm/TableGen/Error.h"
17#include "llvm/TableGen/TableGenBackend.h"
18#include "llvm/TargetParser/SubtargetFeature.h"
19
20using namespace llvm;
21
22using FeatureMapTy = DenseMap<const Record *, unsigned>;
23using ConstRecVec = std::vector<const Record *>;
24
25TargetFeaturesEmitter::TargetFeaturesEmitter(const RecordKeeper &R)
26 : Records(R) {
27 ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions(ClassName: "Target");
28 if (Targets.size() == 0)
29 PrintFatalError(Msg: "No 'Target' subclasses defined!");
30 if (Targets.size() != 1)
31 PrintFatalError(Msg: "Multiple subclasses of Target defined!");
32 Target = Targets[0]->getName();
33}
34
35FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {
36 ArrayRef<const Record *> DefList =
37 Records.getAllDerivedDefinitions(ClassName: "SubtargetFeature");
38
39 unsigned N = DefList.size();
40 if (N == 0)
41 return FeatureMapTy();
42
43 if (N + 1 > MAX_SUBTARGET_FEATURES)
44 PrintFatalError(
45 Msg: "Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
46
47 NamespaceEmitter NS(OS, Target);
48
49 OS << "enum {\n";
50
51 FeatureMapTy FeatureMap;
52 for (unsigned I = 0; I < N; ++I) {
53 const Record *Def = DefList[I];
54 // Print the Feature Name.
55 OS << " " << Def->getName() << " = " << I << ",\n";
56
57 FeatureMap[Def] = I;
58 }
59
60 OS << " " << "NumSubtargetFeatures = " << N << "\n";
61
62 // Close enumeration.
63 OS << "};\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 FeatureMapTy FeatureMap;
153 {
154 IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_ENUM");
155 NamespaceEmitter NS(OS, "llvm");
156 FeatureMap = enumeration(OS);
157 }
158
159 {
160 IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_KV");
161 NamespaceEmitter NS(OS, "llvm");
162
163 printFeatureKeyValues(OS, FeatureMap);
164 OS << "\n";
165
166 printCPUKeyValues(OS, FeatureMap);
167 OS << "\n";
168 }
169}
170
171static TableGen::Emitter::OptClass<TargetFeaturesEmitter>
172 X("gen-target-features", "Generate subtarget enumerations");
173