LLVM学习笔记(37)

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

内容简介: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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Learn Python the Hard Way

Learn Python the Hard Way

Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99

Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具