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 cl::OptionCategory Options("llvm-exegesis options");
21 cl::OptionCategory BenchmarkOptions("llvm-exegesis benchmark options");
22 cl::OptionCategory AnalysisOptions("llvm-exegesis analysis options");
23
~ExegesisTarget()24 ExegesisTarget::~ExegesisTarget() {} // anchor.
25
26 static ExegesisTarget *FirstTarget = nullptr;
27
lookup(Triple TT)28 const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {
29 for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) {
30 if (T->matchesArch(TT.getArch()))
31 return T;
32 }
33 return nullptr;
34 }
35
36 Expected<std::unique_ptr<pfm::Counter>>
createCounter(StringRef CounterName,const LLVMState &) const37 ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &) const {
38 pfm::PerfEvent Event(CounterName);
39 if (!Event.valid())
40 return llvm::make_error<Failure>(
41 llvm::Twine("Unable to create counter with name '")
42 .concat(CounterName)
43 .concat("'"));
44
45 return std::make_unique<pfm::Counter>(std::move(Event));
46 }
47
registerTarget(ExegesisTarget * Target)48 void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
49 if (FirstTarget == nullptr) {
50 FirstTarget = Target;
51 return;
52 }
53 if (Target->Next != nullptr)
54 return; // Already registered.
55 Target->Next = FirstTarget;
56 FirstTarget = Target;
57 }
58
createSnippetGenerator(InstructionBenchmark::ModeE Mode,const LLVMState & State,const SnippetGenerator::Options & Opts) const59 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator(
60 InstructionBenchmark::ModeE Mode, const LLVMState &State,
61 const SnippetGenerator::Options &Opts) const {
62 switch (Mode) {
63 case InstructionBenchmark::Unknown:
64 return nullptr;
65 case InstructionBenchmark::Latency:
66 return createSerialSnippetGenerator(State, Opts);
67 case InstructionBenchmark::Uops:
68 case InstructionBenchmark::InverseThroughput:
69 return createParallelSnippetGenerator(State, Opts);
70 }
71 return nullptr;
72 }
73
74 Expected<std::unique_ptr<BenchmarkRunner>>
createBenchmarkRunner(InstructionBenchmark::ModeE Mode,const LLVMState & State,BenchmarkPhaseSelectorE BenchmarkPhaseSelector,InstructionBenchmark::ResultAggregationModeE ResultAggMode) const75 ExegesisTarget::createBenchmarkRunner(
76 InstructionBenchmark::ModeE Mode, const LLVMState &State,
77 BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
78 InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
79 PfmCountersInfo PfmCounters = State.getPfmCounters();
80 switch (Mode) {
81 case InstructionBenchmark::Unknown:
82 return nullptr;
83 case InstructionBenchmark::Latency:
84 case InstructionBenchmark::InverseThroughput:
85 if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
86 !PfmCounters.CycleCounter) {
87 const char *ModeName = Mode == InstructionBenchmark::Latency
88 ? "latency"
89 : "inverse_throughput";
90 return make_error<Failure>(
91 Twine("can't run '")
92 .concat(ModeName)
93 .concat(
94 "' mode, sched model does not define a cycle counter. You "
95 "can pass --skip-measurements to skip the actual "
96 "benchmarking."));
97 }
98 return createLatencyBenchmarkRunner(State, Mode, BenchmarkPhaseSelector,
99 ResultAggMode);
100 case InstructionBenchmark::Uops:
101 if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
102 !PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
103 return make_error<Failure>(
104 "can't run 'uops' mode, sched model does not define uops or issue "
105 "counters. You can pass --skip-measurements to skip the actual "
106 "benchmarking.");
107 return createUopsBenchmarkRunner(State, BenchmarkPhaseSelector,
108 ResultAggMode);
109 }
110 return nullptr;
111 }
112
createSerialSnippetGenerator(const LLVMState & State,const SnippetGenerator::Options & Opts) const113 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator(
114 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
115 return std::make_unique<SerialSnippetGenerator>(State, Opts);
116 }
117
createParallelSnippetGenerator(const LLVMState & State,const SnippetGenerator::Options & Opts) const118 std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator(
119 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
120 return std::make_unique<ParallelSnippetGenerator>(State, Opts);
121 }
122
createLatencyBenchmarkRunner(const LLVMState & State,InstructionBenchmark::ModeE Mode,BenchmarkPhaseSelectorE BenchmarkPhaseSelector,InstructionBenchmark::ResultAggregationModeE ResultAggMode) const123 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
124 const LLVMState &State, InstructionBenchmark::ModeE Mode,
125 BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
126 InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
127 return std::make_unique<LatencyBenchmarkRunner>(
128 State, Mode, BenchmarkPhaseSelector, ResultAggMode);
129 }
130
createUopsBenchmarkRunner(const LLVMState & State,BenchmarkPhaseSelectorE BenchmarkPhaseSelector,InstructionBenchmark::ResultAggregationModeE) const131 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(
132 const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
133 InstructionBenchmark::ResultAggregationModeE /*unused*/) const {
134 return std::make_unique<UopsBenchmarkRunner>(State, BenchmarkPhaseSelector);
135 }
136
137 static_assert(std::is_pod<PfmCountersInfo>::value,
138 "We shouldn't have dynamic initialization here");
139 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
140 0u};
141
getPfmCounters(StringRef CpuName) const142 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {
143 assert(llvm::is_sorted(
144 CpuPfmCounters,
145 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) {
146 return strcmp(LHS.CpuName, RHS.CpuName) < 0;
147 }) &&
148 "CpuPfmCounters table is not sorted");
149
150 // Find entry
151 auto Found = llvm::lower_bound(CpuPfmCounters, CpuName);
152 if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) {
153 // Use the default.
154 if (!CpuPfmCounters.empty() && CpuPfmCounters.begin()->CpuName[0] == '\0') {
155 Found = CpuPfmCounters.begin(); // The target specifies a default.
156 } else {
157 return PfmCountersInfo::Default; // No default for the target.
158 }
159 }
160 assert(Found->PCI && "Missing counters");
161 return *Found->PCI;
162 }
163
~SavedState()164 ExegesisTarget::SavedState::~SavedState() {} // anchor.
165
166 namespace {
167
168 // Default implementation.
169 class ExegesisDefaultTarget : public ExegesisTarget {
170 public:
ExegesisDefaultTarget()171 ExegesisDefaultTarget() : ExegesisTarget({}) {}
172
173 private:
setRegTo(const MCSubtargetInfo & STI,unsigned Reg,const APInt & Value) const174 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
175 const APInt &Value) const override {
176 llvm_unreachable("Not yet implemented");
177 }
178
matchesArch(Triple::ArchType Arch) const179 bool matchesArch(Triple::ArchType Arch) const override {
180 llvm_unreachable("never called");
181 return false;
182 }
183 };
184
185 } // namespace
186
getDefault()187 const ExegesisTarget &ExegesisTarget::getDefault() {
188 static ExegesisDefaultTarget Target;
189 return Target;
190 }
191
192 } // namespace exegesis
193 } // namespace llvm
194