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. /// CodeGenModels ctor interprets machine model records and populates maps.
CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
const CodeGenTarget &TGT): const CodeGenTarget &TGT):
Records(RK), Target(TGT), NumItineraryClasses(0) { Records(RK), Target(TGT) {
Sets.addFieldExpander("InstRW", "Instrs"); Sets.addFieldExpander("InstRW", "Instrs");
@ -502,40 +502,25 @@ void CodeGenSchedModels::collectSchedClasses() {
// NoItinerary is always the first class at Idx=0 // NoItinerary is always the first class at Idx=0
SchedClasses.resize(1); 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); SchedClasses.back().ProcIndices.push_back(0);
SchedClassIdxMap[SchedClasses.back().Name] = 0;
// Gather and sort all itinerary classes used by instruction descriptions. // Create a SchedClass for each unique combination of itinerary class and
RecVec ItinClassList; // SchedRW list.
for (CodeGenTarget::inst_iterator I = Target.inst_begin(), for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I) { E = Target.inst_end(); I != E; ++I) {
Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary"); 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; 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. // ProcIdx == 0 indicates the class applies to all processors.
IdxVec ProcIndices(1, 0); IdxVec ProcIndices(1, 0);
addSchedClass(Writes, Reads, ProcIndices);
unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices);
InstrClassMap[(*I)->TheDef] = SCIdx;
} }
// Create classes for InstRW defs. // Create classes for InstRW defs.
RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
@ -549,68 +534,70 @@ void CodeGenSchedModels::collectSchedClasses() {
DEBUG(EnableDump = true); DEBUG(EnableDump = true);
if (!EnableDump) if (!EnableDump)
return; return;
for (CodeGenTarget::inst_iterator I = Target.inst_begin(), for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I) { E = Target.inst_end(); I != E; ++I) {
Record *SchedDef = (*I)->TheDef;
std::string InstName = (*I)->TheDef->getName(); 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 Writes;
IdxVec Reads; IdxVec Reads;
findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
dbgs() << "SchedRW machine model for " << InstName; Writes, Reads);
for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
dbgs() << " " << SchedWrites[*WI].Name; dbgs() << " " << SchedWrites[*WI].Name;
for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
dbgs() << " " << SchedReads[*RI].Name; dbgs() << " " << SchedReads[*RI].Name;
dbgs() << '\n'; dbgs() << '\n';
} }
unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(),
if (SCIdx) { PE = ProcModels.end(); PI != PE; ++PI) {
const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; if (!std::count(ProcIndices.begin(), ProcIndices.end(), PI->Index))
for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); dbgs() << "No machine model for " << (*I)->TheDef->getName()
RWI != RWE; ++RWI) { << " on processor " << PI->ModelName << '\n';
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';
} }
} }
} }
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 /// Find an SchedClass that has been inferred from a per-operand list of
/// SchedWrites and SchedReads. /// SchedWrites and SchedReads.
unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef,
const IdxVec &Writes,
const IdxVec &Reads) const { const IdxVec &Reads) const {
for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) {
// Classes with InstRWs may have the same Writes/Reads as a class originally if (I->ItinClassDef == ItinClassDef
// produced by a SchedRW definition. We need to be able to recover the && I->Writes == Writes && I->Reads == Reads) {
// 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) {
return I - schedClassBegin(); return I - schedClassBegin();
} }
} }
@ -621,29 +608,17 @@ unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes,
unsigned CodeGenSchedModels::getSchedClassIdx( unsigned CodeGenSchedModels::getSchedClassIdx(
const CodeGenInstruction &Inst) const { const CodeGenInstruction &Inst) const {
unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef); return 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;
} }
std::string CodeGenSchedModels::createSchedClassName( std::string CodeGenSchedModels::createSchedClassName(
const IdxVec &OperWrites, const IdxVec &OperReads) { Record *ItinClassDef, const IdxVec &OperWrites, const IdxVec &OperReads) {
std::string Name; std::string Name;
if (ItinClassDef && ItinClassDef->getName() != "NoItinerary")
Name = ItinClassDef->getName();
for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) { for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) {
if (WI != OperWrites.begin()) if (!Name.empty())
Name += '_'; Name += '_';
Name += SchedWrites[*WI].Name; Name += SchedWrites[*WI].Name;
} }
@ -665,17 +640,18 @@ std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) {
return Name; return Name;
} }
/// Add an inferred sched class from a per-operand list of SchedWrites and /// Add an inferred sched class from an itinerary class and per-operand list of
/// SchedReads. ProcIndices contains the set of IDs of processors that may /// SchedWrites and SchedReads. ProcIndices contains the set of IDs of
/// utilize this class. /// processors that may utilize this class.
unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
const IdxVec &OperWrites,
const IdxVec &OperReads, const IdxVec &OperReads,
const IdxVec &ProcIndices) const IdxVec &ProcIndices)
{ {
assert(!ProcIndices.empty() && "expect at least one ProcIdx"); assert(!ProcIndices.empty() && "expect at least one ProcIdx");
unsigned Idx = findSchedClassIdx(OperWrites, OperReads); unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads);
if (Idx) { if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
IdxVec PI; IdxVec PI;
std::set_union(SchedClasses[Idx].ProcIndices.begin(), std::set_union(SchedClasses[Idx].ProcIndices.begin(),
SchedClasses[Idx].ProcIndices.end(), SchedClasses[Idx].ProcIndices.end(),
@ -687,7 +663,9 @@ unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites,
Idx = SchedClasses.size(); Idx = SchedClasses.size();
SchedClasses.resize(Idx+1); SchedClasses.resize(Idx+1);
CodeGenSchedClass &SC = SchedClasses.back(); 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.Writes = OperWrites;
SC.Reads = OperReads; SC.Reads = OperReads;
SC.ProcIndices = ProcIndices; SC.ProcIndices = ProcIndices;
@ -709,19 +687,10 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes");
for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) { for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) {
unsigned SCIdx = 0;
InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I); InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I);
if (Pos != InstrClassMap.end()) if (Pos == InstrClassMap.end())
SCIdx = Pos->second; PrintFatalError((*I)->getLoc(), "No sched class for instruction.");
else { unsigned SCIdx = Pos->second;
// 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"));
}
unsigned CIdx = 0, CEnd = ClassInstrs.size(); unsigned CIdx = 0, CEnd = ClassInstrs.size();
for (; CIdx != CEnd; ++CIdx) { for (; CIdx != CEnd; ++CIdx) {
if (ClassInstrs[CIdx].first == SCIdx) if (ClassInstrs[CIdx].first == SCIdx)
@ -741,7 +710,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second;
// If the all instrs in the current class are accounted for, then leave // If the all instrs in the current class are accounted for, then leave
// them mapped to their old class. // 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 && assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
"expected a generic SchedClass"); "expected a generic SchedClass");
continue; continue;
@ -749,6 +718,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
unsigned SCIdx = SchedClasses.size(); unsigned SCIdx = SchedClasses.size();
SchedClasses.resize(SCIdx+1); SchedClasses.resize(SCIdx+1);
CodeGenSchedClass &SC = SchedClasses.back(); CodeGenSchedClass &SC = SchedClasses.back();
SC.Index = SCIdx;
SC.Name = createSchedClassName(InstDefs); SC.Name = createSchedClassName(InstDefs);
// Preserve ItinDef and Writes/Reads for processors without an InstRW entry. // Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; 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. // Gather the processor itineraries.
void CodeGenSchedModels::collectProcItins() { void CodeGenSchedModels::collectProcItins() {
for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(),
PE = ProcModels.end(); PI != PE; ++PI) { PE = ProcModels.end(); PI != PE; ++PI) {
CodeGenProcModel &ProcModel = *PI; CodeGenProcModel &ProcModel = *PI;
RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); if (!ProcModel.hasItineraries())
// Skip empty itinerary.
if (ItinRecords.empty())
continue; 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 // Insert each itinerary data record in the correct position within
// the processor model's ItinDefList. // the processor model's ItinDefList.
for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) {
Record *ItinData = ItinRecords[i]; Record *ItinData = ItinRecords[i];
Record *ItinDef = ItinData->getValueAsDef("TheClass"); Record *ItinDef = ItinData->getValueAsDef("TheClass");
if (!SchedClassIdxMap.count(ItinDef->getName())) { SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
DEBUG(dbgs() << ProcModel.ItinsDef->getName() for( ; SCI != SCE; ++SCI) {
<< " has unused itinerary class " << ItinDef->getName() << '\n'); if (SCI->ItinClassDef == ItinDef) {
continue; 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. // Check for missing itinerary entries.
assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); 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 /// Infer new classes from existing classes. In the process, this may create new
/// SchedWrites from sequences of existing SchedWrites. /// SchedWrites from sequences of existing SchedWrites.
void CodeGenSchedModels::inferSchedClasses() { void CodeGenSchedModels::inferSchedClasses() {
DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n");
// Visit all existing classes and newly created classes. // Visit all existing classes and newly created classes.
for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {
assert(SchedClasses[Idx].Index == Idx && "bad SCIdx");
if (SchedClasses[Idx].ItinClassDef) if (SchedClasses[Idx].ItinClassDef)
inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);
else if (!SchedClasses[Idx].InstRWs.empty()) if (!SchedClasses[Idx].InstRWs.empty())
inferFromInstRWs(Idx); inferFromInstRWs(Idx);
else { if (!SchedClasses[Idx].Writes.empty()) {
inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
Idx, SchedClasses[Idx].ProcIndices); Idx, SchedClasses[Idx].ProcIndices);
} }
@ -1295,8 +1283,8 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end());
CodeGenSchedTransition SCTrans; CodeGenSchedTransition SCTrans;
SCTrans.ToClassIdx = SCTrans.ToClassIdx =
SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant, SchedModels.addSchedClass(/*ItinClassDef=*/0, OperWritesVariant,
ProcIndices); OperReadsVariant, ProcIndices);
SCTrans.ProcIndices = ProcIndices; SCTrans.ProcIndices = ProcIndices;
// The final PredTerm is unique set of predicates guarding the transition. // The final PredTerm is unique set of predicates guarding the transition.
RecVec Preds; RecVec Preds;
@ -1642,7 +1630,7 @@ void CodeGenSchedRW::dump() const {
} }
void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
dbgs() << "SCHEDCLASS " << Name << '\n' dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n'
<< " Writes: "; << " Writes: ";
for (unsigned i = 0, N = Writes.size(); i < N; ++i) { for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
SchedModels->getSchedWrite(Writes[i]).dump(); SchedModels->getSchedWrite(Writes[i]).dump();

View File

@ -125,6 +125,7 @@ struct CodeGenSchedTransition {
/// itinerary class. Each inherits the processor index from the ItinRW record /// itinerary class. Each inherits the processor index from the ItinRW record
/// that mapped the itinerary class to the variant Writes or Reads. /// that mapped the itinerary class to the variant Writes or Reads.
struct CodeGenSchedClass { struct CodeGenSchedClass {
unsigned Index;
std::string Name; std::string Name;
Record *ItinClassDef; Record *ItinClassDef;
@ -141,12 +142,16 @@ struct CodeGenSchedClass {
// off to join another inferred class. // off to join another inferred class.
RecVec InstRWs; RecVec InstRWs;
CodeGenSchedClass(): ItinClassDef(0) {} CodeGenSchedClass(): Index(0), ItinClassDef(0) {}
CodeGenSchedClass(Record *rec): ItinClassDef(rec) {
Name = rec->getName(); bool isKeyEqual(Record *IC, const IdxVec &W, const IdxVec &R) {
ProcIndices.push_back(0); 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 #ifndef NDEBUG
void dump(const CodeGenSchedModels *SchedModels) const; void dump(const CodeGenSchedModels *SchedModels) const;
#endif #endif
@ -189,11 +194,16 @@ struct CodeGenProcModel {
// Per-operand machine model resources associated with this processor. // Per-operand machine model resources associated with this processor.
RecVec ProcResourceDefs; RecVec ProcResourceDefs;
RecVec ProcResGroupDefs;
CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef, CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef,
Record *IDef) : Record *IDef) :
Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {}
bool hasItineraries() const {
return !ItinsDef->getValueAsListOfDefs("IID").empty();
}
bool hasInstrSchedModel() const { bool hasInstrSchedModel() const {
return !WriteResDefs.empty() || !ItinRWDefs.empty(); return !WriteResDefs.empty() || !ItinRWDefs.empty();
} }
@ -227,24 +237,11 @@ class CodeGenSchedModels {
// List of unique SchedClasses. // List of unique SchedClasses.
std::vector<CodeGenSchedClass> 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. // Any inferred SchedClass has an index greater than NumInstrSchedClassses.
unsigned NumInstrSchedClasses; unsigned NumInstrSchedClasses;
// Map Instruction to SchedClass index. Only for Instructions mentioned in // Map each instruction to its unique SchedClass index considering the
// InstRW records. // combination of it's itinerary class, SchedRW list, and InstRW records.
typedef DenseMap<Record*, unsigned> InstClassMapTy; typedef DenseMap<Record*, unsigned> InstClassMapTy;
InstClassMapTy InstrClassMap; InstClassMapTy InstrClassMap;
@ -280,6 +277,9 @@ public:
ProcIter procModelBegin() const { return ProcModels.begin(); } ProcIter procModelBegin() const { return ProcModels.begin(); }
ProcIter procModelEnd() const { return ProcModels.end(); } ProcIter procModelEnd() const { return ProcModels.end(); }
// Return true if any processors have itineraries.
bool hasItineraries() const;
// Get a SchedWrite from its index. // Get a SchedWrite from its index.
const CodeGenSchedRW &getSchedWrite(unsigned Idx) const { const CodeGenSchedRW &getSchedWrite(unsigned Idx) const {
assert(Idx < SchedWrites.size() && "bad SchedWrite index"); assert(Idx < SchedWrites.size() && "bad SchedWrite index");
@ -311,16 +311,6 @@ public:
// Return true if the given write record is referenced by a ReadAdvance. // Return true if the given write record is referenced by a ReadAdvance.
bool hasReadOfWrite(Record *WriteDef) const; 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. // Get a SchedClass from its index.
CodeGenSchedClass &getSchedClass(unsigned Idx) { CodeGenSchedClass &getSchedClass(unsigned Idx) {
assert(Idx < SchedClasses.size() && "bad SchedClass index"); assert(Idx < SchedClasses.size() && "bad SchedClass index");
@ -336,28 +326,26 @@ public:
// for NoItinerary. // for NoItinerary.
unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const; 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; typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter;
SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } SchedClassIter schedClassBegin() const { return SchedClasses.begin(); }
SchedClassIter schedClassEnd() const { return SchedClasses.end(); } 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 &Writes, IdxVec &Reads) const;
void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const; void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const;
void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const; void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const;
void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead, void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
const CodeGenProcModel &ProcModel) const; const CodeGenProcModel &ProcModel) const;
unsigned addSchedClass(const IdxVec &OperWrites, const IdxVec &OperReads, unsigned addSchedClass(Record *ItinDef, const IdxVec &OperWrites,
const IdxVec &ProcIndices); const IdxVec &OperReads, const IdxVec &ProcIndices);
unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); 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, Record *findProcResUnits(Record *ProcResKind,
const CodeGenProcModel &PM) const; const CodeGenProcModel &PM) const;
@ -375,7 +363,8 @@ private:
void collectSchedClasses(); void collectSchedClasses();
std::string createSchedClassName(const IdxVec &OperWrites, std::string createSchedClassName(Record *ItinClassDef,
const IdxVec &OperWrites,
const IdxVec &OperReads); const IdxVec &OperReads);
std::string createSchedClassName(const RecVec &InstDefs); std::string createSchedClassName(const RecVec &InstDefs);
void createInstRWClass(Record *InstRWDef); 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 // If this processor defines no itineraries, then leave the itinerary list
// empty. // empty.
std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
if (ProcModel.ItinDefList.empty()) if (!ProcModel.hasItineraries())
continue; continue;
// Reserve index==0 for NoItinerary.
ItinList.resize(SchedModels.numItineraryClasses()+1);
const std::string &Name = ProcModel.ItinsDef->getName(); const std::string &Name = ProcModel.ItinsDef->getName();
// For each itinerary data ItinList.resize(SchedModels.numInstrSchedClasses());
for (unsigned SchedClassIdx = 0, assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
SchedClassEnd = ProcModel.ItinDefList.size();
for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
// Next itinerary data // Next itinerary data
@ -869,27 +867,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
} }
IdxVec Writes = SCI->Writes; IdxVec Writes = SCI->Writes;
IdxVec Reads = SCI->Reads; IdxVec Reads = SCI->Reads;
if (SCI->ItinClassDef) { if (!SCI->InstRWs.empty()) {
assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs"); // This class has a default ReadWrite list which can be overriden by
// 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
// InstRW definitions. // InstRW definitions.
Record *RWDef = 0; Record *RWDef = 0;
for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
@ -907,6 +886,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
Writes, Reads); 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. // Sum resources across all operand writes.
std::vector<MCWriteProcResEntry> WriteProcResources; std::vector<MCWriteProcResEntry> WriteProcResources;
std::vector<MCWriteLatencyEntry> WriteLatencies; std::vector<MCWriteLatencyEntry> WriteLatencies;
@ -924,7 +920,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
// If this Write is not referenced by a ReadAdvance, don't distinguish it // If this Write is not referenced by a ReadAdvance, don't distinguish it
// from other WriteLatency entries. // from other WriteLatency entries.
if (!SchedModels.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) { if (!SchedModels.hasReadOfWrite(
SchedModels.getSchedWrite(WriteID).TheDef)) {
WriteID = 0; WriteID = 0;
} }
WLEntry.WriteResourceID = WriteID; 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 // The first class is always invalid. We no way to distinguish it except by
// name and position. // name and position.
assert(SchedModels.getSchedClass(0).Name == "NoItinerary" assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
&& "invalid class not first"); && "invalid class not first");
OS << " {DBGFIELD(\"InvalidSchedClass\") " OS << " {DBGFIELD(\"InvalidSchedClass\") "
<< MCSchedClassDesc::InvalidNumMicroOps << MCSchedClassDesc::InvalidNumMicroOps
@ -1197,7 +1194,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
- SchedModels.schedClassBegin()) << ",\n"; - SchedModels.schedClassBegin()) << ",\n";
else else
OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; OS << " 0, 0, 0, 0, // No instruction-level machine model.\n";
if (SchedModels.hasItineraryClasses()) if (SchedModels.hasItineraries())
OS << " " << PI->ItinsDef->getName() << ");\n"; OS << " " << PI->ItinsDef->getName() << ");\n";
else else
OS << " 0); // No Itinerary\n"; OS << " 0); // No Itinerary\n";
@ -1254,7 +1251,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
<< "#define DBGFIELD(x)\n" << "#define DBGFIELD(x)\n"
<< "#endif\n"; << "#endif\n";
if (SchedModels.hasItineraryClasses()) { if (SchedModels.hasItineraries()) {
std::vector<std::vector<InstrItinerary> > ProcItinLists; std::vector<std::vector<InstrItinerary> > ProcItinLists;
// Emit the stage data // Emit the stage data
EmitStageAndOperandCycleData(OS, ProcItinLists); EmitStageAndOperandCycleData(OS, ProcItinLists);
@ -1295,7 +1292,7 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
if (SCI->Transitions.empty()) if (SCI->Transitions.empty())
continue; continue;
VariantClasses.push_back(SCI - SchedModels.schedClassBegin()); VariantClasses.push_back(SCI->Index);
} }
if (!VariantClasses.empty()) { if (!VariantClasses.empty()) {
OS << " switch (SchedClass) {\n"; OS << " switch (SchedClass) {\n";
@ -1342,13 +1339,8 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
if (*PI == 0) if (*PI == 0)
break; break;
} }
unsigned SCIdx = 0; if (SC.isInferred())
if (SC.ItinClassDef) OS << " return " << SC.Index << ";\n";
SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef);
else
SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads);
if (SCIdx != *VCI)
OS << " return " << SCIdx << ";\n";
OS << " break;\n"; OS << " break;\n";
} }
OS << " };\n"; OS << " };\n";
@ -1454,7 +1446,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< Target << "WriteProcResTable, " << Target << "WriteProcResTable, "
<< Target << "WriteLatencyTable, " << Target << "WriteLatencyTable, "
<< Target << "ReadAdvanceTable, "; << Target << "ReadAdvanceTable, ";
if (SchedModels.hasItineraryClasses()) { if (SchedModels.hasItineraries()) {
OS << '\n'; OS.indent(22); OS << '\n'; OS.indent(22);
OS << Target << "Stages, " OS << Target << "Stages, "
<< Target << "OperandCycles, " << Target << "OperandCycles, "
@ -1511,7 +1503,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "extern const llvm::MCReadAdvanceEntry " OS << "extern const llvm::MCReadAdvanceEntry "
<< Target << "ReadAdvanceTable[];\n"; << Target << "ReadAdvanceTable[];\n";
if (SchedModels.hasItineraryClasses()) { if (SchedModels.hasItineraries()) {
OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n";
OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
@ -1535,7 +1527,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< Target << "WriteLatencyTable, " << Target << "WriteLatencyTable, "
<< Target << "ReadAdvanceTable, "; << Target << "ReadAdvanceTable, ";
OS << '\n'; OS.indent(22); OS << '\n'; OS.indent(22);
if (SchedModels.hasItineraryClasses()) { if (SchedModels.hasItineraries()) {
OS << Target << "Stages, " OS << Target << "Stages, "
<< Target << "OperandCycles, " << Target << "OperandCycles, "
<< Target << "ForwardingPaths, "; << Target << "ForwardingPaths, ";