LLVM学习笔记(42)

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

内容简介:3.6.2.2..3.1. SchedReadWrite数据的收集描述类似SandyBridge处理器指令执行细节的方法不同于Atom这样的处理器,上面的处理对这些处理器不适用。这些处理器使用WriteRes或SchedWriteRes描述SchedWrite对资源的使用,依靠ReadAdvance或SchedReadAdvance来描述对特定的SchedWrite,特定SchedRead的预读情况。为了处理这些定义,首先需要找出与当前处理的调度类型相关的SchedWrite与SchedRead定义。Su

3.6.2.2.3. 资源的数据

3.6.2.2..3.1. SchedReadWrite数据的收集

描述类似SandyBridge处理器指令执行细节的方法不同于Atom这样的处理器,上面的处理对这些处理器不适用。这些处理器使用WriteRes或SchedWriteRes描述SchedWrite对资源的使用,依靠ReadAdvance或SchedReadAdvance来描述对特定的SchedWrite,特定SchedRead的预读情况。为了处理这些定义,首先需要找出与当前处理的调度类型相关的SchedWrite与SchedRead定义。

SubtargetEmitter::EmitSchedModel(续)

1266   OS << "\n// ===============================================================\n"

1267   << "// Data tables for the new per-operand machine model.\n";

1268  

1269   SchedClassTables SchedTables;

1270   for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),

1271   PE = SchedModels.procModelEnd(); PI != PE; ++PI) {

1272   (*PI, SchedTables);

1273   }

1274   (SchedTables, OS);

1275  

1276   // Emit the processor machine model

1277   (OS);

1278   // Emit the processor lookup data

1279   (OS);

1280  

1281   OS << "#undef DBGFIELD";

1282   }

1269行的SchedClassTables是SubtargetEmitter的内嵌类,在SchedClassDesc表中每个处理器的每个调度类型都有一个对应项。

38        struct SchedClassTables {

39        std::vector<std::vector<> > ProcSchedClasses;

40        std::vector<> WriteProcResources;

41        std::vector<> WriteLatencies;

42        std::vector<std::string> WriterNames;

43        std::vector<> ReadAdvanceEntries;

44       

45        // Reserve an invalid entry at index 0

46        SchedClassTables() {

47        ProcSchedClasses.resize(1);

48        WriteProcResources.resize(1);

49        WriteLatencies.resize(1);

50        WriterNames.push_back("InvalidWrite");

51        ReadAdvanceEntries.resize(1);

52        }

53        };

其中MCSchedClassDesc的定义如下。它是MC对资源调度的描述方式。

101      struct MCSchedClassDesc {

102      static const unsigned short InvalidNumMicroOps = UINT16_MAX;

103      static const unsigned short VariantNumMicroOps = UINT16_MAX - 1;

104     

105      #ifndef NDEBUG

106      const char* Name;

107      #endif

108      unsigned short NumMicroOps;

109      bool     BeginGroup;

110      bool     EndGroup;

111      unsigned WriteProcResIdx; // First index into WriteProcResTable.

112      unsigned NumWriteProcResEntries;

113      unsigned WriteLatencyIdx; // First index into WriteLatencyTable.

114      unsigned NumWriteLatencyEntries;

115      unsigned ReadAdvanceIdx; // First index into ReadAdvanceTable.

116      unsigned NumReadAdvanceEntries;

117     

118      bool isValid() const {

119      return NumMicroOps != InvalidNumMicroOps;

120      }

121      bool isVariant() const {

122      return NumMicroOps == VariantNumMicroOps;

123      }

124      };

类型MCWriteProcResEntry用于描述指定调度类型在指定周期数里消耗指定处理器资源。

55        struct MCWriteProcResEntry {

56        unsigned ProcResourceIdx;

57        unsigned Cycles;

58       

59        bool operator ==( const MCWriteProcResEntry &Other) const {

60        return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles;

61        }

62        };

类型MCWriteLatencyEntry用于记录执行一个指定的SchedWrite定义所需的处理器周期。

69        struct MCWriteLatencyEntry {

70        int Cycles;

71        unsigned WriteResourceID;

72       

73        bool operator ==( const MCWriteLatencyEntry &Other) const {

74        return Cycles == Other.Cycles && WriteResourceID == Other.WriteResourceID;

75        }

76        };

