LLVM学习笔记(36)

3.5.1.7. 推导调度类型

前面,我们已经各种相关的定义通过CodeGenSchedModels中的各式容器关联起来。现在我们将根据这些定义推导出所有的调度类型。在840行遍历所有的调度类型。注意,这个遍历的终止条件SchedClasses.size()是动态的,包括了新添加的类型,因为在下面的处理里会向该容器添加新的调度类型。

836     void CodeGenSchedModels::inferSchedClasses() {

837       DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n");

838    

839       // Visit all existing classes and newly created classes.

840       for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {

841         assert(SchedClasses[Idx].Index == Idx && "bad SCIdx");

842    

843         if (SchedClasses[Idx].ItinClassDef)

844         inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);

845         if (!SchedClasses[Idx].InstRWs.empty())

846           inferFromInstRWs(Idx);

847         if (!SchedClasses[Idx].Writes.empty()) {

848           inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,

849                       Idx, SchedClasses[Idx].ProcIndices);

850         }

851         assert(SchedClasses.size() < (NumInstrSchedClasses*6) &&

852                "too many SchedVariants");

853       }

854     }

3.5.1.7.1. 从ItinRW定义推导

首先处理将一组InstrItinClass(执行步骤)映射到一组SchedReadWrite(资源使用)的ItinRW定义(843行)。为了方便起见,我们将涉及的定义重新列出如下:

402     class ItinRW<list<SchedReadWrite> rw, list<InstrItinClass> iic> {

403       list<InstrItinClass> MatchedItinClasses = iic;

404       list<SchedReadWrite> OperandReadWrites = rw;

405       SchedMachineModel SchedModel = ?;

406     }

其中OperandReadWrites的成员可以是SchedWriteVariant与的SchedReadVariant定义,两者的基类都是SchedVariant。SchedVariant定义包含了一组Variants,每个Variant(SchedVar)都有一个谓词,在谓词条件满足时,应用Selected援引的一组SchedReadWrite对象。

361     class SchedVariant<list<SchedVar> variants> {

362       list<SchedVar> Variants = variants;

363       bit Variadic = 0;

364       SchedMachineModel SchedModel = ?;

365     }

 

355     class SchedVar<SchedPredicate pred, list<SchedReadWrite> selected> {

356       SchedPredicate Predicate = pred;

357       list<SchedReadWrite> Selected = selected;

358     }

 

374     class SchedWriteVariant<list<SchedVar> variants> : SchedWrite,

375       SchedVariant<variants> {

376     }

 

383     class SchedReadVariant<list<SchedVar> variants> : SchedRead,

384       SchedVariant<variants> {

385     }

另外,SchedReadWrite定义(match)可能被SchedAlias修改为另一个(alias)。

415     class SchedAlias<SchedReadWrite match, SchedReadWrite alias> {

416       SchedReadWrite MatchRW = match;

417       SchedReadWrite AliasRW = alias;

418       SchedMachineModel SchedModel = ?;

419     }

而OperandReadWrites的内容还可以是WriteSequence:

224     class WriteSequence<list<SchedWrite> writes, int rep = 1> : SchedWrite {

225       list<SchedWrite> Writes = writes;

226       int Repeat = rep;

227       SchedMachineModel SchedModel = ?;

228     }

更为复杂的是,上述定义中的SchedWrite及SchedReadWrite仍然可以是SchedWriteVariant,SchedReadVariant,WriteSequence以及相关的SchedAlias(当然,很复杂定义出现的可能性很小)。举一个ARM的例子,下面是ARM CortexA9处理器指令调度定义的一个片段(ARMScheduleA9.td):

1912  let SchedModel = CortexA9Model in {

1926  def A9WriteIssue : SchedWriteRes<[]> { let Latency = 0; }

2037  def A9WriteLMAdr : SchedWriteVariant<[

2038    SchedVar<A9LMAdr1Pred, [A9WriteAdr1]>,

2039    SchedVar<A9LMAdr2Pred, [A9WriteAdr2]>,

2040    SchedVar<A9LMAdr3Pred, [A9WriteAdr3]>,

2041    SchedVar<A9LMAdr4Pred, [A9WriteAdr4]>,

2042    SchedVar<A9LMAdr5Pred, [A9WriteAdr5]>,

2043    SchedVar<A9LMAdr6Pred, [A9WriteAdr6]>,

2044    SchedVar<A9LMAdr7Pred, [A9WriteAdr7]>,

2045    SchedVar<A9LMAdr8Pred, [A9WriteAdr8]>,

2046    // For unknown LDM/VLDM/VSTM, assume 2 32-bit registers.

2047    SchedVar<A9LMUnknownPred, [A9WriteAdr2]>]>;

2086  def A9WriteLM : SchedWriteVariant<[

2087   SchedVar<A9LMAdr1Pred, A9WriteLMOpsList.Writes[0-1]>,

2088   SchedVar<A9LMAdr2Pred, A9WriteLMOpsList.Writes[0-3]>,

2089   SchedVar<A9LMAdr3Pred, A9WriteLMOpsList.Writes[0-5]>,

2090   SchedVar<A9LMAdr4Pred, A9WriteLMOpsList.Writes[0-7]>,

2091   SchedVar<A9LMAdr5Pred, A9WriteLMOpsList.Writes[0-9]>,

2092    SchedVar<A9LMAdr6Pred, A9WriteLMOpsList.Writes[0-11]>,

2093    SchedVar<A9LMAdr7Pred, A9WriteLMOpsList.Writes[0-13]>,

2094    SchedVar<A9LMAdr8Pred, A9WriteLMOpsList.Writes[0-15]>,

2095    // For unknown LDMs, define the maximum number of writes, but only

2096    // make the first two consume resources.

2097    SchedVar<A9LMUnknownPred, [A9WriteL1, A9WriteL1Hi,

2098                               A9WriteL2, A9WriteL2Hi,

2099                               A9WriteL3Hi, A9WriteL3Hi,

2100                               A9WriteL4Hi, A9WriteL4Hi,

2101                               A9WriteL5Hi, A9WriteL5Hi,

2102                               A9WriteL6Hi, A9WriteL6Hi,

2103                               A9WriteL7Hi, A9WriteL7Hi,

2104                               A9WriteL8Hi, A9WriteL8Hi]>]> {

2105    let Variadic = 1;

2106  }

2339  def :ItinRW<[A9WriteLM, A9WriteLMAdr, A9WriteIssue], [IIC_iLoad_m, IIC_iPop]>;

2529  }

