Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -1352,7 +1352,7 @@ OpSize16, Requires<[Not64BitMode]>; } -let Constraints = "$src = $dst", SchedRW = [WriteALU] in { +let Constraints = "$src = $dst", SchedRW = [WriteBSWAP32] in { // This instruction is a consequence of BSWAP32r observing operand size. The // encoding is valid, but the behavior is undefined. let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in @@ -1363,6 +1363,7 @@ "bswap{l}\t$dst", [(set GR32:$dst, (bswap GR32:$src))]>, OpSize32, TB; +let SchedRW = [WriteBSWAP64] in def BSWAP64r : RI<0xC8, AddRegFrm, (outs GR64:$dst), (ins GR64:$src), "bswap{q}\t$dst", [(set GR64:$dst, (bswap GR64:$src))]>, TB; Index: lib/Target/X86/X86SchedBroadwell.td =================================================================== --- lib/Target/X86/X86SchedBroadwell.td +++ lib/Target/X86/X86SchedBroadwell.td @@ -110,7 +110,6 @@ defm : BWWriteResPair; // Integer ALU + flags op. defm : BWWriteResPair; // Integer multiplication. defm : BWWriteResPair; // Integer 64-bit multiplication. - defm : BWWriteResPair; defm : BWWriteResPair; defm : BWWriteResPair; @@ -120,6 +119,9 @@ defm : BWWriteResPair; defm : BWWriteResPair; +defm : BWWriteResPair; // +defm : BWWriteResPair; // + defm : BWWriteResPair; def : WriteRes { let Latency = 3; } // Integer multiplication, high part. @@ -699,20 +701,6 @@ } def: InstRW<[BWWriteResGroup18], (instrs SFENCE)>; -def BWWriteResGroup19 : SchedWriteRes<[BWPort06,BWPort15]> { - let Latency = 2; - let NumMicroOps = 2; - let ResourceCycles = [1,1]; -} -def: InstRW<[BWWriteResGroup19], (instrs BSWAP64r)>; - -def BWWriteResGroup19_1 : SchedWriteRes<[BWPort15]> { - let Latency = 1; - let NumMicroOps = 1; - let ResourceCycles = [1]; -} -def: InstRW<[BWWriteResGroup19_1], (instrs BSWAP32r)>; - def BWWriteResGroup20 : SchedWriteRes<[BWPort06,BWPort0156]> { let Latency = 2; let NumMicroOps = 2; Index: lib/Target/X86/X86SchedHaswell.td =================================================================== --- lib/Target/X86/X86SchedHaswell.td +++ lib/Target/X86/X86SchedHaswell.td @@ -122,6 +122,10 @@ defm : HWWriteResPair; defm : HWWriteResPair; defm : HWWriteResPair; + +defm : HWWriteResPair; +defm : HWWriteResPair; + def : WriteRes { let Latency = 3; } defm : HWWriteResPair; defm : HWWriteResPair; @@ -1149,20 +1153,6 @@ } def: InstRW<[HWWriteResGroup33], (instregex "MMX_MOVDQ2Qrr")>; -def HWWriteResGroup34 : SchedWriteRes<[HWPort06,HWPort15]> { - let Latency = 2; - let NumMicroOps = 2; - let ResourceCycles = [1,1]; -} -def: InstRW<[HWWriteResGroup34], (instrs BSWAP64r)>; - -def HWWriteResGroup34_1 : SchedWriteRes<[HWPort15]> { - let Latency = 1; - let NumMicroOps = 1; - let ResourceCycles = [1]; -} -def: InstRW<[HWWriteResGroup34_1], (instrs BSWAP32r)>; - def HWWriteResGroup35 : SchedWriteRes<[HWPort06,HWPort0156]> { let Latency = 2; let NumMicroOps = 2; Index: lib/Target/X86/X86SchedSandyBridge.td =================================================================== --- lib/Target/X86/X86SchedSandyBridge.td +++ lib/Target/X86/X86SchedSandyBridge.td @@ -111,6 +111,9 @@ defm : SBWriteResPair; defm : SBWriteResPair; +defm : SBWriteResPair; +defm : SBWriteResPair; + defm : SBWriteResPair; defm : SBWriteResPair; defm : SBWriteResPair; @@ -619,20 +622,6 @@ def: InstRW<[SBWriteResGroup15], (instrs CWD, FNSTSW16r)>; -def SBWriteResGroup16 : SchedWriteRes<[SBPort1,SBPort05]> { - let Latency = 2; - let NumMicroOps = 2; - let ResourceCycles = [1,1]; -} -def: InstRW<[SBWriteResGroup16], (instrs BSWAP64r)>; - -def SBWriteResGroup16_1 : SchedWriteRes<[SBPort1]> { - let Latency = 1; - let NumMicroOps = 1; - let ResourceCycles = [1]; -} -def: InstRW<[SBWriteResGroup16_1], (instrs BSWAP32r)>; - def SBWriteResGroup18 : SchedWriteRes<[SBPort5,SBPort015]> { let Latency = 2; let NumMicroOps = 2; Index: lib/Target/X86/X86SchedSkylakeClient.td =================================================================== --- lib/Target/X86/X86SchedSkylakeClient.td +++ lib/Target/X86/X86SchedSkylakeClient.td @@ -110,6 +110,9 @@ defm : SKLWriteResPair; // Integer multiplication. defm : SKLWriteResPair; // Integer 64-bit multiplication. +defm : SKLWriteResPair; // +defm : SKLWriteResPair; // + defm : SKLWriteResPair; defm : SKLWriteResPair; defm : SKLWriteResPair; @@ -698,20 +701,6 @@ } def: InstRW<[SKLWriteResGroup21], (instrs SFENCE)>; -def SKLWriteResGroup22 : SchedWriteRes<[SKLPort06,SKLPort15]> { - let Latency = 2; - let NumMicroOps = 2; - let ResourceCycles = [1,1]; -} -def: InstRW<[SKLWriteResGroup22], (instrs BSWAP64r)>; - -def SKLWriteResGroup22_1 : SchedWriteRes<[SKLPort15]> { - let Latency = 1; - let NumMicroOps = 1; - let ResourceCycles = [1]; -} -def: InstRW<[SKLWriteResGroup22_1], (instrs BSWAP32r)>; - def SKLWriteResGroup23 : SchedWriteRes<[SKLPort06,SKLPort0156]> { let Latency = 2; let NumMicroOps = 2; Index: lib/Target/X86/X86SchedSkylakeServer.td =================================================================== --- lib/Target/X86/X86SchedSkylakeServer.td +++ lib/Target/X86/X86SchedSkylakeServer.td @@ -110,6 +110,9 @@ defm : SKXWriteResPair; // Integer multiplication. defm : SKXWriteResPair; // Integer 64-bit multiplication. +defm : SKXWriteResPair; // +defm : SKXWriteResPair; // + defm : SKXWriteResPair; defm : SKXWriteResPair; defm : SKXWriteResPair; @@ -722,20 +725,6 @@ } def: InstRW<[SKXWriteResGroup21], (instrs SFENCE)>; -def SKXWriteResGroup22 : SchedWriteRes<[SKXPort06,SKXPort15]> { - let Latency = 2; - let NumMicroOps = 2; - let ResourceCycles = [1,1]; -} -def: InstRW<[SKXWriteResGroup22], (instrs BSWAP64r)>; - -def SKXWriteResGroup22_1 : SchedWriteRes<[SKXPort15]> { - let Latency = 1; - let NumMicroOps = 1; - let ResourceCycles = [1]; -} -def: InstRW<[SKXWriteResGroup22_1], (instrs BSWAP32r)>; - def SKXWriteResGroup23 : SchedWriteRes<[SKXPort06,SKXPort0156]> { let Latency = 2; let NumMicroOps = 2; Index: lib/Target/X86/X86Schedule.td =================================================================== --- lib/Target/X86/X86Schedule.td +++ lib/Target/X86/X86Schedule.td @@ -118,6 +118,9 @@ def WriteIMulH : SchedWrite; // Integer multiplication, high part. def WriteLEA : SchedWrite; // LEA instructions can't fold loads. +defm WriteBSWAP32: X86SchedWritePair; // Byte Order (Endiannes) Swap +defm WriteBSWAP64: X86SchedWritePair; // Byte Order (Endiannes) Swap + // Integer division. defm WriteDiv8 : X86SchedWritePair; defm WriteDiv16 : X86SchedWritePair; Index: lib/Target/X86/X86ScheduleAtom.td =================================================================== --- lib/Target/X86/X86ScheduleAtom.td +++ lib/Target/X86/X86ScheduleAtom.td @@ -81,6 +81,9 @@ defm : AtomWriteResPair; defm : AtomWriteResPair; +defm : AtomWriteResPair; +defm : AtomWriteResPair; + defm : AtomWriteResPair; defm : AtomWriteResPair; defm : AtomWriteResPair; @@ -489,7 +492,6 @@ let ResourceCycles = [1]; } def : InstRW<[AtomWrite0_1], (instrs FXAM, LD_Frr, - BSWAP32r, BSWAP64r, MOVSX64rr32)>; def : SchedAlias; def : SchedAlias; Index: lib/Target/X86/X86ScheduleBtVer2.td =================================================================== --- lib/Target/X86/X86ScheduleBtVer2.td +++ lib/Target/X86/X86ScheduleBtVer2.td @@ -168,6 +168,9 @@ defm : JWriteResIntPair; // i64 multiplication defm : X86WriteRes; +defm : JWriteResIntPair; +defm : JWriteResIntPair; + defm : JWriteResIntPair; defm : JWriteResIntPair; defm : JWriteResIntPair; Index: lib/Target/X86/X86ScheduleSLM.td =================================================================== --- lib/Target/X86/X86ScheduleSLM.td +++ lib/Target/X86/X86ScheduleSLM.td @@ -97,6 +97,10 @@ defm : SLMWriteResPair; defm : SLMWriteResPair; defm : SLMWriteResPair; + +defm : SLMWriteResPair; +defm : SLMWriteResPair; + defm : SLMWriteResPair; defm : SLMWriteResPair; defm : SLMWriteResPair; Index: lib/Target/X86/X86ScheduleZnver1.td =================================================================== --- lib/Target/X86/X86ScheduleZnver1.td +++ lib/Target/X86/X86ScheduleZnver1.td @@ -179,6 +179,10 @@ defm : ZnWriteResPair; defm : ZnWriteResPair; defm : ZnWriteResPair; + +defm : ZnWriteResPair; +defm : ZnWriteResPair; + defm : ZnWriteResPair; defm : ZnWriteResPair; defm : ZnWriteResPair; @@ -537,12 +541,6 @@ //LAHF def : InstRW<[WriteMicrocoded], (instrs LAHF)>; -// BSWAP. -def ZnWriteBSwap : SchedWriteRes<[ZnALU]> { - let ResourceCycles = [4]; -} -def : InstRW<[ZnWriteBSwap], (instregex "BSWAP")>; - // MOVBE. // r,m. def ZnWriteMOVBE : SchedWriteRes<[ZnAGU, ZnALU]> { 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,89 @@ } } +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 out of " << ProcModels.size() << " 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. + if (RWDefs.size()) { + for (Record *RWDef : RWDefs) { + IdxVec Writes; + IdxVec Reads; + findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, + Reads); + + if ((Writes.size() == SC.Writes.size()) && + (Reads.size() == SC.Reads.size())) { + // TODO: do we need sorting Write & Reads? + for (unsigned I = 0; I < SC.Writes.size(); I++) { + if (!SchedWrites[SC.Writes[I]].TheDef || + !SchedWrites[Writes[I]].TheDef) + continue; + const RecordVal *R = + SchedWrites[SC.Writes[I]].TheDef->getValue("Latency"); + // FIXME: We should deal with default Latency here + if (!R || !R->getValue()) + continue; + auto SCLat = + SchedWrites[SC.Writes[I]].TheDef->getValueAsInt("Latency"); + auto SCuOp = + SchedWrites[SC.Writes[I]].TheDef->getValueAsInt("NumMicroOps"); + auto Lat = SchedWrites[Writes[I]].TheDef->getValueAsInt("Latency"); + auto uOp = + SchedWrites[Writes[I]].TheDef->getValueAsInt("NumMicroOps"); + if ((SCLat == Lat) && (SCuOp == uOp)) + OS << "Overridden verion of inst '" << InstName + << "' has the same latency & uOp values as the original one " + "for model '" + << getProcModel(RWDef->getValueAsDef("SchedModel")).ModelName + << "'\n"; + } + if (!str.empty()) { + PrintWarning(OS.str()); + str.clear(); + } + } + } + } + } +} + // Get the SchedClass index for an instruction. unsigned CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const {