[llvm] [TableGen] Add a field to filter out GenericTable entries (PR #65458)

Wang Pengcheng via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 8 00:07:36 PDT 2023


https://github.com/wangpc-pp updated https://github.com/llvm/llvm-project/pull/65458:

>From c7c59dcfb5774f09e8a3c31fe76220872724d213 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Wed, 6 Sep 2023 17:13:40 +0800
Subject: [PATCH 1/3] [TableGen] Add a field to filter out GenericTable entries

A field `FilterClassField` is added to `GenericTable` class, which
is an optional bit field of `FilterClass`. If specified, only those
records with this field being true will have corresponding entries
in the table.
---
 llvm/docs/TableGen/BackEnds.rst               | 20 +++++++++++++------
 llvm/include/llvm/TableGen/SearchableTable.td |  6 ++++++
 .../utils/TableGen/SearchableTableEmitter.cpp | 18 ++++++++++++++++-
 3 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 07dff5a30e2168b..7576a9219a8ea72 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -689,6 +689,10 @@ This class provides six fields.
 * ``string FilterClass``. The table will have one entry for each record
   that derives from this class.
 
+* ``string FilterClassField``. This is an optional field of ``FilterClass``
+  which should be `bit` type. If specified, only those records with this field
+  being true will have corresponding entries in the table.
+
 * ``string CppTypeName``. The name of the C++ struct/class type of the
   table that holds the entries. If unspecified, the ``FilterClass`` name is
   used.
@@ -734,22 +738,25 @@ irrelevant.
 
   def ATable : GenericTable {
     let FilterClass = "AEntry";
+    let FilterClassField = "IsNeeded";
     let Fields = ["Str", "Val1", "Val2"];
     let PrimaryKey = ["Val1", "Val2"];
     let PrimaryKeyName = "lookupATableByValues";
   }
 
-  class AEntry<string str, int val1, int val2> {
+  class AEntry<string str, int val1, int val2, bit isNeeded> {
     string Str = str;
     bits<8> Val1 = val1;
     bits<10> Val2 = val2;
+    bit IsNeeded = isNeeded;
   }
 
-  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>;
+  def : AEntry<"Bob",   5, 3, 1>;
+  def : AEntry<"Carol", 2, 6, 1>;
+  def : AEntry<"Ted",   4, 4, 1>;
+  def : AEntry<"Alice", 4, 5, 1>;
+  def : AEntry<"Costa", 2, 1, 1>;
+  def : AEntry<"Dale",  2, 1, 0>;
 
 Here is the generated C++ code. The declaration of ``lookupATableByValues``
 is guarded by ``GET_ATable_DECL``, while the definitions are guarded by
@@ -768,6 +775,7 @@ is guarded by ``GET_ATable_DECL``, while the definitions are guarded by
     { "Ted", 0x4, 0x4 }, // 2
     { "Alice", 0x4, 0x5 }, // 3
     { "Bob", 0x5, 0x3 }, // 4
+    /* { "Dale", 0x2, 0x1 }, // 5 */ // No this line as `IsNeeded` is 0.
   };
 
   const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
diff --git a/llvm/include/llvm/TableGen/SearchableTable.td b/llvm/include/llvm/TableGen/SearchableTable.td
index 61dfa5c7070646b..9dddd5e578ff125 100644
--- a/llvm/include/llvm/TableGen/SearchableTable.td
+++ b/llvm/include/llvm/TableGen/SearchableTable.td
@@ -60,6 +60,12 @@ class GenericTable {
   // derives from that class.
   string FilterClass;
 
+  // A field of FilterClass to filter out entries. This is an optional field
+  // of ``FilterClass`` which should be `bit` type. If specified, only those
+  // records with this field being true will have corresponding entries in the
+  // table.
+  string FilterClassField = ?;
+
   // Name of the C++ struct/class type that holds table entries. The
   // declaration of this type is not generated automatically.
   string CppTypeName = FilterClass;
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index b6af02c28a80640..ee1af0ec70df08b 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -720,7 +720,23 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
                       Twine("Table FilterClass '") +
                           FilterClass + "' does not exist");
 
-    collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
+    RecordVal *FilterClassFieldVal = TableRec->getValue("FilterClassField");
+    std::vector<Record *> Definitions =
+        Records.getAllDerivedDefinitions(FilterClass);
+    if (auto *FilterClassFieldInit =
+            dyn_cast<StringInit>(FilterClassFieldVal->getValue())) {
+      StringRef FilterClassField = FilterClassFieldInit->getValue();
+      llvm::erase_if(Definitions, [&](const Record *R) {
+        const RecordVal *Filter = R->getValue(FilterClassField);
+        if (auto *BitV = dyn_cast<BitInit>(Filter->getValue()))
+          return !BitV->getValue();
+
+        PrintFatalError(Filter, Twine("FilterClassField '") + FilterClass +
+                                    "' should be a bit value");
+        return true;
+      });
+    }
+    collectTableEntries(*Table, Definitions);
 
     if (!TableRec->isValueUnset("PrimaryKey")) {
       Table->PrimaryKey =

>From c1864aaa96f5f11bc89e7fe4a8f620fe7d3602f1 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Thu, 7 Sep 2023 12:05:45 +0800
Subject: [PATCH 2/3] fixup! [TableGen] Add a field to filter out GenericTable
 entries

Add a test in `llvm/test/TableGen/generic-tables.td` and make
detailed document
---
 llvm/docs/TableGen/BackEnds.rst      | 60 +++++++++++++++++++++-
 llvm/test/TableGen/generic-tables.td | 74 ++++++++++++++++++++++++++--
 2 files changed, 129 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 7576a9219a8ea72..67ad76dcbf4c43a 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -691,7 +691,8 @@ This class provides six fields.
 
 * ``string FilterClassField``. This is an optional field of ``FilterClass``
   which should be `bit` type. If specified, only those records with this field
-  being true will have corresponding entries in the table.
+  being true will have corresponding entries in the table. This field won't be
+  included in generated C++ fields if it isn't included in ``Fields`` list.
 
 * ``string CppTypeName``. The name of the C++ struct/class type of the
   table that holds the entries. If unspecified, the ``FilterClass`` name is
@@ -906,6 +907,63 @@ causes the lookup function to change as follows:
     struct KeyType {
     ...
 
+We can construct two GenericTables with the same ``FilterClass``, so that they
+select from the same overall set of records, but assign them with different
+``FilterClassField`` values so that they include different subsets of the
+records of that class.
+
+For example, we can create two tables that contain only even or odd records.
+Fields ``IsEven`` and ``IsOdd`` won't be included in generated C++ fields
+because they aren't included in ``Fields`` list.
+
+.. code-block:: text
+
+  class EEntry<bits<8> value> {
+    bits<8> Value = value;
+    bit IsEven = !eq(!and(value, 1), 0);
+    bit IsOdd = !not(IsEven);
+  }
+
+  foreach i = {1-10} in {
+    def : EEntry<i>;
+  }
+
+  def EEntryEvenTable : GenericTable {
+    let FilterClass = "EEntry";
+    let FilterClassField = "IsEven";
+    let Fields = ["Value"];
+    let PrimaryKey = ["Value"];
+    let PrimaryKeyName = "lookupEEntryEvenTableByValue";
+  }
+
+  def EEntryOddTable : GenericTable {
+    let FilterClass = "EEntry";
+    let FilterClassField = "IsOdd";
+    let Fields = ["Value"];
+    let PrimaryKey = ["Value"];
+    let PrimaryKeyName = "lookupEEntryOddTableByValue";
+  }
+
+The generated tables are:
+
+.. code-block:: text
+
+  constexpr EEntry EEntryEvenTable[] = {
+    { 0x2 }, // 0
+    { 0x4 }, // 1
+    { 0x6 }, // 2
+    { 0x8 }, // 3
+    { 0xA }, // 4
+  };
+
+  constexpr EEntry EEntryOddTable[] = {
+    { 0x1 }, // 0
+    { 0x3 }, // 1
+    { 0x5 }, // 2
+    { 0x7 }, // 3
+    { 0x9 }, // 4
+  };
+
 Search Indexes
 ~~~~~~~~~~~~~~
 
diff --git a/llvm/test/TableGen/generic-tables.td b/llvm/test/TableGen/generic-tables.td
index dc9debf152cef90..f604f7777b3df9b 100644
--- a/llvm/test/TableGen/generic-tables.td
+++ b/llvm/test/TableGen/generic-tables.td
@@ -24,10 +24,11 @@ include "llvm/TableGen/SearchableTable.td"
 
 // CHECK-LABEL: GET_ATable_IMPL
 // CHECK: constexpr AEntry ATable[] = {
-// CHECK:   { "baz"
-// CHECK:   { "foo"
-// CHECK:   { "foobar"
-// CHECK:   { "bar"
+// CHECK-NOT:   { "aaa"
+// CHECK:       { "baz"
+// CHECK:       { "foo"
+// CHECK:       { "foobar"
+// CHECK:       { "bar"
 // CHECK: };
 
 // CHECK: const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
@@ -38,8 +39,10 @@ class AEntry<string str, int val1, int val2> {
   string Str = str;
   bits<8> Val1 = val1;
   bits<10> Val2 = val2;
+  bit IsNeeded = 1;
 }
 
+def : AEntry<"aaa", 0, 0> { let IsNeeded = 0; }
 def : AEntry<"bar",    5, 3>;
 def : AEntry<"baz",    2, 6>;
 def : AEntry<"foo",    4, 4>;
@@ -47,6 +50,7 @@ def : AEntry<"foobar", 4, 5>;
 
 def ATable : GenericTable {
   let FilterClass = "AEntry";
+  let FilterClassField = "IsNeeded";
   let Fields = ["Str", "Val1", "Val2"];
 
   let PrimaryKey = ["Val1", "Val2"];
@@ -171,3 +175,65 @@ def DTable : GenericTable {
 }
 
 #endif // ERROR1
+
+// CHECK-LABEL: GET_EEntryEvenTable_DECL
+// CHECK: const EEntry *lookupEEntryEvenTableByValue(uint8_t Value);
+
+// CHECK-LABEL: GET_EEntryEvenTable_IMPL
+// CHECK: constexpr EEntry EEntryEvenTable[] = {
+// CHECK:   { 0x2
+// CHECK:   { 0x4
+// CHECK:   { 0x6
+// CHECK:   { 0x8
+// CHECK:   { 0xA
+// CHECK: };
+
+// CHECK: const EEntry *lookupEEntryEvenTableByValue(uint8_t Value) {
+// CHECK:   return &*Idx;
+// CHECK: }
+
+// CHECK-LABEL: GET_EEntryOddTable_DECL
+// CHECK: const EEntry *lookupEEntryOddTableByValue(uint8_t Value);
+
+// CHECK-LABEL: GET_EEntryOddTable_IMPL
+// CHECK: constexpr EEntry EEntryOddTable[] = {
+// CHECK:   { 0x1
+// CHECK:   { 0x3
+// CHECK:   { 0x5
+// CHECK:   { 0x7
+// CHECK:   { 0x9
+// CHECK: };
+
+// CHECK: const EEntry *lookupEEntryOddTableByValue(uint8_t Value) {
+// CHECK:   return &*Idx;
+// CHECK: }
+
+// We can construct two GenericTables with the same FilterClass, so that they
+// select from the same overall set of records, but assign them with different
+// FilterClassField values so that they include different subsets of the records
+// of that class.
+class EEntry<bits<8> value> {
+  bits<8> Value = value;
+  bit IsEven = !eq(!and(value, 1), 0);
+  bit IsOdd = !not(IsEven);
+}
+
+foreach i = {1-10} in {
+  def : EEntry<i>;
+}
+
+def EEntryEvenTable : GenericTable {
+  let FilterClass = "EEntry";
+  let FilterClassField = "IsEven";
+  let Fields = ["Value"];
+  let PrimaryKey = ["Value"];
+  let PrimaryKeyName = "lookupEEntryEvenTableByValue";
+}
+
+def EEntryOddTable : GenericTable {
+  let FilterClass = "EEntry";
+  let FilterClassField = "IsOdd";
+  let Fields = ["Value"];
+  let PrimaryKey = ["Value"];
+  let PrimaryKeyName = "lookupEEntryOddTableByValue";
+}

>From eb7f47f6c81364a1379cba5eb97d2e18d3acbcc7 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Fri, 8 Sep 2023 15:04:57 +0800
Subject: [PATCH 3/3] fixup! [TableGen] Add a field to filter out GenericTable
 entries

Address comments
---
 llvm/docs/TableGen/BackEnds.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 67ad76dcbf4c43a..5cbb3232ef02387 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -776,7 +776,7 @@ is guarded by ``GET_ATable_DECL``, while the definitions are guarded by
     { "Ted", 0x4, 0x4 }, // 2
     { "Alice", 0x4, 0x5 }, // 3
     { "Bob", 0x5, 0x3 }, // 4
-    /* { "Dale", 0x2, 0x1 }, // 5 */ // No this line as `IsNeeded` is 0.
+    /* { "Dale", 0x2, 0x1 }, // 5 */ // We don't generate this line as `IsNeeded` is 0.
   };
 
   const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {



More information about the llvm-commits mailing list