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