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