LLVM学习笔记(37)

栏目: 服务器 · 编程工具 · 发布时间: 6年前

内容简介:InstRW为一组指令重新绑定SchedReadWrite。在前面CodeGenSchedModels的方法里已经为InstRW定义准备了CodeGenSchedClass对象,并在CodeGenSchedClass对象的InstRWs容器里记录了该InstRW定义的Record实例。但对InstRW定义的处理并没完成,因为InstRW定义中的OperandReadWrites尚未处理,这些定义可能会衍生出一些新的调度类型,就像ItinRW的那样。因此在inferSchedClasses的846行,如果当

3.5.1.6.2. 从InstRW定义推导

InstRW为一组指令重新绑定SchedReadWrite。在前面CodeGenSchedModels的方法里已经为InstRW定义准备了CodeGenSchedClass对象,并在CodeGenSchedClass对象的InstRWs容器里记录了该InstRW定义的Record实例。但对InstRW定义的处理并没完成,因为InstRW定义中的OperandReadWrites尚未处理,这些定义可能会衍生出一些新的调度类型,就像ItinRW的那样。

因此在inferSchedClasses的846行,如果当前CodeGenSchedClass对象的InstRWs容器不为空,表明这个对象至少对应一个InstRW定义。886行展开这些InstRW定义的Instrs成员,得到该InstRW定义所应用的指令组。然后在888行的循环里确定该InstRW定义与当前CodeGenSchedClass对象相关。

882      void CodeGenSchedModels::inferFromInstRWs (unsigned SCIdx) {

883      for (unsigned I = 0, E = SchedClasses[SCIdx].InstRWs.size(); I != E; ++I) {

884      assert (SchedClasses[SCIdx].InstRWs.size() == E && "InstrRWs was mutated!");

885      Record *Rec = SchedClasses[SCIdx].InstRWs[I];

886      const RecVec *InstDefs = Sets.(Rec);

887      RecIter II = InstDefs->begin(), IE = InstDefs->end();

888      for (; II != IE; ++II) {

889      if (InstrClassMap[*II] == SCIdx)

890      break ;

891      }

892      // If this class no longer has any instructions mapped to it, it has become

893          // irrelevant.

894      if (II == IE)

895      continue ;

896      IdxVec Writes, Reads;

897      findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);

898      unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index;

899      IdxVec ProcIndices(1, PIdx);

900      (Writes, Reads, SCIdx, ProcIndices); // May mutate SchedClasses.

901      }

902      }

接下来,类似于ItinRW,根据InstRW定义的OperandReadWrites里的内容来推导新的调度类型。

3.5.1.6.3. 从CodeGenSchedClass的Writes容器内容推导

我们知道一个CodeGenSchedClass对象由成员ItinClassDef,Writes与Reads的内容决定。

对于从ItinRW定义以及InstRW定义推导得到的CodeGenSchedClass对象,它们的ItinClassDef都是NULL,在容器Writes与Reads里,所有可能存在的SchedVariant定义都被展开了。

但对于从指令定义得到的CodeGenSchedClass对象,容器Writes与Reads的内容来自对应指令定义的SchedRW成员(类型list<SchedReadWrite>),这里面可能存在SchedVariant定义。

因此需要在inferSchedClasses的848行对它们调用一次inferFromRW。注意,参数ProcIndices来自SchedClasses[Idx].ProcIndices,这是适用该调度类型的处理器集合。因此,getIntersectingVariants的1095~1109行必须设计成那个样子。

​​​​​​​3.5.1.7. 保存资源对象

在构建了所有的调度类型CodeGenSchedClass实例后,CodeGenSchedModels构造函数最后调用CodeGenSchedModels::collectProcResources方法来保存调度类型需要资源的Record对象。