我们将使用这个例子来帮助学习下面的处理代码。这个例子将原来比如使用IIC_iLoad_m描述的指令定义LDM的调度特征,细分为9类。每一类由A9WriteLM,A9WriteLMAdr及A9WriteIssue里指定谓词选择的一个SchedReadWrite定义组成。

首先,在CodeGenSchedModels::inferSchedClasses()的844行,如果调度类型的ItinClassDef不为空(来自指令定义的Itinerary,描述指令的执行步骤),需要检查这个Itinerary定义是否对某些处理器改写了(根据ItinRW定义,参考从ItinRW定义推导一节)。

857     void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,

858                                                 unsigned FromClassIdx) {

859       for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {

860         const CodeGenProcModel &PM = ProcModels[PIdx];

861         // For all ItinRW entries.

862         bool HasMatch = false;

863         for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();

864              II != IE; ++II) {

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

866           if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))

867             continue;

868           if (HasMatch)

869             PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "

870                           + ItinClassDef->getName()

871                           + " in ItinResources for " + PM.ModelName);

872           HasMatch = true;

873           IdxVec Writes, Reads;

874           findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);

875           IdxVec ProcIndices(1, PIdx);

876           inferFromRW(Writes, Reads, FromClassIdx, ProcIndices);

877         }

878       }

879     }

ItinRW的定义都保存在它们所援引处理器CodeGenSchedModels对象的ItinRWDefs容器里。因此,859行循环遍历所有的CodeGenSchedModels实例,找出与ItinClassDef相关的对象,记录其序号。对同一个处理器,不能存在映射同一个InstrItinClass的多个ItinRW定义,因为这样带来了二义性。在874行获取该ItinRW匹配的那组SchedReadWrite,然后据此推导新调度类型。

对上面的例子,在874行得到Writes的内容是:[A9WriteLM, A9WriteLMAdr, A9WriteIssue]。接下来由下面的方法执行调度类型推导。

1325  void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites,

1326                                       const IdxVec &OperReads,

1327                                       unsigned FromClassIdx,

1328                                       const IdxVec &ProcIndices) {

1329    DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") ");

1330 

1331    // Create a seed transition with an empty PredTerm and the expanded sequences

1332    // of SchedWrites for the current SchedClass.

1333    std::vector<PredTransition> LastTransitions;

1334    LastTransitions.resize(1);

1335    LastTransitions.back().ProcIndices.append(ProcIndices.begin(),

1336                                              ProcIndices.end());

1337 

1338    for (IdxIter I = OperWrites.begin(), E = OperWrites.end(); I != E; ++I) {

1339      IdxVec WriteSeq;

1340      expandRWSequence(*I, WriteSeq, /*IsRead=*/false);

1341      unsigned Idx = LastTransitions[0].WriteSequences.size();

1342      LastTransitions[0].WriteSequences.resize(Idx + 1);

1343      SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences[Idx];

1344      for (IdxIter WI = WriteSeq.begin(), WE = WriteSeq.end(); WI != WE; ++WI)

1345        Seq.push_back(*WI);

1346      DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");

1347    }

1348    DEBUG(dbgs() << " Reads: ");

1349    for (IdxIter I = OperReads.begin(), E = OperReads.end(); I != E; ++I) {

1350      IdxVec ReadSeq;

1351      expandRWSequence(*I, ReadSeq, /*IsRead=*/true);

1352      unsigned Idx = LastTransitions[0].ReadSequences.size();

1353      LastTransitions[0].ReadSequences.resize(Idx + 1);

1354      SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences[Idx];

1355      for (IdxIter RI = ReadSeq.begin(), RE = ReadSeq.end(); RI != RE; ++RI)

1356        Seq.push_back(*RI);

1357      DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");

1358    }

1359    DEBUG(dbgs() << '\n');

1360 

1361    // Collect all PredTransitions for individual operands.

1362    // Iterate until no variant writes remain.

1363    while (hasVariant(LastTransitions, *this)) {

1364      PredTransitions Transitions(*this);

1365      for (std::vector<PredTransition>::const_iterator

1366             I = LastTransitions.begin(), E = LastTransitions.end();

1367           I != E; ++I) {

1368        Transitions.substituteVariants(*I);

1369      }

1370      DEBUG(Transitions.dump());

1371      LastTransitions.swap(Transitions.TransVec);

1372    }

1373    // If the first transition has no variants, nothing to do.

1374    if (LastTransitions[0].PredTerm.empty())

1375      return;

1376 

1377    // WARNING: We are about to mutate the SchedClasses vector. Do not refer to

1378    // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions.

1379    inferFromTransitions(LastTransitions, FromClassIdx, *this);

