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