Skip to content

Commit df50bbb

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: ``` std::pair<const SysReg *, const SysReg *>lookupSysRegByEncoding(uint16_t Encoding) { SysReg Key; Key.Encoding = Encoding; auto Table = ArrayRef(SysRegsList); auto It = std::equal_range(Table.begin(), Table.end(), Key, [](const SysReg &LHS, const SysReg &RHS) { if (LHS.Encoding < RHS.Encoding) return true; if (LHS.Encoding > RHS.Encoding) return false; return false; }); return llvm::make_range(It.first, It.second); ```
1 parent e258bb3 commit df50bbb

File tree

4 files changed

+189
-32
lines changed

4 files changed

+189
-32
lines changed

llvm/include/llvm/TableGen/SearchableTable.td

Lines changed: 8 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,11 @@ 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
143+
// a std::pair<> of iterators pointing to start and end value of the range
144+
// e.g. lookupSysRegByEncoding returns multiple CSRs for same encoding.
145+
bit ReturnRange = false;
138146
}
139147

140148
// Legacy table type with integrated enum.

llvm/lib/Target/RISCV/RISCVSystemOperands.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def SysRegsList : GenericTable {
4949

5050
let PrimaryKey = [ "Encoding" ];
5151
let PrimaryKeyName = "lookupSysRegByEncoding";
52+
let PrimaryKeyReturnRange = false;
5253
}
5354

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

llvm/utils/TableGen/SearchableTableEmitter.cpp

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ struct SearchIndex {
6868
SMLoc Loc; // Source location of PrimaryKey or Key field definition.
6969
SmallVector<GenericField, 1> Fields;
7070
bool EarlyOut = false;
71+
bool ReturnRange = false;
7172
};
7273

7374
struct GenericTable {
@@ -190,15 +191,18 @@ class SearchableTableEmitter {
190191
void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
191192
void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
192193
void emitLookupDeclaration(const GenericTable &Table,
193-
const SearchIndex &Index, raw_ostream &OS);
194+
const SearchIndex &Index, bool ShouldReturnRange,
195+
raw_ostream &OS);
194196
void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
195-
bool IsPrimary, raw_ostream &OS);
197+
bool IsPrimary, bool ShouldReturnRange,
198+
raw_ostream &OS);
196199
void emitIfdef(StringRef Guard, raw_ostream &OS);
197200

198201
bool parseFieldType(GenericField &Field, Init *II);
199202
std::unique_ptr<SearchIndex>
200203
parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
201-
const std::vector<StringRef> &Key, bool EarlyOut);
204+
const std::vector<StringRef> &Key, bool EarlyOut,
205+
bool ReturnRange);
202206
void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
203207
StringRef ValueField,
204208
const std::vector<Record *> &Items);
@@ -319,9 +323,10 @@ void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
319323
void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
320324
const SearchIndex &Index,
321325
bool IsPrimary,
326+
bool ShouldReturnRange,
322327
raw_ostream &OS) {
323328
OS << "\n";
324-
emitLookupDeclaration(Table, Index, OS);
329+
emitLookupDeclaration(Table, Index, ShouldReturnRange, OS);
325330
OS << " {\n";
326331

327332
std::vector<Record *> IndexRowsStorage;
@@ -426,16 +431,24 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
426431
OS << " return nullptr;\n\n";
427432
}
428433

429-
OS << " struct KeyType {\n";
430-
for (const auto &Field : Index.Fields) {
431-
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
432-
<< " " << Field.Name << ";\n";
434+
if (ShouldReturnRange)
435+
OS << " " << IndexTypeName << " Key;\n";
436+
else {
437+
OS << " struct KeyType {\n";
438+
for (const auto &Field : Index.Fields) {
439+
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
440+
<< " " << Field.Name << ";\n";
441+
}
442+
OS << " };\n";
443+
OS << " KeyType Key = {";
433444
}
434-
OS << " };\n";
435-
OS << " KeyType Key = {";
445+
436446
ListSeparator LS;
437447
for (const auto &Field : Index.Fields) {
438-
OS << LS << Field.Name;
448+
if (ShouldReturnRange)
449+
OS << " Key." << Field.Name << " = " << Field.Name;
450+
else
451+
OS << LS << Field.Name;
439452
if (isa<StringRecTy>(Field.RecType)) {
440453
OS << ".upper()";
441454
if (IsPrimary)
@@ -445,12 +458,21 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
445458
"case-insensitive comparison of field '" +
446459
Field.Name + "'");
447460
}
461+
if (ShouldReturnRange)
462+
OS << ";\n";
448463
}
449-
OS << "};\n";
464+
if (!ShouldReturnRange)
465+
OS << "};\n";
450466

451467
OS << " auto Table = ArrayRef(" << IndexName << ");\n";
452-
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
453-
OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
468+
if (ShouldReturnRange) {
469+
OS << " auto It = std::equal_range(Table.begin(), Table.end(), Key,\n";
470+
OS << " [](const " << IndexTypeName << " &LHS, const " << IndexTypeName
471+
<< " &RHS) {\n";
472+
} else {
473+
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
474+
OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
475+
}
454476

