diff --git a/docs/CommandGuide/llvm-exegesis.rst b/docs/CommandGuide/llvm-exegesis.rst index bf21563722f..f27db9e57ed 100644 --- a/docs/CommandGuide/llvm-exegesis.rst +++ b/docs/CommandGuide/llvm-exegesis.rst @@ -224,6 +224,10 @@ OPTIONS If set, ignore instructions that do not have a sched class (class idx = 0). + .. option:: -mcpu= + + If set, measure the cpu characteristics using the counters for this CPU. This + is useful when creating new sched models (the host CPU is unknown to LLVM). EXIT STATUS ----------- diff --git a/docs/CommandGuide/tblgen.rst b/docs/CommandGuide/tblgen.rst index 55b54294846..3105e0c8076 100644 --- a/docs/CommandGuide/tblgen.rst +++ b/docs/CommandGuide/tblgen.rst @@ -130,6 +130,10 @@ OPTIONS Generate enhanced disassembly info. +.. option:: -gen-exegesis + + Generate llvm-exegesis tables. + .. option:: -version Show the version number of this program. diff --git a/include/llvm/MC/MCSchedule.h b/include/llvm/MC/MCSchedule.h index 8990c2e3c0d..41305296b00 100644 --- a/include/llvm/MC/MCSchedule.h +++ b/include/llvm/MC/MCSchedule.h @@ -183,22 +183,6 @@ struct MCExtraProcessorInfo { unsigned NumRegisterFiles; const MCRegisterCostEntry *RegisterCostTable; unsigned NumRegisterCostEntries; - - struct PfmCountersInfo { - // An optional name of a performance counter that can be used to measure - // cycles. - const char *CycleCounter; - - // An optional name of a performance counter that can be used to measure - // uops. - const char *UopsCounter; - - // For each MCProcResourceDesc defined by the processor, an optional list of - // names of performance counters that can be used to measure the resource - // utilization. - const char **IssueCounters; - }; - PfmCountersInfo PfmCounters; }; /// Machine model for scheduling, bundling, and heuristics. diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index 538605a57ab..c2c56b0aca1 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -1555,3 +1555,8 @@ include "llvm/Target/GlobalISel/Target.td" // Pull in the common support for the Global ISel DAG-based selector generation. // include "llvm/Target/GlobalISel/SelectionDAGCompat.td" + +//===----------------------------------------------------------------------===// +// Pull in the common support for Pfm Counters generation. +// +include "llvm/Target/TargetPfmCounters.td" diff --git a/include/llvm/Target/TargetPfmCounters.td b/include/llvm/Target/TargetPfmCounters.td new file mode 100644 index 00000000000..0a55a558f30 --- /dev/null +++ b/include/llvm/Target/TargetPfmCounters.td @@ -0,0 +1,46 @@ +//===- TargetPfmCounters.td - Target Pfm Counters -*- tablegen ----------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the target-independent interfaces for performance counters. + +// Definition of a hardware counters from libpfm identifiers. +class PfmCounter { + // The name of the counter that measures events. + // The name can be "some_counter + some_other_counter", in which case the + // measured value is the sum of events on these counters. + string Counter = counter; +} + +// Issue counters can be tied to a ProcResource +class PfmIssueCounter + : PfmCounter { + // The name of the ProcResource on which uops are issued. This is used by + // llvm-exegesis to compare measurements with values in the SchedModels. + // If the CPU has a sched model, this should correspond to the name of a + // ProcResource. + string ResourceName = resource_name; +} + +def NoPfmCounter : PfmCounter <""> {} + +// Set of PfmCounters for measuring sched model characteristics. +class ProcPfmCounters { + // Processors can define how to measure cycles by defining a CycleCounter. + PfmCounter CycleCounter = NoPfmCounter; + // Processors can define how to measure uops by defining a UopsCounter. + PfmCounter UopsCounter = NoPfmCounter; + // Processors can define how to measure issued uops by defining IssueCounters. + list IssueCounters = []; +} + +// A binding of a set of counters to a CPU. +class PfmCountersBinding { + string CpuName = cpu_name; + ProcPfmCounters Counters = counters; +} diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index 77b1927f932..141e0669388 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -557,31 +557,3 @@ class RetireControlUnit { int MaxRetirePerCycle = retirePerCycle; SchedMachineModel SchedModel = ?; } - -// Allow the definition of hardware counters. -class PfmCounter { - SchedMachineModel SchedModel = ?; -} - -// Each processor can define how to measure cycles by defining a -// PfmCycleCounter. -class PfmCycleCounter : PfmCounter { - string Counter = counter; -} - -// Each ProcResourceUnits can define how to measure issued uops by defining -// a PfmIssueCounter. -class PfmIssueCounter counters> - : PfmCounter{ - // The resource units on which uops are issued. - ProcResourceUnits Resource = resource; - // The list of counters that measure issue events. - list Counters = counters; -} - -// Each processor can define how to measure NumMicroOps by defining a -// PfmUopsCounter. -class PfmUopsCounter : PfmCounter { - string Counter = counter; -} - diff --git a/lib/Target/X86/CMakeLists.txt b/lib/Target/X86/CMakeLists.txt index 4495bc20618..5ded1f971a0 100644 --- a/lib/Target/X86/CMakeLists.txt +++ b/lib/Target/X86/CMakeLists.txt @@ -13,6 +13,7 @@ tablegen(LLVM X86GenInstrInfo.inc -gen-instr-info) tablegen(LLVM X86GenRegisterBank.inc -gen-register-bank) tablegen(LLVM X86GenRegisterInfo.inc -gen-register-info) tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM X86GenExegesis.inc -gen-exegesis) if (X86_GEN_FOLD_TABLES) tablegen(LLVM X86GenFoldTables.inc -gen-x86-fold-tables) diff --git a/lib/Target/X86/X86PfmCounters.td b/lib/Target/X86/X86PfmCounters.td index 684cadd4962..9e0f0c4f64a 100644 --- a/lib/Target/X86/X86PfmCounters.td +++ b/lib/Target/X86/X86PfmCounters.td @@ -11,73 +11,92 @@ // //===----------------------------------------------------------------------===// -let SchedModel = SandyBridgeModel in { -def SBCycleCounter : PfmCycleCounter<"unhalted_core_cycles">; -def SBPort0Counter : PfmIssueCounter; -def SBPort1Counter : PfmIssueCounter; -def SBPort23Counter : PfmIssueCounter; -def SBPort4Counter : PfmIssueCounter; -def SBPort5Counter : PfmIssueCounter; -def SBUopsCounter : PfmUopsCounter<"uops_issued:any">; -} +def UnhaltedCoreCyclesPfmCounter : PfmCounter<"unhalted_core_cycles">; +def UopsIssuedPfmCounter : PfmCounter<"uops_issued:any">; -let SchedModel = HaswellModel in { -def HWCycleCounter : PfmCycleCounter<"unhalted_core_cycles">; -def HWPort0Counter : PfmIssueCounter; -def HWPort1Counter : PfmIssueCounter; -def HWPort2Counter : PfmIssueCounter; -def HWPort3Counter : PfmIssueCounter; -def HWPort4Counter : PfmIssueCounter; -def HWPort5Counter : PfmIssueCounter; -def HWPort6Counter : PfmIssueCounter; -def HWPort7Counter : PfmIssueCounter; -def HWUopsCounter : PfmUopsCounter<"uops_issued:any">; +def SandyBridgePfmCounters : ProcPfmCounters { + let CycleCounter = UnhaltedCoreCyclesPfmCounter; + let UopsCounter = UopsIssuedPfmCounter; + let IssueCounters = [ + PfmIssueCounter<"SBPort0", "uops_dispatched_port:port_0">, + PfmIssueCounter<"SBPort1", "uops_dispatched_port:port_1">, + PfmIssueCounter<"SBPort23", "uops_dispatched_port:port_2 + uops_dispatched_port:port_3">, + PfmIssueCounter<"SBPort4", "uops_dispatched_port:port_4">, + PfmIssueCounter<"SBPort5", "uops_dispatched_port:port_5"> + ]; } +def : PfmCountersBinding<"sandybridge", SandyBridgePfmCounters>; -let SchedModel = BroadwellModel in { -def BWCycleCounter : PfmCycleCounter<"unhalted_core_cycles">; -def BWPort0Counter : PfmIssueCounter; -def BWPort1Counter : PfmIssueCounter; -def BWPort2Counter : PfmIssueCounter; -def BWPort3Counter : PfmIssueCounter; -def BWPort4Counter : PfmIssueCounter; -def BWPort5Counter : PfmIssueCounter; -def BWPort6Counter : PfmIssueCounter; -def BWPort7Counter : PfmIssueCounter; -def BWUopsCounter : PfmUopsCounter<"uops_issued:any">; +def HaswellPfmCounters : ProcPfmCounters { + let CycleCounter = UnhaltedCoreCyclesPfmCounter; + let UopsCounter = UopsIssuedPfmCounter; + let IssueCounters = [ + PfmIssueCounter<"HWPort0", "uops_dispatched_port:port_0">, + PfmIssueCounter<"HWPort1", "uops_dispatched_port:port_1">, + PfmIssueCounter<"HWPort2", "uops_dispatched_port:port_2">, + PfmIssueCounter<"HWPort3", "uops_dispatched_port:port_3">, + PfmIssueCounter<"HWPort4", "uops_dispatched_port:port_4">, + PfmIssueCounter<"HWPort5", "uops_dispatched_port:port_5">, + PfmIssueCounter<"HWPort6", "uops_dispatched_port:port_6">, + PfmIssueCounter<"HWPort7", "uops_dispatched_port:port_7"> + ]; } +def : PfmCountersBinding<"haswell", HaswellPfmCounters>; -let SchedModel = SkylakeClientModel in { -def SKLCycleCounter : PfmCycleCounter<"unhalted_core_cycles">; -def SKLPort0Counter : PfmIssueCounter; -def SKLPort1Counter : PfmIssueCounter; -def SKLPort2Counter : PfmIssueCounter; -def SKLPort3Counter : PfmIssueCounter; -def SKLPort4Counter : PfmIssueCounter; -def SKLPort5Counter : PfmIssueCounter; -def SKLPort6Counter : PfmIssueCounter; -def SKLPort7Counter : PfmIssueCounter; -def SKLUopsCounter : PfmUopsCounter<"uops_issued:any">; +def BroadwellPfmCounters : ProcPfmCounters { + let CycleCounter = UnhaltedCoreCyclesPfmCounter; + let UopsCounter = UopsIssuedPfmCounter; + let IssueCounters = [ + PfmIssueCounter<"BWPort0", "uops_executed_port:port_0">, + PfmIssueCounter<"BWPort1", "uops_executed_port:port_1">, + PfmIssueCounter<"BWPort2", "uops_executed_port:port_2">, + PfmIssueCounter<"BWPort3", "uops_executed_port:port_3">, + PfmIssueCounter<"BWPort4", "uops_executed_port:port_4">, + PfmIssueCounter<"BWPort5", "uops_executed_port:port_5">, + PfmIssueCounter<"BWPort6", "uops_executed_port:port_6">, + PfmIssueCounter<"BWPort7", "uops_executed_port:port_7"> + ]; } +def : PfmCountersBinding<"broadwell", BroadwellPfmCounters>; -let SchedModel = SkylakeServerModel in { -def SKXCycleCounter : PfmCycleCounter<"unhalted_core_cycles">; -def SKXPort0Counter : PfmIssueCounter; -def SKXPort1Counter : PfmIssueCounter; -def SKXPort2Counter : PfmIssueCounter; -def SKXPort3Counter : PfmIssueCounter; -def SKXPort4Counter : PfmIssueCounter; -def SKXPort5Counter : PfmIssueCounter; -def SKXPort6Counter : PfmIssueCounter; -def SKXPort7Counter : PfmIssueCounter; -def SKXUopsCounter : PfmUopsCounter<"uops_issued:any">; +def SkylakeClientPfmCounters : ProcPfmCounters { + let CycleCounter = UnhaltedCoreCyclesPfmCounter; + let UopsCounter = UopsIssuedPfmCounter; + let IssueCounters = [ + PfmIssueCounter<"SKLPort0", "uops_dispatched_port:port_0">, + PfmIssueCounter<"SKLPort1", "uops_dispatched_port:port_1">, + PfmIssueCounter<"SKLPort2", "uops_dispatched_port:port_2">, + PfmIssueCounter<"SKLPort3", "uops_dispatched_port:port_3">, + PfmIssueCounter<"SKLPort4", "uops_dispatched_port:port_4">, + PfmIssueCounter<"SKLPort5", "uops_dispatched_port:port_5">, + PfmIssueCounter<"SKLPort6", "uops_dispatched_port:port_6">, + PfmIssueCounter<"SKLPort7", "uops_dispatched_port:port_7"> + ]; } +def : PfmCountersBinding<"skylake", SkylakeClientPfmCounters>; -let SchedModel = BtVer2Model in { -def JCycleCounter : PfmCycleCounter<"cpu_clk_unhalted">; -def JUopsCounter : PfmUopsCounter<"retired_uops">; -def JFPU0Counter : PfmIssueCounter; -def JFPU1Counter : PfmIssueCounter; +def SkylakeServerPfmCounters : ProcPfmCounters { + let CycleCounter = UnhaltedCoreCyclesPfmCounter; + let UopsCounter = UopsIssuedPfmCounter; + let IssueCounters = [ + PfmIssueCounter<"SKXPort0", "uops_dispatched_port:port_0">, + PfmIssueCounter<"SKXPort1", "uops_dispatched_port:port_1">, + PfmIssueCounter<"SKXPort2", "uops_dispatched_port:port_2">, + PfmIssueCounter<"SKXPort3", "uops_dispatched_port:port_3">, + PfmIssueCounter<"SKXPort4", "uops_dispatched_port:port_4">, + PfmIssueCounter<"SKXPort5", "uops_dispatched_port:port_5">, + PfmIssueCounter<"SKXPort6", "uops_dispatched_port:port_6">, + PfmIssueCounter<"SKXPort7", "uops_dispatched_port:port_7"> + ]; } +def : PfmCountersBinding<"skylake-avx512", SkylakeServerPfmCounters>; + +def BtVer2PfmCounters : ProcPfmCounters { + let CycleCounter = PfmCounter<"cpu_clk_unhalted">; + let UopsCounter = PfmCounter<"retired_uops">; + let IssueCounters = [ + PfmIssueCounter<"JFPU0", "dispatched_fpu:pipe0">, + PfmIssueCounter<"JFPU1", "dispatched_fpu:pipe1"> + ]; +} +def : PfmCountersBinding<"btver2", BtVer2PfmCounters>; diff --git a/tools/llvm-exegesis/lib/AArch64/Target.cpp b/tools/llvm-exegesis/lib/AArch64/Target.cpp index be8f0b41ede..0197420f433 100644 --- a/tools/llvm-exegesis/lib/AArch64/Target.cpp +++ b/tools/llvm-exegesis/lib/AArch64/Target.cpp @@ -53,6 +53,10 @@ static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth, } // namespace class ExegesisAArch64Target : public ExegesisTarget { +public: + ExegesisAArch64Target() : ExegesisTarget({}) {} + +private: std::vector setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg, const llvm::APInt &Value) const override { diff --git a/tools/llvm-exegesis/lib/Latency.cpp b/tools/llvm-exegesis/lib/Latency.cpp index 602b379faf3..3d18e37f4c3 100644 --- a/tools/llvm-exegesis/lib/Latency.cpp +++ b/tools/llvm-exegesis/lib/Latency.cpp @@ -12,6 +12,8 @@ #include "Assembler.h" #include "BenchmarkRunner.h" #include "MCInstrDescView.h" +#include "PerfHelper.h" +#include "Target.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" @@ -165,12 +167,7 @@ LatencySnippetGenerator::generateCodeTemplates(const Instruction &Instr) const { } const char *LatencyBenchmarkRunner::getCounterName() const { - if (!State.getSubtargetInfo().getSchedModel().hasExtraProcessorInfo()) - llvm::report_fatal_error("sched model is missing extra processor info!"); - const char *CounterName = State.getSubtargetInfo() - .getSchedModel() - .getExtraProcessorInfo() - .PfmCounters.CycleCounter; + const char *CounterName = State.getPfmCounters().CycleCounter; if (!CounterName) llvm::report_fatal_error("sched model does not define a cycle counter"); return CounterName; diff --git a/tools/llvm-exegesis/lib/LlvmState.cpp b/tools/llvm-exegesis/lib/LlvmState.cpp index 58e9db315d5..b5580c83cf5 100644 --- a/tools/llvm-exegesis/lib/LlvmState.cpp +++ b/tools/llvm-exegesis/lib/LlvmState.cpp @@ -36,14 +36,17 @@ LLVMState::LLVMState(const std::string &Triple, const std::string &CpuName) { llvm::errs() << "no exegesis target for " << Triple << ", using default\n"; TheExegesisTarget = &ExegesisTarget::getDefault(); } + PfmCounters = &TheExegesisTarget->getPfmCounters(CpuName); + RATC.reset(new RegisterAliasingTrackerCache( getRegInfo(), getFunctionReservedRegs(getTargetMachine()))); IC.reset(new InstructionsCache(getInstrInfo(), getRATC())); } -LLVMState::LLVMState() +LLVMState::LLVMState(const std::string &CpuName) : LLVMState(llvm::sys::getProcessTriple(), - llvm::sys::getHostCPUName().str()) {} + CpuName.empty() ? llvm::sys::getHostCPUName().str() : CpuName) { +} std::unique_ptr LLVMState::createTargetMachine() const { diff --git a/tools/llvm-exegesis/lib/LlvmState.h b/tools/llvm-exegesis/lib/LlvmState.h index 918738551d0..be1e7979a17 100644 --- a/tools/llvm-exegesis/lib/LlvmState.h +++ b/tools/llvm-exegesis/lib/LlvmState.h @@ -30,12 +30,14 @@ namespace llvm { namespace exegesis { class ExegesisTarget; +class PfmCountersInfo; // An object to initialize LLVM and prepare objects needed to run the // measurements. class LLVMState { public: - LLVMState(); + // Uses the host triple. If CpuName is empty, uses the host CPU. + LLVMState(const std::string &CpuName); LLVMState(const std::string &Triple, const std::string &CpuName); // For tests. @@ -57,14 +59,18 @@ public: const llvm::MCSubtargetInfo &getSubtargetInfo() const { return *TargetMachine->getMCSubtargetInfo(); } + const RegisterAliasingTrackerCache &getRATC() const { return *RATC; } const InstructionsCache &getIC() const { return *IC; } + const PfmCountersInfo &getPfmCounters() const { return *PfmCounters; } + private: const ExegesisTarget *TheExegesisTarget; std::unique_ptr TargetMachine; std::unique_ptr RATC; std::unique_ptr IC; + const PfmCountersInfo *PfmCounters; }; } // namespace exegesis diff --git a/tools/llvm-exegesis/lib/Target.cpp b/tools/llvm-exegesis/lib/Target.cpp index b7828a13da0..588c40e8c7f 100644 --- a/tools/llvm-exegesis/lib/Target.cpp +++ b/tools/llvm-exegesis/lib/Target.cpp @@ -85,10 +85,37 @@ ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const { return llvm::make_unique(State); } +static_assert(std::is_pod::value, + "We shouldn't have dynamic initialization here"); +const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr}; + +const PfmCountersInfo & +ExegesisTarget::getPfmCounters(llvm::StringRef CpuName) const { + assert(std::is_sorted( + CpuPfmCounters.begin(), CpuPfmCounters.end(), + [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) { + return strcmp(LHS.CpuName, RHS.CpuName) < 0; + }) && + "CpuPfmCounters table is not sorted"); + + // Find entry + auto Found = + std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName); + if (Found == CpuPfmCounters.end() || + llvm::StringRef(Found->CpuName) != CpuName) { + return PfmCountersInfo::Default; + } + assert(Found->PCI && "Missing counters"); + return *Found->PCI; +} + namespace { // Default implementation. class ExegesisDefaultTarget : public ExegesisTarget { +public: + ExegesisDefaultTarget() : ExegesisTarget({}) {} + private: std::vector setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg, diff --git a/tools/llvm-exegesis/lib/Target.h b/tools/llvm-exegesis/lib/Target.h index 2e94727d78d..a6ec36bebb3 100644 --- a/tools/llvm-exegesis/lib/Target.h +++ b/tools/llvm-exegesis/lib/Target.h @@ -31,8 +31,42 @@ namespace llvm { namespace exegesis { +struct PfmCountersInfo { + // An optional name of a performance counter that can be used to measure + // cycles. + const char *const CycleCounter; + + // An optional name of a performance counter that can be used to measure + // uops. + const char *const UopsCounter; + + // An IssueCounter specifies how to measure uops issued to specific proc + // resources. + struct IssueCounter { + const char *const Counter; + // The name of the ProcResource that this counter measures. + const char *const ProcResName; + }; + // An optional list of IssueCounters. + const IssueCounter *const IssueCounters; + const unsigned NumIssueCounters; + + static const PfmCountersInfo Default; +}; + +struct CpuAndPfmCounters { + const char *const CpuName; + const PfmCountersInfo *const PCI; + bool operator<(llvm::StringRef S) const { + return llvm::StringRef(CpuName) < S; + } +}; + class ExegesisTarget { public: + explicit ExegesisTarget(llvm::ArrayRef CpuPfmCounters) + : CpuPfmCounters(CpuPfmCounters) {} + // Targets can use this to add target-specific passes in assembleToStream(); virtual void addTargetSpecificPasses(llvm::PassManagerBase &PM) const {} @@ -83,6 +117,10 @@ public: virtual ~ExegesisTarget(); + // Returns the Pfm counters for the given CPU (or the default if no pfm + // counters are defined for this CPU). + const PfmCountersInfo &getPfmCounters(llvm::StringRef CpuName) const; + private: virtual bool matchesArch(llvm::Triple::ArchType Arch) const = 0; @@ -98,6 +136,7 @@ private: const LLVMState &State) const; const ExegesisTarget *Next = nullptr; + const llvm::ArrayRef CpuPfmCounters; }; } // namespace exegesis diff --git a/tools/llvm-exegesis/lib/Uops.cpp b/tools/llvm-exegesis/lib/Uops.cpp index 5aa726218c7..9768f4533f7 100644 --- a/tools/llvm-exegesis/lib/Uops.cpp +++ b/tools/llvm-exegesis/lib/Uops.cpp @@ -223,24 +223,22 @@ UopsSnippetGenerator::generateCodeTemplates(const Instruction &Instr) const { llvm::Expected> UopsBenchmarkRunner::runMeasurements(const FunctionExecutor &Executor) const { - const auto &SchedModel = State.getSubtargetInfo().getSchedModel(); - std::vector Result; - const auto &PfmCounters = SchedModel.getExtraProcessorInfo().PfmCounters; + const PfmCountersInfo &PCI = State.getPfmCounters(); // Uops per port. - for (unsigned ProcResIdx = 1; - ProcResIdx < SchedModel.getNumProcResourceKinds(); ++ProcResIdx) { - const char *const Counters = PfmCounters.IssueCounters[ProcResIdx]; - if (!Counters) + for (const auto *IssueCounter = PCI.IssueCounters, + *IssueCounterEnd = PCI.IssueCounters + PCI.NumIssueCounters; + IssueCounter != IssueCounterEnd; ++IssueCounter) { + if (!IssueCounter->Counter) continue; - auto ExpectedCounterValue = Executor.runAndMeasure(Counters); + auto ExpectedCounterValue = Executor.runAndMeasure(IssueCounter->Counter); if (!ExpectedCounterValue) return ExpectedCounterValue.takeError(); - Result.push_back(BenchmarkMeasure::Create( - SchedModel.getProcResource(ProcResIdx)->Name, *ExpectedCounterValue)); + Result.push_back(BenchmarkMeasure::Create(IssueCounter->ProcResName, + *ExpectedCounterValue)); } // NumMicroOps. - if (const char *const UopsCounter = PfmCounters.UopsCounter) { + if (const char *const UopsCounter = PCI.UopsCounter) { auto ExpectedCounterValue = Executor.runAndMeasure(UopsCounter); if (!ExpectedCounterValue) return ExpectedCounterValue.takeError(); diff --git a/tools/llvm-exegesis/lib/X86/Target.cpp b/tools/llvm-exegesis/lib/X86/Target.cpp index 69804849e62..6ae228e1124 100644 --- a/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/tools/llvm-exegesis/lib/X86/Target.cpp @@ -329,7 +329,13 @@ private: std::vector Instructions; }; +#include "X86GenExegesis.inc" + class ExegesisX86Target : public ExegesisTarget { +public: + ExegesisX86Target() : ExegesisTarget(X86CpuPfmCounters) {} + +private: void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override { // Lowers FP pseudo-instructions, e.g. ABS_Fp32 -> ABS_F. PM.add(llvm::createX86FloatingPointStackifierPass()); diff --git a/tools/llvm-exegesis/llvm-exegesis.cpp b/tools/llvm-exegesis/llvm-exegesis.cpp index 689a1e097c6..a28e68ec006 100644 --- a/tools/llvm-exegesis/llvm-exegesis.cpp +++ b/tools/llvm-exegesis/llvm-exegesis.cpp @@ -94,6 +94,13 @@ static cl::opt AnalysisInconsistenciesOutputFile("analysis-inconsistencies-output-file", cl::desc(""), cl::init("-")); +static cl::opt + CpuName("mcpu", + cl::desc( + "cpu name to use for pfm counters, leave empty to autodetect"), + cl::init("")); + + static ExitOnError ExitOnErr; #ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET @@ -321,7 +328,7 @@ void benchmarkMain() { LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET(); #endif - const LLVMState State; + const LLVMState State(CpuName); const auto Opcodes = getOpcodesOrDie(State.getInstrInfo()); std::vector Configurations; @@ -399,7 +406,7 @@ static void analysisMain() { llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetDisassembler(); // Read benchmarks. - const LLVMState State; + const LLVMState State(""); const std::vector Points = ExitOnErr(InstructionBenchmark::readYamls(State, BenchmarkFile)); llvm::outs() << "Parsed " << Points.size() << " benchmark points\n"; diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 0428249f917..c88365a2b8c 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -21,6 +21,7 @@ add_tablegen(llvm-tblgen LLVM DAGISelMatcher.cpp DFAPacketizerEmitter.cpp DisassemblerEmitter.cpp + ExegesisEmitter.cpp FastISelEmitter.cpp FixedLenDecoderEmitter.cpp GlobalISelEmitter.cpp diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index e94ed760fc4..a9a36a87ef3 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -350,7 +350,7 @@ processSTIPredicate(STIPredicateFunction &Fn, unsigned OpcodeIdx = Opcode2Index[Opcode]; if (OpcodeMasks[OpcodeIdx].first[ProcIndex]) { std::string Message = - "Opcode " + Opcode->getName().str() + + "Opcode " + Opcode->getName().str() + " used by multiple InstructionEquivalenceClass definitions."; PrintFatalError(EC->getLoc(), Message); } @@ -487,9 +487,6 @@ void CodeGenSchedModels::collectOptionalProcessorInfo() { // Collect processor RetireControlUnit descriptors if available. collectRetireControlUnits(); - // Find pfm counter definitions for each processor. - collectPfmCounters(); - checkCompleteness(); } @@ -1789,32 +1786,6 @@ void CodeGenSchedModels::collectRegisterFiles() { } } -// Collect all the RegisterFile definitions available in this target. -void CodeGenSchedModels::collectPfmCounters() { - for (Record *Def : Records.getAllDerivedDefinitions("PfmIssueCounter")) { - CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); - PM.PfmIssueCounterDefs.emplace_back(Def); - } - for (Record *Def : Records.getAllDerivedDefinitions("PfmCycleCounter")) { - CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); - if (PM.PfmCycleCounterDef) { - PrintFatalError(Def->getLoc(), - "multiple cycle counters for " + - Def->getValueAsDef("SchedModel")->getName()); - } - PM.PfmCycleCounterDef = Def; - } - for (Record *Def : Records.getAllDerivedDefinitions("PfmUopsCounter")) { - CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); - if (PM.PfmUopsCounterDef) { - PrintFatalError(Def->getLoc(), - "multiple uops counters for " + - Def->getValueAsDef("SchedModel")->getName()); - } - PM.PfmUopsCounterDef = Def; - } -} - // Collect and sort WriteRes, ReadAdvance, and ProcResources. void CodeGenSchedModels::collectProcResources() { ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 39443bb35e9..9bde5f4e759 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -246,11 +246,6 @@ struct CodeGenProcModel { // Optional Retire Control Unit definition. Record *RetireControlUnit; - // List of PfmCounters. - RecVec PfmIssueCounterDefs; - Record *PfmCycleCounterDef = nullptr; - Record *PfmUopsCounterDef = nullptr; - CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef, Record *IDef) : Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef), @@ -265,10 +260,7 @@ struct CodeGenProcModel { } bool hasExtraProcessorInfo() const { - return RetireControlUnit || !RegisterFiles.empty() || - !PfmIssueCounterDefs.empty() || - PfmCycleCounterDef != nullptr || - PfmUopsCounterDef != nullptr; + return RetireControlUnit || !RegisterFiles.empty(); } unsigned getProcResourceIdx(Record *PRDef) const; @@ -593,8 +585,6 @@ private: void collectRegisterFiles(); - void collectPfmCounters(); - void collectOptionalProcessorInfo(); std::string createSchedClassName(Record *ItinClassDef, diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 2766fcca161..305d2d19ff4 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -711,4 +711,3 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // Sort the argument attributes for later benefit. llvm::sort(ArgumentAttributes); } - diff --git a/utils/TableGen/ExegesisEmitter.cpp b/utils/TableGen/ExegesisEmitter.cpp new file mode 100644 index 00000000000..083d7439451 --- /dev/null +++ b/utils/TableGen/ExegesisEmitter.cpp @@ -0,0 +1,212 @@ +//===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits llvm-exegesis information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "exegesis-emitter" + +namespace { + +class ExegesisEmitter { +public: + ExegesisEmitter(RecordKeeper &RK); + + void run(raw_ostream &OS) const; + +private: + unsigned getPfmCounterId(llvm::StringRef Name) const { + const auto It = PfmCounterNameTable.find(Name); + if (It == PfmCounterNameTable.end()) + PrintFatalError("no pfm counter id for " + Name); + return It->second; + } + + // Collects all the ProcPfmCounters definitions available in this target. + void emitPfmCounters(raw_ostream &OS) const; + + void emitPfmCountersInfo(const Record &Def, + unsigned &IssueCountersTableOffset, + raw_ostream &OS) const; + + void emitPfmCountersLookupTable(raw_ostream &OS) const; + + RecordKeeper &Records; + std::string Target; + + // Table of counter name -> counter index. + const std::map PfmCounterNameTable; +}; + +static std::map +collectPfmCounters(const RecordKeeper &Records) { + std::map PfmCounterNameTable; + const auto AddPfmCounterName = [&PfmCounterNameTable]( + const Record *PfmCounterDef) { + const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter"); + if (!Counter.empty()) + PfmCounterNameTable.emplace(Counter, 0); + }; + for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) { + // Check that ResourceNames are unique. + llvm::SmallSet Seen; + for (const Record *IssueCounter : + Def->getValueAsListOfDefs("IssueCounters")) { + const llvm::StringRef ResourceName = + IssueCounter->getValueAsString("ResourceName"); + if (ResourceName.empty()) + PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName"); + if (!Seen.insert(ResourceName).second) + PrintFatalError(IssueCounter->getLoc(), + "duplicate ResourceName " + ResourceName); + AddPfmCounterName(IssueCounter); + } + AddPfmCounterName(Def->getValueAsDef("CycleCounter")); + AddPfmCounterName(Def->getValueAsDef("UopsCounter")); + } + unsigned Index = 0; + for (auto &NameAndIndex : PfmCounterNameTable) + NameAndIndex.second = Index++; + return PfmCounterNameTable; +} + +ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK) + : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) { + std::vector Targets = Records.getAllDerivedDefinitions("Target"); + if (Targets.size() == 0) + PrintFatalError("ERROR: No 'Target' subclasses defined!"); + if (Targets.size() != 1) + PrintFatalError("ERROR: Multiple subclasses of Target defined!"); + Target = Targets[0]->getName(); +} + +void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, + unsigned &IssueCountersTableOffset, + raw_ostream &OS) const { + const auto CycleCounter = + Def.getValueAsDef("CycleCounter")->getValueAsString("Counter"); + const auto UopsCounter = + Def.getValueAsDef("UopsCounter")->getValueAsString("Counter"); + const size_t NumIssueCounters = + Def.getValueAsListOfDefs("IssueCounters").size(); + + // This is the default, do not emit. + if (CycleCounter.empty() && UopsCounter.empty() && NumIssueCounters == 0) + return; + + OS << "\nstatic const PfmCountersInfo " << Target << Def.getName() + << " = {\n"; + + // Cycle Counter. + if (CycleCounter.empty()) + OS << " nullptr, // No cycle counter.\n"; + else + OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter) + << "], // Cycle counter\n"; + + // Uops Counter. + if (UopsCounter.empty()) + OS << " nullptr, // No uops counter.\n"; + else + OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter) + << "], // Uops counter\n"; + + // Issue Counters + if (NumIssueCounters == 0) + OS << " nullptr, // No issue counters.\n 0\n"; + else + OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset + << ", " << NumIssueCounters << " // Issue counters.\n"; + + OS << "};\n"; + IssueCountersTableOffset += NumIssueCounters; +} + +void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { + // Emit the counter name table. + OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n"; + for (const auto &NameAndIndex : PfmCounterNameTable) + OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second + << "\n"; + OS << "};\n\n"; + + // Emit the IssueCounters table. + const auto PfmCounterDefs = + Records.getAllDerivedDefinitions("ProcPfmCounters"); + OS << "static const PfmCountersInfo::IssueCounter " << Target + << "PfmIssueCounters[] = {\n"; + for (const Record *Def : PfmCounterDefs) { + for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters")) + OS << " { " << Target << "PfmCounterNames[" + << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \"" + << ICDef->getValueAsString("ResourceName") << "\"},\n"; + } + + OS << "};\n"; + + // Now generate the PfmCountersInfo. + unsigned IssueCountersTableOffset = 0; + for (const Record *Def : PfmCounterDefs) + emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS); + + OS << "\n"; +} + +void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const { + std::vector Bindings = + Records.getAllDerivedDefinitions("PfmCountersBinding"); + llvm::sort(Bindings, [](const Record *L, const Record *R) { + return L->getValueAsString("CpuName") < R->getValueAsString("CpuName"); + }); + + OS << "// Sorted (by CpuName) array of pfm counters.\n" + << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n"; + for (Record *Binding : Bindings) { + // Emit as { "cpu", procinit }, + OS << " { \"" // + << Binding->getValueAsString("CpuName") << "\"," // + << " &" << Target << Binding->getValueAsDef("Counters")->getName() // + << " },\n"; + } + OS << "};\n\n"; +} + +void ExegesisEmitter::run(raw_ostream &OS) const { + emitSourceFileHeader("Exegesis Tables", OS); + emitPfmCounters(OS); + emitPfmCountersLookupTable(OS); +} + +} // end anonymous namespace + +namespace llvm { + +void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) { + ExegesisEmitter(RK).run(OS); +} + +} // end namespace llvm diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index d1ea968590f..4ff52b3e44e 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -697,80 +697,12 @@ SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel, return CostTblIndex; } -static bool EmitPfmIssueCountersTable(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { - unsigned NumCounterDefs = 1 + ProcModel.ProcResourceDefs.size(); - std::vector CounterDefs(NumCounterDefs); - bool HasCounters = false; - for (const Record *CounterDef : ProcModel.PfmIssueCounterDefs) { - const Record *&CD = CounterDefs[ProcModel.getProcResourceIdx( - CounterDef->getValueAsDef("Resource"))]; - if (CD) { - PrintFatalError(CounterDef->getLoc(), - "multiple issue counters for " + - CounterDef->getValueAsDef("Resource")->getName()); - } - CD = CounterDef; - HasCounters = true; - } - if (!HasCounters) { - return false; - } - OS << "\nstatic const char* " << ProcModel.ModelName - << "PfmIssueCounters[] = {\n"; - for (unsigned i = 0; i != NumCounterDefs; ++i) { - const Record *CounterDef = CounterDefs[i]; - if (CounterDef) { - const auto PfmCounters = CounterDef->getValueAsListOfStrings("Counters"); - if (PfmCounters.empty()) - PrintFatalError(CounterDef->getLoc(), "empty counter list"); - OS << " \"" << PfmCounters[0]; - for (unsigned p = 1, e = PfmCounters.size(); p != e; ++p) - OS << ",\" \"" << PfmCounters[p]; - OS << "\", // #" << i << " = "; - OS << CounterDef->getValueAsDef("Resource")->getName() << "\n"; - } else { - OS << " nullptr, // #" << i << "\n"; - } - } - OS << "};\n"; - return true; -} - -static void EmitPfmCounters(const CodeGenProcModel &ProcModel, - const bool HasPfmIssueCounters, raw_ostream &OS) { - OS << " {\n"; - // Emit the cycle counter. - if (ProcModel.PfmCycleCounterDef) - OS << " \"" << ProcModel.PfmCycleCounterDef->getValueAsString("Counter") - << "\", // Cycle counter.\n"; - else - OS << " nullptr, // No cycle counter.\n"; - - // Emit the uops counter. - if (ProcModel.PfmUopsCounterDef) - OS << " \"" << ProcModel.PfmUopsCounterDef->getValueAsString("Counter") - << "\", // Uops counter.\n"; - else - OS << " nullptr, // No uops counter.\n"; - - // Emit a reference to issue counters table. - if (HasPfmIssueCounters) - OS << " " << ProcModel.ModelName << "PfmIssueCounters\n"; - else - OS << " nullptr // No issue counters.\n"; - OS << " }\n"; -} - void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, raw_ostream &OS) { // Generate a table of register file descriptors (one entry per each user // defined register file), and a table of register costs. unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS); - // Generate a table of ProcRes counter names. - const bool HasPfmIssueCounters = EmitPfmIssueCountersTable(ProcModel, OS); - // Now generate a table for the extra processor info. OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName << "ExtraInfo = {\n "; @@ -783,8 +715,6 @@ void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), NumCostEntries, OS); - EmitPfmCounters(ProcModel, HasPfmIssueCounters, OS); - OS << "};\n"; } @@ -1410,7 +1340,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { } // -// EmitProcessorLookup - generate cpu name to itinerary lookup table. +// EmitProcessorLookup - generate cpu name to sched model lookup tables. // void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { // Gather and sort processor information @@ -1418,12 +1348,11 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { Records.getAllDerivedDefinitions("Processor"); llvm::sort(ProcessorList, LessRecordFieldName()); - // Begin processor table + // Begin processor->sched model table OS << "\n"; - OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" - << "extern const llvm::SubtargetInfoKV " - << Target << "ProcSchedKV[] = {\n"; - + OS << "// Sorted (by key) array of sched model for CPU subtype.\n" + << "extern const llvm::SubtargetInfoKV " << Target + << "ProcSchedKV[] = {\n"; // For each processor for (Record *Processor : ProcessorList) { StringRef Name = Processor->getValueAsString("Name"); @@ -1433,8 +1362,7 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { // Emit as { "cpu", procinit }, OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " },\n"; } - - // End processor table + // End processor->sched model table OS << "};\n"; } @@ -1675,7 +1603,7 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, // Emit target predicates. emitSchedModelHelpersImpl(OS); - + OS << "} // " << ClassName << "::resolveSchedClass\n\n"; OS << "unsigned " << ClassName diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index b78260625cb..d5b6a3c1264 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -53,6 +53,7 @@ enum ActionType { GenX86EVEX2VEXTables, GenX86FoldTables, GenRegisterBank, + GenExegesis, }; namespace { @@ -117,7 +118,9 @@ namespace { clEnumValN(GenX86FoldTables, "gen-x86-fold-tables", "Generate X86 fold tables"), clEnumValN(GenRegisterBank, "gen-register-bank", - "Generate registers bank descriptions"))); + "Generate registers bank descriptions"), + clEnumValN(GenExegesis, "gen-exegesis", + "Generate llvm-exegesis tables"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt @@ -231,6 +234,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenX86FoldTables: EmitX86FoldTables(Records, OS); break; + case GenExegesis: + EmitExegesis(Records, OS); + break; } return false; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 1329a6d833f..f4f2909f8e8 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -89,6 +89,7 @@ void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS); void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS); void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); +void EmitExegesis(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace