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 16 ExegesisTarget::~ExegesisTarget() {} // anchor. 17 18 static ExegesisTarget *FirstTarget = nullptr; 19 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 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 39 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> 55 ExegesisTarget::createBenchmarkRunner(InstructionBenchmark::ModeE Mode, 56 const LLVMState &State) const { 57 switch (Mode) { 58 case InstructionBenchmark::Unknown: 59 return nullptr; 60 case InstructionBenchmark::Latency: 61 case InstructionBenchmark::InverseThroughput: 62 return createLatencyBenchmarkRunner(State, Mode); 63 case InstructionBenchmark::Uops: 64 return createUopsBenchmarkRunner(State); 65 } 66 return nullptr; 67 } 68 69 std::unique_ptr<SnippetGenerator> ExegesisTarget::createLatencySnippetGenerator( 70 const LLVMState &State, const SnippetGenerator::Options &Opts) const { 71 return std::make_unique<LatencySnippetGenerator>(State, Opts); 72 } 73 74 std::unique_ptr<SnippetGenerator> ExegesisTarget::createUopsSnippetGenerator( 75 const LLVMState &State, const SnippetGenerator::Options &Opts) const { 76 return std::make_unique<UopsSnippetGenerator>(State, Opts); 77 } 78 79 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner( 80 const LLVMState &State, InstructionBenchmark::ModeE Mode) const { 81 return std::make_unique<LatencyBenchmarkRunner>(State, Mode); 82 } 83 84 std::unique_ptr<BenchmarkRunner> 85 ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const { 86 return std::make_unique<UopsBenchmarkRunner>(State); 87 } 88 89 void ExegesisTarget::randomizeMCOperand(const Instruction &Instr, 90 const Variable &Var, 91 MCOperand &AssignedValue, 92 const BitVector &ForbiddenRegs) const { 93 const Operand &Op = Instr.getPrimaryOperand(Var); 94 switch (Op.getExplicitOperandInfo().OperandType) { 95 case MCOI::OperandType::OPERAND_IMMEDIATE: 96 // FIXME: explore immediate values too. 97 AssignedValue = MCOperand::createImm(1); 98 break; 99 case MCOI::OperandType::OPERAND_REGISTER: { 100 assert(Op.isReg()); 101 auto AllowedRegs = Op.getRegisterAliasing().sourceBits(); 102 assert(AllowedRegs.size() == ForbiddenRegs.size()); 103 for (auto I : ForbiddenRegs.set_bits()) 104 AllowedRegs.reset(I); 105 AssignedValue = MCOperand::createReg(randomBit(AllowedRegs)); 106 break; 107 } 108 default: 109 break; 110 } 111 } 112 113 static_assert(std::is_pod<PfmCountersInfo>::value, 114 "We shouldn't have dynamic initialization here"); 115 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, 116 0u}; 117 118 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const { 119 assert(std::is_sorted( 120 CpuPfmCounters.begin(), CpuPfmCounters.end(), 121 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) { 122 return strcmp(LHS.CpuName, RHS.CpuName) < 0; 123 }) && 124 "CpuPfmCounters table is not sorted"); 125 126 // Find entry 127 auto Found = 128 std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName); 129 if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) { 130 // Use the default. 131 if (CpuPfmCounters.begin() != CpuPfmCounters.end() && 132 CpuPfmCounters.begin()->CpuName[0] == '\0') { 133 Found = CpuPfmCounters.begin(); // The target specifies a default. 134 } else { 135 return PfmCountersInfo::Default; // No default for the target. 136 } 137 } 138 assert(Found->PCI && "Missing counters"); 139 return *Found->PCI; 140 } 141 142 namespace { 143 144 // Default implementation. 145 class ExegesisDefaultTarget : public ExegesisTarget { 146 public: 147 ExegesisDefaultTarget() : ExegesisTarget({}) {} 148 149 private: 150 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg, 151 const APInt &Value) const override { 152 llvm_unreachable("Not yet implemented"); 153 } 154 155 bool matchesArch(Triple::ArchType Arch) const override { 156 llvm_unreachable("never called"); 157 return false; 158 } 159 }; 160 161 } // namespace 162 163 const ExegesisTarget &ExegesisTarget::getDefault() { 164 static ExegesisDefaultTarget Target; 165 return Target; 166 } 167 168 } // namespace exegesis 169 } // namespace llvm 170