内容简介: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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【每日笔记】【Go学习笔记】2019-01-04 Codis笔记
- 【每日笔记】【Go学习笔记】2019-01-02 Codis笔记
- 【每日笔记】【Go学习笔记】2019-01-07 Codis笔记
- Golang学习笔记-调度器学习
- Vue学习笔记(二)------axios学习
- 算法/NLP/深度学习/机器学习面试笔记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!