mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
eacc62ef10
Summary: We will use this in the AMDGPU backend in a subsequent patch in the stack to lookup target-specific per-intrinsic information. The generic CodeGenIntrinsic machinery is used to ensure that, even though we don't calculate actual enum values here, we do get the intrinsics in the right order for the binary search index. Change-Id: If61cd5587963a4c5a1cc53df1e59c5e4dec1f9dc Reviewers: arsenm, rampitec, b-sumner Subscribers: wdng, tpr, llvm-commits Differential Revision: https://reviews.llvm.org/D44935 llvm-svn: 328937
353 lines
12 KiB
C++
353 lines
12 KiB
C++
//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This tablegen backend emits a generic array initialized by specified fields,
|
|
// together with companion index tables and lookup functions (binary search,
|
|
// currently).
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "CodeGenIntrinsics.h"
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <vector>
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "searchable-table-emitter"
|
|
|
|
namespace {
|
|
|
|
class SearchableTableEmitter {
|
|
RecordKeeper &Records;
|
|
DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
|
|
|
|
public:
|
|
SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
|
|
|
|
void run(raw_ostream &OS);
|
|
|
|
private:
|
|
typedef std::pair<Init *, int> SearchTableEntry;
|
|
|
|
int getAsInt(BitsInit *B) {
|
|
return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
|
|
}
|
|
int getInt(Record *R, StringRef Field) {
|
|
return getAsInt(R->getValueAsBitsInit(Field));
|
|
}
|
|
|
|
std::string primaryRepresentation(Init *I) {
|
|
if (StringInit *SI = dyn_cast<StringInit>(I))
|
|
return SI->getAsString();
|
|
else if (BitsInit *BI = dyn_cast<BitsInit>(I))
|
|
return "0x" + utohexstr(getAsInt(BI));
|
|
else if (BitInit *BI = dyn_cast<BitInit>(I))
|
|
return BI->getValue() ? "true" : "false";
|
|
else if (CodeInit *CI = dyn_cast<CodeInit>(I))
|
|
return CI->getValue();
|
|
else if (DefInit *DI = dyn_cast<DefInit>(I)) {
|
|
if (DI->getDef()->isSubClassOf("Intrinsic"))
|
|
return "Intrinsic::" + getIntrinsic(I).EnumName;
|
|
}
|
|
PrintFatalError(SMLoc(),
|
|
"invalid field type, expected: string, bits, bit or code");
|
|
}
|
|
|
|
std::string searchRepresentation(Init *I) {
|
|
std::string PrimaryRep = primaryRepresentation(I);
|
|
if (!isa<StringInit>(I))
|
|
return PrimaryRep;
|
|
return StringRef(PrimaryRep).upper();
|
|
}
|
|
|
|
bool isIntrinsic(Init *I) {
|
|
if (DefInit *DI = dyn_cast<DefInit>(I))
|
|
return DI->getDef()->isSubClassOf("Intrinsic");
|
|
return false;
|
|
}
|
|
|
|
CodeGenIntrinsic &getIntrinsic(Init *I) {
|
|
std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
|
|
if (!Intr)
|
|
Intr = make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef());
|
|
return *Intr;
|
|
}
|
|
|
|
bool isIntegral(Init *I) {
|
|
return isa<BitsInit>(I) || isIntrinsic(I);
|
|
}
|
|
|
|
std::string searchableFieldType(Init *I) {
|
|
if (isa<StringInit>(I))
|
|
return "const char *";
|
|
else if (BitsInit *BI = dyn_cast<BitsInit>(I)) {
|
|
unsigned NumBits = BI->getNumBits();
|
|
if (NumBits <= 8)
|
|
NumBits = 8;
|
|
else if (NumBits <= 16)
|
|
NumBits = 16;
|
|
else if (NumBits <= 32)
|
|
NumBits = 32;
|
|
else if (NumBits <= 64)
|
|
NumBits = 64;
|
|
else
|
|
PrintFatalError(SMLoc(), "bitfield too large to search");
|
|
return "uint" + utostr(NumBits) + "_t";
|
|
} else if (isIntrinsic(I))
|
|
return "unsigned";
|
|
PrintFatalError(SMLoc(), "Unknown type to search by");
|
|
}
|
|
|
|
void emitMapping(Record *MappingDesc, raw_ostream &OS);
|
|
void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass,
|
|
raw_ostream &OS);
|
|
void
|
|
emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames,
|
|
std::vector<std::string> &SearchFieldNames,
|
|
std::vector<std::vector<SearchTableEntry>> &SearchTables,
|
|
std::vector<Record *> &Items, raw_ostream &OS);
|
|
void emitSearchTable(StringRef Name, StringRef Field,
|
|
std::vector<SearchTableEntry> &SearchTable,
|
|
raw_ostream &OS);
|
|
void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I,
|
|
raw_ostream &OS);
|
|
void emitLookupFunction(StringRef Name, StringRef Field, Init *I,
|
|
raw_ostream &OS);
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
/// Emit an enum providing symbolic access to some preferred field from
|
|
/// C++.
|
|
void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items,
|
|
Record *InstanceClass,
|
|
raw_ostream &OS) {
|
|
StringRef EnumNameField = InstanceClass->getValueAsString("EnumNameField");
|
|
StringRef EnumValueField;
|
|
if (!InstanceClass->isValueUnset("EnumValueField"))
|
|
EnumValueField = InstanceClass->getValueAsString("EnumValueField");
|
|
|
|
OS << "enum " << InstanceClass->getName() << "Values {\n";
|
|
for (auto Item : Items) {
|
|
OS << " " << Item->getValueAsString(EnumNameField);
|
|
if (EnumValueField != StringRef())
|
|
OS << " = " << getInt(Item, EnumValueField);
|
|
OS << ",\n";
|
|
}
|
|
OS << "};\n\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::emitPrimaryTable(
|
|
StringRef Name, std::vector<std::string> &FieldNames,
|
|
std::vector<std::string> &SearchFieldNames,
|
|
std::vector<std::vector<SearchTableEntry>> &SearchTables,
|
|
std::vector<Record *> &Items, raw_ostream &OS) {
|
|
OS << "const " << Name << " " << Name << "sList[] = {\n";
|
|
|
|
for (auto Item : Items) {
|
|
OS << " { ";
|
|
for (unsigned i = 0; i < FieldNames.size(); ++i) {
|
|
OS << primaryRepresentation(Item->getValueInit(FieldNames[i]));
|
|
if (i != FieldNames.size() - 1)
|
|
OS << ", ";
|
|
}
|
|
OS << "},\n";
|
|
}
|
|
OS << "};\n\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::emitSearchTable(
|
|
StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable,
|
|
raw_ostream &OS) {
|
|
OS << "const std::pair<" << searchableFieldType(SearchTable[0].first)
|
|
<< ", int> " << Name << "sBy" << Field << "[] = {\n";
|
|
|
|
if (isa<BitsInit>(SearchTable[0].first)) {
|
|
std::stable_sort(SearchTable.begin(), SearchTable.end(),
|
|
[this](const SearchTableEntry &LHS,
|
|
const SearchTableEntry &RHS) {
|
|
return getAsInt(cast<BitsInit>(LHS.first)) <
|
|
getAsInt(cast<BitsInit>(RHS.first));
|
|
});
|
|
} else if (isIntrinsic(SearchTable[0].first)) {
|
|
std::stable_sort(SearchTable.begin(), SearchTable.end(),
|
|
[this](const SearchTableEntry &LHS,
|
|
const SearchTableEntry &RHS) {
|
|
CodeGenIntrinsic &LHSi = getIntrinsic(LHS.first);
|
|
CodeGenIntrinsic &RHSi = getIntrinsic(RHS.first);
|
|
return std::tie(LHSi.TargetPrefix, LHSi.Name) <
|
|
std::tie(RHSi.TargetPrefix, RHSi.Name);
|
|
});
|
|
} else {
|
|
std::stable_sort(SearchTable.begin(), SearchTable.end(),
|
|
[this](const SearchTableEntry &LHS,
|
|
const SearchTableEntry &RHS) {
|
|
return searchRepresentation(LHS.first) <
|
|
searchRepresentation(RHS.first);
|
|
});
|
|
}
|
|
|
|
for (auto Entry : SearchTable) {
|
|
OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second
|
|
<< " },\n";
|
|
}
|
|
OS << "};\n\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field,
|
|
Init *I, raw_ostream &OS) {
|
|
bool IsIntegral = isIntegral(I);
|
|
std::string FieldType = searchableFieldType(I);
|
|
std::string PairType = "std::pair<" + FieldType + ", int>";
|
|
|
|
// const SysRegs *lookupSysRegByName(const char *Name) {
|
|
OS << "const " << Name << " *"
|
|
<< "lookup" << Name << "By" << Field;
|
|
OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
|
|
<< ") {\n";
|
|
|
|
if (IsIntegral) {
|
|
OS << " auto CanonicalVal = " << Field << ";\n";
|
|
OS << " " << PairType << " Val = {CanonicalVal, 0};\n";
|
|
} else {
|
|
// Make sure the result is null terminated because it's going via "char *".
|
|
OS << " std::string CanonicalVal = " << Field << ".upper();\n";
|
|
OS << " " << PairType << " Val = {CanonicalVal.c_str(), 0};\n";
|
|
}
|
|
|
|
OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field
|
|
<< ");\n";
|
|
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val";
|
|
|
|
if (IsIntegral)
|
|
OS << ");\n";
|
|
else {
|
|
OS << ",\n ";
|
|
OS << "[](const " << PairType << " &LHS, const " << PairType
|
|
<< " &RHS) {\n";
|
|
OS << " return std::strcmp(LHS.first, RHS.first) < 0;\n";
|
|
OS << " });\n\n";
|
|
}
|
|
|
|
OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n";
|
|
OS << " return nullptr;\n";
|
|
|
|
OS << " return &" << Name << "sList[Idx->second];\n";
|
|
OS << "}\n\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::emitLookupDeclaration(StringRef Name,
|
|
StringRef Field, Init *I,
|
|
raw_ostream &OS) {
|
|
bool IsIntegral = isIntegral(I);
|
|
std::string FieldType = searchableFieldType(I);
|
|
OS << "const " << Name << " *"
|
|
<< "lookup" << Name << "By" << Field;
|
|
OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
|
|
<< ");\n\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::emitMapping(Record *InstanceClass,
|
|
raw_ostream &OS) {
|
|
StringRef TableName = InstanceClass->getName();
|
|
std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
|
|
|
|
// Gather all the records we're going to need for this particular mapping.
|
|
std::vector<std::vector<SearchTableEntry>> SearchTables;
|
|
std::vector<std::string> SearchFieldNames;
|
|
|
|
std::vector<std::string> FieldNames;
|
|
for (const RecordVal &Field : InstanceClass->getValues()) {
|
|
std::string FieldName = Field.getName();
|
|
|
|
// Skip uninteresting fields: either built-in, special to us, or injected
|
|
// template parameters (if they contain a ':').
|
|
if (FieldName.find(':') != std::string::npos || FieldName == "NAME" ||
|
|
FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
|
|
FieldName == "EnumValueField")
|
|
continue;
|
|
|
|
FieldNames.push_back(FieldName);
|
|
}
|
|
|
|
for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) {
|
|
SearchTables.emplace_back();
|
|
SearchFieldNames.push_back(Field->getAsUnquotedString());
|
|
}
|
|
|
|
int Idx = 0;
|
|
for (Record *Item : Items) {
|
|
for (unsigned i = 0; i < SearchFieldNames.size(); ++i) {
|
|
Init *SearchVal = Item->getValueInit(SearchFieldNames[i]);
|
|
SearchTables[i].emplace_back(SearchVal, Idx);
|
|
}
|
|
++Idx;
|
|
}
|
|
|
|
OS << "#ifdef GET_" << TableName.upper() << "_DECL\n";
|
|
OS << "#undef GET_" << TableName.upper() << "_DECL\n";
|
|
|
|
// Next emit the enum containing the top-level names for use in C++ code if
|
|
// requested
|
|
if (!InstanceClass->isValueUnset("EnumNameField")) {
|
|
emitMappingEnum(Items, InstanceClass, OS);
|
|
}
|
|
|
|
// And the declarations for the functions that will perform lookup.
|
|
for (unsigned i = 0; i < SearchFieldNames.size(); ++i)
|
|
emitLookupDeclaration(TableName, SearchFieldNames[i],
|
|
SearchTables[i][0].first, OS);
|
|
|
|
OS << "#endif\n\n";
|
|
|
|
OS << "#ifdef GET_" << TableName.upper() << "_IMPL\n";
|
|
OS << "#undef GET_" << TableName.upper() << "_IMPL\n";
|
|
|
|
// The primary data table contains all the fields defined for this map.
|
|
emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items,
|
|
OS);
|
|
|
|
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
|
|
// search can be performed by "Thing".
|
|
for (unsigned i = 0; i < SearchTables.size(); ++i) {
|
|
emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS);
|
|
emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first,
|
|
OS);
|
|
}
|
|
|
|
OS << "#endif\n";
|
|
}
|
|
|
|
void SearchableTableEmitter::run(raw_ostream &OS) {
|
|
// Tables are defined to be the direct descendents of "SearchableEntry".
|
|
Record *SearchableTable = Records.getClass("SearchableTable");
|
|
for (auto &NameRec : Records.getClasses()) {
|
|
Record *Class = NameRec.second.get();
|
|
if (Class->getSuperClasses().size() != 1 ||
|
|
!Class->isSubClassOf(SearchableTable))
|
|
continue;
|
|
emitMapping(Class, OS);
|
|
}
|
|
}
|
|
|
|
namespace llvm {
|
|
|
|
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
|
|
SearchableTableEmitter(RK).run(OS);
|
|
}
|
|
|
|
} // End llvm namespace.
|