1 //===-- Target.h ------------------------------------------------*- 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 /// 9 /// \file 10 /// 11 /// Classes that handle the creation of target-specific objects. This is 12 /// similar to Target/TargetRegistry. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_TOOLS_LLVM_EXEGESIS_TARGET_H 17 #define LLVM_TOOLS_LLVM_EXEGESIS_TARGET_H 18 19 #include "BenchmarkResult.h" 20 #include "BenchmarkRunner.h" 21 #include "Error.h" 22 #include "LlvmState.h" 23 #include "PerfHelper.h" 24 #include "SnippetGenerator.h" 25 #include "llvm/ADT/Triple.h" 26 #include "llvm/CodeGen/TargetPassConfig.h" 27 #include "llvm/IR/CallingConv.h" 28 #include "llvm/IR/LegacyPassManager.h" 29 #include "llvm/MC/MCInst.h" 30 #include "llvm/MC/MCRegisterInfo.h" 31 #include "llvm/Support/Error.h" 32 33 namespace llvm { 34 namespace exegesis { 35 36 struct PfmCountersInfo { 37 // An optional name of a performance counter that can be used to measure 38 // cycles. 39 const char *CycleCounter; 40 41 // An optional name of a performance counter that can be used to measure 42 // uops. 43 const char *UopsCounter; 44 45 // An IssueCounter specifies how to measure uops issued to specific proc 46 // resources. 47 struct IssueCounter { 48 const char *Counter; 49 // The name of the ProcResource that this counter measures. 50 const char *ProcResName; 51 }; 52 // An optional list of IssueCounters. 53 const IssueCounter *IssueCounters; 54 unsigned NumIssueCounters; 55 56 static const PfmCountersInfo Default; 57 }; 58 59 struct CpuAndPfmCounters { 60 const char *CpuName; 61 const PfmCountersInfo *PCI; 62 bool operator<(StringRef S) const { return StringRef(CpuName) < S; } 63 }; 64 65 class ExegesisTarget { 66 public: ExegesisTarget(ArrayRef<CpuAndPfmCounters> CpuPfmCounters)67 explicit ExegesisTarget(ArrayRef<CpuAndPfmCounters> CpuPfmCounters) 68 : CpuPfmCounters(CpuPfmCounters) {} 69 70 // Targets can use this to create target-specific perf counters. 71 virtual Expected<std::unique_ptr<pfm::Counter>> 72 createCounter(StringRef CounterName, const LLVMState &State) const; 73 74 // Targets can use this to add target-specific passes in assembleToStream(); addTargetSpecificPasses(PassManagerBase & PM)75 virtual void addTargetSpecificPasses(PassManagerBase &PM) const {} 76 77 // Generates code to move a constant into a the given register. 78 // Precondition: Value must fit into Reg. 79 virtual std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg, 80 const APInt &Value) const = 0; 81 82 // Returns the register pointing to scratch memory, or 0 if this target 83 // does not support memory operands. The benchmark function uses the 84 // default calling convention. getScratchMemoryRegister(const Triple &)85 virtual unsigned getScratchMemoryRegister(const Triple &) const { return 0; } 86 87 // Fills memory operands with references to the address at [Reg] + Offset. fillMemoryOperands(InstructionTemplate & IT,unsigned Reg,unsigned Offset)88 virtual void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg, 89 unsigned Offset) const { 90 llvm_unreachable( 91 "fillMemoryOperands() requires getScratchMemoryRegister() > 0"); 92 } 93 94 // Returns a counter usable as a loop counter. getLoopCounterRegister(const Triple &)95 virtual unsigned getLoopCounterRegister(const Triple &) const { return 0; } 96 97 // Adds the code to decrement the loop counter and decrementLoopCounterAndJump(MachineBasicBlock & MBB,MachineBasicBlock & TargetMBB,const MCInstrInfo & MII)98 virtual void decrementLoopCounterAndJump(MachineBasicBlock &MBB, 99 MachineBasicBlock &TargetMBB, 100 const MCInstrInfo &MII) const { 101 llvm_unreachable("decrementLoopCounterAndBranch() requires " 102 "getLoopCounterRegister() > 0"); 103 } 104 105 // Returns a list of unavailable registers. 106 // Targets can use this to prevent some registers to be automatically selected 107 // for use in snippets. getUnavailableRegisters()108 virtual ArrayRef<unsigned> getUnavailableRegisters() const { return {}; } 109 110 // Returns the maximum number of bytes a load/store instruction can access at 111 // once. This is typically the size of the largest register available on the 112 // processor. Note that this only used as a hint to generate independant 113 // load/stores to/from memory, so the exact returned value does not really 114 // matter as long as it's large enough. getMaxMemoryAccessSize()115 virtual unsigned getMaxMemoryAccessSize() const { return 0; } 116 117 // Assigns a random operand of the right type to variable Var. 118 // The target is responsible for handling any operand starting from 119 // OPERAND_FIRST_TARGET. randomizeTargetMCOperand(const Instruction & Instr,const Variable & Var,MCOperand & AssignedValue,const BitVector & ForbiddenRegs)120 virtual Error randomizeTargetMCOperand(const Instruction &Instr, 121 const Variable &Var, 122 MCOperand &AssignedValue, 123 const BitVector &ForbiddenRegs) const { 124 return make_error<Failure>( 125 "targets with target-specific operands should implement this"); 126 } 127 128 // Returns true if this instruction is supported as a back-to-back 129 // instructions. 130 // FIXME: Eventually we should discover this dynamically. allowAsBackToBack(const Instruction & Instr)131 virtual bool allowAsBackToBack(const Instruction &Instr) const { 132 return true; 133 } 134 135 // For some instructions, it is interesting to measure how it's performance 136 // characteristics differ depending on it's operands. 137 // This allows us to produce all the interesting variants. 138 virtual std::vector<InstructionTemplate> generateInstructionVariants(const Instruction & Instr,unsigned MaxConfigsPerOpcode)139 generateInstructionVariants(const Instruction &Instr, 140 unsigned MaxConfigsPerOpcode) const { 141 // By default, we're happy with whatever randomizer will give us. 142 return {&Instr}; 143 } 144 145 // Checks hardware and software support for current benchmark mode. 146 // Returns an error if the target host does not have support to run the 147 // benchmark. checkFeatureSupport()148 virtual Error checkFeatureSupport() const { return Error::success(); } 149 150 // Creates a snippet generator for the given mode. 151 std::unique_ptr<SnippetGenerator> 152 createSnippetGenerator(InstructionBenchmark::ModeE Mode, 153 const LLVMState &State, 154 const SnippetGenerator::Options &Opts) const; 155 // Creates a benchmark runner for the given mode. 156 Expected<std::unique_ptr<BenchmarkRunner>> createBenchmarkRunner( 157 InstructionBenchmark::ModeE Mode, const LLVMState &State, 158 InstructionBenchmark::ResultAggregationModeE ResultAggMode = 159 InstructionBenchmark::Min) const; 160 161 // Returns the ExegesisTarget for the given triple or nullptr if the target 162 // does not exist. 163 static const ExegesisTarget *lookup(Triple TT); 164 // Returns the default (unspecialized) ExegesisTarget. 165 static const ExegesisTarget &getDefault(); 166 // Registers a target. Not thread safe. 167 static void registerTarget(ExegesisTarget *T); 168 169 virtual ~ExegesisTarget(); 170 171 // Returns the Pfm counters for the given CPU (or the default if no pfm 172 // counters are defined for this CPU). 173 const PfmCountersInfo &getPfmCounters(StringRef CpuName) const; 174 175 // Saves the CPU state that needs to be preserved when running a benchmark, 176 // and returns and RAII object that restores the state on destruction. 177 // By default no state is preserved. 178 struct SavedState { 179 virtual ~SavedState(); 180 }; withSavedState()181 virtual std::unique_ptr<SavedState> withSavedState() const { 182 return std::make_unique<SavedState>(); 183 } 184 185 private: 186 virtual bool matchesArch(Triple::ArchType Arch) const = 0; 187 188 // Targets can implement their own snippet generators/benchmarks runners by 189 // implementing these. 190 std::unique_ptr<SnippetGenerator> virtual createSerialSnippetGenerator( 191 const LLVMState &State, const SnippetGenerator::Options &Opts) const; 192 std::unique_ptr<SnippetGenerator> virtual createParallelSnippetGenerator( 193 const LLVMState &State, const SnippetGenerator::Options &Opts) const; 194 std::unique_ptr<BenchmarkRunner> virtual createLatencyBenchmarkRunner( 195 const LLVMState &State, InstructionBenchmark::ModeE Mode, 196 InstructionBenchmark::ResultAggregationModeE ResultAggMode) const; 197 std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner( 198 const LLVMState &State, 199 InstructionBenchmark::ResultAggregationModeE ResultAggMode) const; 200 201 const ExegesisTarget *Next = nullptr; 202 const ArrayRef<CpuAndPfmCounters> CpuPfmCounters; 203 }; 204 205 } // namespace exegesis 206 } // namespace llvm 207 208 #endif // LLVM_TOOLS_LLVM_EXEGESIS_TARGET_H 209