MCReadAdvanceEntry由ReadAdvance定义创建,用于描述处理器的流水线旁路,这时写操作的结果可提前若干周期(在ReadAdvance定义中给出)传给后续的读操作。这时UseIdx是这个ReadAdvance定义的索引,WriteResourceID则是旁路支持的SchedWrite的索引,Cycles是缩短的周期(如果是负数则是延长)。

86        struct MCReadAdvanceEntry {

87        unsigned UseIdx;

88        unsigned WriteResourceID;

89        int Cycles;

90       

91        bool operator ==( const MCReadAdvanceEntry &Other) const {

92        return UseIdx == Other.UseIdx && WriteResourceID == Other.WriteResourceID

93        && Cycles == Other.Cycles;

94        }

95        };

1272行的GenSchedClassTables方法就是为特定的处理器生成对应的MCSchedClassDesc实例。在816行CodeGenProcModel::hasInstrSchedModel在容器WriteResDefs或ItinRWDefs不为空时返回true。这意味着对该处理器而言,存在援引它的WriteRes定义或ItinRW定义。注意815行,不管怎么样,SchedTables的ProcSchedClasses容器与CodeGenSchedModels的ProcModels容器最终将同一大小。

813      void SubtargetEmitter::GenSchedClassTables ( const CodeGenProcModel &ProcModel,

814      SchedClassTables &SchedTables) {

815      SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1);

816      if (!ProcModel.hasInstrSchedModel())

817      return ;

818     

819      std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();

820      for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),

821      SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {

822      DEBUG(SCI->dump(&SchedModels));

823     

824      SCTab.resize(SCTab.size() + 1);

825      MCSchedClassDesc &SCDesc = SCTab.back();

826      // SCDesc.Name is guarded by NDEBUG

827      SCDesc.NumMicroOps = 0;

828      SCDesc.BeginGroup = false;

829      SCDesc.EndGroup = false;

830      SCDesc.WriteProcResIdx = 0;

831      SCDesc.WriteLatencyIdx = 0;

832      SCDesc.ReadAdvanceIdx = 0;

833     

834      // A Variant SchedClass has no resources of its own.

8356 bool HasVariants = false;

830      for (std::vector<CodeGenSchedTransition>::const_iterator

837      TI = SCI->Transitions.begin(), TE = SCI->Transitions.end();

838      TI != TE; ++TI) {

839      if (TI->ProcIndices[0] == 0) {

840      HasVariants = true;

841      break ;

842      }

843      IdxIter PIPos = std::find(TI->ProcIndices.begin(),

844      TI->ProcIndices.end(), ProcModel.Index);

845      if (PIPos != TI->ProcIndices.end()) {

846      HasVariants = true;

847      break ;

848      }

849      }

850      if (HasVariants) {

851      SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;

852      continue ;

853      }

854     

855      // Determine if the SchedClass is actually reachable on this processor. If

856          // not don't try to locate the processor resources, it will fail.

857          // If ProcIndices contains 0, this class applies to all processors.

858      assert (!SCI->ProcIndices.empty() && "expect at least one procidx");

859      if (SCI->ProcIndices[0] != 0) {

860      IdxIter PIPos = std::find(SCI->ProcIndices.begin(),

861      SCI->ProcIndices.end(), ProcModel.Index);

862      if (PIPos == SCI->ProcIndices.end())

863      continue ;

864      }

865      IdxVec Writes = SCI->Writes;

866      IdxVec Reads = SCI->Reads;

867      if (!SCI->InstRWs.empty()) {

868      // This class has a default ReadWrite list which can be overriden by

869            // InstRW definitions.

870      Record *RWDef = nullptr;

871      for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();

872      RWI != RWE; ++RWI) {

873      Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");

874      if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {

875      RWDef = *RWI;

876      break ;

877      }

878      }

879      if (RWDef) {

880      Writes.clear();

881      Reads.clear();

882      SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),

883      Writes, Reads);

884      }

885      }

886      if (Writes.empty()) {

887      // Check this processor's itinerary class resources.

888      for (RecIter II = ProcModel.ItinRWDefs.begin(),

889      IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) {

890      RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");

891      if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef)

892      != Matched.end()) {

893      SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"),

894      Writes, Reads);

895      break ;

896      }

897      }

898      if (Writes.empty()) {

899      DEBUG(dbgs() << ProcModel.ModelName

900      << " does not have resources for class " << SCI->Name << '\n');

901      }

