3.11.2. 模式分析
GlobalISel是以DAG指令选择的TD定义处理与分析为基础的。因此,GlobalISelEmitter包含了一个CodeGenDAGPatterns类型的const成员CGP(一旦创建完成,就是只读的),在GlobalISelEmitter构造函数中将完成DAG指令选择令人眼花缭乱的准备工作(参考DAG指令选择器的生成代码一节,直到Match对象序列的优化为止),为GlobalISelEmitter准备好指令的PatternToMatch实例。在此基础上,GlobalISel将生成自己的指令匹配表。
在完成GlobalISelEmitter对象的构造后,立即调用下面的方法进行GlobalISel代码生成的处理。
4240 void GlobalISelEmitter::run(raw_ostream &OS) {
4241 if (!UseCoverageFile.empty()) {
4242 RuleCoverage = CodeGenCoverage();
4243 auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile);
4244 if (!RuleCoverageBufOrErr) {
4245 PrintWarning(SMLoc(), "Missing rule coverage data");
4246 RuleCoverage = None;
4247 } else {
4248 if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) {
4249 PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data");
4250 RuleCoverage = None;
4251 }
4252 }
4253 }
4254
4255 // Track the run-time opcode values
4256 gatherOpcodeValues();
4257 // Track the run-time LLT ID values
4258 gatherTypeIDValues();
4259
4260 // Track the GINodeEquiv definitions.
4261 gatherNodeEquivs();
4262
4263 emitSourceFileHeader(("Global Instruction Selector for the " +
4264 Target.getName() + " target").str(), OS);
4265 std::vector
4266 // Look through the SelectionDAG patterns we found, possibly emitting some.
4267 for (const PatternToMatch &Pat : CGP.ptms()) {
4268 ++NumPatternTotal;
4269
4270 auto MatcherOrErr = runOnPattern(Pat);
4271
4272 // The pattern analysis can fail, indicating an unsupported pattern.
4273 // Report that if we've been asked to do so.
4274 if (auto Err = MatcherOrErr.takeError()) {
4275 if (WarnOnSkippedPatterns) {
4276 PrintWarning(Pat.getSrcRecord()->getLoc(),
4277 "Skipped pattern: " + toString(std::move(Err)));
4278 } else {
4279 consumeError(std::move(Err));
4280 }
4281 ++NumPatternImportsSkipped;
4282 continue;
4283 }
4284
4285 if (RuleCoverage) {
4286 if (RuleCoverage->isCovered(MatcherOrErr->getRuleID()))
4287 ++NumPatternsTested;
4288 else
4289 PrintWarning(Pat.getSrcRecord()->getLoc(),
4290 "Pattern is not covered by a test");
4291 }
4292 Rules.push_back(std::move(MatcherOrErr.get()));
4293 }
3.11.2.1. 准备工作
这实际上就是所谓的SelectionDAG定义的导入。
在GlobalISelEmitter::run()的4256行GlobalISelEmitter::gatherOpcodeValues()收集指令操作码的值。
3081 void GlobalISelEmitter::gatherOpcodeValues() {
3082 InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
3083 }
InstructionOpcodeMatcher的OpcodeValues是DenseMap
在TargetOpcodes.def文件中声明的固定/通用指令
按名字字母序排序的伪指令
按名字字母序排序的其他指令
1550 static void initOpcodeValuesMap(const CodeGenTarget &Target) {
1551 OpcodeValues.clear();
1552
1553 unsigned OpcodeValue = 0;
1554 for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())
1555 OpcodeValues[I] = OpcodeValue++;
1556 }
接着,调用GlobalISelEmitter::gatherTypeIDValues()收集相关的类型信息:
3085 void GlobalISelEmitter::gatherTypeIDValues() {
3086 LLTOperandMatcher::initTypeIDValuesMap();
3087 }
LLTOperandMatcher的静态容器TypeIDValues的类型是std::map
1156 bool hasValue() const override {
1157 if (TypeIDValues.size() != KnownTypes.size())
1158 initTypeIDValuesMap();
1159 return TypeIDValues.count(Ty);
1160 }
这里才是保证TypeIDValues反映已知类型的所在。
类LLTCodeGen名字中的LLT是Low Level Type的缩写,这个类只有一个LLT类型的数据成员,它用于辅助输出GlobalISel生成代码中与LLT相关的代码。
1130 static void initTypeIDValuesMap() {
1131 TypeIDValues.clear();
1132
1133 unsigned ID = 0;
1134 for (const LLTCodeGen LLTy : KnownTypes)
1135 TypeIDValues[LLTy] = ID++;
1136 }
接着,在GlobalISelEmitter::run()的4261行调用GlobalISelEmitter::gatherNodeEquivs()将SDNode节点与等价的GlobalISel节点关联起来:
3103 void GlobalISelEmitter::gatherNodeEquivs() {
3104 assert(NodeEquivs.empty());
3105 for (Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv"))
3106 NodeEquivs[Equiv->getValueAsDef("Node")] = Equiv;
3107
3108 assert(ComplexPatternEquivs.empty());
3109 for (Record *Equiv : RK.getAllDerivedDefinitions("GIComplexPatternEquiv")) {
3110 Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
3111 if (!SelDAGEquiv)
3112 continue;
3113 ComplexPatternEquivs[SelDAGEquiv] = Equiv;
3114 }
3115
3116 assert(SDNodeXFormEquivs.empty());
3117 for (Record *Equiv : RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) {
3118 Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
3119 if (!SelDAGEquiv)
3120 continue;
3120 SDNodeXFormEquivs[SelDAGEquiv] = Equiv;
3120 }
3120 }
GlobalISelEmitter的容器NodeEquivs用于映射SDNode到GINodeEquiv,维护SDNode与指令间的等价性。它的类型是DenseMap
容器ComplexPatternEquivs用于维护ComplexPattern与GIComplexOperandMatcher间的等价性。它的类型也是 DenseMap
同理,容器SDNodeXFormEquivs用于维护SDNodeXForm与GICustomOperandRenderer间的等价性,类型仍然是DenseMap
它们都使用相应的SelectionDAG定义的Record对象作为键值。