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