Machine model. Allow mixed itinerary classes and SchedRW lists.

We always supported a mixture of the old itinerary model and new
per-operand model, but it required a level of indirection to map
itinerary classes to SchedRW lists. This was done for ARM A9.

Now we want to define x86 SchedRW lists, with the goal of removing its
itinerary classes, but still support the itineraries in the mean
time. When I original developed the model, Atom did not have
itineraries, so there was no reason to expect this requirement.

llvm-svn: 177226
This commit is contained in:
Andrew Trick 2013-03-16 18:58:55 +00:00
parent 6d88a690e6
commit bf8a28dc52
3 changed files with 175 additions and 206 deletions

View File

@ -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");
@ -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->isValueUnset("SchedRW"))
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->isValueUnset("SchedRW")) {
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->isValueUnset("SchedRW")
&& (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->isValueUnset("SchedRW")) {
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)->isValueUnset("SchedRW"))
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,46 @@ 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())) {
DEBUG(dbgs() << ProcModel.ItinsDef->getName()
<< " has unused itinerary class " << ItinDef->getName() << '\n');
continue;
SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
for( ; SCI != SCE; ++SCI) {
if (SCI->ItinClassDef == ItinDef) {
ProcModel.ItinDefList[SCI->Index] = ItinData;
break;
}
}
if (SCI == SCE) {
DEBUG(dbgs() << ProcModel.ItinsDef->getName()
<< " 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 +823,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 +1283,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;
@ -1642,7 +1630,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();

View File

@ -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);

View File

@ -447,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
@ -869,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.ModelName
<< " 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();
@ -907,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;
@ -924,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;
@ -1140,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
@ -1197,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";
@ -1254,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);
@ -1295,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";
@ -1342,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";
@ -1454,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, "
@ -1511,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";
@ -1535,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, ";