1433   void CodeGenSchedModels::collectProcResources () {

1434   // Add any subtarget-specific SchedReadWrites that are directly associated

1435     // with processor resources. Refer to the parent SchedClass's ProcIndices to

1436     // determine which processors they apply to.

1437   for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();

1438   SCI != SCE; ++SCI) {

1439   if (SCI->ItinClassDef)

1440   collectItinProcResources (SCI->ItinClassDef);

1441   else {

1442   // This class may have a default ReadWrite list which can be overriden by

1443         // InstRW definitions.

1444   if (!SCI->InstRWs.empty()) {

1445   for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();

1446   RWI != RWE; ++RWI) {

1447   Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");

1448   IdxVec ProcIndices(1, getProcModel(RWModelDef).Index);

1449   IdxVec Writes, Reads;

1450   findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),

1451   Writes, Reads);

1452   collectRWResources(Writes, Reads, ProcIndices);

1453   }

1454   }

1455   (SCI->Writes, SCI->Reads, SCI->ProcIndices);

1456   }

1457   }

前面看过,CodeGenSchedClass对象的ItinClassDef如果不是NULL,那么这个ItinClassDef就是某类指令的执行步骤(itinerary,类型InstrItinClass)。而我们知道ItinRW定义将一组InstrItinClass定义映射到一组SchedReadWrite定义,那么我们需要下面的方法来处理这些ItinRW定义。

1531   void CodeGenSchedModels::collectItinProcResources (Record *ItinClassDef) {

1532   for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {

1533   const CodeGenProcModel &PM = ProcModels[PIdx];

1534   // For all ItinRW entries.

1535   bool HasMatch = false;

1536   for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();

1537   II != IE; ++II) {

1538   RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");

1539   if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))

1540   continue ;

1541   if (HasMatch)

1542   PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "

1543   + ItinClassDef->getName()

1544   + " in ItinResources for " + PM.ModelName);

1545   HasMatch = true;

1546   IdxVec Writes, Reads;

1547   findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);

1548   IdxVec ProcIndices(1, PIdx);

1549   (Writes, Reads, ProcIndices);

1550   }

1551   }

1552   }

首先,遍历处理器的定义查找与参数ItinClassDef相关的ItinRW定义,并获取处理器的索引。现在该处理器的资源由这些ItinRW的OperandReadWrites里的SchedReadWrite定义描述。

1593   void CodeGenSchedModels::collectRWResources ( const IdxVec &Writes,

1594   const IdxVec &Reads,

1595   const IdxVec &ProcIndices) {

1596  

1597   for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)

1598   (*WI, /*IsRead=*/ false, ProcIndices);

1599  

1600   for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)

1601   collectRWResources(*RI, /*IsRead=*/ true, ProcIndices);

1602   }

为了关联资源,TableGen给出了若干特殊的SchedReadWrite派生定义。目标机器由此出发,可以模式自己资源的使用情况。我们需要解析这些特殊SchedReadWrite派生定义的特别语义。

1554   void CodeGenSchedModels::collectRWResources (unsigned RWIdx, bool IsRead,

1555   const IdxVec &ProcIndices) {

1556   const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);

1557   if (SchedRW.TheDef) {

1558   if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) {

1559   for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end();

1560   PI != PE; ++PI) {

1561   (SchedRW.TheDef, *PI);

1562   }

1563   }

1564   else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) {

1565   for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end();

1566   PI != PE; ++PI) {

1567   (SchedRW.TheDef, *PI);

1568   }

1569   }

1570   }

1571   for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();

1572   AI != AE; ++AI) {

1573   IdxVec AliasProcIndices;

1574   if ((*AI)->getValueInit("SchedModel")->isComplete()) {

1575   AliasProcIndices.push_back(

1576   getProcModel((*AI)->getValueAsDef("SchedModel")).Index);

1577   }

1578   else

1579   AliasProcIndices = ProcIndices;

1580   const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW"));

1581   assert (AliasRW.IsRead == IsRead && "cannot alias reads to writes");

1582  

1583   IdxVec ExpandedRWs;

1584   (AliasRW.Index, ExpandedRWs, IsRead);

1585   for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end();

1586   SI != SE; ++SI) {

1587   collectRWResources(*SI, IsRead, AliasProcIndices);

1588   }

1589   }

1590   }