902      }

820行的循环贯穿了整个函数,它太大了,我们只能一部分一部分来看。820行循环是对所有的调度类型进行遍历。SCTab是当前处理器的MCSchedClassDesc实例。前面我们看到,对一个调度类型CodeGenSchedClass,针对一个特定处理器,如果存在将这个调度类型包含的SchedReadWrite定义与InstrItinClass定义映射为另一组SchedReadWrite的ItinRW或InstRW定义,或者该调度类型本身带有包含SchedVariant定义的SchedReadWrite定义,那么会进行调度类型的推导。在这个CodeGenSchedClass实例的Transitions容器会记录下,对该处理器,到新调度类型的迁移。

可以看到,被映射调度类型的MCSchedClassDesc实例完全是相同的(在828~832行设置)。因为对这个处理器而言,这个被映射的调度类型不再有用,新的推导调度类型替代了它。在851行将其NumMicroOps设置为MCSchedClassDesc::VariantNumMicroOps这个特殊值,将在运行时触发推导调度类的查找。

只要这个CodeGenSchedClass对象没有对当前处理器映射到别的对象,就会进入到858行以下。859 ~ 864行确保当前CodeGenSchedClass对象适用于当前的处理器。

前面还看到,对被InstRW定义映射的CodeGenSchedClass对象,CodeGenSchedModels的方法会创建InstRWs容器记录这些InstRW定义的新CodeGenSchedClass对象,并且该对象会继承被映射对象容器Writes与Reads的内容。但这种情形下,容器Writes与Reads原有的内容是无效的,它们应该是这些InstRW定义中的SchedReadWrite定义(域OperandReadWrites),867 ~ 885行处理这个情形。886 ~ 897行则是处理itinRW的定义。

3.6.2.2.3.2. SchedReadWrite及资源间的关联

我们知道对于复杂的处理器来说,能将操作数的SchedWrite定义关联到资源的WriteRes,类似的SchedWriteRes,以及描述预读的ReadAdvance及SchedReadAdvance,是其核心的定义。这些就是接下来要处理的内容。在将调度类型相关的SchedRead与SchedWrite定义分别保存到容器Writes及Reads后,在908行首先遍历其中的SchedWrite定义。

SubtargetEmitter::GenSchedClassTables(续)

903      // Sum resources across all operand writes.

904      std::vector<> WriteProcResources;

905      std::vector<> WriteLatencies;

906      std::vector<std::string> WriterNames;

907      std::vector<> ReadAdvanceEntries;

908      for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) {

909      IdxVec WriteSeq;

910      SchedModels.(*WI, WriteSeq, /*IsRead=*/ false,

911      ProcModel);

912     

913      // For each operand, create a latency entry.

914      MCWriteLatencyEntry WLEntry;

915      WLEntry.Cycles = 0;

916      unsigned WriteID = WriteSeq.back();

917      WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);

918      // If this Write is not referenced by a ReadAdvance, don't distinguish it

919            // from other WriteLatency entries.

920      if (!SchedModels.(

921      SchedModels.getSchedWrite(WriteID).TheDef)) {

922      WriteID = 0;

923      }

924      WLEntry.WriteResourceID = WriteID;

925     

926      for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end();

927      WSI != WSE; ++WSI) {

928     

929      Record *WriteRes =

930      (SchedModels.getSchedWrite(*WSI), ProcModel);

931     

932      // Mark the parent class as invalid for unsupported write types.

933      if (WriteRes->getValueAsBit("Unsupported")) {

934      SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;

935      break ;

936      }

937      WLEntry.Cycles += WriteRes->getValueAsInt("Latency");

938      SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");

939      SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");

940      SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");

941     

942      // Create an entry for each ProcResource listed in WriteRes.

943      RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");

944      std::vector<int64_t> Cycles =

945      WriteRes->getValueAsListOfInts("ResourceCycles");

946     

947      (PRVec, Cycles, ProcModel);

948     

949      for (unsigned PRIdx = 0, PREnd = PRVec.size();

950      PRIdx != PREnd; ++PRIdx) {

951      MCWriteProcResEntry WPREntry;

952      WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);

953      assert (WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");

954      WPREntry.Cycles = Cycles[PRIdx];

955      // If this resource is already used in this sequence, add the current

956                // entry's cycles so that the same resource appears to be used

957                // serially, rather than multiple parallel uses. This is important for

958                // in-order machine where the resource consumption is a hazard.

959      unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();

960      for ( ; WPRIdx != WPREnd; ++WPRIdx) {

961      if (WriteProcResources[WPRIdx].ProcResourceIdx

962      == WPREntry.ProcResourceIdx) {

963      WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;

964      break ;

965      }

966      }

967      if (WPRIdx == WPREnd)

968      WriteProcResources.push_back(WPREntry);

969      }

970      }

