3.4.2.4.3.2. 简化
回到TreePattern::InferAllTypes,既然现在类型有可能已经具体化了,那么通过下面的方法尝试简化这棵TreePattern树。
2216 static bool SimplifyTree(TreePatternNode *&N) {
2217 if (N->isLeaf())
2218 return false;
2219
2220 // If we have a bitconvert with a resolved type and if the source and
2221 // destination types are the same, then the bitconvert is useless, remove it.
2222 if (N->getOperator()->getName() == "bitconvert" &&
2223 N->getExtType(0).isConcrete() &&
2224 N->getExtType(0) == N->getChild(0)->getExtType(0) &&
2225 N->getName().empty()) {
2226 N = N->getChild(0);
2227 SimplifyTree(N);
2228 return true;
2229 }
2230
2231 // Walk all children.
2232 bool MadeChange = false;
2233 for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
2234 TreePatternNode *Child = N->getChild(i);
2235 MadeChange |= SimplifyTree(Child);
2236 N->setChild(i, Child);
2237 }
2238 return MadeChange;
2239 }
可以看到,目前只有bitconvert子树才可能简化。Bitconvert代表了整数、浮点及向量值之间的转换,源与目标值都有相同的大小。如果源与目标值类型相同,这个转换可以丢弃。
3.4.2.4.3.3. 类型的最后确定
在TreePattern::InferAllTypes()函数的入口,当前树的具名节点(即node:$name的名字name)被保存在NamedNodes容器。現在2260行遍历这些名字。首先,如果InferAllTypes()传入了非空的参数InNamedTypes,需要确保名字出现在InNamedTypes里。并使用InNamedTypes中对应节点的类型信息来更新当前节点的类型。这个用法出现在Instruction与Pattern定义的处理中,后面会看到。
在此之后,如果NamedNodes容器里存在多个节点对应同一个名字的情形,它们的类型必须一致(2300~2310行)。
而在上述过程里,一旦有节点的类型发生变化,就要回到2252行重新进行处理,直达没有节点的类型在一次处理过程中改变为止。这时,这棵(些)TreePattern树所有节点的类型都应该确定了,这由下面的方法来判定。
498 bool ContainsUnresolvedType() const {
499 for (unsigned i = 0, e = Types.size(); i != e; ++i)
500 if (!Types[i].isConcrete()) return true;
501
502 for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
503 if (getChild(i)->ContainsUnresolvedType()) return true;
504 return false;
505 }
从TreePattern::InferAllTypes()回到CodeGenDAGPatterns::ParsePatternFragments(),对PatFrag定义的处理就此完成。
对v7.0,ContainsUnresolvedType()的定义是: 1561 bool TreePatternNode::ContainsUnresolvedType(TreePattern &TP) const { 1562 for (unsigned i = 0, e = Types.size(); i != e; ++i) 1563 if (!TP.getInfer().isConcrete(Types[i], true)) 1564 return true; 1565 for (unsigned i = 0, e = getNumChildren(); i != e; ++i) 1566 if (getChild(i)->ContainsUnresolvedType(TP)) 1567 return true; 1568 return false; 1569 } 1563行TypeInfo的isConcrete()方法通过TypeSetByHwMode的sValueTypeByHwMode()来执行: 253 bool isConcrete(const TypeSetByHwMode &VTS, bool AllowEmpty) const { 254 return VTS.isValueTypeByHwMode(AllowEmpty); 255 } 下面73行遍历TypeSetByHwMode实例中的Map容器(std::map<unsigned, MachineValueTypeSet),74行检查其中的MachineValueTypeSet容器是否有设置了比特位(对应一个MVT)。 72 bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const { 73 for (const auto &I : *this) { 74 if (I.second.size() > 1) 75 return false; 76 if (!AllowEmpty && I.second.empty()) 77 return false; 78 } 79 return true; 80 } 在AllowEmpty是false的情形下,Map容器里每个MachineValueTypeSet容器中只设置了一个比特位,TypeSetByHwMode的sValueTypeByHwMode()才返回true。 |
3.4.2.4.4. OperandWithDefaultOps
接下来,CodeGenDAGPatterns构造函数处理OperandWithDefaultOps派生定义。这个定义在文件Target.td里。
664 class OperandWithDefaultOps<ValueType ty, dag defaultops>
665 : Operand<ty> {
666 dag DefaultOps = defaultops;
667 }
TableGen使用这个定义用于代表缺省值。它典型的用法有(摘自AMDGPUInstructions.td):
def InstFlag : OperandWithDefaultOps <i32, (ops (i32 0))>;
在这个定义里,缺省值是0。InstFlag可以用在dag中作为操作数,表示自己所代表的缺省值。
CodeGenDAGPatterns对OperandWithDefaultOps定义的处理相当简单。
2507 void CodeGenDAGPatterns::ParseDefaultOperands() {
2508 std::vector<Record*> DefaultOps;
2509 DefaultOps = Records.getAllDerivedDefinitions("OperandWithDefaultOps");
2510
2511 // Find some SDNode.
2512 assert(!SDNodes.empty() && "No SDNodes parsed?");
2513 Init *SomeSDNode = DefInit::get(SDNodes.begin()->first);
2514
2515 for (unsigned i = 0, e = DefaultOps.size(); i != e; ++i) {
2516 DagInit *DefaultInfo = DefaultOps[i]->getValueAsDag("DefaultOps");
2517
2518 // Clone the DefaultInfo dag node, changing the operator from 'ops' to
2519 // SomeSDnode so that we can parse this.
2520 std::vector<std::pair<Init*, std::string> > Ops;
2521 for (unsigned op = 0, e = DefaultInfo->getNumArgs(); op != e; ++op)
2522 Ops.push_back(std::make_pair(DefaultInfo->getArg(op),
2523 DefaultInfo->getArgName(op)));
2524 DagInit *DI = DagInit::get(SomeSDNode, "", Ops);
2525
2526 // Create a TreePattern to parse this.
2527 TreePattern P(DefaultOps[i], DI, false, *this);
2528 assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!");
2529
2530 // Copy the operands over into a DAGDefaultOperand.
2531 DAGDefaultOperand DefaultOpInfo;
2532
2533 TreePatternNode *T = P.getTree(0);
2534 for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) {
2535 TreePatternNode *TPN = T->getChild(op);
2536 while (TPN->ApplyTypeConstraints(P, false))
2537 /* Resolve all types */;
2538
2539 if (TPN->ContainsUnresolvedType()) {
2540 PrintFatalError("Value #" + Twine(i) + " of OperandWithDefaultOps '" +
2541 DefaultOps[i]->getName() +
2542 "' doesn't have a concrete type!");
2543 }
2544 DefaultOpInfo.DefaultOps.push_back(TPN);
2545 }
2546
2547 // Insert it into the DefaultOperands map so we can find it later.
2548 DefaultOperands[DefaultOps[i]] = DefaultOpInfo;
2549 }
2550 }
SDNodes是CodeGenDAGPatterns的std::map<Record*, SDNodeInfo, LessRecordByID>类型容器,LessRecordByID以Record的ID来排序。因此2513行获取第一个出现的SDNode定义,这是imm。因此,2521~2524行将指定的缺省值(DefaultOps)封装为一个DagInit:(imm DefaultOps),由TreePattern构造函数构造该DagInit的模式树。由容器DefaultOperands(std::map<Record*, DAGDefaultOperand, LessRecordByID>)保存这些生成的模式树。