1380  }

上面的代码首先在1333行准备一个临时容器LastTransitions,它主要用于保存中间处理的结果。因此,接下来准备第一个中间结果。随着中间结果中SchedVariant定义的处理,它将扩大为其中不冲突项的数量。其元素类型PredTransition的定义如下。

927     struct PredTransition {

928       // A predicate term is a conjunction of PredChecks.

929       SmallVector<PredCheck, 4> PredTerm;

930       SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;

931       SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;

932       SmallVector<unsigned, 4> ProcIndices;

933     };

PredTransition描述某一步中一个具体的处理结果。当然,中间结果还能包含SchedVariant,因此会根据这个结果进一步展开。到最终,LastTransitions只会包含非SchedVariant与非Sequences的SchedReadWrite结果。

因为SchedVariant定义包含SchedVar列表,而SchedVar又包含SchedReadWrite列表,为了辅助SchedVariant的展开,需要如930及931行定义的WriteSequences与ReadSequences容器。另外,容器PredTerm将用于保存SchedVariant中SchedVar的谓词定义,其中的PredCheck类型定义如下。

918     struct PredCheck {

919       bool IsRead;

920       unsigned RWIdx;

921       Record *Predicate;

922    

922       PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {}

923     };

920行的RWIdx用于关联该谓词所选择的SchedReadWrite定义(即在CodeGenSchedModels的容器SchedWrites或SchedReads里的索引)。

在处理过程中LastTransitions实际上主要作为一个保存中间结果的容器。当然,它也会保存最终结果。SchedVariant展开的主要处理由类PredTransitions提供。当然,这个过程有点复杂,处理也有点微妙。

937     class PredTransitions {

938       CodeGenSchedModels &SchedModels;

939    

940     public:

941       std::vector<PredTransition> TransVec;

942    

943       PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}

944    

945       void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,

946                                     bool IsRead, unsigned StartIdx);

947    

948       void substituteVariants(const PredTransition &Trans);

949    

950     #ifndef NDEBUG

951       void dump() const;

952     #endif

953    

954     private:

955       bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);

956       void getIntersectingVariants(

957         const CodeGenSchedRW &SchedRW, unsigned TransIdx,

958         std::vector<TransVariant> &IntersectingVariants);

959       void pushVariant(const TransVariant &VInfo, bool IsRead);

960     };

在inferFromRW()的1340与1351行,对ItinRW的OperandReadWrites中的SchedWrite与SchedRead定义调用expandRWSequence()方法展开可能存在的WriteSequence定义。不是从WriteSequence派生的定义在下面406行就返回了。至于WriteSequence的派生定义,其Repeat成员指出Writes成员的重复次数,因此410行的循环将该Writes成员展开这个次数。

401     void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,

402                                               bool IsRead) const {

403       const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);

404       if (!SchedRW.IsSequence) {

405         RWSeq.push_back(RWIdx);

406         return;

407       }

408       int Repeat =

409         SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;

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

411         for (IdxIter I = SchedRW.Sequence.begin(), E = SchedRW.Sequence.end();

412              I != E; ++I) {

413           expandRWSequence(*I, RWSeq, IsRead);

414         }

415       }

416     }

从expandRWSequence()方法返回inferFromRW(),注意1343与1354行,这些展开结果只在当前PredTransition对象(当前上下文里LastTransitions只有一项)的WriteSequences或ReadSequences里占据一项。接着在inferFromRW() 1363行的循环处理可能包含SchedWriteVariant或SchedReadVariant的LastTransitions(根据谓词给出的条件,将一个SchedWrite或SchedRead映射到一组SchedWrite或SchedRead)。

其中hasVariant()方法定义如下,它遍历LastTransitions,在上面展开的结果中,查找是否存在SchedWriteVariant或SchedReadVariant。

1016  static bool hasVariant(ArrayRef<PredTransition> Transitions,

1017                         CodeGenSchedModels &SchedModels) {

1018    for (ArrayRef<PredTransition>::iterator

1019           PTI = Transitions.begin(), PTE = Transitions.end();

1020         PTI != PTE; ++PTI) {

1021      for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1022             WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end();

1023           WSI != WSE; ++WSI) {

1024        for (SmallVectorImpl<unsigned>::const_iterator

1025               WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {

1026          if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels))

1027            return true;

1028        }

1029      }

1030      for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1031             RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end();

1032           RSI != RSE; ++RSI) {

1033        for (SmallVectorImpl<unsigned>::const_iterator

1034               RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) {

1035          if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels))

1036            return true;

1037        }

1038      }

1039    }

1040    return false;

1041  }

尽管方法hasAliasedVariants()的名字中有aliased这个字眼,实际上在函数开头的993行却是判断传入的SchedReadWrite是否为SchedWriteVariant或SchedReadVariant。如果不是,继续检查它是否具有别名,如果该别名是一个SchedWriteVariant或SchedReadVariant定义,这就是需要处理的对象。

991     static bool hasAliasedVariants(const CodeGenSchedRW &RW,

992                                    CodeGenSchedModels &SchedModels) {

993       if (RW.HasVariants)

994         return true;

995    

996       for (RecIter I = RW.Aliases.begin(), E = RW.Aliases.end(); I != E; ++I) {

997         const CodeGenSchedRW &AliasRW =

998           SchedModels.getSchedRW((*I)->getValueAsDef("AliasRW"));

999         if (AliasRW.HasVariants)

1000        return true;

1001      if (AliasRW.IsSequence) {

1002        IdxVec ExpandedRWs;

1003        SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead);

1004        for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end();

1005             SI != SE; ++SI) {

1006          if (hasAliasedVariants(SchedModels.getSchedRW(*SI, AliasRW.IsRead),

1007                                 SchedModels)) {

1008            return true;

1009          }

1010        }

1011      }