971      WriteLatencies.push_back(WLEntry);

972      }

973      // Create an entry for each operand Read in this SchedClass.

974          // Entries must be sorted first by UseIdx then by WriteResourceID.

975      for (unsigned UseIdx = 0, EndIdx = Reads.size();

976      UseIdx != EndIdx; ++UseIdx) {

977      Record *ReadAdvance =

978      (SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);

979      if (!ReadAdvance)

980      continue ;

981     

982      // Mark the parent class as invalid for unsupported write types.

983      if (ReadAdvance->getValueAsBit("Unsupported")) {

984      SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;

985      break ;

986      }

987      RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");

988      IdxVec WriteIDs;

989      if (ValidWrites.empty())

990      WriteIDs.push_back(0);

991      else {

992      for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end();

993      VWI != VWE; ++VWI) {

994      WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/ false));

995      }

996      }

997      std::sort(WriteIDs.begin(), WriteIDs.end());

998      for (IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) {

999      MCReadAdvanceEntry RAEntry;

1000   RAEntry.UseIdx = UseIdx;

1001   RAEntry.WriteResourceID = *WI;

1002   RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");

1003   ReadAdvanceEntries.push_back(RAEntry);

1004   }

1005   }

1006   if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {

1007   WriteProcResources.clear();

1008   WriteLatencies.clear();

1009   ReadAdvanceEntries.clear();

1010   }

因为在SchedAlias定义可以将一个SchedReadWrite定义映射为另一个SchedReadWrite定义,因此需要调用方法expandRWSeqForProc来确保,在存在一个SchedAlias定义时,得到的SchedReadWrite定义是正确的。对一个特定的SchedReadWrite,只能有一个SchedAlias定义。因为SchedReadWrite的别名可以是一个SchedAlias,也可以是一个包含SchedAlias的WriteSequence,因此需要对这个定义递归调用expandRWSeqForProc(441与454行)。

420      void CodeGenSchedModels::expandRWSeqForProc (

421      unsigned RWIdx, IdxVec &RWSeq, bool IsRead,

422      const CodeGenProcModel &ProcModel) const {

423     

424      const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead);

425      Record *AliasDef = nullptr;

426      for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();

427      AI != AE; ++AI) {

428      const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW"));

429      if ((*AI)->getValueInit("SchedModel")->isComplete()) {

430      Record *ModelDef = (*AI)->getValueAsDef("SchedModel");

431      if (&getProcModel(ModelDef) != &ProcModel)

432      continue ;

433      }

434      if (AliasDef)

435      PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "

436      "defined for processor " + ProcModel.ModelName +

437      " Ensure only one SchedAlias exists per RW.");

438      AliasDef = AliasRW.TheDef;

439      }

440      if (AliasDef) {

441      expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead),

442      RWSeq, IsRead,ProcModel);

443      return ;

444      }

445      if (!SchedWrite.IsSequence) {

446      RWSeq.push_back(RWIdx);

447      return ;

448      }

449      int Repeat =

450      SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1;

451      for (int i = 0; i < Repeat; ++i) {

452      for (IdxIter I = SchedWrite.Sequence.begin(), E = SchedWrite.Sequence.end();

453      I != E; ++I) {

454      expandRWSeqForProc(*I, RWSeq, IsRead, ProcModel);

455      }

456      }

457      }

注意传递给expandRWSeqForProc的参数WriteSeq,它是908行循环里的局部容器,因此它保存的是每个在910行调用expandRWSeqForProc展开的SchedReadWrite定义。在920行调用下面这个方法来判断这个展开后的SchedWrite定义是否被一个ProcReadAdvance定义所援引。如果不是,这些写入之间是不需要区分的,可以把WriteID置为0。

