3.5.1.3. 初步构建调度类型
每条指令定义中的成员Itinerary是InstrItinClass类型,用以描述该指令的执行步骤。前面我们已经看过一些X86指令定义的例子,其中成员Itinerary被设置为InstrItinClass的派生定义,比如用在指令LOCK_ArithBinOp8mr的IIC_ALU_NONMEM。
另外,指令定义里的成员SchedRW(类型list
496 void CodeGenSchedModels::collectSchedClasses() {
497
498 // NoItinerary is always the first class at Idx=0
499 SchedClasses.resize(1);
500 SchedClasses.back().Index = 0;
501 SchedClasses.back().Name = "NoInstrModel";
502 SchedClasses.back().ItinClassDef = Records.getDef("NoItinerary");
503 SchedClasses.back().ProcIndices.push_back(0);
504
505 // Create a SchedClass for each unique combination of itinerary class and
506 // SchedRW list.
507 for (const CodeGenInstruction *Inst : Target.instructions()) { ßv7.0删除
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { ßv7.0增加
508 Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary");
509 IdxVec Writes, Reads;
510 if (!Inst->TheDef->isValueUnset("SchedRW"))
511 findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
512
513 // ProcIdx == 0 indicates the class applies to all processors.
514 IdxVec ProcIndices(1, 0);
515
516 unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices);
517 InstrClassMap[Inst->TheDef] = SCIdx;
518 }
519 // Create classes for InstRW defs.
520 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
521 std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord());
522 for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI)
523 createInstRWClass(*OI);
524
525 NumInstrSchedClasses = SchedClasses.size();
526
527 bool EnableDump = false;
528 DEBUG(EnableDump = true);
529 if (!EnableDump)
530 return;
531
532 for (const CodeGenInstruction *Inst : Target.instructions()) { <- v7.0删除
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { <- v7.0增加
533 std::string InstName = Inst->TheDef->getName();
534 unsigned SCIdx = InstrClassMap.lookup(Inst->TheDef);
535 if (!SCIdx) {
536 dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n';
537 continue;
538 }
539 CodeGenSchedClass &SC = getSchedClass(SCIdx);
540 if (SC.ProcIndices[0] != 0)
541 PrintFatalError(Inst->TheDef->getLoc(), "Instruction's sched class "
542 "must not be subtarget specific.");
543
544 IdxVec ProcIndices;
545 if (SC.ItinClassDef->getName() != "NoItinerary") {
546 ProcIndices.push_back(0);
547 dbgs() << "Itinerary for " << InstName << ": "
548 << SC.ItinClassDef->getName() << '\n';
549 }
550 if (!SC.Writes.empty()) {
551 ProcIndices.push_back(0);
552 dbgs() << "SchedRW machine model for " << InstName;
553 for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI)
554 dbgs() << " " << SchedWrites[*WI].Name;
555 for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI)
556 dbgs() << " " << SchedReads[*RI].Name;
557 dbgs() << '\n';
558 }
559 const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
560 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
561 RWI != RWE; ++RWI) {
562 const CodeGenProcModel &ProcModel =
563 getProcModel((*RWI)->getValueAsDef("SchedModel"));
564 ProcIndices.push_back(ProcModel.Index);
565 dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName;
566 IdxVec Writes;
567 IdxVec Reads;
568 findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
569 Writes, Reads);
570 for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
571 dbgs() << " " << SchedWrites[*WI].Name;
572 for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
573 dbgs() << " " << SchedReads[*RI].Name;
574 dbgs() << '\n';
575 }
576 for (std::vector
577 PE = ProcModels.end(); PI != PE; ++PI) {
578 if (!std::count(ProcIndices.begin(), ProcIndices.end(), PI->Index))
579 dbgs() << "No machine model for " << Inst->TheDef->getName()
580 << " on processor " << PI->ModelName << '\n';
581 }
582 }
583 }
CodeGenSchedModels的容器SchedClasses的类型是std::vector
127 struct CodeGenSchedClass {
128 unsigned Index;
129 std::string Name;
130 Record *ItinClassDef;
131
132 IdxVec Writes;
133 IdxVec Reads;
134 // Sorted list of ProcIdx, where ProcIdx==0 implies any processor.
135 IdxVec ProcIndices;
136
137 std::vector
138
139 // InstRW records associated with this class. These records may refer to an
140 // Instruction no longer mapped to this class by InstrClassMap. These
141 // Instructions should be ignored by this class because they have been split
142 // off to join another inferred class.
143 RecVec InstRWs;
144
145 CodeGenSchedClass(): Index(0), ItinClassDef(nullptr) {} <- v7.0删除
CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef) <- v7.0增加
: Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
146
147 bool isKeyEqual(Record *IC, const IdxVec &W, const IdxVec &R) { <- v7.0删除
148 return ItinClassDef == IC && Writes == W && Reads == R;
149 }
bool isKeyEqual(Record *IC, ArrayRef
ArrayRef
return ItinClassDef == IC && makeArrayRef(Writes) == W &&
makeArrayRef(Reads) == R;
}
150
151 // Is this class generated from a variants if existing classes? Instructions
152 // are never mapped directly to inferred scheduling classes.
153 bool isInferred() const { return !ItinClassDef; }
154
155 #ifndef NDEBUG
156 void dump(const CodeGenSchedModels *SchedModels) const;
157 #endif
158 };
132行的Writes容器保存的是来自SchedWrite派生定义的CodeGenSchedRW对象在SchedModels(CodeGenSchedModels实例)的SchedWrites容器里的索引。类似的,Reads容器保存SchedRead派生定义的CodeGenSchedRW对象在SchedModels的SchedReads容器里的索引。
另外,为了支持emplace_back()操作,v7.0改写了构造函数的定义。
每条指令都将映射到一个调度类型。一共有四种调度类型:
首先构建的是对应NoItinerary定义的调度类,在503行CodeGenSchedClass的ProcIndices容器记录了对应CodeGenProcModel对象在ProcModels容器里的索引。
接着,在507行循环首先获取Instruction->Itinerary的值(缺省为NoItinerary),接着如果设置了Instruction->SchedRW域,由findRWs()方法获取该SchedRW域内援引的SchedReadWrite定义(如果它们有设置的话):
382 void CodeGenSchedModels::findRWs(const RecVec &RWDefs,
383 IdxVec &Writes, IdxVec &Reads) const {
384 RecVec WriteDefs;
385 RecVec ReadDefs;
386 splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs);
387 findRWs(WriteDefs, Writes, false);
388 findRWs(ReadDefs, Reads, true);
389 }
首先由辅助函数splitSchedReadWrites()区分SchedWrite及SchedRead定义。
367 namespace llvm {
368 void splitSchedReadWrites(const RecVec &RWDefs,
369 RecVec &WriteDefs, RecVec &ReadDefs) {
370 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) {
371 if ((*RWI)->isSubClassOf("SchedWrite"))
372 WriteDefs.push_back(*RWI);
373 else {
374 assert((*RWI)->isSubClassOf("SchedRead") && "unknown SchedReadWrite");
375 ReadDefs.push_back(*RWI);
376 }
377 }
378 }
379 } // namespace llvm
在上面387与388行,调用findRWs()将这些被援引的SchedWrite及SchedRead定义在SchedReads或SchedWrites容器里的索引记录到临时容器Writes与Reads。接着,Writes与Reads作为参数传递给下面的方法。
638 unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
639 const IdxVec &OperWrites,
640 const IdxVec &OperReads,
641 const IdxVec &ProcIndices)
642 {
643 assert(!ProcIndices.empty() && "expect at least one ProcIdx");
644
645 unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads);
646 if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
647 IdxVec PI;
648 std::set_union(SchedClasses[Idx].ProcIndices.begin(),
649 SchedClasses[Idx].ProcIndices.end(),
650 ProcIndices.begin(), ProcIndices.end(),
651 std::back_inserter(PI));
652 SchedClasses[Idx].ProcIndices.swap(PI);
653 return Idx;
654 }
655 Idx = SchedClasses.size();
656 SchedClasses.resize(Idx+1);
657 CodeGenSchedClass &SC = SchedClasses.back();
658 SC.Index = Idx;
659 SC.Name = createSchedClassName(ItinClassDef, OperWrites, OperReads);
660 SC.ItinClassDef = ItinClassDef;
661 SC.Writes = OperWrites;
662 SC.Reads = OperReads;
663 SC.ProcIndices = ProcIndices;
664
665 return Idx;
666 }
参数ProcIndices保存了与这个调度类型相关的CodeGenProcModel对象的索引,索引0处的对象代表NoSchedModel与NoItineraries。
CodeGenSchedClass对象是否相同取决于成员ItinClassDef,Writes及Reads的内容。645行的findSchedClassIdx()方法遍历SchedClasses容器,查找包含ItinClassDef,OperWrites,OperReads的CodeGenSchedClass对象索引,若不存在这样的对象,则返回0。因为SchedClasses[0]是有效的,代表NoItinerary,因此在findSchedClassIdx返回0时,还需检查这个调度类是否就是NoItinerary,即646行第二个条件是否成立。
另外,由于CodeGenSchedClass对象唯一取决于成员ItinClassDef,Writes及Reads的内容,因此它的命字也是由这些成员包含的对象名合成的。
如果这样的CodeGenSchedClass对象尚未生成,addSchedClass()在SchedClasses容器里构建一个。addSchedClass返回这个调度类的索引,容器InstrClassMap(DenseMap
CodeGenSchedModels::collectSchedClasses()接下来处理InstRW定义。InstRW可以改变一组指令的SchedRead与SchedWrite的设定。在522行循环,在对所有InstRW定义的Record对象按名字排序后,依次对它们调用下面的方法,根据InstRW定义构建可能需要的新调度类型。CodeGenSchedClass的容器InstRWs如果不为空,记录了将相应指令映射到其他调度类的InstRW定义。
670 void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
671 // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that
672 // intersects with an existing class via a previous InstRWDef. Instrs that do
673 // not intersect with an existing class refer back to their former class as
674 // determined from ItinDef or SchedRW.
675 SmallVector
676 // Sort Instrs into sets.
677 const RecVec *InstDefs = Sets.expand(InstRWDef);
678 if (InstDefs->empty())
679 PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes");
680
681 for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) {
682 InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I);
683 if (Pos == InstrClassMap.end())
684 PrintFatalError((*I)->getLoc(), "No sched class for instruction.");
685 unsigned SCIdx = Pos->second;
686 unsigned CIdx = 0, CEnd = ClassInstrs.size();
687 for (; CIdx != CEnd; ++CIdx) {
688 if (ClassInstrs[CIdx].first == SCIdx)
689 break;
690 }
691 if (CIdx == CEnd) {
692 ClassInstrs.resize(CEnd + 1);
693 ClassInstrs[CIdx].first = SCIdx;
694 }
695 ClassInstrs[CIdx].second.push_back(*I);
696 }
697 // For each set of Instrs, create a new class if necessary, and map or remap
698 // the Instrs to it.
699 unsigned CIdx = 0, CEnd = ClassInstrs.size();
700 for (; CIdx != CEnd; ++CIdx) {
701 unsigned OldSCIdx = ClassInstrs[CIdx].first;
702 ArrayRef
703 // If the all instrs in the current class are accounted for, then leave
704 // them mapped to their old class.
705 if (OldSCIdx) {
706 const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs;
707 if (!RWDefs.empty()) {
708 const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]);
709 unsigned OrigNumInstrs = 0;
710 for (RecIter I = OrigInstDefs->begin(), E = OrigInstDefs->end();
711 I != E; ++I) {
712 if (InstrClassMap[*I] == OldSCIdx)
713 ++OrigNumInstrs;
714 }
715 if (OrigNumInstrs == InstDefs.size()) {
716 assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
717 "expected a generic SchedClass");
718 DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":"
719 << SchedClasses[OldSCIdx].Name << " on "
720 << InstRWDef->getValueAsDef("SchedModel")->getName() << "\n");
721 SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef);
722 continue;
723 }
724 }
725 }
726 unsigned SCIdx = SchedClasses.size();
727 SchedClasses.resize(SCIdx+1);
728 CodeGenSchedClass &SC = SchedClasses.back();
729 SC.Index = SCIdx;
730 SC.Name = createSchedClassName(InstDefs);
731 DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on "
732 << InstRWDef->getValueAsDef("SchedModel")->getName() << "\n");
733
734 // Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
735 SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef;
736 SC.Writes = SchedClasses[OldSCIdx].Writes;
737 SC.Reads = SchedClasses[OldSCIdx].Reads;
738 SC.ProcIndices.push_back(0);
739 // Map each Instr to this new class.
740 // Note that InstDefs may be a smaller list than InstRWDef's "Instrs".
741 Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel");
742 SmallSet
743 for (ArrayRef
744 II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) {
745 unsigned OldSCIdx = InstrClassMap[*II];
746 if (OldSCIdx && RemappedClassIDs.insert(OldSCIdx).second) {
747 for (RecIter RI = SchedClasses[OldSCIdx].InstRWs.begin(),
748 RE = SchedClasses[OldSCIdx].InstRWs.end(); RI != RE; ++RI) {
749 if ((*RI)->getValueAsDef("SchedModel") == RWModelDef) {
750 PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " +
751 (*II)->getName() + " also matches " +
752 (*RI)->getValue("Instrs")->getValue()->getAsString());
753 }
754 assert(*RI != InstRWDef && "SchedClass has duplicate InstRW def");
755 SC.InstRWs.push_back(*RI);
756 }
757 }
758 InstrClassMap[*II] = SCIdx;
759 }
760 SC.InstRWs.push_back(InstRWDef);
761 }
762 }
InstRW定义给出了一组指令,将它们的调度类重载为指定的一组SchedReadWrite定义。临时容器ClassInstrs用于将这些指令与它们原有的调度类关联起来。
InstRW定义通过dag成员Instrs来指定这组指令,Instrs是一个匹配指令操作码的正则表达式(它的操作符必须是instregex),因此首先在677行展开这个dag值。这个表达式由InstRegexOp类处理,得到对应的Record对象。
接着,681行循环找出这些指令原来指派的调度类型。collectSchedClasses()在前面已经将指令的Record实例与CodeGenSchedClass实例在SchedClasses容器里的序号通过InstrClassMap容器关联起来。因此,682行的查找一定成功。使用SmallMapVector
然后,在700行遍历原来指派给InstRW指定指令的调度类型。调度类型CodeGenSchedClass对象的容器InstRWs如果不为空,表明这个CodeGenSchedClass对象是由InstRW定义生成(726~760行),这时它的ProcIndices[0]一定是0(满足716行断言)。容器InstRWs里包含它所接受指令的instregex表达式Record对象。注意,InstrClassMap会更新这些指令的调度类索引(758行),因此如果后面还有针对这些指令的InstRW定义,就会找到这些CodeGenSchedClass对象,这也就是这些对象里InstRWs容器里内容的来源。对于这些对象,如果要重新映射的整个调度类(715行条件),那么这个CodeGenSchedClass对象就可以重用。
如果第一次重新映射,或者再次重新映射只涉及部分指令,就要创建新的调度类。注意,对后者,需要把旧的调度类的InstRWs的内容拷贝过来(755行)。这应该是用于检查的目的(747行循环)。另外,在730行,因为这些调度类型由一组InstRW定义唯一确定,因此它们的名字就是这些InstRW的名字组合。
回到collectSchedClasses(),从527行开始的代码大部分是用于调试的目的。
V7.0稍微重构了CodeGenSchedModels::createInstRWClass(),使之更清晰: 778 void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { 779 // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that 780 // intersects with an existing class via a previous InstRWDef. Instrs that do 781 // not intersect with an existing class refer back to their former class as 782 // determined from ItinDef or SchedRW. 783 SmallMapVector 784 // Sort Instrs into sets. 785 const RecVec *InstDefs = Sets.expand(InstRWDef); 786 if (InstDefs->empty()) 787 PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); 788 789 for (Record *InstDef : *InstDefs) { 790 InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef); 791 if (Pos == InstrClassMap.end()) 792 PrintFatalError(InstDef->getLoc(), "No sched class for instruction."); 793 unsigned SCIdx = Pos->second; 794 ClassInstrs[SCIdx].push_back(InstDef); 795 } 796 // For each set of Instrs, create a new class if necessary, and map or remap 797 // the Instrs to it. 798 for (auto &Entry : ClassInstrs) { 799 unsigned OldSCIdx = Entry.first; 800 ArrayRef 801 // If the all instrs in the current class are accounted for, then leave 802 // them mapped to their old class. 803 if (OldSCIdx) { 804 const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs; 805 if (!RWDefs.empty()) { 806 const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]); 807 unsigned OrigNumInstrs = 808 count_if(*OrigInstDefs, [&](Record *OIDef) { 809 return InstrClassMap[OIDef] == OldSCIdx; 810 }); 811 if (OrigNumInstrs == InstDefs.size()) { 812 assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && 813 "expected a generic SchedClass"); 814 Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); 815 // Make sure we didn't already have a InstRW containing this 816 // instruction on this model. 817 for (Record *RWD : RWDefs) { 818 if (RWD->getValueAsDef("SchedModel") == RWModelDef && 819 RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { 820 for (Record *Inst : InstDefs) { 821 PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " + 822 Inst->getName() + " also matches " + 823 RWD->getValue("Instrs")->getValue()->getAsString()); 824 } 825 } 826 } 827 LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" 828 << SchedClasses[OldSCIdx].Name << " on " 829 << RWModelDef->getName() << "\n"); 830 SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef); 831 continue; 832 } 833 } 834 } 835 unsigned SCIdx = SchedClasses.size(); 836 SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr); 837 CodeGenSchedClass &SC = SchedClasses.back(); 838 LLVM_DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on " 839 << InstRWDef->getValueAsDef("SchedModel")->getName() 840 << "\n"); 841 842 // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. 843 SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; 844 SC.Writes = SchedClasses[OldSCIdx].Writes; 845 SC.Reads = SchedClasses[OldSCIdx].Reads; 846 SC.ProcIndices.push_back(0); 847 // If we had an old class, copy it's InstRWs to this new class. 848 if (OldSCIdx) { 849 Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); 850 for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { 851 if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { 852 for (Record *InstDef : InstDefs) { 853 PrintFatalError(OldRWDef->getLoc(), "Overlapping InstRW def " + 854 InstDef->getName() + " also matches " + 855 OldRWDef->getValue("Instrs")->getValue()->getAsString()); 856 } 857 } 858 assert(OldRWDef != InstRWDef && 859 "SchedClass has duplicate InstRW def"); 860 SC.InstRWs.push_back(OldRWDef); 861 } 862 } 863 // Map each Instr to this new class. 864 for (Record *InstDef : InstDefs) 865 InstrClassMap[InstDef] = SCIdx; 866 SC.InstRWs.push_back(InstRWDef); 867 } 868 } 基本逻辑还是一样的。就不再赘述了。 |
3.5.1.4. 执行步骤的关联
某些处理器,像Atom(v7.0不适用于)通过执行步骤来描述指令调度,这时,在其Processor定义的ProcItin(类型ProcessorItineraries)的IID域(类型list
775 void CodeGenSchedModels::collectProcItins() {
776 for (CodeGenProcModel &ProcModel : ProcModels) {
777 if (!ProcModel.hasItineraries())
778 continue;
779
780 RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
781 assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect");
782
783 // Populate ItinDefList with Itinerary records.
784 ProcModel.ItinDefList.resize(NumInstrSchedClasses);
785
786 // Insert each itinerary data record in the correct position within
787 // the processor model's ItinDefList.
788 for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) {
789 Record *ItinData = ItinRecords[i];
790 Record *ItinDef = ItinData->getValueAsDef("TheClass");
791 bool FoundClass = false;
792 for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
793 SCI != SCE; ++SCI) {
794 // Multiple SchedClasses may share an itinerary. Update all of them.
795 if (SCI->ItinClassDef == ItinDef) {
796 ProcModel.ItinDefList[SCI->Index] = ItinData;
797 FoundClass = true;
798 }
799 }
800 if (!FoundClass) {
801 DEBUG(dbgs() << ProcModel.ItinsDef->getName()
802 << " missing class for itinerary " << ItinDef->getName() << '\n');
803 }
804 }
805 // Check for missing itinerary entries.
806 assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
807 DEBUG(
808 for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) {
809 if (!ProcModel.ItinDefList[i])
810 dbgs() << ProcModel.ItinsDef->getName()
811 << " missing itinerary for class "
812 << SchedClasses[i].Name << '\n';
813 });
814 }
815 }
3.5.1.5. ItinRW定义的处理
类似于InstRW,在执行步骤已经给出的情形下,ItinRW定义将一组InstrItinClass(即执行步骤)映射到一组SchedReadWrite。如果目标机器的描述给出了ItinRW的定义,就要通过下面的方法通过CodeGenProcModel实例将这些定义关联起来。
818 void CodeGenSchedModels::collectProcItinRW() {
819 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
820 std::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord());
821 for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) {
822 if (!(*II)->getValueInit("SchedModel")->isComplete())
823 PrintFatalError((*II)->getLoc(), "SchedModel is undefined");
824 Record *ModelDef = (*II)->getValueAsDef("SchedModel");
825 ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
826 if (I == ProcModelMap.end()) {
827 PrintFatalError((*II)->getLoc(), "Undefined SchedMachineModel "
828 + ModelDef->getName());
829 }
830 ProcModels[I->second].ItinRWDefs.push_back(*II);
831 }
832 }
容器ProcModelMap以描述处理器行程的Record对象为键(可能是ProcessorItineraries派生定义,也可能是SchedMachineModel派生定义),值是CodeGenProcModel实例在ProcModels容器的索引(DenseMap
3.5.1.6. V7.0收集不支持的特性
V7.0在SchedMachineModel的定义里增加了list
941 void CodeGenSchedModels::collectProcUnsupportedFeatures() {
942 for (CodeGenProcModel &ProcModel : ProcModels) {
943 for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) {
944 ProcModel.UnsupportedFeaturesDefs.push_back(Pred);
945 }
946 }
947 }