[llvm] 2f78081 - [TableGen] Add a field to filter out GenericTable entries (#65458)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 8 01:27:15 PDT 2023
Author: Wang Pengcheng
Date: 2023-09-08T16:27:11+08:00
New Revision: 2f780812ed2e7e3d45b1254be61fcb321476a29d
URL: https://github.com/llvm/llvm-project/commit/2f780812ed2e7e3d45b1254be61fcb321476a29d
DIFF: https://github.com/llvm/llvm-project/commit/2f780812ed2e7e3d45b1254be61fcb321476a29d.diff
LOG: [TableGen] Add a field to filter out GenericTable entries (#65458)
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.
Added:
Modified:
llvm/docs/TableGen/BackEnds.rst
llvm/include/llvm/TableGen/SearchableTable.td
llvm/test/TableGen/generic-tables.td
llvm/utils/TableGen/SearchableTableEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 07dff5a30e2168b..5cbb3232ef02387 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -689,6 +689,11 @@ 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. 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
used.
@@ -734,22 +739,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 +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 */ // We don't generate this line as `IsNeeded` is 0.
};
const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
@@ -898,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
diff erent
+``FilterClassField`` values so that they include
diff erent 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/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/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
diff erent
+// FilterClassField values so that they include
diff erent 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";
+}
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 =
More information about the llvm-commits
mailing list