Index: include/llvm/CodeGen/TargetSchedule.h =================================================================== --- include/llvm/CodeGen/TargetSchedule.h +++ include/llvm/CodeGen/TargetSchedule.h @@ -196,9 +196,9 @@ const MachineInstr *DepMI) const; /// Compute the reciprocal throughput of the given instruction. - Optional computeReciprocalThroughput(const MachineInstr *MI) const; - Optional computeReciprocalThroughput(const MCInst &MI) const; - Optional computeReciprocalThroughput(unsigned Opcode) const; + double computeReciprocalThroughput(const MachineInstr *MI) const; + double computeReciprocalThroughput(const MCInst &MI) const; + double computeReciprocalThroughput(unsigned Opcode) const; }; } // end namespace llvm Index: include/llvm/MC/MCSchedule.h =================================================================== --- include/llvm/MC/MCSchedule.h +++ include/llvm/MC/MCSchedule.h @@ -362,14 +362,14 @@ const MCInst &Inst) const; // Returns the reciprocal throughput information from a MCSchedClassDesc. - static Optional + static double getReciprocalThroughput(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc); - static Optional + static double getReciprocalThroughput(unsigned SchedClass, const InstrItineraryData &IID); - Optional + double getReciprocalThroughput(const MCSubtargetInfo &STI, const MCInstrInfo &MCII, const MCInst &Inst) const; Index: lib/CodeGen/TargetSchedule.cpp =================================================================== --- lib/CodeGen/TargetSchedule.cpp +++ lib/CodeGen/TargetSchedule.cpp @@ -322,7 +322,7 @@ return 0; } -Optional +double TargetSchedModel::computeReciprocalThroughput(const MachineInstr *MI) const { if (hasInstrItineraries()) { unsigned SchedClass = MI->getDesc().getSchedClass(); @@ -332,10 +332,11 @@ if (hasInstrSchedModel()) return MCSchedModel::getReciprocalThroughput(*STI, *resolveSchedClass(MI)); - return Optional(); + + return std::nan(""); } -Optional +double TargetSchedModel::computeReciprocalThroughput(unsigned Opcode) const { unsigned SchedClass = TII->get(Opcode).getSchedClass(); if (hasInstrItineraries()) @@ -346,10 +347,11 @@ if (SCDesc.isValid() && !SCDesc.isVariant()) return MCSchedModel::getReciprocalThroughput(*STI, SCDesc); } - return Optional(); + + return std::nan(""); } -Optional +double TargetSchedModel::computeReciprocalThroughput(const MCInst &MI) const { if (hasInstrSchedModel()) return SchedModel.getReciprocalThroughput(*STI, *TII, MI); Index: lib/CodeGen/TargetSubtargetInfo.cpp =================================================================== --- lib/CodeGen/TargetSubtargetInfo.cpp +++ lib/CodeGen/TargetSubtargetInfo.cpp @@ -67,13 +67,12 @@ return false; } -static std::string createSchedInfoStr(unsigned Latency, - Optional RThroughput) { +static std::string createSchedInfoStr(unsigned Latency, double RThroughput) { static const char *SchedPrefix = " sched: ["; std::string Comment; raw_string_ostream CS(Comment); - if (RThroughput.hasValue()) - CS << SchedPrefix << Latency << format(":%2.2f", RThroughput.getValue()) + if (!std::isnan(RThroughput)) + CS << SchedPrefix << Latency << format(":%2.2f", RThroughput) << "]"; else CS << SchedPrefix << Latency << ":?]"; @@ -90,7 +89,7 @@ TargetSchedModel TSchedModel; TSchedModel.init(this); unsigned Latency = TSchedModel.computeInstrLatency(&MI); - Optional RThroughput = TSchedModel.computeReciprocalThroughput(&MI); + double RThroughput = TSchedModel.computeReciprocalThroughput(&MI); return createSchedInfoStr(Latency, RThroughput); } @@ -109,8 +108,7 @@ getInstrInfo()->get(MCI.getOpcode()).getSchedClass()); } else return std::string(); - Optional RThroughput = - TSchedModel.computeReciprocalThroughput(MCI); + double RThroughput = TSchedModel.computeReciprocalThroughput(MCI); return createSchedInfoStr(Latency, RThroughput); } Index: lib/MC/MCSchedule.cpp =================================================================== --- lib/MC/MCSchedule.cpp +++ lib/MC/MCSchedule.cpp @@ -85,32 +85,43 @@ llvm_unreachable("unsupported variant scheduling class"); } -Optional +double MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc) { - Optional Throughput; + // fmin(NaN, number) returns number. But this function can return NaN if a + // schedule class specifies a latency without specifying a valid throughput. + double Throughput = std::numeric_limits::quiet_NaN(); const MCSchedModel &SM = STI.getSchedModel(); const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc); const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc); + + // If an instruction has no latency (consumes no execution resources), then + // assume that it can execute at the maximum issue width scaled by number of + // micro-ops for the schedule class. + if (!computeInstrLatency(STI, SCDesc)) + Throughput = SM.IssueWidth / SCDesc.NumMicroOps; + for (; I != E; ++I) { if (!I->Cycles) continue; unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits; double Temp = NumUnits * 1.0 / I->Cycles; - Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; + Throughput = std::fmin(Throughput, Temp); } - return Throughput ? 1 / Throughput.getValue() : Throughput; + return 1.0 / Throughput; } -Optional +double MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, const MCInstrInfo &MCII, const MCInst &Inst) const { - Optional Throughput; unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass(); const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass); + + // If there's no valid class, assume that the instruction executes/completes + // at the maximum issue width. if (!SCDesc->isValid()) - return Throughput; + return 1.0 / IssueWidth; unsigned CPUID = getProcessorID(); while (SCDesc->isVariant()) { @@ -124,17 +135,24 @@ llvm_unreachable("unsupported variant scheduling class"); } -Optional +double MCSchedModel::getReciprocalThroughput(unsigned SchedClass, const InstrItineraryData &IID) { - Optional Throughput; + // fmin(NaN, number) returns number, so this function always returns a number. + double Throughput = std::numeric_limits::quiet_NaN(); const InstrStage *I = IID.beginStage(SchedClass); const InstrStage *E = IID.endStage(SchedClass); + + // If there are no execution resources for this class, then assume that it can + // execute at the maximum default issue width. + if (I == E) + Throughput = DefaultIssueWidth; + for (; I != E; ++I) { if (!I->getCycles()) continue; double Temp = countPopulation(I->getUnits()) * 1.0 / I->getCycles(); - Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; + Throughput = std::fmin(Throughput, Temp); } - return Throughput ? 1 / Throughput.getValue() : Throughput; + return 1.0 / Throughput; } Index: test/CodeGen/X86/sse-schedule.ll =================================================================== --- test/CodeGen/X86/sse-schedule.ll +++ test/CodeGen/X86/sse-schedule.ll @@ -6225,7 +6225,7 @@ ; ; BTVER2-SSE-LABEL: test_fnop: ; BTVER2-SSE: # %bb.0: -; BTVER2-SSE-NEXT: xorps %xmm0, %xmm0 # sched: [0:?] +; BTVER2-SSE-NEXT: xorps %xmm0, %xmm0 # sched: [0:0.50] ; BTVER2-SSE-NEXT: #APP ; BTVER2-SSE-NEXT: nop # sched: [1:0.50] ; BTVER2-SSE-NEXT: #NO_APP @@ -6233,7 +6233,7 @@ ; ; BTVER2-LABEL: test_fnop: ; BTVER2: # %bb.0: -; BTVER2-NEXT: vxorps %xmm0, %xmm0, %xmm0 # sched: [0:?] +; BTVER2-NEXT: vxorps %xmm0, %xmm0, %xmm0 # sched: [0:0.50] ; BTVER2-NEXT: #APP ; BTVER2-NEXT: nop # sched: [1:0.50] ; BTVER2-NEXT: #NO_APP