summaryrefslogtreecommitdiffstats
path: root/llvm/utils
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2016-07-05 21:23:04 +0000
committerTim Northover <tnorthover@apple.com>2016-07-05 21:23:04 +0000
commite6ae6767d9e0f0e2083e4b4e3d731fbedc00a8ed (patch)
tree9f1928ad7ad9e10905c5d09f6cae9affd00d8c89 /llvm/utils
parent88403d7a840f09395e45bb1e0a757cf8362beb5a (diff)
downloadbcm5719-llvm-e6ae6767d9e0f0e2083e4b4e3d731fbedc00a8ed.tar.gz
bcm5719-llvm-e6ae6767d9e0f0e2083e4b4e3d731fbedc00a8ed.zip
AArch64: TableGenerate system instruction operands.
The way the named arguments for various system instructions are handled at the moment has a few problems: - Large-scale duplication between AArch64BaseInfo.h and AArch64BaseInfo.cpp - That weird Mapping class that I have no idea what I was on when I thought it was a good idea. - Searches are performed linearly through the entire list. - We print absolutely all registers in upper-case, even though some are canonically mixed case (SPSel for example). - The ARM ARM specifies sysregs in terms of 5 fields, but those are relegated to comments in our implementation, with a slightly opaque hex value indicating the canonical encoding LLVM will use. This adds a new TableGen backend to produce efficiently searchable tables, and switches AArch64 over to using that infrastructure. llvm-svn: 274576
Diffstat (limited to 'llvm/utils')
-rw-r--r--llvm/utils/TableGen/CMakeLists.txt1
-rw-r--r--llvm/utils/TableGen/SearchableTableEmitter.cpp320
-rw-r--r--llvm/utils/TableGen/TableGen.cpp8
-rw-r--r--llvm/utils/TableGen/TableGenBackends.h1
4 files changed, 329 insertions, 1 deletions
diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt
index eef1540424d..e8fe30f5ac7 100644
--- a/llvm/utils/TableGen/CMakeLists.txt
+++ b/llvm/utils/TableGen/CMakeLists.txt
@@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
+ SearchableTableEmitter.cpp
SubtargetEmitter.cpp
TableGen.cpp
X86DisassemblerTables.cpp
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
new file mode 100644
index 00000000000..1b0e67f835f
--- /dev/null
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -0,0 +1,320 @@
+//===- 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/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 <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+using namespace llvm;
+
+#define DEBUG_TYPE "searchable-table-emitter"
+
+namespace {
+
+class SearchableTableEmitter {
+ RecordKeeper &Records;
+
+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();
+ }
+ 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();
+ }
+
+ 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";
+ }
+ 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) {
+ std::string EnumNameField = InstanceClass->getValueAsString("EnumNameField");
+ std::string 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 {
+ 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 = isa<BitsInit>(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.data(), 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 StringRef(LHS.first) < StringRef(RHS.first);\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 = isa<BitsInit>(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) {
+ std::string 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_" << StringRef(TableName).upper() << "_DECL\n";
+ OS << "#undef GET_" << StringRef(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_" << StringRef(TableName).upper() << "_IMPL\n";
+ OS << "#undef GET_" << StringRef(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.
diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index cf751235535..24dbe5d3a28 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -43,7 +43,8 @@ enum ActionType {
PrintSets,
GenOptParserDefs,
GenCTags,
- GenAttributes
+ GenAttributes,
+ GenSearchableTables,
};
namespace {
@@ -89,6 +90,8 @@ namespace {
"Generate ctags-compatible index"),
clEnumValN(GenAttributes, "gen-attrs",
"Generate attributes"),
+ clEnumValN(GenSearchableTables, "gen-searchable-tables",
+ "Generate generic binary-searchable table"),
clEnumValEnd));
cl::opt<std::string>
@@ -172,6 +175,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenAttributes:
EmitAttributes(Records, OS);
break;
+ case GenSearchableTables:
+ EmitSearchableTables(Records, OS);
+ break;
}
return false;
diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h
index d9dd3d15769..51e017fe659 100644
--- a/llvm/utils/TableGen/TableGenBackends.h
+++ b/llvm/utils/TableGen/TableGenBackends.h
@@ -79,6 +79,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
+void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace
OpenPOWER on IntegriCloud