LLVM学习笔记(17)补

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.0ContainsUnresolvedType()的定义是:

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  }

1563TypeInfoisConcrete()方法通过TypeSetByHwModesValueTypeByHwMode()来执行:

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       }

AllowEmptyfalse的情形下,Map容器里每个MachineValueTypeSet容器中只设置了一个比特位,TypeSetByHwModesValueTypeByHwMode()才返回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>)保存这些生成的模式树。

猜你喜欢

转载自blog.csdn.net/wuhui_gdnt/article/details/89230074