LLVM学习笔记(35)

3.5.1.3. 初步构建调度类型

每条指令定义中的成员Itinerary是InstrItinClass类型,用以描述该指令的执行步骤。前面我们已经看过一些X86指令定义的例子,其中成员Itinerary被设置为InstrItinClass的派生定义,比如用在指令LOCK_ArithBinOp8mr的IIC_ALU_NONMEM。

另外,指令定义里的成员SchedRW(类型list<SchedReadWrite>)则是描述该指令对资源的占用。它也可以用作指令调度依据。对指令来说,成员Itinerary以及SchedRW将唯一地确定指令的调度类型,这些成员相同的指令应该具有相同的调度类型。

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<CodeGenProcModel>::iterator PI = ProcModels.begin(),

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<CodeGenSchedClass>,其中类型CodeGenSchedClass用于保存描述一个调度类型所需的信息。它的定义如下:

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<CodeGenSchedTransition> Transitions;

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<unsigned> W,                                                        <- v7.0增加

                  ArrayRef<unsigned> R) const {

    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改写了构造函数的定义。

每条指令都将映射到一个调度类型。一共有四种调度类型:

  1. 带有ItinClassDef组的显式定义的行程,Writes与ReadDefs是空。对任意处理器ProcIndices都是0(表示适用于所有的处理器)。
  2. 一条指令定义中一组SchedWrites与SchedRead所描述的隐含类型,它由所有的次级目标机器共享。对任意处理器ProcIndices都是0。
  3. 在每处理器基础上,带有一组将指令映射到SchedWrites以及SchedReads的InstRW的隐含类。InstrClassMap应该将相同的指令映射到这个类。ProcIndices包含所有为这个类提供InstRW的处理器。没有InstRW定义的处理器仍然可以定义ItinClassDef,Writes或Reads。
  4. 代表可能在运行时解析的另一个类别变种的推导类型。ProcIndices包含可能要求这个类的处理器。在展开这个变种时在SchedClass间传播这个ProcIndices。可以从一个itinerary类别推导出多个SchedClass,每一个实例都从将该itinerary类映射到Writes或Reads变种的ItinRW记录中继承处理器索引。

首先构建的是对应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<Record*, unsigned>)将这个索引与指令的Record对象关联起来。

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<std::pair<unsigned, SmallVector<Record *, 8> >, 4> ClassInstrs;

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<Record*> InstDefs = ClassInstrs[CIdx].second;

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<unsigned, 4> RemappedClassIDs;

743         for (ArrayRef<Record*>::const_iterator

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<unsigned, SmallVector<Record *, 8>, 4>类型的临时容器ClassInstrs,是因为可能有多条指令属于同一个调度类型。

然后,在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<unsigned, SmallVector<Record *, 8>, 4> ClassInstrs;

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<Record*> InstDefs = Entry.second;

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<InstrItinData>)给出了一组执行步骤的描述(使用哪些资源、时延等。参考ATOM的描述一节)。在指令的定义中通过成员Itinerary(类型InstrItinClass)指定所适用的执行步骤。前面看到指令的执行步骤是确定指令所属调度类型的一个重要组成,对处理器的CodeGenProcModel对象而言,容器ItinDefList(std::vector<Record*>类型,以CodeGenProcModel对象的在ProcModels容器的索引为下标)关联起了执行步骤与相关的调度类型。现在,通过下面的CodeGenSchedModels::collectProcItins()填充这个容器。

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<Record*, unsigned>类型)。不过如果要使用ItinRW定义,Processor定义必须使用SchedMachineModel来描述处理器行程,因为当前处理器必须是使用SchedMachineModel才有必要使用ItinRW来映射已经存在的一组InstrItinClass。这里将ItinRW的Record对象记录在使用它的处理器的CodeGenProcModel对象的ItinRWDefs容器里(std::vector<Record*>类型)。

​​​​​​​3.5.1.6. V7.0收集不支持的特性

V7.0SchedMachineModel的定义里增加了list<Predicate> UnsupportedFeatures域,用于由于新ISA扩展或实现限制,现实了部分ISA的处理器。这个域用于记录这些不支持的特性,这样在为该处理器指令生成指令选择的谓词时,会跳过相关检查。

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     }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值