首先,SchedWrite有一个特殊的派生类型——SchedWriteRes,它本身就会关联到一组资源,作用与WriteRes类似。CodeGenProcModel对象专门有记录WriteRes与SchedWriteRes的Record对象的容器WriteResDefs。

1674   void CodeGenSchedModels::addWriteRes (Record *ProcWriteResDef, unsigned PIdx) {

1675   assert (PIdx && "don't add resources to an invalid Processor model");

1676  

1677   RecVec &WRDefs = ProcModels[PIdx].WriteResDefs;

1678   RecIter WRI = std::find(WRDefs.begin(), WRDefs.end(), ProcWriteResDef);

1679   if (WRI != WRDefs.end())

1680   return ;

1681   WRDefs.push_back(ProcWriteResDef);

1682  

1683   // Visit ProcResourceKinds referenced by the newly discovered WriteRes.

1684   RecVec ProcResDefs = ProcWriteResDef->getValueAsListOfDefs("ProcResources");

1685   for (RecIter WritePRI = ProcResDefs.begin(), WritePRE = ProcResDefs.end();

1686   WritePRI != WritePRE; ++WritePRI) {

1687   (*WritePRI, ProcModels[PIdx]);

1688   }

1689   }

WriteRes与SchedWriteRes还派生自基类ProcWriteResources,具有类型为list<ProcResourceKind>的成员ProcResources。这就是WriteRes与SchedWriteRes所关联的资源,这些资源的定义需要被记录下来。

1651   void CodeGenSchedModels::addProcResource (Record *ProcResKind,

1652   CodeGenProcModel &PM) {

1653   for (;;) {

1654   Record *ProcResUnits =(ProcResKind, PM);

1655  

1656   // See if this ProcResource is already associated with this processor.

1657   RecIter I = std::find(PM.ProcResourceDefs.begin(),

1658   PM.ProcResourceDefs.end(), ProcResUnits);

1659   if (I != PM.ProcResourceDefs.end())

1660   return ;

1661  

1662   PM.ProcResourceDefs.push_back(ProcResUnits);

1663   if (ProcResUnits->isSubClassOf("ProcResGroup"))

1664   return ;

1665  

1666   if (!ProcResUnits->getValueInit("Super")->isComplete())

1667   return ;

1668  

1669   ProcResKind = ProcResUnits->getValueAsDef("Super");

1670   }

1671   }

上面的参数ProcResKind可能是ProcResource派生定义,也可能是ProcResGroup派生定义。其中ProcResource派生自ProcResourceKind与ProcResourceUnits,而ProcResGroup只是ProcResourceKind的派生定义。因此,给定一个ProcResKind,如果它是ProcResourceUnits派生定义,我们就知道它是一个ProcResource。否则就是一个ProcResGroup。因此,下面1611行以下处理ProcResGroup定义。

1606   Record * CodeGenSchedModels::findProcResUnits (Record *ProcResKind,

1607   const CodeGenProcModel &PM) const {

1608   if (ProcResKind->isSubClassOf("ProcResourceUnits"))

1609   return ProcResKind;

1610  

1611   Record *ProcUnitDef = nullptr;

1612   RecVec ProcResourceDefs =

1613   Records.getAllDerivedDefinitions("ProcResourceUnits");

1614  

1615   for (RecIter RI = ProcResourceDefs.begin(), RE = ProcResourceDefs.end();

1616   RI != RE; ++RI) {

1617  

1618   if ((*RI)->getValueAsDef("Kind") == ProcResKind

1619   && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) {

1620   if (ProcUnitDef) {

1621   PrintFatalError((*RI)->getLoc(),

1622   "Multiple ProcessorResourceUnits associated with "

1623   + ProcResKind->getName());

1624   }

1625   ProcUnitDef = *RI;

1626   }

1627   }

1628   RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");

1629   for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end();

1630   RI != RE; ++RI) {

1631  

1632   if (*RI == ProcResKind

1633   && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) {

1634   if (ProcUnitDef) {

1635   PrintFatalError((*RI)->getLoc(),

1636   "Multiple ProcessorResourceUnits associated with "

1637   + ProcResKind->getName());

1638   }

1639   ProcUnitDef = *RI;

1640   }

1641   }

