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( 72 InstructionBenchmark::ModeE Mode, const LLVMState &State, 73 InstructionBenchmark::ResultAggregationModeE ResultAggMode) 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, ResultAggMode); 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, ResultAggMode); 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, 111 InstructionBenchmark::ResultAggregationModeE ResultAggMode) const { 112 return std::make_unique<LatencyBenchmarkRunner>(State, Mode, ResultAggMode); 113 } 114 115 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner( 116 const LLVMState &State, 117 InstructionBenchmark::ResultAggregationModeE /*unused*/) const { 118 return std::make_unique<UopsBenchmarkRunner>(State); 119 } 120 121 static_assert(std::is_pod<PfmCountersInfo>::value, 122 "We shouldn't have dynamic initialization here"); 123 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, 124 0u}; 125 126 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const { 127 assert(llvm::is_sorted( 128 CpuPfmCounters, 129 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) { 130 return strcmp(LHS.CpuName, RHS.CpuName) < 0; 131 }) && 132 "CpuPfmCounters table is not sorted"); 133 134 // Find entry 135 auto Found = llvm::lower_bound(CpuPfmCounters, CpuName); 136 if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) { 137 // Use the default. 138 if (!CpuPfmCounters.empty() && 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 ExegesisTarget::SavedState::~SavedState() {} // anchor. 149 150 namespace { 151 152 // Default implementation. 153 class ExegesisDefaultTarget : public ExegesisTarget { 154 public: 155 ExegesisDefaultTarget() : ExegesisTarget({}) {} 156 157 private: 158 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg, 159 const APInt &Value) const override { 160 llvm_unreachable("Not yet implemented"); 161 } 162 163 bool matchesArch(Triple::ArchType Arch) const override { 164 llvm_unreachable("never called"); 165 return false; 166 } 167 }; 168 169 } // namespace 170 171 const ExegesisTarget &ExegesisTarget::getDefault() { 172 static ExegesisDefaultTarget Target; 173 return Target; 174 } 175 176 } // namespace exegesis 177 } // namespace llvm 178