1 //===-- Target.cpp ----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "Target.h" 9 10 #include "LatencyBenchmarkRunner.h" 11 #include "ParallelSnippetGenerator.h" 12 #include "SerialSnippetGenerator.h" 13 #include "UopsBenchmarkRunner.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/Support/Error.h" 16 17 namespace llvm { 18 namespace exegesis { 19 20 ExegesisTarget::~ExegesisTarget() {} // anchor. 21 22 static ExegesisTarget *FirstTarget = nullptr; 23 24 const ExegesisTarget *ExegesisTarget::lookup(Triple TT) { 25 for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) { 26 if (T->matchesArch(TT.getArch())) 27 return T; 28 } 29 return nullptr; 30 } 31 32 Expected<std::unique_ptr<pfm::Counter>> 33 ExegesisTarget::createCounter(const char *CounterName, 34 const LLVMState &) const { 35 pfm::PerfEvent Event(CounterName); 36 if (!Event.valid()) 37 return llvm::make_error<Failure>( 38 llvm::Twine("Unable to create counter with name '") 39 .concat(CounterName) 40 .concat("'")); 41 42 return std::make_unique<pfm::Counter>(std::move(Event)); 43 } 44 45 void ExegesisTarget::registerTarget(ExegesisTarget *Target) { 46 if (FirstTarget == nullptr) { 47 FirstTarget = Target; 48 return; 49 } 50 if (Target->Next != nullptr) 51 return; // Already registered. 52 Target->Next = FirstTarget; 53 FirstTarget = Target; 54 } 55 56 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator( 57 InstructionBenchmark::ModeE Mode, const LLVMState &State, 58 const SnippetGenerator::Options &Opts) const { 59 switch (Mode) { 60 case InstructionBenchmark::Unknown: 61 return nullptr; 62 case InstructionBenchmark::Latency: 63 return createSerialSnippetGenerator(State, Opts); 64 case InstructionBenchmark::Uops: 65 case InstructionBenchmark::InverseThroughput: 66 return createParallelSnippetGenerator(State, Opts); 67 } 68 return nullptr; 69 } 70 71 Expected<std::unique_ptr<BenchmarkRunner>> 72 ExegesisTarget::createBenchmarkRunner(InstructionBenchmark::ModeE Mode, 73 const LLVMState &State) const { 74 PfmCountersInfo PfmCounters = State.getPfmCounters(); 75 switch (Mode) { 76 case InstructionBenchmark::Unknown: 77 return nullptr; 78 case InstructionBenchmark::Latency: 79 case InstructionBenchmark::InverseThroughput: 80 if (!PfmCounters.CycleCounter) { 81 const char *ModeName = Mode == InstructionBenchmark::Latency 82 ? "latency" 83 : "inverse_throughput"; 84 return make_error<Failure>( 85 Twine("can't run '") 86 .concat(ModeName) 87 .concat("' mode, sched model does not define a cycle counter.")); 88 } 89 return createLatencyBenchmarkRunner(State, Mode); 90 case InstructionBenchmark::Uops: 91 if (!PfmCounters.UopsCounter && !PfmCounters.IssueCounters) 92 return make_error<Failure>("can't run 'uops' mode, sched model does not " 93 "define uops or issue counters."); 94 return createUopsBenchmarkRunner(State); 95 } 96 return nullptr; 97 } 98 99 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator( 100 const LLVMState &State, const SnippetGenerator::Options &Opts) const { 101 return std::make_unique<SerialSnippetGenerator>(State, Opts); 102 } 103 104 std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator( 105 const LLVMState &State, const SnippetGenerator::Options &Opts) const { 106 return std::make_unique<ParallelSnippetGenerator>(State, Opts); 107 } 108 109 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner( 110 const LLVMState &State, InstructionBenchmark::ModeE Mode) const { 111 return std::make_unique<LatencyBenchmarkRunner>(State, Mode); 112 } 113 114 std::unique_ptr<BenchmarkRunner> 115 ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const { 116 return std::make_unique<UopsBenchmarkRunner>(State); 117 } 118 119 static_assert(std::is_pod<PfmCountersInfo>::value, 120 "We shouldn't have dynamic initialization here"); 121 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, 122 0u}; 123 124 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const { 125 assert(llvm::is_sorted( 126 CpuPfmCounters, 127 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) { 128 return strcmp(LHS.CpuName, RHS.CpuName) < 0; 129 }) && 130 "CpuPfmCounters table is not sorted"); 131 132 // Find entry 133 auto Found = 134 std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName); 135 if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) { 136 // Use the default. 137 if (CpuPfmCounters.begin() != CpuPfmCounters.end() && 138 CpuPfmCounters.begin()->CpuName[0] == '\0') { 139 Found = CpuPfmCounters.begin(); // The target specifies a default. 140 } else { 141 return PfmCountersInfo::Default; // No default for the target. 142 } 143 } 144 assert(Found->PCI && "Missing counters"); 145 return *Found->PCI; 146 } 147 148 namespace { 149 150 // Default implementation. 151 class ExegesisDefaultTarget : public ExegesisTarget { 152 public: 153 ExegesisDefaultTarget() : ExegesisTarget({}) {} 154 155 private: 156 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg, 157 const APInt &Value) const override { 158 llvm_unreachable("Not yet implemented"); 159 } 160 161 bool matchesArch(Triple::ArchType Arch) const override { 162 llvm_unreachable("never called"); 163 return false; 164 } 165 }; 166 167 } // namespace 168 169 const ExegesisTarget &ExegesisTarget::getDefault() { 170 static ExegesisDefaultTarget Target; 171 return Target; 172 } 173 174 } // namespace exegesis 175 } // namespace llvm 176