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 "Latency.h"
11 #include "Uops.h"
12
13 namespace llvm {
14 namespace exegesis {
15
~ExegesisTarget()16 ExegesisTarget::~ExegesisTarget() {} // anchor.
17
18 static ExegesisTarget *FirstTarget = nullptr;
19
lookup(Triple TT)20 const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {
21 for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) {
22 if (T->matchesArch(TT.getArch()))
23 return T;
24 }
25 return nullptr;
26 }
27
registerTarget(ExegesisTarget * Target)28 void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
29 if (FirstTarget == nullptr) {
30 FirstTarget = Target;
31 return;
32 }
33 if (Target->Next != nullptr)
34 return; // Already registered.
35 Target->Next = FirstTarget;
36 FirstTarget = Target;
37 }
38
createSnippetGenerator(InstructionBenchmark::ModeE Mode,const LLVMState & State,const SnippetGenerator::Options & Opts) const39 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator(
40 InstructionBenchmark::ModeE Mode, const LLVMState &State,
41 const SnippetGenerator::Options &Opts) const {
42 switch (Mode) {
43 case InstructionBenchmark::Unknown:
44 return nullptr;
45 case InstructionBenchmark::Latency:
46 return createLatencySnippetGenerator(State, Opts);
47 case InstructionBenchmark::Uops:
48 case InstructionBenchmark::InverseThroughput:
49 return createUopsSnippetGenerator(State, Opts);
50 }
51 return nullptr;
52 }
53
54 std::unique_ptr<BenchmarkRunner>
createBenchmarkRunner(InstructionBenchmark::ModeE Mode,const LLVMState & State) const55 ExegesisTarget::createBenchmarkRunner(InstructionBenchmark::ModeE Mode,
56 const LLVMState &State) const {
57 PfmCountersInfo PfmCounters = State.getPfmCounters();
58 switch (Mode) {
59 case InstructionBenchmark::Unknown:
60 return nullptr;
61 case InstructionBenchmark::Latency:
62 case InstructionBenchmark::InverseThroughput:
63 if (!PfmCounters.CycleCounter) {
64 const char *ModeName = Mode == InstructionBenchmark::Latency
65 ? "latency"
66 : "inverse_throughput";
67 report_fatal_error(Twine("can't run '").concat(ModeName).concat("' mode, "
68 "sched model does not define a cycle counter."));
69 }
70 return createLatencyBenchmarkRunner(State, Mode);
71 case InstructionBenchmark::Uops:
72 if (!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
73 report_fatal_error("can't run 'uops' mode, sched model does not define "
74 "uops or issue counters.");
75 return createUopsBenchmarkRunner(State);
76 }
77 return nullptr;
78 }
79
createLatencySnippetGenerator(const LLVMState & State,const SnippetGenerator::Options & Opts) const80 std::unique_ptr<SnippetGenerator> ExegesisTarget::createLatencySnippetGenerator(
81 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
82 return std::make_unique<LatencySnippetGenerator>(State, Opts);
83 }
84
createUopsSnippetGenerator(const LLVMState & State,const SnippetGenerator::Options & Opts) const85 std::unique_ptr<SnippetGenerator> ExegesisTarget::createUopsSnippetGenerator(
86 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
87 return std::make_unique<UopsSnippetGenerator>(State, Opts);
88 }
89
createLatencyBenchmarkRunner(const LLVMState & State,InstructionBenchmark::ModeE Mode) const90 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
91 const LLVMState &State, InstructionBenchmark::ModeE Mode) const {
92 return std::make_unique<LatencyBenchmarkRunner>(State, Mode);
93 }
94
95 std::unique_ptr<BenchmarkRunner>
createUopsBenchmarkRunner(const LLVMState & State) const96 ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const {
97 return std::make_unique<UopsBenchmarkRunner>(State);
98 }
99
randomizeMCOperand(const Instruction & Instr,const Variable & Var,MCOperand & AssignedValue,const BitVector & ForbiddenRegs) const100 void ExegesisTarget::randomizeMCOperand(const Instruction &Instr,
101 const Variable &Var,
102 MCOperand &AssignedValue,
103 const BitVector &ForbiddenRegs) const {
104 const Operand &Op = Instr.getPrimaryOperand(Var);
105 switch (Op.getExplicitOperandInfo().OperandType) {
106 case MCOI::OperandType::OPERAND_IMMEDIATE:
107 // FIXME: explore immediate values too.
108 AssignedValue = MCOperand::createImm(1);
109 break;
110 case MCOI::OperandType::OPERAND_REGISTER: {
111 assert(Op.isReg());
112 auto AllowedRegs = Op.getRegisterAliasing().sourceBits();
113 assert(AllowedRegs.size() == ForbiddenRegs.size());
114 for (auto I : ForbiddenRegs.set_bits())
115 AllowedRegs.reset(I);
116 AssignedValue = MCOperand::createReg(randomBit(AllowedRegs));
117 break;
118 }
119 default:
120 break;
121 }
122 }
123
124 static_assert(std::is_pod<PfmCountersInfo>::value,
125 "We shouldn't have dynamic initialization here");
126 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
127 0u};
128
getPfmCounters(StringRef CpuName) const129 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {
130 assert(std::is_sorted(
131 CpuPfmCounters.begin(), CpuPfmCounters.end(),
132 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) {
133 return strcmp(LHS.CpuName, RHS.CpuName) < 0;
134 }) &&
135 "CpuPfmCounters table is not sorted");
136
137 // Find entry
138 auto Found =
139 std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName);
140 if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) {
141 // Use the default.
142 if (CpuPfmCounters.begin() != CpuPfmCounters.end() &&
143 CpuPfmCounters.begin()->CpuName[0] == '\0') {
144 Found = CpuPfmCounters.begin(); // The target specifies a default.
145 } else {
146 return PfmCountersInfo::Default; // No default for the target.
147 }
148 }
149 assert(Found->PCI && "Missing counters");
150 return *Found->PCI;
151 }
152
153 namespace {
154
155 // Default implementation.
156 class ExegesisDefaultTarget : public ExegesisTarget {
157 public:
ExegesisDefaultTarget()158 ExegesisDefaultTarget() : ExegesisTarget({}) {}
159
160 private:
setRegTo(const MCSubtargetInfo & STI,unsigned Reg,const APInt & Value) const161 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
162 const APInt &Value) const override {
163 llvm_unreachable("Not yet implemented");
164 }
165
matchesArch(Triple::ArchType Arch) const166 bool matchesArch(Triple::ArchType Arch) const override {
167 llvm_unreachable("never called");
168 return false;
169 }
170 };
171
172 } // namespace
173
getDefault()174 const ExegesisTarget &ExegesisTarget::getDefault() {
175 static ExegesisDefaultTarget Target;
176 return Target;
177 }
178
179 } // namespace exegesis
180 } // namespace llvm
181