1012    }

1013    return false;

1014  }

对需要处理的SchedWriteVariant或SchedReadVariant定义,在inferFromRW()的1364行首先生成一个PredTransitions实例。在1368行对LastTransitions容器的每一项(对应一个中间结果)调用下面的方法,将其中SchedVariant定义包含的SchedVar列表,根据它们的Predicate,选择相应的Selected成员。

1247  void PredTransitions::substituteVariants(const PredTransition &Trans) {

1248    // Build up a set of partial results starting at the back of

1249    // PredTransitions. Remember the first new transition.

1250    unsigned StartIdx = TransVec.size();

1251    TransVec.resize(TransVec.size() + 1);

1252    TransVec.back().PredTerm = Trans.PredTerm;

1253    TransVec.back().ProcIndices = Trans.ProcIndices;

1254 

1255    // Visit each original write sequence.

1256    for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1257           WSI = Trans.WriteSequences.begin(), WSE = Trans.WriteSequences.end();

1258         WSI != WSE; ++WSI) {

1259      // Push a new (empty) write sequence onto all partial Transitions.

1260      for (std::vector<PredTransition>::iterator I =

1261             TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {

1262        I->WriteSequences.resize(I->WriteSequences.size() + 1);

1263      }

1264      substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx);

1265    }

1266    // Visit each original read sequence.

1267    for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1268           RSI = Trans.ReadSequences.begin(), RSE = Trans.ReadSequences.end();

1269         RSI != RSE; ++RSI) {

1270      // Push a new (empty) read sequence onto all partial Transitions.

1271      for (std::vector<PredTransition>::iterator I =

1272             TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {

1273       I->ReadSequences.resize(I->ReadSequences.size() + 1);

1274      }

1275      substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx);

1276    }

1277  }

首先在LastTransitions当前项的TransVec容器里开辟一项用于当前的SchedVariant的处理(注意一开始TransVec容器是空的)。在1256与1267行循环,依次处理前面展开的结果。以前面的例子来说,WSI将依次援引A9WriteLM,A9WriteLMAdr,A9WriteIssue展开的结果。1260与1271行循环是必要的,因为在1264与1275行执行的substituteVariantOperand()方法会扩大TransVec容器来保存SchedVariant中不冲突的展开结果。

substituteVariantOperand()展开SchedVariant。参数RWSeq就是ItinRW的OperandReadWrites中某个SchedReadWrite展开的结果,对上面的例子,它是A9WriteLM,A9WriteLMAdr,A9WriteIssue其中之一。

对于其中既不是SchedWriteVariant或SchedReadVariant,别名也不是SchedWriteVariant或SchedReadVariant的定义,直接记录在当前的ReadSequences或WriteSequences容器里,无需特别处理(1221与1223行 )。

1206  void PredTransitions::substituteVariantOperand(

1207    const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {

1208 

1209    // Visit each original RW within the current sequence.

1210    for (SmallVectorImpl<unsigned>::const_iterator

1211           RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) {

1212      const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(*RWI, IsRead);

1213      // Push this RW on all partial PredTransitions or distribute variants.

1214      // New PredTransitions may be pushed within this loop which should not be

1215      // revisited (TransEnd must be loop invariant).

1216      for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size();

1217           TransIdx != TransEnd; ++TransIdx) {

1218        // In the common case, push RW onto the current operand's sequence.

1219        if (!hasAliasedVariants(SchedRW, SchedModels)) {

1220          if (IsRead)

1221            TransVec[TransIdx].ReadSequences.back().push_back(*RWI);

1222          else

1223            TransVec[TransIdx].WriteSequences.back().push_back(*RWI);

1224          continue;

1225        }

1226        // Distribute this partial PredTransition across intersecting variants.

1227        // This will push a copies of TransVec[TransIdx] on the back of TransVec.

1228        std::vector<TransVariant> IntersectingVariants;

1229        getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants);

1230        // Now expand each variant on top of its copy of the transition.

1231        for (std::vector<TransVariant>::const_iterator

1232               IVI = IntersectingVariants.begin(),

1233               IVE = IntersectingVariants.end();

1234             IVI != IVE; ++IVI) {

1235          pushVariant(*IVI, IsRead);

1236        }

1237      }

1238    }

1239  }

至于SchedWriteVariant或SchedReadVariant或者别名为SchedWriteVariant或SchedReadVariant的定义,在1228行首先准备一个std::vector<TransVariant>类型的容器。它用于保存Variant与展开项的关联结果,其中TransVariant的定义如下:

906     struct TransVariant {

907       Record *VarOrSeqDef;  // Variant or sequence.

908       unsigned RWIdx;       // Index of this variant or sequence's matched type.

909       unsigned ProcIdx;     // Processor model index or zero for any.

910       unsigned TransVecIdx; // Index into PredTransitions::TransVec.

911    

912       TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti):

913         VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}

914     };

其中907行的VarOrSeqDef是SchedVariant中Variant的某一项,910行的TransVecIdx是该SchedVar或WriteSequence(来自SchedAlias)在PredTransitions的TransVec容器的索引。RWIdx则是这个SchedWriteVariant或SchedReadVariant在CodeGenSchedModels实例的SchedWrites或SchedReads容器里的索引。而ProcIdx则是相应的CodeGenProcModel实例的索引。

