Home | History | Annotate | Line # | Download | only in lib
      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 "LatencyBenchmarkRunner.h"
     11 #include "ParallelSnippetGenerator.h"
     12 #include "SerialSnippetGenerator.h"
     13 #include "UopsBenchmarkRunner.h"
     14 #include "llvm/ADT/Twine.h"
     15 #include "llvm/Support/Error.h"
     16 
     17 namespace llvm {
     18 namespace exegesis {
     19 
     20 ExegesisTarget::~ExegesisTarget() {} // anchor.
     21 
     22 static ExegesisTarget *FirstTarget = nullptr;
     23 
     24 const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {
     25   for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) {
     26     if (T->matchesArch(TT.getArch()))
     27       return T;
     28   }
     29   return nullptr;
     30 }
     31 
     32 Expected<std::unique_ptr<pfm::Counter>>
     33 ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &) const {
     34   pfm::PerfEvent Event(CounterName);
     35   if (!Event.valid())
     36     return llvm::make_error<Failure>(
     37         llvm::Twine("Unable to create counter with name '")
     38             .concat(CounterName)
     39             .concat("'"));
     40 
     41   return std::make_unique<pfm::Counter>(std::move(Event));
     42 }
     43 
     44 void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
     45   if (FirstTarget == nullptr) {
     46     FirstTarget = Target;
     47     return;
     48   }
     49   if (Target->Next != nullptr)
     50     return; // Already registered.
     51   Target->Next = FirstTarget;
     52   FirstTarget = Target;
     53 }
     54 
     55 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator(
     56     InstructionBenchmark::ModeE Mode, const LLVMState &State,
     57     const SnippetGenerator::Options &Opts) const {
     58   switch (Mode) {
     59   case InstructionBenchmark::Unknown:
     60     return nullptr;
     61   case InstructionBenchmark::Latency:
     62     return createSerialSnippetGenerator(State, Opts);
     63   case InstructionBenchmark::Uops:
     64   case InstructionBenchmark::InverseThroughput:
     65     return createParallelSnippetGenerator(State, Opts);
     66   }
     67   return nullptr;
     68 }
     69 
     70 Expected<std::unique_ptr<BenchmarkRunner>>
     71 ExegesisTarget::createBenchmarkRunner(
     72     InstructionBenchmark::ModeE Mode, const LLVMState &State,
     73     InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
     74   PfmCountersInfo PfmCounters = State.getPfmCounters();
     75   switch (Mode) {
     76   case InstructionBenchmark::Unknown:
     77     return nullptr;
     78   case InstructionBenchmark::Latency:
     79   case InstructionBenchmark::InverseThroughput:
     80     if (!PfmCounters.CycleCounter) {
     81       const char *ModeName = Mode == InstructionBenchmark::Latency
     82                                  ? "latency"
     83                                  : "inverse_throughput";
     84       return make_error<Failure>(
     85           Twine("can't run '")
     86               .concat(ModeName)
     87               .concat("' mode, sched model does not define a cycle counter."));
     88     }
     89     return createLatencyBenchmarkRunner(State, Mode, ResultAggMode);
     90   case InstructionBenchmark::Uops:
     91     if (!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
     92       return make_error<Failure>("can't run 'uops' mode, sched model does not "
     93                                  "define uops or issue counters.");
     94     return createUopsBenchmarkRunner(State, ResultAggMode);
     95   }
     96   return nullptr;
     97 }
     98 
     99 std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator(
    100     const LLVMState &State, const SnippetGenerator::Options &Opts) const {
    101   return std::make_unique<SerialSnippetGenerator>(State, Opts);
    102 }
    103 
    104 std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator(
    105     const LLVMState &State, const SnippetGenerator::Options &Opts) const {
    106   return std::make_unique<ParallelSnippetGenerator>(State, Opts);
    107 }
    108 
    109 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
    110     const LLVMState &State, InstructionBenchmark::ModeE Mode,
    111     InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
    112   return std::make_unique<LatencyBenchmarkRunner>(State, Mode, ResultAggMode);
    113 }
    114 
    115 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(
    116     const LLVMState &State,
    117     InstructionBenchmark::ResultAggregationModeE /*unused*/) const {
    118   return std::make_unique<UopsBenchmarkRunner>(State);
    119 }
    120 
    121 static_assert(std::is_pod<PfmCountersInfo>::value,
    122               "We shouldn't have dynamic initialization here");
    123 const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
    124                                                   0u};
    125 
    126 const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {
    127   assert(llvm::is_sorted(
    128              CpuPfmCounters,
    129              [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) {
    130                return strcmp(LHS.CpuName, RHS.CpuName) < 0;
    131              }) &&
    132          "CpuPfmCounters table is not sorted");
    133 
    134   // Find entry
    135   auto Found = llvm::lower_bound(CpuPfmCounters, CpuName);
    136   if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) {
    137     // Use the default.
    138     if (!CpuPfmCounters.empty() && CpuPfmCounters.begin()->CpuName[0] == '\0') {
    139       Found = CpuPfmCounters.begin(); // The target specifies a default.
    140     } else {
    141       return PfmCountersInfo::Default; // No default for the target.
    142     }
    143   }
    144   assert(Found->PCI && "Missing counters");
    145   return *Found->PCI;
    146 }
    147 
    148 ExegesisTarget::SavedState::~SavedState() {} // anchor.
    149 
    150 namespace {
    151 
    152 // Default implementation.
    153 class ExegesisDefaultTarget : public ExegesisTarget {
    154 public:
    155   ExegesisDefaultTarget() : ExegesisTarget({}) {}
    156 
    157 private:
    158   std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
    159                                const APInt &Value) const override {
    160     llvm_unreachable("Not yet implemented");
    161   }
    162 
    163   bool matchesArch(Triple::ArchType Arch) const override {
    164     llvm_unreachable("never called");
    165     return false;
    166   }
    167 };
    168 
    169 } // namespace
    170 
    171 const ExegesisTarget &ExegesisTarget::getDefault() {
    172   static ExegesisDefaultTarget Target;
    173   return Target;
    174 }
    175 
    176 } // namespace exegesis
    177 } // namespace llvm
    178