455477
for (const auto &Field : Index.Fields) {
456478
if (isa<StringRecTy>(Field.RecType)) {
@@ -478,25 +500,34 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
478500
OS << " return false;\n";
479501
OS << " });\n\n";
480502

481-
OS << " if (Idx == Table.end()";
482-
483-
for (const auto &Field : Index.Fields)
484-
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
485-
OS << ")\n return nullptr;\n";
503+
if (!ShouldReturnRange) {
504+
OS << " if (Idx == Table.end()";
505+
for (const auto &Field : Index.Fields)
506+
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
507+
}
486508

487-
if (IsPrimary)
509+
if (ShouldReturnRange)
510+
OS << " return llvm::make_range(It.first, It.second);\n";
511+
else if (IsPrimary) {
512+
OS << ")\n return nullptr;\n\n";
488513
OS << " return &*Idx;\n";
489-
else
514+
} else {
515+
OS << ")\n return nullptr;\n\n";
490516
OS << " return &" << Table.Name << "[Idx->_index];\n";
517+
}
491518

492519
OS << "}\n";
493520
}
494521

495522
void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
496523
const SearchIndex &Index,
524+
bool ShouldReturnRange,
497525
raw_ostream &OS) {
498-
OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
499-
526+
if (ShouldReturnRange)
527+
OS << "llvm::iterator_range<const " << Table.CppTypeName << " *>";
528+
else
529+
OS << "const " << Table.CppTypeName << " *";
530+
OS << Index.Name << "(";
500531
ListSeparator LS;
501532
for (const auto &Field : Index.Fields)
502533
OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
@@ -510,11 +541,12 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
510541

511542
// Emit the declarations for the functions that will perform lookup.
512543
if (Table.PrimaryKey) {
513-
emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
544+
auto &Index = Table.PrimaryKey;
545+
emitLookupDeclaration(Table, *Index, Index->ReturnRange, OS);
514546
OS << ";\n";
515547
}
516548
for (const auto &Index : Table.Indices) {
517-
emitLookupDeclaration(Table, *Index, OS);
549+
emitLookupDeclaration(Table, *Index, Index->ReturnRange, OS);
518550
OS << ";\n";
519551
}
520552

@@ -540,10 +572,14 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
540572

541573
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
542574
// search can be performed by "Thing".
543-
if (Table.PrimaryKey)
544-
emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
575+
if (Table.PrimaryKey) {
576+
auto &Index = Table.PrimaryKey;
577+
emitLookupFunction(Table, *Index, /*IsPrimary=*/true, Index->ReturnRange,
578+
OS);
579+
}
545580
for (const auto &Index : Table.Indices)
546-
emitLookupFunction(Table, *Index, false, OS);
581+
emitLookupFunction(Table, *Index, /*IsPrimary=*/false, Index->ReturnRange,
582+
OS);
547583

548584
OS << "#endif\n\n";
549585
}
@@ -569,11 +605,12 @@ bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
569605

570606
std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
571607
GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
572-
const std::vector<StringRef> &Key, bool EarlyOut) {
608+
const std::vector<StringRef> &Key, bool EarlyOut, bool ReturnRange) {
573609
auto Index = std::make_unique<SearchIndex>();
574610
Index->Name = std::string(Name);
575611
Index->Loc = KeyRecVal->getLoc();
576612
Index->EarlyOut = EarlyOut;
613+
Index->ReturnRange = ReturnRange;
577614

578615
for (const auto &FieldName : Key) {
579616
const GenericField *Field = Table.getFieldByName(FieldName);
@@ -769,7 +806,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
769806
parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
770807
TableRec->getValueAsString("PrimaryKeyName"),
771808
TableRec->getValueAsListOfStrings("PrimaryKey"),
772-
TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
809+
TableRec->getValueAsBit("PrimaryKeyEarlyOut"),
810+
TableRec->getValueAsBit("PrimaryKeyReturnRange"));
773811

774812
llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
775813
return compareBy(LHS, RHS, *Table->PrimaryKey);
@@ -793,7 +831,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
793831
Table.Indices.push_back(
794832
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
795833
IndexRec->getValueAsListOfStrings("Key"),
796-
IndexRec->getValueAsBit("EarlyOut")));
834+
IndexRec->getValueAsBit("EarlyOut"),
835+
IndexRec->getValueAsBit("ReturnRange")));
797836
}
798837

799838
// Translate legacy tables.
@@ -848,7 +887,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
848887
std::string Name =
849888
(Twine("lookup") + Table->CppTypeName + "By" + Field).str();
850889
Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
851-
Name, {Field}, false));
890+
Name, {Field}, false, false));
852891
}
853892

854893
Tables.emplace_back(std::move(Table));

0 commit comments

Comments
 (0)