Skip to content

Commit 40fb941

Browse files
committed
[RISCV]Add support for resolving encoding conflicts among vendor specific CSRs
This patch adds the framework for resolving encoding conflicts among CSRs. Specifically, this patch adds a support for emitting a new lookup function for the primary key which return a pair of iterators pointing to first and last value hence giving a range of values which satisfies the query. While printing the CSR name during objdump, iterate over the range and print the name of only that CSR which satisifes the feature requirement of subtarget. Below is the signature of the new function that will be emitted for primary key: ``` llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding) { struct KeyType { uint16_t Encoding; }; KeyType Key = {Encoding}; struct Comp { bool operator()(const SysReg &LHS, const KeyType &RHS) const { if (LHS.Encoding < RHS.Encoding) return true; if (LHS.Encoding > RHS.Encoding) return false; return false; } bool operator()(const KeyType &LHS, const SysReg &RHS) const { if (LHS.Encoding < RHS.Encoding) return true; if (LHS.Encoding > RHS.Encoding) return false; return false; } }; auto Table = ArrayRef(SysRegsList); auto It = std::equal_range(Table.begin(), Table.end(), Key, Comp()); return llvm::make_range(It.first, It.second); } ``` NOTE: Emitting a different signature for returning a range of results is only supported by primary key.
1 parent e258bb3 commit 40fb941

File tree

4 files changed

+275
-41
lines changed

4 files changed

+275
-41
lines changed

llvm/docs/TableGen/BackEnds.rst

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@ This class provides six fields.
717717

718718
* ``bit PrimaryKeyEarlyOut``. See the third example below.
719719

720+
* ``bit PrimaryKeyReturnRange``. when set to 1, modifies the lookup function’s
721+
definition to return a range of results rather than a single pointer to the
722+
object. This feature proves useful when multiple objects meet the criteria
723+
specified by the lookup function. Currently, it is supported only for primary
724+
lookup functions. Refer to the fourth example below for further details.
725+
720726
TableGen attempts to deduce the type of each of the table fields so that it
721727
can format the C++ initializers in the emitted table. It can deduce ``bit``,
722728
``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``. These can be
@@ -972,6 +978,79 @@ The generated tables are:
972978
{ 0x9 }, // 4
973979
};
974980
981+
.. code-block:: text
982+
983+
class SysReg<string name, bits<12> op> {
984+
string Name = name;
985+
bits<12> Encoding = op;
986+
code FeaturesRequired = [{ {} }];
987+
}
988+
989+
def List1 : GenericTable {
990+
let FilterClass = "SysReg";
991+
let Fields = [
992+
"Name", "Encoding", "FeaturesRequired",
993+
];
994+
995+
let PrimaryKey = [ "Encoding" ];
996+
let PrimaryKeyName = "lookupSysRegByEncoding";
997+
let PrimaryKeyReturnRange = true;
998+
}
999+
1000+
let FeaturesRequired = [{ {Feature1} }] in {
1001+
def : SysReg<"csr1", 0x7C0>;
1002+
}
1003+
1004+
let FeaturesRequired = [{ {Feature2} }] in {
1005+
def : SysReg<"csr2", 0x7C0>;
1006+
}
1007+
1008+
The generated table is:
1009+
1010+
.. code-block:: text
1011+
1012+
constexpr SysReg List1[] = {
1013+
{ "csr1", 0x7C0, {Feature1} }, // 0
1014+
{ "csr2", 0x7C0, {Feature2} }, // 1
1015+
};
1016+
1017+
In the table above, both csr1 and csr2 share the same encoding. When
1018+
``PrimaryKeyReturnRange`` is set to false, the lookupSysRegByEncoding function
1019+
consistently returns the first CSR (in this case, csr1). However, this approach
1020+
may not always be suitable. To address this, if scenarios exist where multiple
1021+
objects match the criteria sought by the lookup function, we can
1022+
return a range of results by setting ``PrimaryKeyReturnRange`` to true.
1023+
Below, you’ll find the C++ code emitted for the above example when
1024+
``PrimaryKeyReturnRange`` is enabled.
1025+
1026+
.. code-block:: text
1027+
1028+
llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding) {
1029+
struct KeyType {
1030+
uint16_t Encoding;
1031+
};
1032+
KeyType Key = {Encoding};
1033+
struct Comp {
1034+
bool operator()(const SysReg &LHS, const KeyType &RHS) const {
1035+
if (LHS.Encoding < RHS.Encoding)
1036+
return true;
1037+
if (LHS.Encoding > RHS.Encoding)
1038+
return false;
1039+
return false;
1040+
}
1041+
bool operator()(const KeyType &LHS, const SysReg &RHS) const {
1042+
if (LHS.Encoding < RHS.Encoding)
1043+
return true;
1044+
if (LHS.Encoding > RHS.Encoding)
1045+
return false;
1046+
return false;
1047+
}
1048+
};
1049+
auto Table = ArrayRef(List1);
1050+
auto It = std::equal_range(Table.begin(), Table.end(), Key, Comp());
1051+
return llvm::make_range(It.first, It.second);
1052+
}
1053+
9751054
Search Indexes
9761055
~~~~~~~~~~~~~~
9771056