然后调用getIntersectingVariants()方法,注意这个调用在1216行开始的循环的内部,因此对某一个SchedRW,对每个正在处理的展开,都调用这个方法一遍。

1053~1090行将SchedVariant中Variant的每一项或SchedAlias中AliasRW的每一项记录到Variants里。然后在1091行循环遍历Variants容器。在SchedReadWrite定义中SchedModel域可以不设置(即问号),表示是一个通用设置。但如果设置了SchedModel域,必须将VarProcIdx与AliasProcIdx设置为它所援引的CodeGenProcModel实例的索引。

1046  void PredTransitions::getIntersectingVariants(

1047    const CodeGenSchedRW &SchedRW, unsigned TransIdx,

1048    std::vector<TransVariant> &IntersectingVariants) {

1049 

1050    bool GenericRW = false;

1051 

1052    std::vector<TransVariant> Variants;

1053    if (SchedRW.HasVariants) {

1054      unsigned VarProcIdx = 0;

1055      if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) {

1056        Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel");

1057        VarProcIdx = SchedModels.getProcModel(ModelDef).Index;

1058      }

1059      // Push each variant. Assign TransVecIdx later.

1060      const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");

1061      for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI)

1062       Variants.push_back(TransVariant(*RI, SchedRW.Index, VarProcIdx, 0));

1063      if (VarProcIdx == 0)

1064        GenericRW = true;

1065    }

1066    for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();

1067         AI != AE; ++AI) {

1068      // If either the SchedAlias itself or the SchedReadWrite that it aliases

1069      // to is defined within a processor model, constrain all variants to

1070      // that processor.

1071      unsigned AliasProcIdx = 0;

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

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

1074        AliasProcIdx = SchedModels.getProcModel(ModelDef).Index;

1075      }

1076      const CodeGenSchedRW &AliasRW =

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

1078 

1079      if (AliasRW.HasVariants) {

1080        const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants");

1081        for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI)

1082          Variants.push_back(TransVariant(*RI, AliasRW.Index, AliasProcIdx, 0));

1083      }

1084      if (AliasRW.IsSequence) {

1085        Variants.push_back(

1086          TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0));

1087      }

1088      if (AliasProcIdx == 0)

1089        GenericRW = true;

1090    }

1091    for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) {

1092      TransVariant &Variant = Variants[VIdx];

1093      // Don't expand variants if the processor models don't intersect.

1094      // A zero processor index means any processor.

1095      SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices;

1096      if (ProcIndices[0] && Variants[VIdx].ProcIdx) {

1097        unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(),

1098                                  Variant.ProcIdx);

1099        if (!Cnt)

1100          continue;

1101        if (Cnt > 1) {

1102          const CodeGenProcModel &PM =

1103            *(SchedModels.procModelBegin() + Variant.ProcIdx);

1104          PrintFatalError(Variant.VarOrSeqDef->getLoc(),

1105                          "Multiple variants defined for processor " +

1106                          PM.ModelName +

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

1108        }

1109      }

1110      if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) {

1111        Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");

1112        if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))

1113          continue;

1114      }

1115      if (IntersectingVariants.empty()) {

1116        // The first variant builds on the existing transition.

1117        Variant.TransVecIdx = TransIdx;

1118        IntersectingVariants.push_back(Variant);

1119      }

1120      else {

1121        // Push another copy of the current transition for more variants.

1122        Variant.TransVecIdx = TransVec.size();

1123        IntersectingVariants.push_back(Variant);

1124        TransVec.push_back(TransVec[TransIdx]);

1125      }

1126    }

1127    if (GenericRW && IntersectingVariants.empty()) {

1128      PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has "

1129                      "a matching predicate on any processor");

1130    }

1131  }

1096行首先判断这对SchedVar是否共享相同的处理器模型。如果是,则通过mutuallyExclusive()方法检查其谓词与当前PredTransition对象记录的谓词是否兼容。

972     bool PredTransitions::mutuallyExclusive(Record *PredDef,

973                                             ArrayRef<PredCheck> Term) {

974    

975       for (ArrayRef<PredCheck>::iterator I = Term.begin(), E = Term.end();

976            I != E; ++I) {

977         if (I->Predicate == PredDef)

978           return false;

979    

980         const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(I->RWIdx, I->IsRead);

981         assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant");

982         RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");

983         for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) {

984           if ((*VI)->getValueAsDef("Predicate") == PredDef)

985             return true;

986         }

987       }

988       return false;

989     }

参数Term来自TransVec[TransIdx].PredTerm,它在substituteVariants()方法中来自LastTransitions当前项的PredTerm。而LastTransitions各项中的PredTerm则是在inferFromRW()的substituteVariants()操作后与Transitions交换得到的(inferFromRW()的1371行)。而LastTransitions的PredTerm一开始是空的(Transitions的PredTerm容器开始也是空的,一旦处理了一个SchedVar定义,就会保存它的谓词定义以及包含这个SchedVar的SchedVariant的索引【下面pushVariant()的1148行】)。

上面代码所表达的逻辑是这样的:与一个给定SchedVariant对象相关的谓词都视为彼此互斥,即使这些谓词所表示的条件不是互斥的。这没问题,因为选择给定SchedWrite的谓词总是以它们在.td文件里定义是次序来检查。后面的条件隐含地否定了任何前面的条件。

