Index: include/llvm/Target/TargetSchedule.td =================================================================== --- include/llvm/Target/TargetSchedule.td +++ include/llvm/Target/TargetSchedule.td @@ -98,6 +98,10 @@ // or there will be no way to catch simple errors in the model // resulting from changes to the instruction definitions. bit CompleteModel = 1; + // TableGen can check the scheduling model for completeness. Currently most + // models that claim to be complete are actually not, so for now subtargets + // have to explicitely opt-in to the checking. + bit CheckCompleteness = 0; bit NoModel = 0; // Special tag to indicate missing machine model. } Index: utils/TableGen/CodeGenSchedule.h =================================================================== --- utils/TableGen/CodeGenSchedule.h +++ utils/TableGen/CodeGenSchedule.h @@ -401,6 +401,8 @@ void inferSchedClasses(); + void checkCompleteness(); + void inferFromRW(ArrayRef OperWrites, ArrayRef OperReads, unsigned FromClassIdx, ArrayRef ProcIndices); void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx); Index: utils/TableGen/CodeGenSchedule.cpp =================================================================== --- utils/TableGen/CodeGenSchedule.cpp +++ utils/TableGen/CodeGenSchedule.cpp @@ -126,6 +126,8 @@ // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and // ProcResourceDefs. collectProcResources(); + + checkCompleteness(); } /// Gather all processor models. @@ -1523,6 +1525,49 @@ } } +void CodeGenSchedModels::checkCompleteness() { + bool Complete = true; + bool HadCompleteModel = false; + for (const CodeGenProcModel &ProcModel : procModels()) { + // Note that long-term we should check "CompleteModel", but for now most + // models that claim to be complete are actually not so we use a separate + // "CheckCompleteness" bit. + if (!ProcModel.ModelDef->getValueAsBit("CheckCompleteness")) + continue; + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { + if (Inst->hasNoSchedulingInfo) + continue; + unsigned SCIdx = getSchedClassIdx(*Inst); + if (!SCIdx) { + if (Inst->TheDef->isValueUnset("SchedRW") && !HadCompleteModel) { + PrintError("No schedule information for instruction '" + + Inst->TheDef->getName() + "'"); + Complete = false; + } + continue; + } + + const CodeGenSchedClass &SC = getSchedClass(SCIdx); + if (!SC.Writes.empty()) + continue; + + const RecVec &InstRWs = SC.InstRWs; + auto I = std::find_if(InstRWs.begin(), InstRWs.end(), + [&ProcModel] (const Record *R) { + return R->getValueAsDef("SchedModel") == ProcModel.ModelDef; + }); + if (I == InstRWs.end()) { + PrintError("'" + ProcModel.ModelName + "' lacks information for '" + + Inst->TheDef->getName() + "'"); + Complete = false; + } + } + HadCompleteModel = true; + } + if (!Complete) + PrintFatalError("Incomplete schedule model"); +} + // Collect itinerary class resources for each processor. void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) { for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {