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