Index: utils/TableGen/CodeGenSchedule.h =================================================================== --- utils/TableGen/CodeGenSchedule.h +++ utils/TableGen/CodeGenSchedule.h @@ -443,6 +443,8 @@ void collectSchedClasses(); + void checkSchedClasses(); + void collectRetireControlUnits(); void collectRegisterFiles(); Index: utils/TableGen/CodeGenSchedule.cpp =================================================================== --- utils/TableGen/CodeGenSchedule.cpp +++ utils/TableGen/CodeGenSchedule.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" @@ -33,6 +34,16 @@ #define DEBUG_TYPE "subtarget-emitter" +#ifdef EXPENSIVE_CHECKS +// FIXME: TableGen is failed iff EXPENSIVE_CHECKS defined +static constexpr bool OptCheckSchedClasses = true; +#else +// FIXME: the default value should be false +static cl::opt OptCheckSchedClasses( + "check-sched-class-table", cl::init(true), cl::Hidden, + cl::desc("Check sched class table on different types of inconsistencies")); +#endif + #ifndef NDEBUG static void dumpIdxVec(ArrayRef V) { for (unsigned Idx : V) @@ -223,6 +234,7 @@ collectOptionalProcessorInfo(); checkCompleteness(); + checkSchedClasses(); } void CodeGenSchedModels::collectRetireControlUnits() { @@ -699,6 +711,69 @@ } } +void CodeGenSchedModels::checkSchedClasses() { + if (!OptCheckSchedClasses) + return; + + std::string str; + raw_string_ostream OS(str); + + // Check each instruction for each model to see if its overridden. + // Iff YES it's a candidate for separate Sched Class + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { + StringRef InstName = Inst->TheDef->getName(); + unsigned SCIdx = getSchedClassIdx(*Inst); + if (!SCIdx) + continue; + CodeGenSchedClass &SC = getSchedClass(SCIdx); + if (SC.Writes.empty()) + continue; + const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; + if (RWDefs.empty()) + continue; + // FIXME: what should be threshold here? + if (RWDefs.size() > (ProcModels.size() / 2)) { + // FIXME: this dump hangs the execution !!! + // SC.dump(&Target.getSchedModels()); + OS << "SchedRW machine model for inst '" << InstName << "' ("; + for (auto I : SC.Writes) + OS << " " << SchedWrites[I].Name; + for (auto I : SC.Reads) + OS << " " << SchedReads[I].Name; + OS << " ) should be removed because it's overriden " << RWDefs.size() + << " times for the following models:\n\t"; + for (Record *RWDef : RWDefs) + OS << " " << getProcModel(RWDef->getValueAsDef("SchedModel")).ModelName; + + PrintWarning(OS.str()); + str.clear(); + } + + /* + // TODO: here we should check latency/uop in SC vs. RWDef. Maybe we + // should do it iff RWDefs.size() == 1 only. + // Iff latnecy/uop are the same then warn about unnecessary redefine. + for (Record *RWDef : RWDefs) { + const CodeGenProcModel &ProcModel = + getProcModel(RWDef->getValueAsDef("SchedModel")); + LLVM_DEBUG(dbgs() << "InstRW on " << ProcModel.ModelName << " for " + << InstName); + IdxVec Writes; + IdxVec Reads; + findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + LLVM_DEBUG({ + for (unsigned WIdx : Writes) + dbgs() << " " << SchedWrites[WIdx].Name; + for (unsigned RIdx : Reads) + dbgs() << " " << SchedReads[RIdx].Name; + dbgs() << '\n'; + }); + } + */ + } +} + // Get the SchedClass index for an instruction. unsigned CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const {