diff options
Diffstat (limited to 'utils/TableGen')
-rw-r--r-- | utils/TableGen/CodeGenDAGPatterns.cpp | 82 | ||||
-rw-r--r-- | utils/TableGen/CodeGenDAGPatterns.h | 7 | ||||
-rw-r--r-- | utils/TableGen/CodeGenRegisters.h | 4 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.cpp | 255 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.h | 67 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.h | 6 | ||||
-rw-r--r-- | utils/TableGen/RegisterInfoEmitter.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/SubtargetEmitter.cpp | 182 | ||||
-rw-r--r-- | utils/TableGen/X86RecognizableInstr.cpp | 11 |
10 files changed, 348 insertions, 270 deletions
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 72fb771..0090706 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -57,7 +57,7 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { } -EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) { +EEVT::TypeSet::TypeSet(ArrayRef<MVT::SimpleValueType> VTList) { assert(!VTList.empty() && "empty list?"); TypeVec.append(VTList.begin(), VTList.end()); @@ -76,7 +76,7 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP, bool (*Pred)(MVT::SimpleValueType), const char *PredicateName) { assert(isCompletelyUnknown()); - const std::vector<MVT::SimpleValueType> &LegalTypes = + ArrayRef<MVT::SimpleValueType> LegalTypes = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); if (TP.hasError()) @@ -956,6 +956,40 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, llvm_unreachable("Invalid ConstraintType!"); } +// Update the node type to match an instruction operand or result as specified +// in the ins or outs lists on the instruction definition. Return true if the +// type was actually changed. +bool TreePatternNode::UpdateNodeTypeFromInst(unsigned ResNo, + Record *Operand, + TreePattern &TP) { + // The 'unknown' operand indicates that types should be inferred from the + // context. + if (Operand->isSubClassOf("unknown_class")) + return false; + + // The Operand class specifies a type directly. + if (Operand->isSubClassOf("Operand")) + return UpdateNodeType(ResNo, getValueType(Operand->getValueAsDef("Type")), + TP); + + // PointerLikeRegClass has a type that is determined at runtime. + if (Operand->isSubClassOf("PointerLikeRegClass")) + return UpdateNodeType(ResNo, MVT::iPTR, TP); + + // Both RegisterClass and RegisterOperand operands derive their types from a + // register class def. + Record *RC = 0; + if (Operand->isSubClassOf("RegisterClass")) + RC = Operand; + else if (Operand->isSubClassOf("RegisterOperand")) + RC = Operand->getValueAsDef("RegClass"); + + assert(RC && "Unknown operand type"); + CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo(); + return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP); +} + + //===----------------------------------------------------------------------===// // SDNodeInfo implementation // @@ -1575,26 +1609,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // (outs) list of the instruction. // FIXME: Cap at one result so far. unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; - for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) { - Record *ResultNode = Inst.getResult(ResNo); - - if (ResultNode->isSubClassOf("PointerLikeRegClass")) { - MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP); - } else if (ResultNode->isSubClassOf("RegisterOperand")) { - Record *RegClass = ResultNode->getValueAsDef("RegClass"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(RegClass); - MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); - } else if (ResultNode->isSubClassOf("unknown_class")) { - // Nothing to do. - } else { - assert(ResultNode->isSubClassOf("RegisterClass") && - "Operands should be register classes!"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(ResultNode); - MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); - } - } + for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) + MadeChange |= UpdateNodeTypeFromInst(ResNo, Inst.getResult(ResNo), TP); // If the instruction has implicit defs, we apply the first one as a result. // FIXME: This sucks, it should apply all implicit defs. @@ -1636,29 +1652,9 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return false; } - MVT::SimpleValueType VT; TreePatternNode *Child = getChild(ChildNo++); unsigned ChildResNo = 0; // Instructions always use res #0 of their op. - - if (OperandNode->isSubClassOf("RegisterClass")) { - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(OperandNode); - MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP); - } else if (OperandNode->isSubClassOf("RegisterOperand")) { - Record *RegClass = OperandNode->getValueAsDef("RegClass"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(RegClass); - MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP); - } else if (OperandNode->isSubClassOf("Operand")) { - VT = getValueType(OperandNode->getValueAsDef("Type")); - MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP); - } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { - MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP); - } else if (OperandNode->isSubClassOf("unknown_class")) { - // Nothing to do. - } else - llvm_unreachable("Unknown operand type!"); - + MadeChange |= Child->UpdateNodeTypeFromInst(ChildResNo, OperandNode, TP); MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); } diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 424f02f..6190798 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -59,7 +59,7 @@ namespace EEVT { public: TypeSet() {} TypeSet(MVT::SimpleValueType VT, TreePattern &TP); - TypeSet(const std::vector<MVT::SimpleValueType> &VTList); + TypeSet(ArrayRef<MVT::SimpleValueType> VTList); bool isCompletelyUnknown() const { return TypeVec.empty(); } @@ -463,6 +463,11 @@ public: // Higher level manipulation routines. return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP); } + // Update node type with types inferred from an instruction operand or result + // def from the ins/outs lists. + // Return true if the type changed. + bool UpdateNodeTypeFromInst(unsigned ResNo, Record *Operand, TreePattern &TP); + /// ContainsUnresolvedType - Return true if this tree contains any /// unresolved types. bool ContainsUnresolvedType() const { diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index a1921a4..4f2cc28 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -261,7 +261,7 @@ namespace llvm { public: unsigned EnumValue; std::string Namespace; - std::vector<MVT::SimpleValueType> VTs; + SmallVector<MVT::SimpleValueType, 4> VTs; unsigned SpillSize; unsigned SpillAlignment; int CopyCost; @@ -274,7 +274,7 @@ namespace llvm { const std::string &getName() const { return Name; } std::string getQualifiedName() const; - const std::vector<MVT::SimpleValueType> &getValueTypes() const {return VTs;} + ArrayRef<MVT::SimpleValueType> getValueTypes() const {return VTs;} unsigned getNumValueTypes() const { return VTs.size(); } MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const { diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 23b79fc..227019d 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -88,7 +88,7 @@ struct InstRegexOp : public SetTheory::Operator { /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT): - Records(RK), Target(TGT), NumItineraryClasses(0) { + Records(RK), Target(TGT) { Sets.addFieldExpander("InstRW", "Instrs"); @@ -217,7 +217,7 @@ void CodeGenSchedModels::collectSchedRW() { for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { Record *SchedDef = (*I)->TheDef; - if (!SchedDef->isSubClassOf("Sched")) + if (SchedDef->isValueUnset("SchedRW")) continue; RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW"); for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) { @@ -502,40 +502,25 @@ void CodeGenSchedModels::collectSchedClasses() { // NoItinerary is always the first class at Idx=0 SchedClasses.resize(1); - SchedClasses.back().Name = "NoItinerary"; + SchedClasses.back().Index = 0; + SchedClasses.back().Name = "NoInstrModel"; + SchedClasses.back().ItinClassDef = Records.getDef("NoItinerary"); SchedClasses.back().ProcIndices.push_back(0); - SchedClassIdxMap[SchedClasses.back().Name] = 0; - // Gather and sort all itinerary classes used by instruction descriptions. - RecVec ItinClassList; + // Create a SchedClass for each unique combination of itinerary class and + // SchedRW list. for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary"); - // Map a new SchedClass with no index. - if (!SchedClassIdxMap.count(ItinDef->getName())) { - SchedClassIdxMap[ItinDef->getName()] = 0; - ItinClassList.push_back(ItinDef); - } - } - // Assign each itinerary class unique number, skipping NoItinerary==0 - NumItineraryClasses = ItinClassList.size(); - std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); - for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) { - Record *ItinDef = ItinClassList[i]; - SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size(); - SchedClasses.push_back(CodeGenSchedClass(ItinDef)); - } - // Infer classes from SchedReadWrite resources listed for each - // instruction definition that inherits from class Sched. - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - if (!(*I)->TheDef->isSubClassOf("Sched")) - continue; IdxVec Writes, Reads; - findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + if (!(*I)->TheDef->isValueUnset("SchedRW")) + findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + // ProcIdx == 0 indicates the class applies to all processors. IdxVec ProcIndices(1, 0); - addSchedClass(Writes, Reads, ProcIndices); + + unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices); + InstrClassMap[(*I)->TheDef] = SCIdx; } // Create classes for InstRW defs. RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); @@ -549,68 +534,70 @@ void CodeGenSchedModels::collectSchedClasses() { DEBUG(EnableDump = true); if (!EnableDump) return; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { - Record *SchedDef = (*I)->TheDef; + std::string InstName = (*I)->TheDef->getName(); - if (SchedDef->isSubClassOf("Sched")) { + unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); + if (!SCIdx) { + dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; + continue; + } + CodeGenSchedClass &SC = getSchedClass(SCIdx); + if (SC.ProcIndices[0] != 0) + PrintFatalError((*I)->TheDef->getLoc(), "Instruction's sched class " + "must not be subtarget specific."); + + IdxVec ProcIndices; + if (SC.ItinClassDef->getName() != "NoItinerary") { + ProcIndices.push_back(0); + dbgs() << "Itinerary for " << InstName << ": " + << SC.ItinClassDef->getName() << '\n'; + } + if (!SC.Writes.empty()) { + ProcIndices.push_back(0); + dbgs() << "SchedRW machine model for " << InstName; + for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI) + dbgs() << " " << SchedWrites[*WI].Name; + for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI) + dbgs() << " " << SchedReads[*RI].Name; + dbgs() << '\n'; + } + const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); + RWI != RWE; ++RWI) { + const CodeGenProcModel &ProcModel = + getProcModel((*RWI)->getValueAsDef("SchedModel")); + ProcIndices.push_back(ProcModel.Index); + dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; IdxVec Writes; IdxVec Reads; - findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); - dbgs() << "SchedRW machine model for " << InstName; + findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) dbgs() << " " << SchedWrites[*WI].Name; for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) dbgs() << " " << SchedReads[*RI].Name; dbgs() << '\n'; } - unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); - if (SCIdx) { - const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; - for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); - RWI != RWE; ++RWI) { - const CodeGenProcModel &ProcModel = - getProcModel((*RWI)->getValueAsDef("SchedModel")); - dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; - IdxVec Writes; - IdxVec Reads; - findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) - dbgs() << " " << SchedWrites[*WI].Name; - for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) - dbgs() << " " << SchedReads[*RI].Name; - dbgs() << '\n'; - } - continue; - } - if (!SchedDef->isSubClassOf("Sched") - && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) { - dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; + for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), + PE = ProcModels.end(); PI != PE; ++PI) { + if (!std::count(ProcIndices.begin(), ProcIndices.end(), PI->Index)) + dbgs() << "No machine model for " << (*I)->TheDef->getName() + << " on processor " << PI->ModelName << '\n'; } } } -unsigned CodeGenSchedModels::getSchedClassIdx( - const RecVec &RWDefs) const { - - IdxVec Writes, Reads; - findRWs(RWDefs, Writes, Reads); - return findSchedClassIdx(Writes, Reads); -} - /// Find an SchedClass that has been inferred from a per-operand list of /// SchedWrites and SchedReads. -unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, +unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef, + const IdxVec &Writes, const IdxVec &Reads) const { for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { - // Classes with InstRWs may have the same Writes/Reads as a class originally - // produced by a SchedRW definition. We need to be able to recover the - // original class index for processors that don't match any InstRWs. - if (I->ItinClassDef || !I->InstRWs.empty()) - continue; - - if (I->Writes == Writes && I->Reads == Reads) { + if (I->ItinClassDef == ItinClassDef + && I->Writes == Writes && I->Reads == Reads) { return I - schedClassBegin(); } } @@ -621,29 +608,17 @@ unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, unsigned CodeGenSchedModels::getSchedClassIdx( const CodeGenInstruction &Inst) const { - unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef); - if (SCIdx) - return SCIdx; - - // If this opcode isn't mapped by the subtarget fallback to the instruction - // definition's SchedRW or ItinDef values. - if (Inst.TheDef->isSubClassOf("Sched")) { - RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW"); - return getSchedClassIdx(RWs); - } - Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); - assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); - unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); - assert(Idx <= NumItineraryClasses && "bad ItinClass index"); - return Idx; + return InstrClassMap.lookup(Inst.TheDef); } std::string CodeGenSchedModels::createSchedClassName( - const IdxVec &OperWrites, const IdxVec &OperReads) { + Record *ItinClassDef, const IdxVec &OperWrites, const IdxVec &OperReads) { std::string Name; + if (ItinClassDef && ItinClassDef->getName() != "NoItinerary") + Name = ItinClassDef->getName(); for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) { - if (WI != OperWrites.begin()) + if (!Name.empty()) Name += '_'; Name += SchedWrites[*WI].Name; } @@ -665,17 +640,18 @@ std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) { return Name; } -/// Add an inferred sched class from a per-operand list of SchedWrites and -/// SchedReads. ProcIndices contains the set of IDs of processors that may -/// utilize this class. -unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, +/// Add an inferred sched class from an itinerary class and per-operand list of +/// SchedWrites and SchedReads. ProcIndices contains the set of IDs of +/// processors that may utilize this class. +unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef, + const IdxVec &OperWrites, const IdxVec &OperReads, const IdxVec &ProcIndices) { assert(!ProcIndices.empty() && "expect at least one ProcIdx"); - unsigned Idx = findSchedClassIdx(OperWrites, OperReads); - if (Idx) { + unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads); + if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) { IdxVec PI; std::set_union(SchedClasses[Idx].ProcIndices.begin(), SchedClasses[Idx].ProcIndices.end(), @@ -687,7 +663,9 @@ unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, Idx = SchedClasses.size(); SchedClasses.resize(Idx+1); CodeGenSchedClass &SC = SchedClasses.back(); - SC.Name = createSchedClassName(OperWrites, OperReads); + SC.Index = Idx; + SC.Name = createSchedClassName(ItinClassDef, OperWrites, OperReads); + SC.ItinClassDef = ItinClassDef; SC.Writes = OperWrites; SC.Reads = OperReads; SC.ProcIndices = ProcIndices; @@ -709,19 +687,10 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) { - unsigned SCIdx = 0; InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I); - if (Pos != InstrClassMap.end()) - SCIdx = Pos->second; - else { - // This instruction has not been mapped yet. Get the original class. All - // instructions in the same InstrRW class must be from the same original - // class because that is the fall-back class for other processors. - Record *ItinDef = (*I)->getValueAsDef("Itinerary"); - SCIdx = SchedClassIdxMap.lookup(ItinDef->getName()); - if (!SCIdx && (*I)->isSubClassOf("Sched")) - SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW")); - } + if (Pos == InstrClassMap.end()) + PrintFatalError((*I)->getLoc(), "No sched class for instruction."); + unsigned SCIdx = Pos->second; unsigned CIdx = 0, CEnd = ClassInstrs.size(); for (; CIdx != CEnd; ++CIdx) { if (ClassInstrs[CIdx].first == SCIdx) @@ -741,7 +710,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; // If the all instrs in the current class are accounted for, then leave // them mapped to their old class. - if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { + if (OldSCIdx && SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && "expected a generic SchedClass"); continue; @@ -749,6 +718,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { unsigned SCIdx = SchedClasses.size(); SchedClasses.resize(SCIdx+1); CodeGenSchedClass &SC = SchedClasses.back(); + SC.Index = SCIdx; SC.Name = createSchedClassName(InstDefs); // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; @@ -780,32 +750,48 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { } } +// True if collectProcItins found anything. +bool CodeGenSchedModels::hasItineraries() const { + for (CodeGenSchedModels::ProcIter PI = procModelBegin(), PE = procModelEnd(); + PI != PE; ++PI) { + if (PI->hasItineraries()) + return true; + } + return false; +} + // Gather the processor itineraries. void CodeGenSchedModels::collectProcItins() { for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), PE = ProcModels.end(); PI != PE; ++PI) { CodeGenProcModel &ProcModel = *PI; - RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); - // Skip empty itinerary. - if (ItinRecords.empty()) + if (!ProcModel.hasItineraries()) continue; - ProcModel.ItinDefList.resize(NumItineraryClasses+1); + RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); + assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect"); + + // Populate ItinDefList with Itinerary records. + ProcModel.ItinDefList.resize(NumInstrSchedClasses); // Insert each itinerary data record in the correct position within // the processor model's ItinDefList. for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { Record *ItinData = ItinRecords[i]; Record *ItinDef = ItinData->getValueAsDef("TheClass"); - if (!SchedClassIdxMap.count(ItinDef->getName())) { + bool FoundClass = false; + for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd(); + SCI != SCE; ++SCI) { + // Multiple SchedClasses may share an itinerary. Update all of them. + if (SCI->ItinClassDef == ItinDef) { + ProcModel.ItinDefList[SCI->Index] = ItinData; + FoundClass = true; + } + } + if (!FoundClass) { DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " has unused itinerary class " << ItinDef->getName() << '\n'); - continue; + << " missing class for itinerary " << ItinDef->getName() << '\n'); } - assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); - unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); - assert(Idx <= NumItineraryClasses && "bad ItinClass index"); - ProcModel.ItinDefList[Idx] = ItinData; } // Check for missing itinerary entries. assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); @@ -839,13 +825,17 @@ void CodeGenSchedModels::collectProcItinRW() { /// Infer new classes from existing classes. In the process, this may create new /// SchedWrites from sequences of existing SchedWrites. void CodeGenSchedModels::inferSchedClasses() { + DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); + // Visit all existing classes and newly created classes. for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { + assert(SchedClasses[Idx].Index == Idx && "bad SCIdx"); + if (SchedClasses[Idx].ItinClassDef) inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); - else if (!SchedClasses[Idx].InstRWs.empty()) + if (!SchedClasses[Idx].InstRWs.empty()) inferFromInstRWs(Idx); - else { + if (!SchedClasses[Idx].Writes.empty()) { inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, Idx, SchedClasses[Idx].ProcIndices); } @@ -1295,8 +1285,8 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); CodeGenSchedTransition SCTrans; SCTrans.ToClassIdx = - SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant, - ProcIndices); + SchedModels.addSchedClass(/*ItinClassDef=*/0, OperWritesVariant, + OperReadsVariant, ProcIndices); SCTrans.ProcIndices = ProcIndices; // The final PredTerm is unique set of predicates guarding the transition. RecVec Preds; @@ -1542,6 +1532,20 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, ProcUnitDef = *RI; } } + RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); + for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end(); + RI != RE; ++RI) { + + if (*RI == ProcResKind + && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) { + if (ProcUnitDef) { + PrintFatalError((*RI)->getLoc(), + "Multiple ProcessorResourceUnits associated with " + + ProcResKind->getName()); + } + ProcUnitDef = *RI; + } + } if (!ProcUnitDef) { PrintFatalError(ProcResKind->getLoc(), "No ProcessorResources associated with " @@ -1563,6 +1567,9 @@ void CodeGenSchedModels::addProcResource(Record *ProcResKind, return; PM.ProcResourceDefs.push_back(ProcResUnits); + if (ProcResUnits->isSubClassOf("ProcResGroup")) + return; + if (!ProcResUnits->getValueInit("Super")->isComplete()) return; @@ -1625,7 +1632,7 @@ void CodeGenSchedRW::dump() const { } void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { - dbgs() << "SCHEDCLASS " << Name << '\n' + dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n' << " Writes: "; for (unsigned i = 0, N = Writes.size(); i < N; ++i) { SchedModels->getSchedWrite(Writes[i]).dump(); diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 78f115e..e5b9118 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -125,6 +125,7 @@ struct CodeGenSchedTransition { /// itinerary class. Each inherits the processor index from the ItinRW record /// that mapped the itinerary class to the variant Writes or Reads. struct CodeGenSchedClass { + unsigned Index; std::string Name; Record *ItinClassDef; @@ -141,12 +142,16 @@ struct CodeGenSchedClass { // off to join another inferred class. RecVec InstRWs; - CodeGenSchedClass(): ItinClassDef(0) {} - CodeGenSchedClass(Record *rec): ItinClassDef(rec) { - Name = rec->getName(); - ProcIndices.push_back(0); + CodeGenSchedClass(): Index(0), ItinClassDef(0) {} + + bool isKeyEqual(Record *IC, const IdxVec &W, const IdxVec &R) { + return ItinClassDef == IC && Writes == W && Reads == R; } + // Is this class generated from a variants if existing classes? Instructions + // are never mapped directly to inferred scheduling classes. + bool isInferred() const { return !ItinClassDef; } + #ifndef NDEBUG void dump(const CodeGenSchedModels *SchedModels) const; #endif @@ -189,11 +194,16 @@ struct CodeGenProcModel { // Per-operand machine model resources associated with this processor. RecVec ProcResourceDefs; + RecVec ProcResGroupDefs; CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef, Record *IDef) : Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} + bool hasItineraries() const { + return !ItinsDef->getValueAsListOfDefs("IID").empty(); + } + bool hasInstrSchedModel() const { return !WriteResDefs.empty() || !ItinRWDefs.empty(); } @@ -227,24 +237,11 @@ class CodeGenSchedModels { // List of unique SchedClasses. std::vector<CodeGenSchedClass> SchedClasses; - // Map SchedClass name to itinerary index. - // These are either explicit itinerary classes or classes implied by - // instruction definitions with SchedReadWrite lists. - StringMap<unsigned> SchedClassIdxMap; - - // SchedClass indices 1 up to and including NumItineraryClasses identify - // itinerary classes that are explicitly used for this target's instruction - // definitions. NoItinerary always has index 0 regardless of whether it is - // explicitly referenced. - // - // Any implied SchedClass has an index greater than NumItineraryClasses. - unsigned NumItineraryClasses; - // Any inferred SchedClass has an index greater than NumInstrSchedClassses. unsigned NumInstrSchedClasses; - // Map Instruction to SchedClass index. Only for Instructions mentioned in - // InstRW records. + // Map each instruction to its unique SchedClass index considering the + // combination of it's itinerary class, SchedRW list, and InstRW records. typedef DenseMap<Record*, unsigned> InstClassMapTy; InstClassMapTy InstrClassMap; @@ -280,6 +277,9 @@ public: ProcIter procModelBegin() const { return ProcModels.begin(); } ProcIter procModelEnd() const { return ProcModels.end(); } + // Return true if any processors have itineraries. + bool hasItineraries() const; + // Get a SchedWrite from its index. const CodeGenSchedRW &getSchedWrite(unsigned Idx) const { assert(Idx < SchedWrites.size() && "bad SchedWrite index"); @@ -311,16 +311,6 @@ public: // Return true if the given write record is referenced by a ReadAdvance. bool hasReadOfWrite(Record *WriteDef) const; - // Check if any instructions are assigned to an explicit itinerary class other - // than NoItinerary. - bool hasItineraryClasses() const { return NumItineraryClasses > 0; } - - // Return the number of itinerary classes in use by this target's instruction - // descriptions, not including "NoItinerary". - unsigned numItineraryClasses() const { - return NumItineraryClasses; - } - // Get a SchedClass from its index. CodeGenSchedClass &getSchedClass(unsigned Idx) { assert(Idx < SchedClasses.size() && "bad SchedClass index"); @@ -336,28 +326,26 @@ public: // for NoItinerary. unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const; - unsigned getSchedClassIdx(const RecVec &RWDefs) const; - - unsigned getSchedClassIdxForItin(const Record *ItinDef) { - return SchedClassIdxMap[ItinDef->getName()]; - } - typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter; SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } SchedClassIter schedClassEnd() const { return SchedClasses.end(); } + unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; } + void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const; void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const; void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const; void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead, const CodeGenProcModel &ProcModel) const; - unsigned addSchedClass(const IdxVec &OperWrites, const IdxVec &OperReads, - const IdxVec &ProcIndices); + unsigned addSchedClass(Record *ItinDef, const IdxVec &OperWrites, + const IdxVec &OperReads, const IdxVec &ProcIndices); unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); - unsigned findSchedClassIdx(const IdxVec &Writes, const IdxVec &Reads) const; + unsigned findSchedClassIdx(Record *ItinClassDef, + const IdxVec &Writes, + const IdxVec &Reads) const; Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM) const; @@ -375,7 +363,8 @@ private: void collectSchedClasses(); - std::string createSchedClassName(const IdxVec &OperWrites, + std::string createSchedClassName(Record *ItinClassDef, + const IdxVec &OperWrites, const IdxVec &OperReads); std::string createSchedClassName(const RecVec &InstDefs); void createInstRWClass(Record *InstRWDef); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index dd3f6e2..8b292b9 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -229,7 +229,7 @@ getRegisterVTs(Record *R) const { for (unsigned i = 0, e = RCs.size(); i != e; ++i) { const CodeGenRegisterClass &RC = *RCs[i]; if (RC.contains(Reg)) { - const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes(); + ArrayRef<MVT::SimpleValueType> InVTs = RC.getValueTypes(); Result.insert(Result.end(), InVTs.begin(), InVTs.end()); } } diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 4a1c6d8..6271443 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -68,7 +68,7 @@ class CodeGenTarget { mutable DenseMap<const Record*, CodeGenInstruction*> Instructions; mutable CodeGenRegBank *RegBank; mutable std::vector<Record*> RegAltNameIndices; - mutable std::vector<MVT::SimpleValueType> LegalValueTypes; + mutable SmallVector<MVT::SimpleValueType, 8> LegalValueTypes; void ReadRegAltNameIndices() const; void ReadInstructions() const; void ReadLegalValueTypes() const; @@ -129,7 +129,7 @@ public: /// specified physical register. std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const; - const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const { + ArrayRef<MVT::SimpleValueType> getLegalValueTypes() const { if (LegalValueTypes.empty()) ReadLegalValueTypes(); return LegalValueTypes; } @@ -137,7 +137,7 @@ public: /// isLegalValueType - Return true if the specified value type is natively /// supported by the target (i.e. there are registers that directly hold it). bool isLegalValueType(MVT::SimpleValueType VT) const { - const std::vector<MVT::SimpleValueType> &LegalVTs = getLegalValueTypes(); + ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes(); for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i) if (LegalVTs[i] == VT) return true; return false; diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index cf22511..1b5d90b 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -1031,7 +1031,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } // Build a shared array of value types. - SequenceToOffsetTable<std::vector<MVT::SimpleValueType> > VTSeqs; + SequenceToOffsetTable<SmallVector<MVT::SimpleValueType, 4> > VTSeqs; for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) VTSeqs.add(RegisterClasses[rc]->VTs); VTSeqs.layout(); diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index fc8d00d..5fb811e 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -87,6 +87,8 @@ class SubtargetEmitter { const CodeGenProcModel &ProcModel); Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, const CodeGenProcModel &ProcModel); + void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, + const CodeGenProcModel &ProcModel); void GenSchedClassTables(const CodeGenProcModel &ProcModel, SchedClassTables &SchedTables); void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); @@ -445,17 +447,15 @@ EmitStageAndOperandCycleData(raw_ostream &OS, // If this processor defines no itineraries, then leave the itinerary list // empty. std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); - if (ProcModel.ItinDefList.empty()) + if (!ProcModel.hasItineraries()) continue; - // Reserve index==0 for NoItinerary. - ItinList.resize(SchedModels.numItineraryClasses()+1); - const std::string &Name = ProcModel.ItinsDef->getName(); - // For each itinerary data - for (unsigned SchedClassIdx = 0, - SchedClassEnd = ProcModel.ItinDefList.size(); + ItinList.resize(SchedModels.numInstrSchedClasses()); + assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); + + for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { // Next itinerary data @@ -631,13 +631,31 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { Record *PRDef = ProcModel.ProcResourceDefs[i]; - // Find the SuperIdx - unsigned SuperIdx = 0; Record *SuperDef = 0; - if (PRDef->getValueInit("Super")->isComplete()) { - SuperDef = - SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), ProcModel); - SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + unsigned SuperIdx = 0; + unsigned NumUnits = 0; + bool IsBuffered = true; + if (PRDef->isSubClassOf("ProcResGroup")) { + RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); + for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); + RUI != RUE; ++RUI) { + if (!NumUnits) + IsBuffered = (*RUI)->getValueAsBit("Buffered"); + else if(IsBuffered != (*RUI)->getValueAsBit("Buffered")) + PrintFatalError(PRDef->getLoc(), + "Mixing buffered and unbuffered resources."); + NumUnits += (*RUI)->getValueAsInt("NumUnits"); + } + } + else { + // Find the SuperIdx + if (PRDef->getValueInit("Super")->isComplete()) { + SuperDef = SchedModels.findProcResUnits( + PRDef->getValueAsDef("Super"), ProcModel); + SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + } + NumUnits = PRDef->getValueAsInt("NumUnits"); + IsBuffered = PRDef->getValueAsBit("Buffered"); } // Emit the ProcResourceDesc if (i+1 == e) @@ -645,8 +663,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; if (PRDef->getName().size() < 15) OS.indent(15 - PRDef->getName().size()); - OS << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx << ", " - << PRDef->getValueAsBit("Buffered") << "}" << Sep << " // #" << i+1; + OS << NumUnits << ", " << SuperIdx << ", " + << IsBuffered << "}" << Sep << " // #" << i+1; if (SuperDef) OS << ", Super=" << SuperDef->getName(); OS << "\n"; @@ -763,6 +781,51 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, return ResDef; } +// Expand an explicit list of processor resources into a full list of implied +// resource groups that cover them. +// +// FIXME: Effectively consider a super-resource a group that include all of its +// subresources to allow mixing and matching super-resources and groups. +// +// FIXME: Warn if two overlapping groups don't have a common supergroup. +void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, + std::vector<int64_t> &Cycles, + const CodeGenProcModel &ProcModel) { + // Default to 1 resource cycle. + Cycles.resize(PRVec.size(), 1); + for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { + RecVec SubResources; + if (PRVec[i]->isSubClassOf("ProcResGroup")) { + SubResources = PRVec[i]->getValueAsListOfDefs("Resources"); + std::sort(SubResources.begin(), SubResources.end(), LessRecord()); + } + else { + SubResources.push_back(PRVec[i]); + } + for (RecIter PRI = ProcModel.ProcResourceDefs.begin(), + PRE = ProcModel.ProcResourceDefs.end(); + PRI != PRE; ++PRI) { + if (*PRI == PRVec[i] || !(*PRI)->isSubClassOf("ProcResGroup")) + continue; + RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); + std::sort(SuperResources.begin(), SuperResources.end(), LessRecord()); + RecIter SubI = SubResources.begin(), SubE = SubResources.end(); + RecIter SuperI = SuperResources.begin(), SuperE = SuperResources.end(); + for ( ; SubI != SubE && SuperI != SuperE; ++SuperI) { + if (*SubI < *SuperI) + break; + else if (*SuperI < *SubI) + continue; + ++SubI; + } + if (SubI == SubE) { + PRVec.push_back(*PRI); + Cycles.push_back(Cycles[i]); + } + } + } +} + // Generate the SchedClass table for this processor and update global // tables. Must be called for each processor in order. void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, @@ -804,27 +867,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } IdxVec Writes = SCI->Writes; IdxVec Reads = SCI->Reads; - if (SCI->ItinClassDef) { - assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs"); - // Check this processor's itinerary class resources. - for (RecIter II = ProcModel.ItinRWDefs.begin(), - IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { - RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); - if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) - != Matched.end()) { - SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - break; - } - } - if (Writes.empty()) { - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " does not have resources for itinerary class " - << SCI->ItinClassDef->getName() << '\n'); - } - } - else if (!SCI->InstRWs.empty()) { - // This class may have a default ReadWrite list which can be overriden by + if (!SCI->InstRWs.empty()) { + // This class has a default ReadWrite list which can be overriden by // InstRW definitions. Record *RWDef = 0; for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); @@ -842,6 +886,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, Writes, Reads); } } + if (Writes.empty()) { + // Check this processor's itinerary class resources. + for (RecIter II = ProcModel.ItinRWDefs.begin(), + IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) + != Matched.end()) { + SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + break; + } + } + if (Writes.empty()) { + DEBUG(dbgs() << ProcModel.ModelName + << " does not have resources for class " << SCI->Name << '\n'); + } + } // Sum resources across all operand writes. std::vector<MCWriteProcResEntry> WriteProcResources; std::vector<MCWriteLatencyEntry> WriteLatencies; @@ -859,7 +920,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); // If this Write is not referenced by a ReadAdvance, don't distinguish it // from other WriteLatency entries. - if (!SchedModels.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) { + if (!SchedModels.hasReadOfWrite( + SchedModels.getSchedWrite(WriteID).TheDef)) { WriteID = 0; } WLEntry.WriteResourceID = WriteID; @@ -884,16 +946,29 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); std::vector<int64_t> Cycles = WriteRes->getValueAsListOfInts("ResourceCycles"); + + ExpandProcResources(PRVec, Cycles, ProcModel); + for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd; ++PRIdx) { MCWriteProcResEntry WPREntry; WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); - if (Cycles.size() > PRIdx) - WPREntry.Cycles = Cycles[PRIdx]; - else - WPREntry.Cycles = 1; - WriteProcResources.push_back(WPREntry); + WPREntry.Cycles = Cycles[PRIdx]; + // If this resource is already used in this sequence, add the current + // entry's cycles so that the same resource appears to be used + // serially, rather than multiple parallel uses. This is important for + // in-order machine where the resource consumption is a hazard. + unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); + for( ; WPRIdx != WPREnd; ++WPRIdx) { + if (WriteProcResources[WPRIdx].ProcResourceIdx + == WPREntry.ProcResourceIdx) { + WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; + break; + } + } + if (WPRIdx == WPREnd) + WriteProcResources.push_back(WPREntry); } } WriteLatencies.push_back(WLEntry); @@ -1062,7 +1137,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, // The first class is always invalid. We no way to distinguish it except by // name and position. - assert(SchedModels.getSchedClass(0).Name == "NoItinerary" + assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" && "invalid class not first"); OS << " {DBGFIELD(\"InvalidSchedClass\") " << MCSchedClassDesc::InvalidNumMicroOps @@ -1119,7 +1194,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { - SchedModels.schedClassBegin()) << ",\n"; else OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; - if (SchedModels.hasItineraryClasses()) + if (SchedModels.hasItineraries()) OS << " " << PI->ItinsDef->getName() << ");\n"; else OS << " 0); // No Itinerary\n"; @@ -1176,7 +1251,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { << "#define DBGFIELD(x)\n" << "#endif\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { std::vector<std::vector<InstrItinerary> > ProcItinLists; // Emit the stage data EmitStageAndOperandCycleData(OS, ProcItinLists); @@ -1217,7 +1292,7 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { if (SCI->Transitions.empty()) continue; - VariantClasses.push_back(SCI - SchedModels.schedClassBegin()); + VariantClasses.push_back(SCI->Index); } if (!VariantClasses.empty()) { OS << " switch (SchedClass) {\n"; @@ -1264,13 +1339,8 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, if (*PI == 0) break; } - unsigned SCIdx = 0; - if (SC.ItinClassDef) - SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef); - else - SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads); - if (SCIdx != *VCI) - OS << " return " << SCIdx << ";\n"; + if (SC.isInferred()) + OS << " return " << SC.Index << ";\n"; OS << " break;\n"; } OS << " };\n"; @@ -1376,7 +1446,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << '\n'; OS.indent(22); OS << Target << "Stages, " << Target << "OperandCycles, " @@ -1433,7 +1503,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "extern const llvm::MCReadAdvanceEntry " << Target << "ReadAdvanceTable[];\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; @@ -1457,7 +1527,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; OS << '\n'; OS.indent(22); - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index b00f7ea..8471faa 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -764,6 +764,17 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { HANDLE_OPERAND(immediate) HANDLE_OPERAND(immediate) break; + case X86Local::MRM_F8: + if (Opcode == 0xc6) { + assert(numPhysicalOperands == 1 && + "Unexpected number of operands for X86Local::MRM_F8"); + HANDLE_OPERAND(immediate) + } else if (Opcode == 0xc7) { + assert(numPhysicalOperands == 1 && + "Unexpected number of operands for X86Local::MRM_F8"); + HANDLE_OPERAND(relocation) + } + break; case X86Local::MRMInitReg: // Ignored. break; |