@@ -987,6 +1066,8 @@ function. This class provides three fields.
9871066

9881067
* ``bit EarlyOut``. See the third example in `Generic Tables`_.
9891068

1069+
* ``bit ReturnRange``. See the fourth example in `Generic Tables`_.
1070+
9901071
Here is an example of a secondary key added to the ``CTable`` above. The
9911072
generated function looks up entries based on the ``Name`` and ``Kind`` fields.
9921073

llvm/include/llvm/TableGen/SearchableTable.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ class GenericTable {
114114

115115
// See SearchIndex.EarlyOut
116116
bit PrimaryKeyEarlyOut = false;
117+
118+
// See SearchIndex.ReturnRange
119+
bit PrimaryKeyReturnRange = false;
117120
}
118121

119122
// Define a record derived from this class to generate an additional search
@@ -135,6 +138,12 @@ class SearchIndex {
135138
//
136139
// Can only be used when the first field is an integral (non-string) type.
137140
bit EarlyOut = false;
141+
142+
// If true, will generate a different function signature which will return an
143+
// iterator range of pointers giving the starting and end value of the range.
144+
// This feature is only supported for primary key only.
145+
// e.g. lookupSysRegByEncoding returns multiple CSRs for same encoding.
146+
bit ReturnRange = false;
138147
}
139148

140149
// Legacy table type with integrated enum.