352      bool CodeGenSchedModels::hasReadOfWrite (Record *WriteDef) const {

353      for (unsigned i = 0, e = SchedReads.size(); i < e; ++i) {

354      Record *ReadDef = SchedReads[i].TheDef;

355      if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance"))

356      continue ;

357     

358      RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites");

359      if (std::find(ValidWrites.begin(), ValidWrites.end(), WriteDef)

360      != ValidWrites.end()) {

361      return true;

362      }

363      }

364      return false;

365      }

接着在926行循环里遍历展开后的CodeGenSchedRW对象(实际上是在CodeGenSchedModels实例的SchedWrites容器里的索引),通过下面的方法找出将其关联到处理器资源的WriteRes以及SchedWriteRes定义。其中SchedWriteRes定义本身就是从SchedWrite派生的,如果这个SchedWrite定义就是SchedWriteRes,那么就它了(660行)。如果不是,接下来需要检查这个SchedWrite定义是否有别名,别名是否为适用于指定处理器的SchedWriteRes。

654      Record * SubtargetEmitter::FindWriteResources (

655      const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {

656     

657      // Check if the SchedWrite is already subtarget-specific and directly

658        // specifies a set of processor resources.

659      if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))

660      return SchedWrite.TheDef;

661     

662      Record *AliasDef = nullptr;

663      for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();

664      AI != AE; ++AI) {

665      const CodeGenSchedRW &AliasRW =

666      SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));

667      if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {

668      Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");

669      if (&SchedModels.getProcModel(ModelDef) != &ProcModel)

670      continue ;

671      }

672      if (AliasDef)

673      PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "

674      "defined for processor " + ProcModel.ModelName +

675      " Ensure only one SchedAlias exists per RW.");

676      AliasDef = AliasRW.TheDef;

677      }

678      if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))

679      return AliasDef;

680     

681      // Check this processor's list of write resources.

682      Record *ResDef = nullptr;

683      for (RecIter WRI = ProcModel.WriteResDefs.begin(),

684      WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) {

685      if (!(*WRI)->isSubClassOf("WriteRes"))

686      continue ;

687      if (AliasDef == (*WRI)->getValueAsDef("WriteType")

688      || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) {

689      if (ResDef) {

690      PrintFatalError((*WRI)->getLoc(), "Resources are defined for both "

691      "SchedWrite and its alias on processor " +

692      ProcModel.ModelName);

693      }

694      ResDef = *WRI;

695      }

696      }

697      // TODO: If ProcModel has a base model (previous generation processor),

698        // then call FindWriteResources recursively with that model here.

699      if (!ResDef) {

700      PrintFatalError(ProcModel.ModelDef->getLoc(),

701      std::string("Processor does not define resources for ")

702      + SchedWrite.TheDef->getName());

703      }

704      return ResDef;

705      }

如果上述两种情况都不是,就要查找是否存在相关的WriteRes定义了(没有就出错了)。

WriteRes与SchedWriteRes定义的Record对象都保存在CodeGenSchedModels实例的WriteResDefs容器里。因此遍历这个容器就能找到援引该SchedWrite定义的WriteRes。处理器可以设置WriteRes的成员Unsupported来表示不支持该关联。在这种情形下,需要把对应MCSchedClassDesc对象的NumMicroOps设置为InvalidNumMicroOps,并终止处理。不过目前LLVM还没有使用这个机制。

对于支持的WriteRes定义,通过下面的方法获取其所援引的资源以及包含这些资源的上级资源。

763      void SubtargetEmitter::ExpandProcResources (RecVec &PRVec,

764      std::vector<int64_t> &Cycles,

765      const CodeGenProcModel &PM) {

766      // Default to 1 resource cycle.

767      Cycles.resize(PRVec.size(), 1);

768      for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {

769      Record *PRDef = PRVec[i];

770      RecVec SubResources;

771      if (PRDef->isSubClassOf("ProcResGroup"))

772      SubResources = PRDef->getValueAsListOfDefs("Resources");

773      else {

774      SubResources.push_back(PRDef);

775      PRDef = SchedModels.(PRVec[i], PM);

776      for (Record *SubDef = PRDef;

777      SubDef->getValueInit("Super")->isComplete();) {

778      if (SubDef->isSubClassOf("ProcResGroup")) {

779      // Disallow this for simplicitly.

780      PrintFatalError(SubDef->getLoc(), "Processor resource group "

781      " cannot be a super resources.");

782      }

783      Record *SuperDef =

784      SchedModels.(SubDef->getValueAsDef("Super"), PM);

785      PRVec.push_back(SuperDef);

786      Cycles.push_back(Cycles[i]);

787      SubDef = SuperDef;

788      }

789      }

790      for (RecIter PRI = PM.ProcResourceDefs.begin(),

791      PRE = PM.ProcResourceDefs.end();

792      PRI != PRE; ++PRI) {

793      if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup"))

794      continue ;

795      RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources");

796      RecIter SubI = SubResources.begin(), SubE = SubResources.end();

797      for ( ; SubI != SubE; ++SubI) {

798      if (std::find(SuperResources.begin(), SuperResources.end(), *SubI)

799      == SuperResources.end()) {

800      break ;

801      }

802      }

803      if (SubI == SubE) {

804      PRVec.push_back(*PRI);

805      Cycles.push_back(Cycles[i]);

806      }

807      }

808      }

809      }

