216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This tablegen backend emits llvm-exegesis information.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "llvm/ADT/STLExtras.h"
 | |
| #include "llvm/ADT/SmallSet.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/Format.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| #include "llvm/TableGen/Error.h"
 | |
| #include "llvm/TableGen/Record.h"
 | |
| #include "llvm/TableGen/TableGenBackend.h"
 | |
| #include <algorithm>
 | |
| #include <cassert>
 | |
| #include <cstdint>
 | |
| #include <map>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| #define DEBUG_TYPE "exegesis-emitter"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class ExegesisEmitter {
 | |
| public:
 | |
|   ExegesisEmitter(RecordKeeper &RK);
 | |
| 
 | |
|   void run(raw_ostream &OS) const;
 | |
| 
 | |
| private:
 | |
|   unsigned getPfmCounterId(llvm::StringRef Name) const {
 | |
|     const auto It = PfmCounterNameTable.find(Name);
 | |
|     if (It == PfmCounterNameTable.end())
 | |
|       PrintFatalError("no pfm counter id for " + Name);
 | |
|     return It->second;
 | |
|   }
 | |
| 
 | |
|   // Collects all the ProcPfmCounters definitions available in this target.
 | |
|   void emitPfmCounters(raw_ostream &OS) const;
 | |
| 
 | |
|   void emitPfmCountersInfo(const Record &Def,
 | |
|                            unsigned &IssueCountersTableOffset,
 | |
|                            raw_ostream &OS) const;
 | |
| 
 | |
|   void emitPfmCountersLookupTable(raw_ostream &OS) const;
 | |
| 
 | |
|   RecordKeeper &Records;
 | |
|   std::string Target;
 | |
| 
 | |
|   // Table of counter name -> counter index.
 | |
|   const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
 | |
| };
 | |
| 
 | |
| static std::map<llvm::StringRef, unsigned>
 | |
| collectPfmCounters(const RecordKeeper &Records) {
 | |
|   std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
 | |
|   const auto AddPfmCounterName = [&PfmCounterNameTable](
 | |
|                                      const Record *PfmCounterDef) {
 | |
|     const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
 | |
|     if (!Counter.empty())
 | |
|       PfmCounterNameTable.emplace(Counter, 0);
 | |
|   };
 | |
|   for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {
 | |
|     // Check that ResourceNames are unique.
 | |
|     llvm::SmallSet<llvm::StringRef, 16> Seen;
 | |
|     for (const Record *IssueCounter :
 | |
|          Def->getValueAsListOfDefs("IssueCounters")) {
 | |
|       const llvm::StringRef ResourceName =
 | |
|           IssueCounter->getValueAsString("ResourceName");
 | |
|       if (ResourceName.empty())
 | |
|         PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");
 | |
|       if (!Seen.insert(ResourceName).second)
 | |
|         PrintFatalError(IssueCounter->getLoc(),
 | |
|                         "duplicate ResourceName " + ResourceName);
 | |
|       AddPfmCounterName(IssueCounter);
 | |
|     }
 | |
|     AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
 | |
|     AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
 | |
|   }
 | |
|   unsigned Index = 0;
 | |
|   for (auto &NameAndIndex : PfmCounterNameTable)
 | |
|     NameAndIndex.second = Index++;
 | |
|   return PfmCounterNameTable;
 | |
| }
 | |
| 
 | |
| ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
 | |
|     : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
 | |
|   std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
 | |
|   if (Targets.size() == 0)
 | |
|     PrintFatalError("ERROR: No 'Target' subclasses defined!");
 | |
|   if (Targets.size() != 1)
 | |
|     PrintFatalError("ERROR: Multiple subclasses of Target defined!");
 | |
|   Target = std::string(Targets[0]->getName());
 | |
| }
 | |
| 
 | |
| void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
 | |
|                                           unsigned &IssueCountersTableOffset,
 | |
