内容简介: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/深度学习/机器学习面试笔记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。