[llvm] 1f870bd - Add detailed reference for the SearchableTables backend.

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 10:49:51 PDT 2020


Author: Paul C. Anagnostopoulos
Date: 2020-09-08T13:48:12-04:00
New Revision: 1f870bd9284ad55dff96ab6f99afd92fd5f294be

URL: https://github.com/llvm/llvm-project/commit/1f870bd9284ad55dff96ab6f99afd92fd5f294be
DIFF: https://github.com/llvm/llvm-project/commit/1f870bd9284ad55dff96ab6f99afd92fd5f294be.diff

LOG: Add detailed reference for the SearchableTables backend.

Added: 
    

Modified: 
    llvm/docs/TableGen/BackEnds.rst

Removed: 
    


################################################################################
diff  --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 8b3133835668..a93f2ace7880 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -226,16 +226,14 @@ SearchableTables
 
 **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
 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
 about complex image and memory buffer instructions.
 
-More documentation is available in ``include/llvm/TableGen/SearchableTable.td``,
-which also contains the definitions of TableGen classes which must be
-instantiated in order to define the enums and tables emitted by this backend.
+See `SearchableTables Reference`_ for a detailed description.
 
 CTags
 -----
@@ -438,6 +436,381 @@ used for documenting user-facing attributes.
 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
 ----
 


        


More information about the llvm-commits mailing list