From 92649883119aaa8edd9ccf612eaaff5ccc8fcc77 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Sat, 22 Sep 2012 02:24:21 +0000 Subject: [PATCH] Machine Model (-schedmodel only). Added SchedAliases. Allow subtargets to tie SchedReadWrite types to processor specific sequences or variants. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164451 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Target/TargetSchedule.td | 33 +++- utils/TableGen/CodeGenSchedule.cpp | 247 ++++++++++++++++++++------ utils/TableGen/CodeGenSchedule.h | 31 +++- utils/TableGen/SubtargetEmitter.cpp | 104 ++++++++--- 4 files changed, 327 insertions(+), 88 deletions(-) diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index 07eb2ce47c4..cf3d2505906 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -101,6 +101,10 @@ class ProcResourceKind; // cycle that the instruction issues in-order, forcing an interlock // with subsequent instructions that require the same resource until // the number of ResourceCyles specified in WriteRes expire. +// +// SchedModel ties these units to a processor for any stand-alone defs +// of this class. Instances of subclass ProcResource will be automatically +// attached to a processor, so SchedModel is not needed. class ProcResourceUnits { ProcResourceKind Kind = kind; int NumUnits = num; @@ -152,12 +156,17 @@ class SchedRead : SchedReadWrite; // If the final write in this sequence is a SchedWriteVariant marked // Variadic, then the list of prior writes are distributed across all // operands after resolving the predicate for the final write. +// +// SchedModel silences warnings but is ignored. class WriteSequence writes, int rep = 1> : SchedWrite { list Writes = writes; int Repeat = rep; + SchedMachineModel SchedModel = ?; } // Define values common to WriteRes and SchedWriteRes. +// +// SchedModel ties these resources to a processor. class ProcWriteResources resources> { list ProcResources = resources; list ResourceCycles = []; @@ -217,12 +226,15 @@ class SchedWriteRes resources> : SchedWrite, ProcWriteResources; // Define values common to ReadAdvance and SchedReadAdvance. +// +// SchedModel ties these resources to a processor. class ProcReadAdvance writes = []> { int Cycles = cycles; list ValidWrites = writes; // Allow a processor to mark some scheduling classes as unsupported // for stronger verification. bit Unsupported = 0; + SchedMachineModel SchedModel = ?; } // A processor may define a ReadAdvance associated with a SchedRead @@ -237,7 +249,6 @@ class ProcReadAdvance writes = []> { // to issue earlier relative to the writer. class ReadAdvance writes = []> : ProcReadAdvance { - SchedMachineModel SchedModel = ?; SchedRead ReadType = read; } @@ -261,6 +272,8 @@ class PredicateProlog { // particular MachineInstr. The code snippet is used as an // if-statement's expression. Available variables are MI, SchedModel, // and anything defined in a PredicateProlog. +// +// SchedModel silences warnings but is ignored. class SchedPredicate { SchedMachineModel SchedModel = ?; code Predicate = pred; @@ -281,6 +294,7 @@ class SchedVar selected> { list Selected = selected; } +// SchedModel silences warnings but is ignored. class SchedVariant variants> { list Variants = variants; bit Variadic = 0; @@ -309,6 +323,8 @@ class SchedReadVariant variants> : SchedRead, // Map a set of opcodes to a list of SchedReadWrite types. This allows // the subtarget to easily override specific operations. +// +// SchedModel ties this opcode mapping to a processor. class InstRW rw, list instrs> { list OperandReadWrites = rw; list Instrs = instrs; @@ -318,8 +334,23 @@ class InstRW rw, list instrs> { // Map a set of itinerary classes to SchedReadWrite resources. This is // used to bootstrap a target (e.g. ARM) when itineraries already // exist and changing InstrInfo is undesirable. +// +// SchedModel ties this ItineraryClass mapping to a processor. class ItinRW rw, list iic> { list MatchedItinClasses = iic; list OperandReadWrites = rw; SchedMachineModel SchedModel = ?; } + +// Alias a target-defined SchedReadWrite to a processor specific +// SchedReadWrite. This allows a subtarget to easily map a +// SchedReadWrite type onto a WriteSequence, SchedWriteVariant, or +// SchedReadVariant. +// +// SchedModel will usually be provided by surrounding let statement +// and ties this SchedAlias mapping to a processor. +class SchedAlias { + SchedReadWrite MatchRW = match; + SchedReadWrite AliasRW = alias; + SchedMachineModel SchedModel = ?; +} diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 7946b42b2cf..e54202e3f27 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -61,7 +61,7 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, collectSchedClasses(); // Find instruction itineraries for each processor. Sort and populate - // CodeGenProcMode::ItinDefList. (Cycle-to-cycle itineraries). This requires + // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires // all itinerary classes to be discovered. collectProcItins(); @@ -204,6 +204,25 @@ void CodeGenSchedModels::collectSchedRW() { } } } + // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted + // for the loop below that initializes Alias vectors. + RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias"); + std::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord()); + for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) { + Record *MatchDef = (*AI)->getValueAsDef("MatchRW"); + Record *AliasDef = (*AI)->getValueAsDef("AliasRW"); + if (MatchDef->isSubClassOf("SchedWrite")) { + if (!AliasDef->isSubClassOf("SchedWrite")) + throw TGError((*AI)->getLoc(), "SchedWrite Alias must be SchedWrite"); + scanSchedRW(AliasDef, SWDefs, RWSet); + } + else { + assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); + if (!AliasDef->isSubClassOf("SchedRead")) + throw TGError((*AI)->getLoc(), "SchedRead Alias must be SchedRead"); + scanSchedRW(AliasDef, SRDefs, RWSet); + } + } // Sort and add the SchedReadWrites directly referenced by instructions or // itinerary resources. Index reads and writes in separate domains. std::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); @@ -224,6 +243,16 @@ void CodeGenSchedModels::collectSchedRW() { findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence, /*IsRead=*/false); } + // Initialize Aliases vectors. + for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) { + Record *AliasDef = (*AI)->getValueAsDef("AliasRW"); + getSchedRW(AliasDef).IsAlias = true; + Record *MatchDef = (*AI)->getValueAsDef("MatchRW"); + CodeGenSchedRW &RW = getSchedRW(MatchDef); + if (RW.IsAlias) + throw TGError((*AI)->getLoc(), "Cannot Alias an Alias"); + RW.Aliases.push_back(*AI); + } DEBUG( for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { dbgs() << WIdx << ": "; @@ -412,7 +441,7 @@ void CodeGenSchedModels::collectSchedClasses() { IdxVec ProcIndices(1, 0); addSchedClass(Writes, Reads, ProcIndices); } - // Create classes for InstReadWrite defs. + // Create classes for InstRW defs. RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) @@ -766,6 +795,17 @@ void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { } namespace { +// Helper for substituteVariantOperand. +struct TransVariant { + Record *VariantDef; + unsigned RWIdx; // Index of this variant's matched type. + unsigned ProcIdx; // Processor model index or zero for any. + unsigned TransVecIdx; // Index into PredTransitions::TransVec. + + TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti): + VariantDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {} +}; + // Associate a predicate with the SchedReadWrite that it guards. // RWIdx is the index of the read/write variant. struct PredCheck { @@ -782,6 +822,7 @@ struct PredTransition { SmallVector PredTerm; SmallVector, 16> WriteSequences; SmallVector, 16> ReadSequences; + SmallVector ProcIndices; }; // Encapsulate a set of partially constructed transitions. @@ -805,8 +846,7 @@ public: private: bool mutuallyExclusive(Record *PredDef, ArrayRef Term); - void pushVariant(unsigned SchedRW, Record *Variant, PredTransition &Trans, - bool IsRead); + void pushVariant(const TransVariant &VInfo, bool IsRead); }; } // anonymous @@ -838,16 +878,26 @@ bool PredTransitions::mutuallyExclusive(Record *PredDef, return false; } -// Push the Reads/Writes selected by this variant onto the given PredTransition. -void PredTransitions::pushVariant(unsigned RWIdx, Record *Variant, - PredTransition &Trans, bool IsRead) { - Trans.PredTerm.push_back( - PredCheck(IsRead, RWIdx, Variant->getValueAsDef("Predicate"))); - RecVec SelectedDefs = Variant->getValueAsListOfDefs("Selected"); +// Push the Reads/Writes selected by this variant onto the PredTransition +// specified by VInfo. +void PredTransitions:: +pushVariant(const TransVariant &VInfo, bool IsRead) { + + PredTransition &Trans = TransVec[VInfo.TransVecIdx]; + + Record *PredDef = VInfo.VariantDef->getValueAsDef("Predicate"); + Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef)); + + // If this operand transition is reached through a processor-specific alias, + // then the whole transition is specific to this processor. + if (VInfo.ProcIdx != 0) + Trans.ProcIndices.assign(1, VInfo.ProcIdx); + + RecVec SelectedDefs = VInfo.VariantDef->getValueAsListOfDefs("Selected"); IdxVec SelectedRWs; SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead); - const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWIdx, IsRead); + const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead); SmallVectorImpl > &RWSequences = IsRead ? Trans.ReadSequences : Trans.WriteSequences; @@ -889,9 +939,48 @@ void PredTransitions::pushVariant(unsigned RWIdx, Record *Variant, } } +static bool hasAliasedVariants(const CodeGenSchedRW &RW, + CodeGenSchedModels &SchedModels) { + if (RW.HasVariants) + return true; + + for (RecIter I = RW.Aliases.begin(), E = RW.Aliases.end(); I != E; ++I) { + if (SchedModels.getSchedRW((*I)->getValueAsDef("AliasRW")).HasVariants) + return true; + } + return false; +} + +static bool hasVariant(ArrayRef Transitions, + CodeGenSchedModels &SchedModels) { + for (ArrayRef::iterator + PTI = Transitions.begin(), PTE = Transitions.end(); + PTI != PTE; ++PTI) { + for (SmallVectorImpl >::const_iterator + WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end(); + WSI != WSE; ++WSI) { + for (SmallVectorImpl::const_iterator + WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { + if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels)) + return true; + } + } + for (SmallVectorImpl >::const_iterator + RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end(); + RSI != RSE; ++RSI) { + for (SmallVectorImpl::const_iterator + RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) { + if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels)) + return true; + } + } + } + return false; +} + // RWSeq is a sequence of all Reads or all Writes for the next read or write // operand. StartIdx is an index into TransVec where partial results -// starts. RWSeq must be applied to all tranistions between StartIdx and the end +// starts. RWSeq must be applied to all transitions between StartIdx and the end // of TransVec. void PredTransitions::substituteVariantOperand( const SmallVectorImpl &RWSeq, bool IsRead, unsigned StartIdx) { @@ -906,7 +995,7 @@ void PredTransitions::substituteVariantOperand( for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size(); TransIdx != TransEnd; ++TransIdx) { // In the common case, push RW onto the current operand's sequence. - if (!SchedRW.HasVariants) { + if (!hasAliasedVariants(SchedRW, SchedModels)) { if (IsRead) TransVec[TransIdx].ReadSequences.back().push_back(*RWI); else @@ -914,28 +1003,74 @@ void PredTransitions::substituteVariantOperand( continue; } // Distribute this partial PredTransition across intersecting variants. - RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); - std::vector > IntersectingVariants; - for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) { - Record *PredDef = (*VI)->getValueAsDef("Predicate"); + RecVec Variants; + if (SchedRW.HasVariants) + Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); + IdxVec VarRWIds(Variants.size(), *RWI); + IdxVec VarProcModels(Variants.size(), 0); + for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); + AI != AE; ++AI) { + unsigned AIdx; + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"), AIdx); + if (!AliasRW.HasVariants) + continue; + + RecVec AliasVars = AliasRW.TheDef->getValueAsListOfDefs("Variants"); + Variants.insert(Variants.end(), AliasVars.begin(), AliasVars.end()); + + VarRWIds.resize(Variants.size(), AIdx); + + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + VarProcModels.resize(Variants.size(), + SchedModels.getProcModel(ModelDef).Index); + } + std::vector IntersectingVariants; + for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) { + Record *PredDef = Variants[VIdx]->getValueAsDef("Predicate"); + + // Don't expand variants if the processor models don't intersect. + // A zero processor index means any processor. + SmallVector &ProcIndices = TransVec[TransIdx].ProcIndices; + if (ProcIndices[0] != 0 && VarProcModels[VIdx] != 0) { + unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(), + VarProcModels[VIdx]); + if (!Cnt) + continue; + if (Cnt > 1) { + const CodeGenProcModel &PM = + *(SchedModels.procModelBegin() + VarProcModels[VIdx]); + throw TGError(Variants[VIdx]->getLoc(), "Multiple variants defined " + "for processor " + PM.ModelName + + " Ensure only one SchedAlias exists per RW."); + } + } if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm)) continue; - if (IntersectingVariants.empty()) + if (IntersectingVariants.empty()) { // The first variant builds on the existing transition. - IntersectingVariants.push_back(std::make_pair(*VI, TransIdx)); + IntersectingVariants.push_back( + TransVariant(Variants[VIdx], VarRWIds[VIdx], VarProcModels[VIdx], + TransIdx)); + } else { // Push another copy of the current transition for more variants. IntersectingVariants.push_back( - std::make_pair(*VI, TransVec.size())); + TransVariant(Variants[VIdx], VarRWIds[VIdx], VarProcModels[VIdx], + TransVec.size())); TransVec.push_back(TransVec[TransIdx]); } } + if (IntersectingVariants.empty()) + throw TGError(SchedRW.TheDef->getLoc(), "No variant of this type has a " + "matching predicate on any processor "); // Now expand each variant on top of its copy of the transition. - for (std::vector >::const_iterator + for (std::vector::const_iterator IVI = IntersectingVariants.begin(), IVE = IntersectingVariants.end(); - IVI != IVE; ++IVI) - pushVariant(*RWI, IVI->first, TransVec[IVI->second], IsRead); + IVI != IVE; ++IVI) { + pushVariant(*IVI, IsRead); + } } } } @@ -952,6 +1087,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { unsigned StartIdx = TransVec.size(); TransVec.resize(TransVec.size() + 1); TransVec.back().PredTerm = Trans.PredTerm; + TransVec.back().ProcIndices = Trans.ProcIndices; // Visit each original write sequence. for (SmallVectorImpl >::const_iterator @@ -977,37 +1113,9 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { } } -static bool hasVariant(ArrayRef Transitions, - CodeGenSchedModels &SchedModels) { - for (ArrayRef::iterator - PTI = Transitions.begin(), PTE = Transitions.end(); - PTI != PTE; ++PTI) { - for (SmallVectorImpl >::const_iterator - WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end(); - WSI != WSE; ++WSI) { - for (SmallVectorImpl::const_iterator - WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { - if (SchedModels.getSchedWrite(*WI).HasVariants) - return true; - } - } - for (SmallVectorImpl >::const_iterator - RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end(); - RSI != RSE; ++RSI) { - for (SmallVectorImpl::const_iterator - RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) { - if (SchedModels.getSchedRead(*RI).HasVariants) - return true; - } - } - } - return false; -} - // Create a new SchedClass for each variant found by inferFromRW. Pass -// ProcIndices by copy to avoid referencing anything from SchedClasses. static void inferFromTransitions(ArrayRef LastTransitions, - unsigned FromClassIdx, IdxVec ProcIndices, + unsigned FromClassIdx, CodeGenSchedModels &SchedModels) { // For each PredTransition, create a new CodeGenSchedTransition, which usually // requires creating a new SchedClass. @@ -1025,10 +1133,11 @@ static void inferFromTransitions(ArrayRef LastTransitions, for (SmallVectorImpl >::const_iterator RSI = I->ReadSequences.begin(), RSE = I->ReadSequences.end(); RSI != RSE; ++RSI) { - // Create a new write representing the expanded sequence. + // Create a new read representing the expanded sequence. OperReadsVariant.push_back( SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true)); } + IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); CodeGenSchedTransition SCTrans; SCTrans.ToClassIdx = SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant, @@ -1047,18 +1156,22 @@ static void inferFromTransitions(ArrayRef LastTransitions, } } -/// Find each variant write that OperWrites or OperaReads refers to and create a -/// new SchedClass for each variant. +// Create new SchedClasses for the given ReadWrite list. If any of the +// ReadWrites refers to a SchedVariant, create a new SchedClass for each variant +// of the ReadWrite list, following Aliases if necessary. void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites, const IdxVec &OperReads, unsigned FromClassIdx, const IdxVec &ProcIndices) { - DEBUG(dbgs() << "INFERRW Writes: "); + DEBUG(dbgs() << "INFER RW: "); // Create a seed transition with an empty PredTerm and the expanded sequences // of SchedWrites for the current SchedClass. std::vector LastTransitions; LastTransitions.resize(1); + LastTransitions.back().ProcIndices.append(ProcIndices.begin(), + ProcIndices.end()); + for (IdxIter I = OperWrites.begin(), E = OperWrites.end(); I != E; ++I) { IdxVec WriteSeq; expandRWSequence(*I, WriteSeq, /*IsRead=*/false); @@ -1100,7 +1213,7 @@ void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites, // WARNING: We are about to mutate the SchedClasses vector. Do not refer to // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions. - inferFromTransitions(LastTransitions, FromClassIdx, ProcIndices, *this); + inferFromTransitions(LastTransitions, FromClassIdx, *this); } // Collect and sort WriteRes, ReadAdvance, and ProcResources. @@ -1200,6 +1313,15 @@ void CodeGenSchedModels::collectRWResources(const IdxVec &Writes, addWriteRes(SchedRW.TheDef, *PI); } } + for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef && AliasRW.TheDef->isSubClassOf("SchedWriteRes")) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + addWriteRes(AliasRW.TheDef, getProcModel(ModelDef).Index); + } + } } for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) { const CodeGenSchedRW &SchedRW = getSchedRW(*RI, /*IsRead=*/true); @@ -1209,6 +1331,15 @@ void CodeGenSchedModels::collectRWResources(const IdxVec &Writes, addReadAdvance(SchedRW.TheDef, *PI); } } + for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef && AliasRW.TheDef->isSubClassOf("SchedReadAdvance")) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + addReadAdvance(AliasRW.TheDef, getProcModel(ModelDef).Index); + } + } } } @@ -1265,6 +1396,8 @@ void CodeGenSchedModels::addProcResource(Record *ProcResKind, // Add resources for a SchedWrite to this processor if they don't exist. void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) { + assert(PIdx && "don't add resources to an invalid Processor model"); + RecVec &WRDefs = ProcModels[PIdx].WriteResDefs; RecIter WRI = std::find(WRDefs.begin(), WRDefs.end(), ProcWriteResDef); if (WRI != WRDefs.end()) diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index ec556c26672..226c3aed5c4 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -45,14 +45,16 @@ void splitSchedReadWrites(const RecVec &RWDefs, struct CodeGenSchedRW { std::string Name; Record *TheDef; + bool IsAlias; bool HasVariants; bool IsVariadic; bool IsSequence; IdxVec Sequence; + RecVec Aliases; - CodeGenSchedRW(): TheDef(0), HasVariants(false), IsVariadic(false), - IsSequence(false) {} - CodeGenSchedRW(Record *Def): TheDef(Def), IsVariadic(false) { + CodeGenSchedRW(): TheDef(0), IsAlias(false), HasVariants(false), + IsVariadic(false), IsSequence(false) {} + CodeGenSchedRW(Record *Def): TheDef(Def), IsAlias(false), IsVariadic(false) { Name = Def->getName(); HasVariants = Def->isSubClassOf("SchedVariant"); if (HasVariants) @@ -65,8 +67,8 @@ struct CodeGenSchedRW { } CodeGenSchedRW(const IdxVec &Seq, const std::string &Name): - Name(Name), TheDef(0), HasVariants(false), IsVariadic(false), - IsSequence(true), Sequence(Seq) { + Name(Name), TheDef(0), IsAlias(false), HasVariants(false), + IsVariadic(false), IsSequence(true), Sequence(Seq) { assert(Sequence.size() > 1 && "implied sequence needs >1 RWs"); } @@ -75,6 +77,7 @@ struct CodeGenSchedRW { assert((!IsVariadic || HasVariants) && "Variadic write needs variants"); assert((!IsSequence || !HasVariants) && "Sequence can't have variant"); assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty"); + assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases"); return TheDef || !Sequence.empty(); } @@ -125,8 +128,10 @@ struct CodeGenSchedClass { std::vector Transitions; - // InstReadWrite records associated with this class. Any Instrs that the - // definitions refer to that are not mapped to this class should be ignored. + // InstRW records associated with this class. These records may refer to an + // Instruction no longer mapped to this class by InstrClassMap. These + // Instructions should be ignored by this class because they have been split + // off to join another inferred class. RecVec InstRWs; CodeGenSchedClass(): ItinClassDef(0) {} @@ -229,7 +234,7 @@ class CodeGenSchedModels { unsigned NumInstrSchedClasses; // Map Instruction to SchedClass index. Only for Instructions mentioned in - // OpReadWrites. + // InstRW records. typedef DenseMap InstClassMapTy; InstClassMapTy InstrClassMap; @@ -281,6 +286,16 @@ public: const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const { return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx); } + CodeGenSchedRW &getSchedRW(Record *Def, unsigned &Idx) { + bool IsRead = Def->isSubClassOf("SchedRead"); + Idx = getSchedRWIdx(Def, IsRead); + return const_cast( + IsRead ? getSchedRead(Idx) : getSchedWrite(Idx)); + } + CodeGenSchedRW &getSchedRW(Record *Def) { + unsigned Idx; + return getSchedRW(Def, Idx); + } unsigned getSchedRWIdx(Record *Def, bool IsRead, unsigned After = 0) const; diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index e7dc983b6c8..4127b379b15 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -81,9 +81,10 @@ class SubtargetEmitter { char Separator); void EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS); - Record *FindWriteResources(Record *WriteDef, + Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel); - Record *FindReadAdvance(Record *ReadDef, const CodeGenProcModel &ProcModel); + Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, + const CodeGenProcModel &ProcModel); void GenSchedClassTables(const CodeGenProcModel &ProcModel, SchedClassTables &SchedTables); void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); @@ -654,48 +655,107 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, // Find the WriteRes Record that defines processor resources for this // SchedWrite. Record *SubtargetEmitter::FindWriteResources( - Record *WriteDef, const CodeGenProcModel &ProcModel) { + const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { // Check if the SchedWrite is already subtarget-specific and directly // specifies a set of processor resources. - if (WriteDef->isSubClassOf("SchedWriteRes")) - return WriteDef; + if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) + return SchedWrite.TheDef; + + // Check this processor's list of aliases for SchedWrite. + Record *AliasDef = 0; + for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + if (AliasDef) + throw TGError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) + return AliasDef; // Check this processor's list of write resources. + Record *ResDef = 0; for (RecIter WRI = ProcModel.WriteResDefs.begin(), WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { if (!(*WRI)->isSubClassOf("WriteRes")) continue; - if (WriteDef == (*WRI)->getValueAsDef("WriteType")) - return *WRI; + if (AliasDef == (*WRI)->getValueAsDef("WriteType") + || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { + if (ResDef) { + throw TGError((*WRI)->getLoc(), "Resources are defined for both " + "SchedWrite and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *WRI; + } } - throw TGError(ProcModel.ModelDef->getLoc(), - std::string("Processor does not define resources for ") - + WriteDef->getName()); + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindWriteResources recursively with that model here. + if (!ResDef) { + throw TGError(ProcModel.ModelDef->getLoc(), + std::string("Processor does not define resources for ") + + SchedWrite.TheDef->getName()); + } + return ResDef; } /// Find the ReadAdvance record for the given SchedRead on this processor or /// return NULL. -Record *SubtargetEmitter::FindReadAdvance(Record *ReadDef, +Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, const CodeGenProcModel &ProcModel) { // Check for SchedReads that directly specify a ReadAdvance. - if (ReadDef->isSubClassOf("SchedReadAdvance")) - return ReadDef; + if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) + return SchedRead.TheDef; + + // Check this processor's list of aliases for SchedRead. + Record *AliasDef = 0; + for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + if (AliasDef) + throw TGError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) + return AliasDef; // Check this processor's ReadAdvanceList. + Record *ResDef = 0; for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { if (!(*RAI)->isSubClassOf("ReadAdvance")) continue; - if (ReadDef == (*RAI)->getValueAsDef("ReadType")) - return *RAI; + if (AliasDef == (*RAI)->getValueAsDef("ReadType") + || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { + if (ResDef) { + throw TGError((*RAI)->getLoc(), "Resources are defined for both " + "SchedRead and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *RAI; + } } - if (ReadDef->getName() != "ReadDefault") { + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindReadAdvance recursively with that model here. + if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { throw TGError(ProcModel.ModelDef->getLoc(), std::string("Processor does not define resources for ") - + ReadDef->getName()); + + SchedRead.TheDef->getName()); } - return NULL; + return ResDef; } // Generate the SchedClass table for this processor and update global @@ -797,8 +857,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); WSI != WSE; ++WSI) { - Record *WriteDef = SchedModels.getSchedWrite(*WSI).TheDef; - Record *WriteRes = FindWriteResources(WriteDef, ProcModel); + Record *WriteRes = + FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); // Mark the parent class as invalid for unsupported write types. if (WriteRes->getValueAsBit("Unsupported")) { @@ -832,8 +892,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // Entries must be sorted first by UseIdx then by WriteResourceID. for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx; ++UseIdx) { - Record *ReadDef = SchedModels.getSchedRead(Reads[UseIdx]).TheDef; - Record *ReadAdvance = FindReadAdvance(ReadDef, ProcModel); + Record *ReadAdvance = + FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); if (!ReadAdvance) continue; -- 2.34.1