LLVM学习笔记(42)

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

内容简介: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容器当前的最后一项(代表当前的处理器)。


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

查看所有标签

猜你喜欢:

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

Fortran95程序设计

Fortran95程序设计

彭国伦 / 中国电力出版社 / 2002-9 / 59.00元

本书介绍了当前国际上广泛流行的高级算法语言Fortran的全新版本Fortran 95。 本书循序渐进、由浅到深,使用结构化及面向对象程序设计观念,以简捷明了的方式把Fortran 95介绍给读者。书中主要讲述了Fortran 95程序设计的方法,包括数值计算、计算机绘图、窗口程序设计、与Visual C/Visual Basic/Delphi的链接、甚至是游戏程序的编写。 本书语言简洁,实......一起来看看 《Fortran95程序设计》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

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

HEX CMYK 互转工具