那么如果满足977行的条件,这意味着前一次展开时这个谓词被选中(即mutuallyExclusive()没有过滤掉它),那么这次它依然适用。因为Term不为空,表示之前已经执行过展开,但展开结果仍然有SchedVariant(这个Term的来源是:pushVariant()将PredCheck实例保存到TransVec容器 à inferFromRW()将TransVec容器内容导入LastTransitions à substituteVariants()将PerdTerm内容赋值给TransVec处理单元的PredTerm)。因为一个SchedVariant的谓词中只有一个是选中的,因此不满足977行条件,就需要983行循环来确定PredDef是否为该SchedVariant的其他谓词。是的话,它就是与Term里给出的谓词互斥的。

如果不互斥,在IntersectingVariants()中记录这个Variant对象,并扩大TransVec记录这些Variant。

以上面的例子来说,首先处理A9WriteLM,Variants的内容是:

TransIdx = 0

[0]: SchedVar<A9LMAdr1Pred, A9WriteLMOpsList.Writes[0-1]>

[1]: SchedVar<A9LMAdr2Pred, A9WriteLMOpsList.Writes[0-3]>

[2]: SchedVar<A9LMAdr3Pred, A9WriteLMOpsList.Writes[0-5]>

[3]: SchedVar<A9LMAdr4Pred, A9WriteLMOpsList.Writes[0-7]>

[4]: SchedVar<A9LMAdr5Pred, A9WriteLMOpsList.Writes[0-9]>

[5]: SchedVar<A9LMAdr6Pred, A9WriteLMOpsList.Writes[0-11]>

[6]: SchedVar<A9LMAdr7Pred, A9WriteLMOpsList.Writes[0-13]>

[7]: SchedVar<A9LMAdr8Pred, A9WriteLMOpsList.Writes[0-15]>

[8]: SchedVar<A9LMUnknownPred, [A9WriteL1, A9WriteL1Hi, A9WriteL2, A9WriteL2Hi,

                             A9WriteL3Hi, A9WriteL3Hi, A9WriteL4Hi, A9WriteL4Hi,

                             A9WriteL5Hi, A9WriteL5Hi, A9WriteL6Hi, A9WriteL6Hi,

                             A9WriteL7Hi, A9WriteL7Hi, A9WriteL8Hi, A9WriteL8Hi]>

IntersectingVariants()中每一项包含Variants对应的一项。同时TransVec中也有9项。

回到substituteVariantOperand()方法,现在容器IntersectingVariants记录了这个SchedVariant定义所对应的要展开的TransVariant实例。在1231行遍历这些实例,并对它们调用下面的pushVariant()方法记录被选中的SchedReadWrite定义。

注意1143行的赋值,VInfo.ProcIdx来自SchedAlias定义的AliasRW域,由getIntersectingVariants()的输出参数IntersectingVariants返回,作为pushVariant()的参数Vinfo传入。因此,该PredTransition实例增加了一个支持的处理器索引。

1135  void PredTransitions::

1136  pushVariant(const TransVariant &VInfo, bool IsRead) {

1137 

1138    PredTransition &Trans = TransVec[VInfo.TransVecIdx];

1139 

1140    // If this operand transition is reached through a processor-specific alias,

1141    // then the whole transition is specific to this processor.

1142    if (VInfo.ProcIdx != 0)

1143      Trans.ProcIndices.assign(1, VInfo.ProcIdx);

1144 

1145    IdxVec SelectedRWs;

1146    if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) {

1147      Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate");

1148      Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef));

1149      RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected");

1150      SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);

1151    }

1152    else {

1153      assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") &&

1154             "variant must be a SchedVariant or aliased WriteSequence");

1155      SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead));

1156    }

1157 

1158    const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead);

1159 

1160    SmallVectorImpl<SmallVector<unsigned,4> > &RWSequences = IsRead

1161      ? Trans.ReadSequences : Trans.WriteSequences;

1162    if (SchedRW.IsVariadic) {

1163      unsigned OperIdx = RWSequences.size()-1;

1164      // Make N-1 copies of this transition's last sequence.

1165      for (unsigned i = 1, e = SelectedRWs.size(); i != e; ++i) {

1166       // Create a temporary copy the vector could reallocate.

1167        RWSequences.reserve(RWSequences.size() + 1);

1168        RWSequences.push_back(RWSequences[OperIdx]);

1169      }

1170      // Push each of the N elements of the SelectedRWs onto a copy of the last

1171      // sequence (split the current operand into N operands).

1172      // Note that write sequences should be expanded within this loop--the entire

1173      // sequence belongs to a single operand.

1174      for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();

1175           RWI != RWE; ++RWI, ++OperIdx) {

1176        IdxVec ExpandedRWs;

1177        if (IsRead)

1178          ExpandedRWs.push_back(*RWI);

1179        else

1180          SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);

1181        RWSequences[OperIdx].insert(RWSequences[OperIdx].end(),

1182                                    ExpandedRWs.begin(), ExpandedRWs.end());

1183      }

1184      assert(OperIdx == RWSequences.size() && "missed a sequence");

1185    }

1186    else {

1187      // Push this transition's expanded sequence onto this transition's last

1188      // sequence (add to the current operand's sequence).

1189      SmallVectorImpl<unsigned> &Seq = RWSequences.back();

1190      IdxVec ExpandedRWs;

1191      for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();

1192           RWI != RWE; ++RWI) {

1193        if (IsRead)

1194          ExpandedRWs.push_back(*RWI);

1195        else

1196          SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);

1197      }

1198      Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end());

1199    }

1200  }

TransVariant实例要么来自SchedVariant的Variants(list<SchedVar>),要么来自SchedAlias的AliasRW(WriteSequence或SchedVariant),这样就不难理解1153行的断言了。对于由SchedVar生成的TransVariant对象,生成的记录谓词的PredCheck实例保存在相关的PredTransition实例中(这就是getIntersectingVariants() 1112行TransVec[TransIdx].PredTerm的来源)。

