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(llvm::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> 40 ExegesisTarget::createSnippetGenerator(InstructionBenchmark::ModeE Mode, 41 const LLVMState &State) const { 42 switch (Mode) { 43 case InstructionBenchmark::Unknown: 44 return nullptr; 45 case InstructionBenchmark::Latency: 46 return createLatencySnippetGenerator(State); 47 case InstructionBenchmark::Uops: 48 case InstructionBenchmark::InverseThroughput: 49 return createUopsSnippetGenerator(State); 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> 70 ExegesisTarget::createLatencySnippetGenerator(const LLVMState &State) const { 71 return std::make_unique<LatencySnippetGenerator>(State); 72 } 73 74 std::unique_ptr<SnippetGenerator> 75 ExegesisTarget::createUopsSnippetGenerator(const LLVMState &State) const { 76 return std::make_unique<UopsSnippetGenerator>(State); 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( 90 const Instruction &Instr, const Variable &Var, 91 llvm::MCOperand &AssignedValue, 92 const llvm::BitVector &ForbiddenRegs) const { 93 const Operand &Op = Instr.getPrimaryOperand(Var); 94 switch (Op.getExplicitOperandInfo().OperandType) { 95 case llvm::MCOI::OperandType::OPERAND_IMMEDIATE: 96 // FIXME: explore immediate values too. 97 AssignedValue = llvm::MCOperand::createImm(1); 98 break; 99 case llvm::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 = llvm::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 & 119 ExegesisTarget::getPfmCounters(llvm::StringRef CpuName) const { 120 assert(std::is_sorted( 121 CpuPfmCounters.begin(), CpuPfmCounters.end(), 122 [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) { 123 return strcmp(LHS.CpuName, RHS.CpuName) < 0; 124 }) && 125 "CpuPfmCounters table is not sorted"); 126 127 // Find entry 128 auto Found = 129 std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName); 130 if (Found == CpuPfmCounters.end() || 131 llvm::StringRef(Found->CpuName) != CpuName) { 132 // Use the default. 133 if (CpuPfmCounters.begin() != CpuPfmCounters.end() && 134 CpuPfmCounters.begin()->CpuName[0] == '\0') { 135 Found = CpuPfmCounters.begin(); // The target specifies a default. 136 } else { 137 return PfmCountersInfo::Default; // No default for the target. 138 } 139 } 140 assert(Found->PCI && "Missing counters"); 141 return *Found->PCI; 142 } 143 144 namespace { 145 146 // Default implementation. 147 class ExegesisDefaultTarget : public ExegesisTarget { 148 public: 149 ExegesisDefaultTarget() : ExegesisTarget({}) {} 150 151 private: 152 std::vector<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI, 153 unsigned Reg, 154 const llvm::APInt &Value) const override { 155 llvm_unreachable("Not yet implemented"); 156 } 157 158 bool matchesArch(llvm::Triple::ArchType Arch) const override { 159 llvm_unreachable("never called"); 160 return false; 161 } 162 }; 163 164 } // namespace 165 166 const ExegesisTarget &ExegesisTarget::getDefault() { 167 static ExegesisDefaultTarget Target; 168 return Target; 169 } 170 171 } // namespace exegesis 172 } // namespace llvm 173