768行的循环收集参数PRVec(它来自WriteRes类型为list<ProcResourceKind>的ProcResources成员)的组成成员(即组成ProcResources的ProcResourceKind成员)。来自ProcResourceUnits类型的定义还可以给出包含它的上级资源,这些上级资源也需要逐级地记录到PRVec里。

790行的循环遍历与这个处理器相关的所有ProcResGroup定义。对某个ProcResGroup定义只有它的资源完全覆盖SubResources,才把它视为一个上级资源,并记录在PRVec里。还要注意,在WriteRes里,如果没有给出ResourceCycles,就都缺省为1。

回到GenSchedClassTables方法,在949行遍历刚收集到的资源定义。如果WriteProcResources容器里已经有这个资源的记录,那么需要累加这个资源的周期数。955行的注释说,这使得该资源看起来被顺序使用,而不是被并行使用。这对于顺序机器是十分重要的。如果WriteProcResources中没有记录这个资源,就把它加入这个容器。接着在971行向WriteLatencies容器加入记录当前操作数延时信息的WLEntry对象。

在975行开始遍历与当前处理调度类型相关的SchedRead定义(实际上我们只关心与之相关的ReadAdvance或SchedReadAdvance定义)。

709      Record * SubtargetEmitter::FindReadAdvance ( const CodeGenSchedRW &SchedRead,

710      const CodeGenProcModel &ProcModel) {

711      // Check for SchedReads that directly specify a ReadAdvance.

712      if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))

713      return SchedRead.TheDef;

714     

715      // Check this processor's list of aliases for SchedRead.

716      Record *AliasDef = nullptr;

717      for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end();

718      AI != AE; ++AI) {

719      const CodeGenSchedRW &AliasRW =

720      SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));

721      if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {

722      Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");

723      if (&SchedModels.getProcModel(ModelDef) != &ProcModel)

724      continue ;

725      }

726      if (AliasDef)

727      PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "

728      "defined for processor " + ProcModel.ModelName +

729      " Ensure only one SchedAlias exists per RW.");

730      AliasDef = AliasRW.TheDef;

731      }

732      if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))

733      return AliasDef;

734     

735      // Check this processor's ReadAdvanceList.

736      Record *ResDef = nullptr;

737      for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(),

738      RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) {

739      if (!(*RAI)->isSubClassOf("ReadAdvance"))

740      continue ;

741      if (AliasDef == (*RAI)->getValueAsDef("ReadType")

742      || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) {

743      if (ResDef) {

744      PrintFatalError((*RAI)->getLoc(), "Resources are defined for both "

745      "SchedRead and its alias on processor " +

746      ProcModel.ModelName);

747      }

748      ResDef = *RAI;

749      }

750      }

751      // TODO: If ProcModel has a base model (previous generation processor),

752        // then call FindReadAdvance recursively with that model here.

753      if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {

754      PrintFatalError(ProcModel.ModelDef->getLoc(),

755      std::string("Processor does not define resources for ")

756      + SchedRead.TheDef->getName());

757      }

758      return ResDef;

759      }

与FindWriteResources类似,FindReadAdvance找出该SchedRead所代表的SchedReadAdvance定义,或援引该SchedRead定义的ReadAdvance定义。只有SchedRead是ReadDefault时(读操作的缺省设置),才允许返回值是一个空指针。