容器SelectedRWs记录相关SchedReadWrite定义的索引(SchedVar是Selected,WriteSequence则是它本身)。在1158行从VInfo.RWIdx得到包含这个SchedVar或WriteSequence的SchedVariant定义的CodeGenSchedRW实例。

如果这个SchedVariant定义不包含可变数量参数(不满足1162行条件),1191行遍历选中SchedVar定义中的Selected或SchedAlias定义中的AliasRW,展开可能出现的WriteSequence,在TransVec[VInfo.TransVecIdx]的ReadSequences或WriteSequences容器里记录这些CodeGenSchedRW对象序号。这些CodeGenSchedRW对象全部保存在容器的最后一个单元,这是与可变参数时最大的区别。

如果这个SchedVariant定义包含可变参数,首先在TransVec[VInfo.TransVecIdx]的ReadSequences或WriteSequences容器里拷贝最后一个单元,使得未使用单元与SelectedRWs的成员可以一一对应。然后,将SelectedRWs中的成员(SchedReadWrite)分别一一对应地记录在这些未使用单元里。

这样对于我们的例子,TransVec的内容是这样的:

TransVec[0].WriteSequences[0]: A9WriteLMOpsList.Writes[0-1], Pred: A9LMAdr1Pred

TransVec[1].WriteSequences[0]: A9WriteLMOpsList.Writes[0-3], Pred: A9LMAdr2Pred

TransVec[2].WriteSequences[0]: A9WriteLMOpsList.Writes[0-5], Pred: A9LMAdr3Pred

TransVec[3].WriteSequences[0]: A9WriteLMOpsList.Writes[0-7], Pred: A9LMAdr4Pred

TransVec[4].WriteSequences[0]: A9WriteLMOpsList.Writes[0-9], Pred: A9LMAdr5Pred

TransVec[5].WriteSequences[0]: A9WriteLMOpsList.Writes[0-11], Pred: A9LMAdr6Pred

TransVec[6].WriteSequences[0]: A9WriteLMOpsList.Writes[0-13], Pred: A9LMAdr7Pred

TransVec[7].WriteSequences[0]: A9WriteLMOpsList.Writes[0-15], Pred: A9LMAdr8Pred

TransVec[8]: Pred: A9LMUnknownPred

WriteSequences[0]: A9WriteL1

WriteSequences[1]: A9WriteL1Hi

WriteSequences[2]: A9WriteL2

WriteSequences[3]: A9WriteL2Hi

WriteSequences[4]: A9WriteL3Hi

WriteSequences[5]: A9WriteL3Hi

WriteSequences[6]: A9WriteL4Hi

WriteSequences[7]: A9WriteL4Hi

WriteSequences[8]: A9WriteL5Hi

WriteSequences[9]: A9WriteL5Hi

WriteSequences[10]: A9WriteL6Hi

WriteSequences[11]: A9WriteL6Hi

WriteSequences[12]: A9WriteL7Hi

WriteSequences[13]: A9WriteL7Hi

WriteSequences[14]: A9WriteL8Hi

WriteSequences[15]: A9WriteL8Hi

从substituteVariantOperand()返回,再次进入substituteVariants()在1256行的循环,处理ItinRW的OperandReadWrites中下一个SchedReadWrite。以上面的例子来说,是A9WriteLMAdr。在1262行,上面所有TransVec的WriteSequences容器都扩大一项。处理后,得到(可以对照mutuallyExclusive()代码看一下):

TransVec[0] A9LMAdr1Pred x 2(封装在PredCheck中,下同):

WriteSequences[0]: A9WriteLMOpsList.Writes[0-1]

WriteSequences[1]: A9WriteAdr1

TransVec[1] A9LMAdr2Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-3]

WriteSequences[1]: A9WriteAdr2

TransVec[2] A9LMAdr3Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-5]

WriteSequences[1]: A9WriteAdr3

TransVec[3] A9LMAdr4Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-7]

WriteSequences[1]: A9WriteAdr4

TransVec[4] A9LMAdr5Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-9]

WriteSequences[1]: A9WriteAdr5

TransVec[5] A9LMAdr6Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-11]

WriteSequences[1]: A9WriteAdr6

TransVec[6] A9LMAdr7Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-13]

WriteSequences[1]: A9WriteAdr7

TransVec[7] A9LMAdr8Pred x 2:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-15]

WriteSequences[1]: A9WriteAdr8

TransVec[8] A9LMUnknownPred x 2:

WriteSequences[0]: A9WriteL1

WriteSequences[1]: A9WriteL1Hi

WriteSequences[2]: A9WriteL2

WriteSequences[3]: A9WriteL2Hi

WriteSequences[4]: A9WriteL3Hi

WriteSequences[5]: A9WriteL3Hi

WriteSequences[6]: A9WriteL4Hi

WriteSequences[7]: A9WriteL4Hi

WriteSequences[8]: A9WriteL5Hi

WriteSequences[9]: A9WriteL5Hi

WriteSequences[10]: A9WriteL6Hi

WriteSequences[11]: A9WriteL6Hi

WriteSequences[12]: A9WriteL7Hi

WriteSequences[13]: A9WriteL7Hi

WriteSequences[14]: A9WriteL8Hi

WriteSequences[15]: A9WriteL8Hi

WriteSequences[16]: A9WriteAdr2

同样,在处理了最后的A9WriteIssue之后,TransVec变成:

TransVec[0] A9LMAdr1Pred x 3(封装在PredCheck中,下同):