|                                           raw_ostream &OS) const {
 | |
|   const auto CycleCounter =
 | |
|       Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
 | |
|   const auto UopsCounter =
 | |
|       Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
 | |
|   const size_t NumIssueCounters =
 | |
|       Def.getValueAsListOfDefs("IssueCounters").size();
 | |
| 
 | |
|   OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
 | |
|      << " = {\n";
 | |
| 
 | |
|   // Cycle Counter.
 | |
|   if (CycleCounter.empty())
 | |
|     OS << "  nullptr,  // No cycle counter.\n";
 | |
|   else
 | |
|     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
 | |
|        << "],  // Cycle counter\n";
 | |
| 
 | |
|   // Uops Counter.
 | |
|   if (UopsCounter.empty())
 | |
|     OS << "  nullptr,  // No uops counter.\n";
 | |
|   else
 | |
|     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
 | |
|        << "],  // Uops counter\n";
 | |
| 
 | |
|   // Issue Counters
 | |
|   if (NumIssueCounters == 0)
 | |
|     OS << "  nullptr,  // No issue counters.\n  0\n";
 | |
|   else
 | |
|     OS << "  " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
 | |
|        << ", " << NumIssueCounters << " // Issue counters.\n";
 | |
| 
 | |
|   OS << "};\n";
 | |
|   IssueCountersTableOffset += NumIssueCounters;
 | |
| }
 | |
| 
 | |
| void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
 | |
|   // Emit the counter name table.
 | |
|   OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n";
 | |
|   for (const auto &NameAndIndex : PfmCounterNameTable)
 | |
|     OS << "  \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
 | |
|        << "\n";
 | |
|   OS << "};\n\n";
 | |
| 
 | |
|   // Emit the IssueCounters table.
 | |
|   const auto PfmCounterDefs =
 | |
|       Records.getAllDerivedDefinitions("ProcPfmCounters");
 | |
|   // Only emit if non-empty.
 | |
|   const bool HasAtLeastOnePfmIssueCounter =
 | |
|       llvm::any_of(PfmCounterDefs, [](const Record *Def) {
 | |
|         return !Def->getValueAsListOfDefs("IssueCounters").empty();
 | |
|       });
 | |
|   if (HasAtLeastOnePfmIssueCounter) {
 | |
|     OS << "static const PfmCountersInfo::IssueCounter " << Target
 | |
|        << "PfmIssueCounters[] = {\n";
 | |
|     for (const Record *Def : PfmCounterDefs) {
 | |
|       for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
 | |
|         OS << "  { " << Target << "PfmCounterNames["
 | |
|            << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
 | |
|            << ICDef->getValueAsString("ResourceName") << "\"},\n";
 | |
|     }
 | |
|     OS << "};\n";
 | |
|   }
 | |
| 
 | |
|   // Now generate the PfmCountersInfo.
 | |
|   unsigned IssueCountersTableOffset = 0;
 | |
|   for (const Record *Def : PfmCounterDefs)
 | |
|     emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
 | |
| 
 | |
|   OS << "\n";
 | |
| } // namespace
 | |
| 
 | |
| void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
 | |
|   std::vector<Record *> Bindings =
 | |
|       Records.getAllDerivedDefinitions("PfmCountersBinding");
 | |
|   assert(!Bindings.empty() && "there must be at least one binding");
 | |
|   llvm::sort(Bindings, [](const Record *L, const Record *R) {
 | |
|     return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
 | |
|   });
 | |
| 
 | |
|   OS << "// Sorted (by CpuName) array of pfm counters.\n"
 | |
|      << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
 | |
|   for (Record *Binding : Bindings) {
 | |
|     // Emit as { "cpu", procinit },
 | |
|     OS << "  { \""                                                        //
 | |
|        << Binding->getValueAsString("CpuName") << "\","                   //
 | |
|        << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
 | |
|        << " },\n";
 | |
|   }
 | |
|   OS << "};\n\n";
 | |
| }
 | |
| 
 | |
| void ExegesisEmitter::run(raw_ostream &OS) const {
 | |
|   emitSourceFileHeader("Exegesis Tables", OS);
 | |
|   emitPfmCounters(OS);
 | |
|   emitPfmCountersLookupTable(OS);
 | |
| }
 | |
| 
 | |
| } // end anonymous namespace
 | |
| 
 | |
| namespace llvm {
 | |
| 
 | |
| void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
 | |
|   ExegesisEmitter(RK).run(OS);
 | |
| }
 | |
| 
 | |
| } // end namespace llvm
 |