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