1642   if (!ProcUnitDef) {

1643   PrintFatalError(ProcResKind->getLoc(),

1644   "No ProcessorResources associated with "

1645   + ProcResKind->getName());

1646   }

1647   return ProcUnitDef;

1648   }

目前ProcResourceUnits仅有的派生类是ProcResource,ProcResource向基类的Kind成员设置了一个特别的ProcResourceKind派生定义——EponymousProcResourceKind,因此ProcResGroup不会满足1618行的条件,1615行循环目前是没有作用的。对同一族处理器,类似的资源单位通常有相同的类型,而且这些资源单位的定义通常还是匿名的,因此ProcResourceUnits定义里专门给出了类型为SchedMachineModel的域SchedModel,用于区分不同的处理器。1632、1633行就是通过资源类型与作用处理器来找出对应的ProcResGroup定义。

CodeGenProcModel实例的容器ProcResourceDefs用于记录ProcResource与ProcResGroup派生定义的Record对象(因为在调用addProcResource 1662行push_back之前没有检查ProcResUnits的类型),而容器ProcResGroupDefs实际上并不使用。

在ProcResourceUnits定义里可以通过Super成员指定包含自己作为子集的更通用的资源单位,如果Super被定义了,就要辗转获取它的Record对象,直到某一级资源单位没有设置Super为止。

SchedRead也有一个特殊的派生类型——SchedReadAdvance,表示可以将关联的SchedWrite的时延降低指定周期。这些SchedReadAdvance必须记录下来。另外,还有一个ReadAdvance,它就像SchedReadAdvance的另一种封装。因此SchedReadAdvance与ReadAdvance将记录在一起。

1692   void CodeGenSchedModels::addReadAdvance (Record *ProcReadAdvanceDef,

1693   unsigned PIdx) {

1694   RecVec &RADefs = ProcModels[PIdx].ReadAdvanceDefs;

1695   RecIter I = std::find(RADefs.begin(), RADefs.end(), ProcReadAdvanceDef);

1696   if (I != RADefs.end())

1697   return ;

1698   RADefs.push_back(ProcReadAdvanceDef);

1699   }

CodeGenProcModel对象的容器ReadAdvanceDefs就用于记录ReadAdvance定义的Record对象。在collectRWResources里对SchedReadWrite别名的处理也很熟悉,首先expandRWSequence展开可能存在的WriteSequence,然后对这些(展开后的)SchedReadWrite调用collectRWResources。

回到CodeGenSchedModels::collectProcResources,如果CodeGenSchedClass实例的ItinClassDef是空的,那么这个对象是根据ItinRW或instRW定义创建的。这些CodeGenSchedClass对象的InstRWs容器都是空的,因此1444~1454行实际上是不会执行的。因此,对从ItinRW与instRW定义衍生的调度类型,实际的处理由1455行的collectRWResources完成。

CodeGenSchedModels::collectProcResources(续)

1458   // Add resources separately defined by each subtarget.

1459   RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes");

1460   for (RecIter WRI = WRDefs.begin(), WRE = WRDefs.end(); WRI != WRE; ++WRI) {

1461   Record *ModelDef = (*WRI)->getValueAsDef("SchedModel");

1462   (*WRI, getProcModel(ModelDef).Index);

1463   }

1464   RecVec SWRDefs = Records.getAllDerivedDefinitions("SchedWriteRes");

1465   for (RecIter WRI = SWRDefs.begin(), WRE = SWRDefs.end(); WRI != WRE; ++WRI) {

1466   Record *ModelDef = (*WRI)->getValueAsDef("SchedModel");

1467   addWriteRes(*WRI, getProcModel(ModelDef).Index);

1468   }

1469   RecVec RADefs = Records.getAllDerivedDefinitions("ReadAdvance");

1470   for (RecIter RAI = RADefs.begin(), RAE = RADefs.end(); RAI != RAE; ++RAI) {

1471   Record *ModelDef = (*RAI)->getValueAsDef("SchedModel");

1472   (*RAI, getProcModel(ModelDef).Index);

1473   }