WriteSequences[0]: A9WriteLMOpsList.Writes[0-1]

WriteSequences[1]: A9WriteAdr1

WriteSequences[2]: A9WriteIssue

TransVec[1] A9LMAdr2Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-3]

WriteSequences[1]: A9WriteAdr2

WriteSequences[2]: A9WriteIssue

TransVec[2] A9LMAdr3Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-5]

WriteSequences[1]: A9WriteAdr3

WriteSequences[2]: A9WriteIssue

TransVec[3] A9LMAdr4Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-7]

WriteSequences[1]: A9WriteAdr4

WriteSequences[2]: A9WriteIssue

TransVec[4] A9LMAdr5Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-9]

WriteSequences[1]: A9WriteAdr5

WriteSequences[2]: A9WriteIssue

TransVec[5] A9LMAdr6Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-11]

WriteSequences[1]: A9WriteAdr6

WriteSequences[2]: A9WriteIssue

TransVec[6] A9LMAdr7Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-13]

WriteSequences[1]: A9WriteAdr7

WriteSequences[2]: A9WriteIssue

TransVec[7] A9LMAdr8Pred x 3:

WriteSequences[0]: A9WriteLMOpsList.Writes[0-15]

WriteSequences[1]: A9WriteAdr8

WriteSequences[2]: A9WriteIssue

TransVec[8] A9LMUnknownPred x 3:

WriteSequences[0]: A9WriteL1

WriteSequences[1]: A9WriteL1Hi

WriteSequences[2]: A9WriteL2

WriteSequences[3]: A9WriteL2Hi

WriteSequences[4]: A9WriteL3Hi

WriteSequences[5]: A9WriteL3Hi

WriteSequences[6]: A9WriteL4Hi

WriteSequences[7]: A9WriteL4Hi

WriteSequences[8]: A9WriteL5Hi

WriteSequences[9]: A9WriteL5Hi

WriteSequences[10]: A9WriteL6Hi

WriteSequences[11]: A9WriteL6Hi

WriteSequences[12]: A9WriteL7Hi

WriteSequences[13]: A9WriteL7Hi

WriteSequences[14]: A9WriteL8Hi

WriteSequences[15]: A9WriteL8Hi

WriteSequences[16]: A9WriteAdr2

WriteSequences[17]: A9WriteIssue

回到CodeGenSchedModels::inferFromRW()。在1371行,Transitions.TransVec导入LastTransitions,重新进入1363行循环,直到 LastTransitions中不包含SchedVariant为止。

一旦有SchedVariant被处理,就需要定义inferFromTransitions()方法来构建与之对应的新调度类型。以我们的例子来说,现在LastTransitions的内容与上面的TransVec一致,因为inferFromRW()里的swap()。

1280  static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,

1281                                   unsigned FromClassIdx,

1282                                   CodeGenSchedModels &SchedModels) {

1283    // For each PredTransition, create a new CodeGenSchedTransition, which usually

1284    // requires creating a new SchedClass.

1285    for (ArrayRef<PredTransition>::iterator

1286           I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) {

1287      IdxVec OperWritesVariant;

1288      for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1289             WSI = I->WriteSequences.begin(), WSE = I->WriteSequences.end();

1290           WSI != WSE; ++WSI) {

1291        // Create a new write representing the expanded sequence.

1292        OperWritesVariant.push_back(

1293          SchedModels.findOrInsertRW(*WSI, /*IsRead=*/false));

1294      }

1295      IdxVec OperReadsVariant;

1296      for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator

1297             RSI = I->ReadSequences.begin(), RSE = I->ReadSequences.end();

1298           RSI != RSE; ++RSI) {

1299        // Create a new read representing the expanded sequence.

1300        OperReadsVariant.push_back(

1301          SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true));

1302      }

1303      IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end());

1304      CodeGenSchedTransition SCTrans;

1305      SCTrans.ToClassIdx =

1306       SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant,

1307                                  OperReadsVariant, ProcIndices);

1308      SCTrans.ProcIndices = ProcIndices;

1309      // The final PredTerm is unique set of predicates guarding the transition.

1310      RecVec Preds;

1311      for (SmallVectorImpl<PredCheck>::const_iterator

1312             PI = I->PredTerm.begin(), PE = I->PredTerm.end(); PI != PE; ++PI) {

1313        Preds.push_back(PI->Predicate);

1314      }

1315      RecIter PredsEnd = std::unique(Preds.begin(), Preds.end());

1316      Preds.resize(PredsEnd - Preds.begin());

1317      SCTrans.PredTerm = Preds;

1318      SchedModels.getSchedClass(FromClassIdx).Transitions.push_back(SCTrans);

1319    }

1320  }

也就是说,上面的每个TransVec项都会产生一个调度类型。除此之外,对每个新生成的调度类型,还会生成一个CodeGenSchedTransition对象,这个对象的定义是:

97       struct CodeGenSchedTransition {

98         unsigned ToClassIdx;

99         IdxVec ProcIndices;

100       RecVec PredTerm;

101     };

对指定的处理器而言,inferFromTransitions()的参数FromClassIdx所代表的调度类型被当前的ItinRW定义修改为ToClassIdx所代表的调度类型。为了记录这个事实,CodeGenSchedClass定义了Transitions容器。注意在1306行构建的CodeGenSchedClass对象,它的ItinClassDef是NULL。这样在inferSchedClasses()的840行循环里,不会再对该CodeGenSchedClass实例调用inferFromRW()方法。

另外,注意1315行将重复的谓词去除,就像我们例子显示的,谓词可能会重复多个。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值