3.6. 描述目标机器的数据结构
描述目标机器的数据结构由TableGen的“-gen-subtarget”选项生成。以X86来说,生成文件是X86GenSubtargetInfo.Inc。
3.6.1. 对目标机器描述的解析
这个选项的处理入口是下面的方法:
1154 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
1155 CodeGenTarget CGTarget(RK);
1156 SubtargetEmitter(RK, CGTarget).run(OS);
1157 }
SubtargetEmitter的构造函数有如下定义。
104 SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT):
105 Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {}
SchedModels是SubtargetEmitter中类型为CodeGenSchedModels的成员,这个构造函数我们已经在前面看过了(这是一个相当复杂的过程,还好我们已经知道了,由此可见LLVM有相当好的代码重用设计)
3.6.2. 代码生成
3.6.2.1. 处理器特征的描述
同样不出所料,SubtargetEmitter::run方法首先输出的与此相关的枚举常量。
1409 void SubtargetEmitter::run(raw_ostream &OS) {
1410 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
1411
1412 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
1413 OS << "#undef GET_SUBTARGETINFO_ENUM\n";
1414
1415 OS << "namespace llvm {\n";
1416 Enumeration(OS, "SubtargetFeature");
1417 OS << "} // End llvm namespace \n";
1418 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
1419
1420 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
1421 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n";
1422
1423 OS << "namespace llvm {\n";
1424 #if 0
1425 OS << "namespace {\n";
1426 #endif
1427 unsigned NumFeatures = FeatureKeyValues(OS);
1428 OS << "\n";
1429 unsigned NumProcs = CPUKeyValues(OS);
1430 OS << "\n";
1431 EmitSchedModel(OS);
1432 OS << "\n";
1433 #if 0
1434 OS << "}\n";
1435 #endif
处理器所具有的特征由SubtargetFeatures派生定义来描述。因此首先需要通过下面的方法来输出标识这些特征的枚举常量。
115 void SubtargetEmitter::Enumeration(raw_ostream &OS,
116 const char *ClassName) {
117 // Get all records of class and sort
118 std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName);
119 std::sort(DefList.begin(), DefList.end(), LessRecord());
120
121 unsigned N = DefList.size();
122 if (N == 0)
123 return;
124 if (N > MAX_SUBTARGET_FEATURES)
125 PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
126
127 OS << "namespace " << Target << " {\n";
128
129 // Open enumeration. Use a 64-bit underlying type.
130 OS << "enum : uint64_t {\n";
131
132 // For each record
133 for (unsigned i = 0; i < N;) {
134 // Next record
135 Record *Def = DefList[i];
136
137 // Get and emit name
138 OS << " " << Def->getName() << " = " << i;
139 if (++i < N) OS << ",";
140
141 OS << "\n";
142 }
143
144 // Close enumeration and namespace
145 OS << "};\n}\n";
146 }
因为这些枚举常量将指定一个特定标志的比特位,可能出于历史原因,LLVM将这些枚举常量限定在64以下(124行的MAX_SUBTARGET_FEATURES,X86目前用到61),输出的结果如下:
#ifdef GET_SUBTARGETINFO_ENUM
#undef GET_SUBTARGETINFO_ENUM
namespace llvm {
namespace X86 {
enum : uint64_t {
Feature3DNow = 0,
Feature3DNowA = 1,
Feature64Bit = 2,
FeatureADX = 3,
…
ProcIntelSLM = 61
};
}
} // End llvm namespace
#endif // GET_SUBTARGETINFO_ENUM
接下来需要输出描述各个处理器具有哪些特性的数据结构。首先输出的是描述特性间包含关系的SubtargetFeatureKV类型数组。SubtargetFeatureKV的定义如下:
52 struct SubtargetFeatureKV {
53 const char *Key; // K-V key string
54 const char *Desc; // Help descriptor
55 FeatureBitset Value; // K-V integer value
56 FeatureBitset Implies; // K-V bit mask
57
58 // Compare routine for std::lower_bound
59 bool operator<(StringRef S) const {
60 return StringRef(Key) < S;
61 }
62 };
其中Key用作排序的键值,Value是该实例所代表的处理器特性,Implies则是该特性所隐含的其他特性。类型FeatureBitset是这样的一个定义:
33 const unsigned MAX_SUBTARGET_FEATURES = 64;
34 class FeatureBitset: public std::bitset<MAX_SUBTARGET_FEATURES> {
35 public:
36 // Cannot inherit constructors because it's not supported by VC++..
37 FeatureBitset() : bitset() {}
38
39 FeatureBitset(const bitset<MAX_SUBTARGET_FEATURES>& B) : bitset(B) {}
40
41 FeatureBitset(std::initializer_list<unsigned> Init) : bitset() {
42 for (auto I = Init.begin() , E = Init.end(); I != E; ++I)
43 set(*I);
44 }
45 };
FeatureBitset保存的就是前面输出的代表各个处理器特性的枚举常量。LLVM提供这个类,是因为std::bitset不提供第三个构造函数的形式(41行),这个构造函数是下面输出X86SubTypeKV所需要的形式。
152 unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) {
153 // Gather and sort all the features
154 std::vector<Record*> FeatureList =
155 Records.getAllDerivedDefinitions("SubtargetFeature");
156
157 if (FeatureList.empty())
158 return 0;
159
160 std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName());
161
162 // Begin feature table
163 OS << "// Sorted (by key) array of values for CPU features.\n"
164 << "extern const llvm::SubtargetFeatureKV " << Target
165 << "FeatureKV[] = {\n";
166
167 // For each feature
168 unsigned NumFeatures = 0;
169 for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) {
170 // Next feature
171 Record *Feature = FeatureList[i];
172
173 const std::string &Name = Feature->getName();
174 const std::string &CommandLineName = Feature->getValueAsString("Name");
175 const std::string &Desc = Feature->getValueAsString("Desc");
176
177 if (CommandLineName.empty()) continue;
178
179 // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } }
180 OS << " { "
181 << "\"" << CommandLineName << "\", "
182 << "\"" << Desc << "\", "
183 << "{ " << Target << "::" << Name << " }, ";
184
185 const std::vector<Record*> &ImpliesList =
186 Feature->getValueAsListOfDefs("Implies");
187
188 if (ImpliesList.empty()) {
189 OS << "{ }";
190 } else {
191 OS << "{ ";
192 for (unsigned j = 0, M = ImpliesList.size(); j < M;) {
193 OS << Target << "::" << ImpliesList[j]->getName();
194 if (++j < M) OS << ", ";
195 }
196 OS << " }";
197 }
198
199 OS << " }";
200 ++NumFeatures;
201
202 // Depending on 'if more in the list' emit comma
203 if ((i + 1) < N) OS << ",";
204
205 OS << "\n";
206 }
207
208 // End feature table
209 OS << "};\n";
210
211 return NumFeatures;
212 }
在这些SubtargetFeatureKV对象里,Key都是这些特性的名字,这样我们得到如下的输出:
#ifdef GET_SUBTARGETINFO_MC_DESC
#undef GET_SUBTARGETINFO_MC_DESC
namespace llvm {
// Sorted (by key) array of values for CPU features.
extern const llvm::SubtargetFeatureKV X86FeatureKV[] = {
{ "16bit-mode", "16-bit mode (i8086)", { X86::Mode16Bit }, { } },
{ "32bit-mode", "32-bit mode (80386)", { X86::Mode32Bit }, { } },
{ "3dnow", "Enable 3DNow! instructions", { X86::Feature3DNow }, { X86::FeatureMMX } },
…
{ "xop", "Enable XOP instructions", { X86::FeatureXOP }, { X86::FeatureFMA4 } }
};
接下来输出的就是描述各个处理器具有哪些特性的SubtargetFeatureKV类型数组。显然对这个数组来说,键值就应该是处理器的名字。
218 unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
219 // Gather and sort processor information
220 std::vector<Record*> ProcessorList =
221 Records.getAllDerivedDefinitions("Processor");
222 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
223
224 // Begin processor table
225 OS << "// Sorted (by key) array of values for CPU subtype.\n"
226 << "extern const llvm::SubtargetFeatureKV " << Target
227 << "SubTypeKV[] = {\n";
228
229 // For each processor
230 for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
231 // Next processor
232 Record *Processor = ProcessorList[i];
233
234 const std::string &Name = Processor->getValueAsString("Name");
235 const std::vector<Record*> &FeatureList =
236 Processor->getValueAsListOfDefs("Features");
237
238 // Emit as { "cpu", "description", { f1 , f2 , ... fn } },
239 OS << " { "
240 << "\"" << Name << "\", "
241 << "\"Select the " << Name << " processor\", ";
242
243 if (FeatureList.empty()) {
244 OS << "{ }";
245 } else {
246 OS << "{ ";
247 for (unsigned j = 0, M = FeatureList.size(); j < M;) {
248 OS << Target << "::" << FeatureList[j]->getName();
249 if (++j < M) OS << ", ";
250 }
251 OS << " }";
252 }
253
254 // The { } is for the "implies" section of this data structure.
255 OS << ", { } }";
256
257 // Depending on 'if more in the list' emit comma
258 if (++i < N) OS << ",";
259
260 OS << "\n";
261 }
262
263 // End processor table
264 OS << "};\n";
265
266 return ProcessorList.size();
267 }
这样,我们就得到如下的一个数组:
extern const llvm::SubtargetFeatureKV X86SubTypeKV[] = {
{ "amdfam10", "Select the amdfam10 processor", { X86::FeatureSSE4A, X86::Feature3DNowA, X86::FeatureCMPXCHG16B, X86::FeatureLZCNT, X86::FeaturePOPCNT, X86::FeatureSlowBTMem, X86::FeatureSlowSHLD }, { } },
{ "athlon", "Select the athlon processor", { X86::Feature3DNowA, X86::FeatureSlowBTMem, X86::FeatureSlowSHLD }, { } },
{ "athlon-4", "Select the athlon-4 processor", { X86::FeatureSSE1, X86::Feature3DNowA, X86::FeatureSlowBTMem, X86::FeatureSlowSHLD }, { } },
…
{ "yonah", "Select the yonah processor", { X86::FeatureSSE3, X86::FeatureSlowBTMem }, { } }
};