llvm/test/TableGen/ReturnRange.td

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// RUN: llvm-tblgen -gen-searchable-tables -I %p/../../include %s | FileCheck %s
2+
// RUN: not llvm-tblgen -DERROR -gen-searchable-tables -I %p/../../include %s 2>&1 \
3+
// RUN: | FileCheck --check-prefix=ERROR %s
4+
5+
include "llvm/TableGen/SearchableTable.td"
6+
7+
class SysReg<string name, bits<12> op> {
8+
string Name = name;
9+
bits<12> Encoding = op;
10+
code FeaturesRequired = [{ {} }];
11+
}
12+
13+
def List1 : GenericTable {
14+
let FilterClass = "SysReg";
15+
let Fields = [
16+
"Name", "Encoding", "FeaturesRequired",
17+
];
18+
19+
let PrimaryKey = [ "Encoding" ];
20+
let PrimaryKeyName = "lookupSysRegByEncoding";
21+
let PrimaryKeyReturnRange = true;
22+
}
23+
24+
let FeaturesRequired = [{ {Feature1} }] in {
25+
def : SysReg<"csr1", 0x7C0>;
26+
}
27+
28+
let FeaturesRequired = [{ {Feature2} }] in {
29+
def : SysReg<"csr2", 0x7C0>;
30+
}
31+
32+
def lookupSysRegByName : SearchIndex {
33+
let Table = List1;
34+
let Key = [ "Name" ];
35+
#ifdef ERROR
36+
// ERROR: Emitting different signature for returning a range of results is only supported for Primary Key.
37+
let ReturnRange = true;
38+
#endif
39+
}
40+
41+
// CHECK: #ifdef GET_List1_DECL
42+
// CHECK-NEXT: llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding);
43+
// CHECK-NEXT: onst SysReg *lookupSysRegByName(StringRef Name);
44+
// CHECK-NEXT: #endif
45+
46+
// CHECK: #ifdef GET_List1_IMPL
47+
// CHECK-NEXT: constexpr SysReg List1[] = {
48+
// CHECK-NEXT: { "csr1", 0x7C0, {Feature1} }, // 0
49+
// CHECK-NEXT: { "csr2", 0x7C0, {Feature2} }, // 1
50+
// CHECK-NEXT: };
51+
52+
// CHECK: llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding) {
53+
// CHECK-NEXT: struct KeyType {
54+
// CHECK-NEXT: uint16_t Encoding;
55+
// CHECK-NEXT: };
56+
// CHECK-NEXT: KeyType Key = {Encoding};
57+
// CHECK-NEXT: struct Comp {
58+
// CHECK-NEXT: bool operator()(const SysReg &LHS, const KeyType &RHS) const {
59+
// CHECK-NEXT: if (LHS.Encoding < RHS.Encoding)
60+
// CHECK-NEXT: return true;
61+
// CHECK-NEXT: if (LHS.Encoding > RHS.Encoding)
62+
// CHECK-NEXT: return false;
63+
// CHECK-NEXT: return false;
64+
// CHECK-NEXT: }
65+
// CHECK-NEXT: bool operator()(const KeyType &LHS, const SysReg &RHS) const {
66+
// CHECK-NEXT: if (LHS.Encoding < RHS.Encoding)
67+
// CHECK-NEXT: return true;
68+
// CHECK-NEXT: if (LHS.Encoding > RHS.Encoding)
69+
// CHECK-NEXT: return false;
70+
// CHECK-NEXT: return false;
71+
// CHECK-NEXT: }
72+
// CHECK-NEXT: };
73+
// CHECK-NEXT: auto Table = ArrayRef(List1);
74+
// CHECK-NEXT: auto It = std::equal_range(Table.begin(), Table.end(), Key, Comp());
75+
// CHECK-NEXT: return llvm::make_range(It.first, It.second);
76+
// CHECK-NEXT: }
77+
78+
// CHECK: const SysReg *lookupSysRegByName(StringRef Name) {
79+
// CHECK-NEXT: struct IndexType {
80+
// CHECK-NEXT: const char * Name;
81+
// CHECK-NEXT: unsigned _index;
82+
// CHECK-NEXT: };
83+
// CHECK-NEXT: static const struct IndexType Index[] = {
84+
// CHECK-NEXT: { "CSR1", 0 },
85+
// CHECK-NEXT: { "CSR2", 1 },
86+
// CHECK-NEXT: };
87+
88+
// CHECK: struct KeyType {
89+
// CHECK-NEXT: std::string Name;
90+
// CHECK-NEXT: };
91+
// CHECK-NEXT: KeyType Key = {Name.upper()};
92+
// CHECK-NEXT: struct Comp {
93+
// CHECK-NEXT: bool operator()(const IndexType &LHS, const KeyType &RHS) const {
94+
// CHECK-NEXT: int CmpName = StringRef(LHS.Name).compare(RHS.Name);
95+
// CHECK-NEXT: if (CmpName < 0) return true;
96+
// CHECK-NEXT: if (CmpName > 0) return false;
97+
// CHECK-NEXT: return false;
98+
// CHECK-NEXT: }
99+
// CHECK-NEXT: };
100+
// CHECK-NEXT: auto Table = ArrayRef(Index);
101+
// CHECK-NEXT: auto Idx = std::lower_bound(Table.begin(), Table.end(), Key, Comp());
102+
// CHECK-NEXT: if (Idx == Table.end() ||
103+
// CHECK-NEXT: Key.Name != Idx->Name)
104+
// CHECK-NEXT: return nullptr;
105+
106+
// CHECK: return &List1[Idx->_index];
107+
// CHECK-NEXT: }
108+
// CHECK-NEXT: #endif

0 commit comments

Comments
 (0)