1474   RecVec SRADefs = Records.getAllDerivedDefinitions("SchedReadAdvance");

1475   for (RecIter RAI = SRADefs.begin(), RAE = SRADefs.end(); RAI != RAE; ++RAI) {

1476   if ((*RAI)->getValueInit("SchedModel")->isComplete()) {

1477   Record *ModelDef = (*RAI)->getValueAsDef("SchedModel");

1478   addReadAdvance(*RAI, getProcModel(ModelDef).Index);

1479   }

1480   }

1481   // Add ProcResGroups that are defined within this processor model, which may

1482     // not be directly referenced but may directly specify a buffer size.

1483   RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");

1484   for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end();

1485   RI != RE; ++RI) {

1486   if (!(*RI)->getValueInit("SchedModel")->isComplete())

1487   continue ;

1488   CodeGenProcModel &PM = getProcModel((*RI)->getValueAsDef("SchedModel"));

1489   RecIter I = std::find(PM.ProcResourceDefs.begin(),

1490   PM.ProcResourceDefs.end(), *RI);

1491   if (I == PM.ProcResourceDefs.end())

1492   PM.ProcResourceDefs.push_back(*RI);

1493   }

1494   // Finalize each ProcModel by sorting the record arrays.

1495   for (CodeGenProcModel &PM : ProcModels) {

1496   std::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(),

1497   LessRecord());

1498   std::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(),

1499   LessRecord());

1500   std::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(),

1501   LessRecord());

1502   DEBUG(

1503   PM.dump();

1504   dbgs() << "WriteResDefs: ";

1505   for (RecIter RI = PM.WriteResDefs.begin(),

1506   RE = PM.WriteResDefs.end(); RI != RE; ++RI) {

1507   if ((*RI)->isSubClassOf("WriteRes"))

1508   dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " ";

1509   else

1510   dbgs() << (*RI)->getName() << " ";

1511   }

1512   dbgs() << "\nReadAdvanceDefs: ";

1513   for (RecIter RI = PM.ReadAdvanceDefs.begin(),

1514   RE = PM.ReadAdvanceDefs.end(); RI != RE; ++RI) {

1515   if ((*RI)->isSubClassOf("ReadAdvance"))

1516   dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " ";

1517   else

1518   dbgs() << (*RI)->getName() << " ";

1519   }

1520   dbgs() << "\nProcResourceDefs: ";

1521   for (RecIter RI = PM.ProcResourceDefs.begin(),

1522   RE = PM.ProcResourceDefs.end(); RI != RE; ++RI) {

1523   dbgs() << (*RI)->getName() << " ";

1524   }

1525   dbgs() << '\n');

1526   verifyProcResourceGroups(PM);

1527   }

1528   }

collectProcResources接下来的处理属于补漏性质。将上面没有覆盖的WriteRes,SchedWriteRes,ReadAdvance,SchedReadAdvance及ProcResGroup保存到CodeGenSchedModels实例的相应容器中。最后对这些容器(WriteResDefs,ReadAdvanceDefs,ProcResourceDefs)按名字排序,并通过verifyProcResourceGroups方法确定重叠的组有共同的超集。


以上所述就是小编给大家介绍的《LLVM学习笔记(37)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

小米之道

小米之道

(美)克莱•舍基 / 张琪 / 浙江人民出版社 / 2017-10-1 / 49.90元

共享经济、自媒体预言者,“互联网先知”克莱·舍基,继《认知盈余》《人人时代》后,聚焦风口上的小米。资深科技商业观察家金错刀、润米咨询创始人刘润作序推荐。附多篇雷军内部讲话,详细解读成功完成“筑底”后小米的全新商业模式 纵观中国互联网发展史,可以明显发现,本土互联网企业的崛起,几乎都是先引入国外商业模式,然后通过强化本土化特点来构筑自己的壁垒。在这种背景下,小米是名副其实的新物种,它走的是相反......一起来看看 《小米之道》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试