回到GenSchedClassTables,同样,ReadAdvance与SchedReadAdvance都可以设置Unsupported域,从特定处理器视野里消失。987~1004行提取ReadAdvance所援引的SchedWrite定义并排序,在998行循环为每个SchedWrite定义创建MCReadAdvanceEntry实例,保存在ReadAdvanceEntries容器。

到1015行,我们已经完成与当前调度类型相关SchedWrite定义关联的资源及SchedReadAdvance及ReadAdvance定义的处理,为它们生成了相应的MCWriteProcResEntry,MCWriteLatencyEntry,及MCReadAdvanceEntry实例。

SubtargetEmitter::GenSchedClassTables(续)

1011   // Add the information for this SchedClass to the global tables using basic

1012       // compression.

1013       //

1014       // WritePrecRes entries are sorted by ProcResIdx.

1015   std::sort(WriteProcResources.begin(), WriteProcResources.end(),

1016   LessWriteProcResources());

1017  

1018   SCDesc.NumWriteProcResEntries = WriteProcResources.size();

1019   std::vector<MCWriteProcResEntry>::iterator WPRPos =

1020   std::search(SchedTables.WriteProcResources.begin(),

1021   SchedTables.WriteProcResources.end(),

1022   WriteProcResources.begin(), WriteProcResources.end());

1023   if (WPRPos != SchedTables.WriteProcResources.end())

1024   SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();

1025   else {

1026   SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();

1027   SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),

1028   WriteProcResources.end());

1029   }

1030   // Latency entries must remain in operand order.

1031   SCDesc.NumWriteLatencyEntries = WriteLatencies.size();

1032   std::vector<MCWriteLatencyEntry>::iterator WLPos =

1033   std::search(SchedTables.WriteLatencies.begin(),

1034   SchedTables.WriteLatencies.end(),

1035   WriteLatencies.begin(), WriteLatencies.end());

1036   if (WLPos != SchedTables.WriteLatencies.end()) {

1037   unsigned idx = WLPos - SchedTables.WriteLatencies.begin();

1038   SCDesc.WriteLatencyIdx = idx;

1039   for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)

1040   if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==

1041   std::string::npos) {

1042   SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];

1043   }

1044   }

1045   else {

1046   SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();

1047   SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(),

1048   WriteLatencies.begin(),

1049   WriteLatencies.end());

1050   SchedTables.WriterNames.insert(SchedTables.WriterNames.end(),

1051   WriterNames.begin(), WriterNames.end());

1052   }

1053   // ReadAdvanceEntries must remain in operand order.

1054   SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();

1055   std::vector<MCReadAdvanceEntry>::iterator RAPos =

1056   std::search(SchedTables.ReadAdvanceEntries.begin(),

1057   SchedTables.ReadAdvanceEntries.end(),

1058   ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());

1059   if (RAPos != SchedTables.ReadAdvanceEntries.end())

1060   SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();

1061   else {

1062   SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();

1063   SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),

1064   ReadAdvanceEntries.end());

1065   }

1066   }

1067   }

在GenSchedClassTables余下的代码里,1015~1029行将当前调度类的所有MCWriteProcResEntry对象添加到SchedTables的容器WriteProcResources(这个容器以及下面提到的容器由所有处理器共享)。注意,对这个调度类而言,它使用的资源可能有多个,因此有多个MCWriteProcResEntry实例,在添加到容器WriteProcResources里时,这些实例是连续添加的,调度类只需记录第一个实例在容器中的索引。

同样,在1031~1052行将当前调度类的所有MCWriteLatencyEntry对象添加到SchedTables的容器WriteLatencies,同时将对应SchedWrite的名字记录到SchedTables的容器WriterNames。在1040行,如果同一个MCWriteLatencyEntry对象对应多个SchedWrite,需要生成合成名字。

最后,1054~1065行将当前调度类的所有MCReadAdvanceEntry对象添加到SchedTables的ReadAdvanceEntries容器。

在这些过程里,SCDesc是代表当前处理的调度类型的MCSchedClassDesc实例。同时,它来自SchedTables的ProcSchedClasses容器当前的最后一项(代表当前的处理器)。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

XML Hacks

XML Hacks

Michael Fitzgerald / O'Reilly Media, Inc. / 2004-07-27 / USD 24.95

Developers and system administrators alike are uncovering the true power of XML, the Extensible Markup Language that enables data to be sent over the Internet from one computer platform to another or ......一起来看看 《XML Hacks》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具