mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
Add detailed reference for the SearchableTables backend.
This commit is contained in:
parent
34fd9f9953
commit
88dabfb171
@ -226,16 +226,14 @@ SearchableTables
|
|||||||
|
|
||||||
**Purpose**: Generate custom searchable tables.
|
**Purpose**: Generate custom searchable tables.
|
||||||
|
|
||||||
**Output**: Enums, global tables and lookup helper functions.
|
**Output**: Enums, global tables, and lookup helper functions.
|
||||||
|
|
||||||
**Usage**: This backend allows generating free-form, target-specific tables
|
**Usage**: This backend allows generating free-form, target-specific tables
|
||||||
from TableGen records. The ARM and AArch64 targets use this backend to generate
|
from TableGen records. The ARM and AArch64 targets use this backend to generate
|
||||||
tables of system registers; the AMDGPU target uses it to generate meta-data
|
tables of system registers; the AMDGPU target uses it to generate meta-data
|
||||||
about complex image and memory buffer instructions.
|
about complex image and memory buffer instructions.
|
||||||
|
|
||||||
More documentation is available in ``include/llvm/TableGen/SearchableTable.td``,
|
See `SearchableTables Reference`_ for a detailed description.
|
||||||
which also contains the definitions of TableGen classes which must be
|
|
||||||
instantiated in order to define the enums and tables emitted by this backend.
|
|
||||||
|
|
||||||
CTags
|
CTags
|
||||||
-----
|
-----
|
||||||
@ -438,6 +436,381 @@ used for documenting user-facing attributes.
|
|||||||
General BackEnds
|
General BackEnds
|
||||||
================
|
================
|
||||||
|
|
||||||
|
SearchableTables Reference
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
A TableGen include file, ``SearchableTable.td``, provides classes for
|
||||||
|
generating C++ searchable tables. These tables are described in the
|
||||||
|
following sections. To generate the C++ code, run ``llvm-tblgen`` with the
|
||||||
|
``--gen-searchable-tables`` option, which invokes the backend that generates
|
||||||
|
the tables from the records you provide.
|
||||||
|
|
||||||
|
Each of the data structures generated for searchable tables is guarded by an
|
||||||
|
``#ifdef``. This allows you to include the generated ``.inc`` file and select only
|
||||||
|
certain data structures for inclusion. The examples below show the macro
|
||||||
|
names used in these guards.
|
||||||
|
|
||||||
|
Generic Enumerated Types
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``GenericEnum`` class makes it easy to define a C++ enumerated type and
|
||||||
|
the enumerated *elements* of that type. To define the type, define a record
|
||||||
|
whose parent class is ``GenericEnum`` and whose name is the desired enum
|
||||||
|
type. This class provides three fields, which you can set in the record
|
||||||
|
using the ``let`` statement.
|
||||||
|
|
||||||
|
* ``string FilterClass``. The enum type will have one element for each record
|
||||||
|
that derives from this class. These records are collected to assemble the
|
||||||
|
complete set of elements.
|
||||||
|
|
||||||
|
* ``string NameField``. The name of a field *in the collected records* that specifies
|
||||||
|
the name of the element. If a record has no such field, the record's
|
||||||
|
name will be used.
|
||||||
|
|
||||||
|
* ``string ValueField``. The name of a field *in the collected records* that
|
||||||
|
specifies the numerical value of the element. If a record has no such
|
||||||
|
field, it will be assigned an integer value. Values are assigned in
|
||||||
|
alphabetical order starting with 0.
|
||||||
|
|
||||||
|
Here is an example where the values of the elements are specified
|
||||||
|
explicitly, as a template argument to the ``BEntry`` class. The resulting
|
||||||
|
C++ code is shown.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def BValues : GenericEnum {
|
||||||
|
let FilterClass = "BEntry";
|
||||||
|
let NameField = "Name";
|
||||||
|
let ValueField = "Encoding";
|
||||||
|
}
|
||||||
|
|
||||||
|
class BEntry<bits<16> enc> {
|
||||||
|
string Name = NAME;
|
||||||
|
bits<16> Encoding = enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
def BFoo : BEntry<0xac>;
|
||||||
|
def BBar : BEntry<0x14>;
|
||||||
|
def BZoo : BEntry<0x80>;
|
||||||
|
def BSnork : BEntry<0x4c>;
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
#ifdef GET_BValues_DECL
|
||||||
|
enum BValues {
|
||||||
|
BBar = 20,
|
||||||
|
BFoo = 172,
|
||||||
|
BSnork = 76,
|
||||||
|
BZoo = 128,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
In the following example, the values of the elements are assigned
|
||||||
|
automatically. Note that values are assigned from 0, in alphabetical order
|
||||||
|
by element name.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def CEnum : GenericEnum {
|
||||||
|
let FilterClass = "CEnum";
|
||||||
|
}
|
||||||
|
|
||||||
|
class CEnum;
|
||||||
|
|
||||||
|
def CFoo : CEnum;
|
||||||
|
def CBar : CEnum;
|
||||||
|
def CBaz : CEnum;
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
#ifdef GET_CEnum_DECL
|
||||||
|
enum CEnum {
|
||||||
|
CBar = 0,
|
||||||
|
CBaz = 1,
|
||||||
|
CFoo = 2,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Generic Tables
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``GenericTable`` class is used to define a searchable generic table.
|
||||||
|
TableGen produces C++ code to define the table entries and also produces
|
||||||
|
the declaration and definition of a function to search the table based on a
|
||||||
|
primary key. To define the table, define a record whose parent class is
|
||||||
|
``GenericTable`` and whose name is the name of the global table of entries.
|
||||||
|
This class provides six fields.
|
||||||
|
|
||||||
|
* ``string FilterClass``. The table will have one entry for each record
|
||||||
|
that derives from this class.
|
||||||
|
|
||||||
|
* ``string CppTypeName``. The name of the C++ struct/class type of the
|
||||||
|
table that holds the entries. If unspecified, the ``FilterClass`` name is
|
||||||
|
used.
|
||||||
|
|
||||||
|
* ``list<string> Fields``. A list of the names of the fields in the
|
||||||
|
collected records that contain the data for the table entries. The order of
|
||||||
|
this list determines the order of the values in the C++ initializers. See
|
||||||
|
below for information about the types of these fields.
|
||||||
|
|
||||||
|
* ``list<string> PrimaryKey``. The list of fields that make up the
|
||||||
|
primary key.
|
||||||
|
|
||||||
|
* ``string PrimaryKeyName``. The name of the generated C++ function
|
||||||
|
that performs a lookup on the primary key.
|
||||||
|
|
||||||
|
* ``bit PrimaryKeyEarlyOut``. See the third example below.
|
||||||
|
|
||||||
|
TableGen attempts to deduce the type of each of the table fields. It can
|
||||||
|
deduce ``bit``, ``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``.
|
||||||
|
These can be used in the primary key. TableGen also deduces ``code``, but it
|
||||||
|
cannot be used in the primary key. Any other field types must be specified
|
||||||
|
explicitly; this is done as shown in the second example below. Such fields
|
||||||
|
cannot be used in the primary key.
|
||||||
|
|
||||||
|
Here is an example where TableGen can deduce the field types. Note that the
|
||||||
|
table entry records are anonymous; the names of entry records are
|
||||||
|
irrelevant.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def ATable : GenericTable {
|
||||||
|
let FilterClass = "AEntry";
|
||||||
|
let Fields = ["Str", "Val1", "Val2"];
|
||||||
|
let PrimaryKey = ["Val1", "Val2"];
|
||||||
|
let PrimaryKeyName = "lookupATableByValues";
|
||||||
|
}
|
||||||
|
|
||||||
|
class AEntry<string str, int val1, int val2> {
|
||||||
|
string Str = str;
|
||||||
|
bits<8> Val1 = val1;
|
||||||
|
bits<10> Val2 = val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
def : AEntry<"Bob", 5, 3>;
|
||||||
|
def : AEntry<"Carol", 2, 6>;
|
||||||
|
def : AEntry<"Ted", 4, 4>;
|
||||||
|
def : AEntry<"Alice", 4, 5>;
|
||||||
|
def : AEntry<"Costa", 2, 1>;
|
||||||
|
|
||||||
|
Here is the generated C++ code. The declaration of ``lookupATableByValues``
|
||||||
|
is guarded by ``GET_ATable_DECL``, while the definitions are guarded by
|
||||||
|
``GET_ATable_IMPL``.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
#ifdef GET_ATable_DECL
|
||||||
|
const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GET_ATable_IMPL
|
||||||
|
constexpr AEntry ATable[] = {
|
||||||
|
{ "Costa", 0x2, 0x1 }, // 0
|
||||||
|
{ "Carol", 0x2, 0x6 }, // 1
|
||||||
|
{ "Ted", 0x4, 0x4 }, // 2
|
||||||
|
{ "Alice", 0x4, 0x5 }, // 3
|
||||||
|
{ "Bob", 0x5, 0x3 }, // 4
|
||||||
|
};
|
||||||
|
|
||||||
|
const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
|
||||||
|
struct KeyType {
|
||||||
|
uint8_t Val1;
|
||||||
|
uint16_t Val2;
|
||||||
|
};
|
||||||
|
KeyType Key = { Val1, Val2 };
|
||||||
|
auto Table = makeArrayRef(ATable);
|
||||||
|
auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
|
||||||
|
[](const AEntry &LHS, const KeyType &RHS) {
|
||||||
|
if (LHS.Val1 < RHS.Val1)
|
||||||
|
return true;
|
||||||
|
if (LHS.Val1 > RHS.Val1)
|
||||||
|
return false;
|
||||||
|
if (LHS.Val2 < RHS.Val2)
|
||||||
|
return true;
|
||||||
|
if (LHS.Val2 > RHS.Val2)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Idx == Table.end() ||
|
||||||
|
Key.Val1 != Idx->Val1 ||
|
||||||
|
Key.Val2 != Idx->Val2)
|
||||||
|
return nullptr;
|
||||||
|
return &*Idx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
The table entries in ``ATable`` are sorted in order by ``Val1``, and within
|
||||||
|
each of those values, by ``Val2``. This allows a binary search of the table,
|
||||||
|
which is performed in the lookup function by ``std::lower_bound``. The
|
||||||
|
lookup function returns a reference to the found table entry, or the null
|
||||||
|
pointer if no entry is found.
|
||||||
|
|
||||||
|
This example includes a field whose type TableGen cannot deduce. The ``Kind``
|
||||||
|
field uses the enumerated type ``CEnum`` defined above. To inform TableGen
|
||||||
|
of the type, the class derived from ``GenericTable`` must include a field
|
||||||
|
named ``TypeOf_``\ *field*, where *field* is the name of the field whose type
|
||||||
|
is required.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def CTable : GenericTable {
|
||||||
|
let FilterClass = "CEntry";
|
||||||
|
let Fields = ["Name", "Kind", "Encoding"];
|
||||||
|
GenericEnum TypeOf_Kind = CEnum;
|
||||||
|
let PrimaryKey = ["Encoding"];
|
||||||
|
let PrimaryKeyName = "lookupCEntryByEncoding";
|
||||||
|
}
|
||||||
|
|
||||||
|
class CEntry<string name, CEnum kind, int enc> {
|
||||||
|
string Name = name;
|
||||||
|
CEnum Kind = kind;
|
||||||
|
bits<16> Encoding = enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
def : CEntry<"Apple", CFoo, 10>;
|
||||||
|
def : CEntry<"Pear", CBaz, 15>;
|
||||||
|
def : CEntry<"Apple", CBar, 13>;
|
||||||
|
|
||||||
|
Here is the generated C++ code.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
#ifdef GET_CTable_DECL
|
||||||
|
const CEntry *lookupCEntryByEncoding(uint16_t Encoding);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GET_CTable_IMPL
|
||||||
|
constexpr CEntry CTable[] = {
|
||||||
|
{ "Apple", CFoo, 0xA }, // 0
|
||||||
|
{ "Apple", CBar, 0xD }, // 1
|
||||||
|
{ "Pear", CBaz, 0xF }, // 2
|
||||||
|
};
|
||||||
|
|
||||||
|
const CEntry *lookupCEntryByEncoding(uint16_t Encoding) {
|
||||||
|
struct KeyType {
|
||||||
|
uint16_t Encoding;
|
||||||
|
};
|
||||||
|
KeyType Key = { Encoding };
|
||||||
|
auto Table = makeArrayRef(CTable);
|
||||||
|
auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
|
||||||
|
[](const CEntry &LHS, const KeyType &RHS) {
|
||||||
|
if (LHS.Encoding < RHS.Encoding)
|
||||||
|
return true;
|
||||||
|
if (LHS.Encoding > RHS.Encoding)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Idx == Table.end() ||
|
||||||
|
Key.Encoding != Idx->Encoding)
|
||||||
|
return nullptr;
|
||||||
|
return &*Idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``PrimaryKeyEarlyOut`` field, when set to 1, modifies the lookup
|
||||||
|
function so that it tests the first field of the primary key to determine
|
||||||
|
whether it is within the range of the collected records' primary keys. If
|
||||||
|
not, the function returns the null pointer without performing the binary
|
||||||
|
search. This is useful for tables that provide data for only some of the
|
||||||
|
elements of a larger enum-based space. The first field of the primary key
|
||||||
|
must be an integral type; it cannot be a string.
|
||||||
|
|
||||||
|
Adding ``let PrimaryKeyEarlyOut = 1`` to the ``ATable`` above:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def ATable : GenericTable {
|
||||||
|
let FilterClass = "AEntry";
|
||||||
|
let Fields = ["Str", "Val1", "Val2"];
|
||||||
|
let PrimaryKey = ["Val1", "Val2"];
|
||||||
|
let PrimaryKeyName = "lookupATableByValues";
|
||||||
|
let PrimaryKeyEarlyOut = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
causes the lookup function to change as follows:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
|
||||||
|
if ((Val1 < 0x2) ||
|
||||||
|
(Val1 > 0x5))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
struct KeyType {
|
||||||
|
...
|
||||||
|
|
||||||
|
Search Indexes
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``SearchIndex`` class is used to define additional lookup functions for
|
||||||
|
generic tables. To define an additional function, define a record whose parent
|
||||||
|
class is ``SearchIndex`` and whose name is the name of the desired lookup
|
||||||
|
function. This class provides three fields.
|
||||||
|
|
||||||
|
* ``GenericTable Table``. The name of the table that is to receive another
|
||||||
|
lookup function.
|
||||||
|
|
||||||
|
* ``list<string> Key``. The list of fields that make up the secondary key.
|
||||||
|
|
||||||
|
* ``bit EarlyOut``. See the third example in `Generic Tables`_.
|
||||||
|
|
||||||
|
Here is an example of a secondary key added to the ``CTable`` above. The
|
||||||
|
generated function looks up entries based on the ``Name`` and ``Kind`` fields.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def lookupCEntry : SearchIndex {
|
||||||
|
let Table = CTable;
|
||||||
|
let Key = ["Name", "Kind"];
|
||||||
|
}
|
||||||
|
|
||||||
|
This use of ``SearchIndex`` generates the following additional C++ code.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
const CEntry *lookupCEntry(StringRef Name, unsigned Kind);
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
const CEntry *lookupCEntryByName(StringRef Name, unsigned Kind) {
|
||||||
|
struct IndexType {
|
||||||
|
const char * Name;
|
||||||
|
unsigned Kind;
|
||||||
|
unsigned _index;
|
||||||
|
};
|
||||||
|
static const struct IndexType Index[] = {
|
||||||
|
{ "APPLE", CBar, 1 },
|
||||||
|
{ "APPLE", CFoo, 0 },
|
||||||
|
{ "PEAR", CBaz, 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyType {
|
||||||
|
std::string Name;
|
||||||
|
unsigned Kind;
|
||||||
|
};
|
||||||
|
KeyType Key = { Name.upper(), Kind };
|
||||||
|
auto Table = makeArrayRef(Index);
|
||||||
|
auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
|
||||||
|
[](const IndexType &LHS, const KeyType &RHS) {
|
||||||
|
int CmpName = StringRef(LHS.Name).compare(RHS.Name);
|
||||||
|
if (CmpName < 0) return true;
|
||||||
|
if (CmpName > 0) return false;
|
||||||
|
if ((unsigned)LHS.Kind < (unsigned)RHS.Kind)
|
||||||
|
return true;
|
||||||
|
if ((unsigned)LHS.Kind > (unsigned)RHS.Kind)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Idx == Table.end() ||
|
||||||
|
Key.Name != Idx->Name ||
|
||||||
|
Key.Kind != Idx->Kind)
|
||||||
|
return nullptr;
|
||||||
|
return &CTable[Idx->_index];
|
||||||
|
}
|
||||||
|
|
||||||
JSON
|
JSON
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user