Skip to content

Commit 26421c4

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) { 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 26421c4

File tree

3 files changed

+179
-29
lines changed

3 files changed

+179
-29
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 a
143+
// iterator range of pointers giving the starting 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.
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+
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+
let FeaturesRequired = [{ {Feature1} }] in {
23+
def : SysReg<"csr1", 0x7C0>;
24+
}
25+
26+
let FeaturesRequired = [{ {Feature2} }] in {
27+
def : SysReg<"csr2", 0x7C0>;
28+
}
29+
30+
// CHECK: #ifdef GET_List1_DECL
31+
// CHECK-NEXT: llvm::iterator_range<const SysReg *>lookupSysRegByEncoding(uint16_t Encoding);
32+
// CHECK-NEXT: #endif
33+
34+
// CHECK: #ifdef GET_List1_IMPL
35+
// CHECK-NEXT: constexpr SysReg List1[] = {
36+
// CHECK-NEXT: { "csr1", 0x7C0, {Feature1} }, // 0
37+
// CHECK-NEXT: { "csr2", 0x7C0, {Feature2} }, // 1
38+
// CHECK-NEXT: };
39+
40+
// CHECK: llvm::iterator_range<const SysReg *>lookupSysRegByEncoding(uint16_t Encoding) {
41+
// CHECK-NEXT: SysReg Key;
42+
// CHECK-NEXT: Key.Encoding = Encoding;
43+
// CHECK-NEXT: auto Table = ArrayRef(List1);
44+
// CHECK-NEXT: auto It = std::equal_range(Table.begin(), Table.end(), Key,
45+
// CHECK-NEXT: [](const SysReg &LHS, const SysReg &RHS) {
46+
// CHECK-NEXT: if (LHS.Encoding < RHS.Encoding)
47+
// CHECK-NEXT: return true;
48+
// CHECK-NEXT: if (LHS.Encoding > RHS.Encoding)
49+
// CHECK-NEXT: return false;
50+
// CHECK-NEXT: return false;
51+
// CHECK-NEXT: });
52+
53+
// CHECK: return llvm::make_range(It.first, It.second);
54+
// CHECK-NEXT: }
55+
// CHECK-NEXT: #endif
56+
57+
def List2 : GenericTable {
58+
let FilterClass = "SysReg";
59+
let Fields = [
60+
"Name", "Encoding", "FeaturesRequired",
61+
];
62+
}
63+
64+
def lookupSysRegByName : SearchIndex {
65+
let Table = List2;
66+
let Key = [ "Name" ];
67+
let ReturnRange = true;
68+
}
69+
70+
// CHECK: #ifdef GET_List2_DECL
71+
// CHECK-NEXT: llvm::iterator_range<const SysReg *>lookupSysRegByName(StringRef Name);
72+
// CHECK-NEXT: #endif
73+
74+
// CHECK: #ifdef GET_List2_IMPL
75+
// CHECK-NEXT: constexpr SysReg List2[] = {
76+
// CHECK-NEXT: { "csr1", 0x7C0, {Feature1} }, // 0
77+
// CHECK-NEXT: { "csr2", 0x7C0, {Feature2} }, // 1
78+
// CHECK-NEXT: };
79+
80+
// CHECK: llvm::iterator_range<const SysReg *>lookupSysRegByName(StringRef Name) {
81+
// CHECK-NEXT: struct IndexType {
82+
// CHECK-NEXT: const char * Name;
83+
// CHECK-NEXT: unsigned _index;
84+
// CHECK-NEXT: };
85+
// CHECK-NEXT: static const struct IndexType Index[] = {
86+
// CHECK-NEXT: { "CSR1", 0 },
87+
// CHECK-NEXT: { "CSR2", 1 },
88+
// CHECK-NEXT: };
89+
90+
// CHECK: IndexType Key;
91+
// CHECK-NEXT: Key.Name = Name.upper();
92+
// CHECK-NEXT: auto Table = ArrayRef(Index);
93+
// CHECK-NEXT: auto It = std::equal_range(Table.begin(), Table.end(), Key,
94+
// CHECK-NEXT: [](const IndexType &LHS, const IndexType &RHS) {
95+
// CHECK-NEXT: int CmpName = StringRef(LHS.Name).compare(RHS.Name);
96+
// CHECK-NEXT: if (CmpName < 0) return true;
97+
// CHECK-NEXT: if (CmpName > 0) return false;
98+
// CHECK-NEXT: return false;
99+
// CHECK-NEXT: });
100+
101+
// CHECK: return llvm::make_range(It.first, It.second);
102+
// CHECK-NEXT: }
103+
// CHECK-NEXT: #endif
104+
105+
// CHECK: #undef GET_List1_DECL
106+
// CHECK-NEXT: #undef GET_List1_IMPL
107+
// CHECK-NEXT: #undef GET_List2_DECL
108+
// CHECK-NEXT: #undef GET_List2_IMPL

llvm/utils/TableGen/SearchableTableEmitter.cpp

Lines changed: 63 additions & 29 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 {
@@ -198,7 +199,8 @@ class SearchableTableEmitter {
198199
bool parseFieldType(GenericField &Field, Init *II);
199200
std::unique_ptr<SearchIndex>
200201
parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
201-
const std::vector<StringRef> &Key, bool EarlyOut);
202+
const std::vector<StringRef> &Key, bool EarlyOut,
203+
bool ReturnRange);
202204
void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
203205
StringRef ValueField,
204206
const std::vector<Record *> &Items);
@@ -426,16 +428,25 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
426428
OS << " return nullptr;\n\n";
427429
}
428430

429-
OS << " struct KeyType {\n";
430-
for (const auto &Field : Index.Fields) {
431-
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
432-
<< " " << Field.Name << ";\n";
431+
bool ShouldReturnRange = Index.ReturnRange;
432+
if (ShouldReturnRange)
433+
OS << " " << IndexTypeName << " Key;\n";
434+
else {
435+
OS << " struct KeyType {\n";
436+
for (const auto &Field : Index.Fields) {
437+
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
438+
<< " " << Field.Name << ";\n";
439+
}
440+
OS << " };\n";
441+
OS << " KeyType Key = {";
433442
}
434-
OS << " };\n";
435-
OS << " KeyType Key = {";
443+
436444
ListSeparator LS;
437445
for (const auto &Field : Index.Fields) {
438-
OS << LS << Field.Name;
446+
if (ShouldReturnRange)
447+
OS << " Key." << Field.Name << " = " << Field.Name;
448+
else
449+
OS << LS << Field.Name;
439450
if (isa<StringRecTy>(Field.RecType)) {
440451
OS << ".upper()";
441452
if (IsPrimary)
@@ -445,12 +456,21 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
445456
"case-insensitive comparison of field '" +
446457
Field.Name + "'");
447458
}
459+
if (ShouldReturnRange)
460+
OS << ";\n";
448461
}
449-
OS << "};\n";
462+
if (!ShouldReturnRange)
463+
OS << "};\n";
450464

451465
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";
466+
if (ShouldReturnRange) {
467+
OS << " auto It = std::equal_range(Table.begin(), Table.end(), Key,\n";
468+
OS << " [](const " << IndexTypeName << " &LHS, const " << IndexTypeName
469+
<< " &RHS) {\n";
470+
} else {
471+
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
472+
OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
473+
}
454474

455475
for (const auto &Field : Index.Fields) {
456476
if (isa<StringRecTy>(Field.RecType)) {
@@ -478,25 +498,33 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
478498
OS << " return false;\n";
479499
OS << " });\n\n";
480500

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";
501+
if (!ShouldReturnRange) {
502+
OS << " if (Idx == Table.end()";
503+
for (const auto &Field : Index.Fields)
504+
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
505+
}
486506

487-
if (IsPrimary)
507+
if (ShouldReturnRange)
508+
OS << " return llvm::make_range(It.first, It.second);\n";
509+
else if (IsPrimary) {
510+
OS << ")\n return nullptr;\n\n";
488511
OS << " return &*Idx;\n";
489-
else
512+
} else {
513+
OS << ")\n return nullptr;\n\n";
490514
OS << " return &" << Table.Name << "[Idx->_index];\n";
515+
}
491516

492517
OS << "}\n";
493518
}
494519

495520
void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
496521
const SearchIndex &Index,
497522
raw_ostream &OS) {
498-
OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
499-
523+
if (Index.ReturnRange)
524+
OS << "llvm::iterator_range<const " << Table.CppTypeName << " *> ";
525+
else
526+
OS << "const " << Table.CppTypeName << " *";
527+
OS << Index.Name << "(";
500528
ListSeparator LS;
501529
for (const auto &Field : Index.Fields)
502530
OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
@@ -510,11 +538,12 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
510538

511539
// Emit the declarations for the functions that will perform lookup.
512540
if (Table.PrimaryKey) {
513-
emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
541+
auto &Index = Table.PrimaryKey;
542+
emitLookupDeclaration(Table, *Index, OS);
514543
OS << ";\n";
515544
}
516545
for (const auto &Index : Table.Indices) {
517-
emitLookupDeclaration(Table, *Index, OS);
546+
emitLookupDeclaration(Table, *Index, OS);
518547
OS << ";\n";
519548
}
520549

@@ -540,10 +569,12 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
540569

541570
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
542571
// search can be performed by "Thing".
543-
if (Table.PrimaryKey)
544-
emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
572+
if (Table.PrimaryKey) {
573+
auto &Index = Table.PrimaryKey;
574+
emitLookupFunction(Table, *Index, /*IsPrimary=*/true, OS);
575+
}
545576
for (const auto &Index : Table.Indices)
546-
emitLookupFunction(Table, *Index, false, OS);
577+
emitLookupFunction(Table, *Index, /*IsPrimary=*/false, OS);
547578

548579
OS << "#endif\n\n";
549580
}
@@ -569,11 +600,12 @@ bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
569600

570601
std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
571602
GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
572-
const std::vector<StringRef> &Key, bool EarlyOut) {
603+
const std::vector<StringRef> &Key, bool EarlyOut, bool ReturnRange) {
573604
auto Index = std::make_unique<SearchIndex>();
574605
Index->Name = std::string(Name);
575606
Index->Loc = KeyRecVal->getLoc();
576607
Index->EarlyOut = EarlyOut;
608+
Index->ReturnRange = ReturnRange;
577609

578610
for (const auto &FieldName : Key) {
579611
const GenericField *Field = Table.getFieldByName(FieldName);
@@ -769,7 +801,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
769801
parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
770802
TableRec->getValueAsString("PrimaryKeyName"),
771803
TableRec->getValueAsListOfStrings("PrimaryKey"),
772-
TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
804+
TableRec->getValueAsBit("PrimaryKeyEarlyOut"),
805+
TableRec->getValueAsBit("PrimaryKeyReturnRange"));
773806

774807
llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
775808
return compareBy(LHS, RHS, *Table->PrimaryKey);
@@ -793,7 +826,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
793826
Table.Indices.push_back(
794827
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
795828
IndexRec->getValueAsListOfStrings("Key"),
796-
IndexRec->getValueAsBit("EarlyOut")));
829+
IndexRec->getValueAsBit("EarlyOut"),
830+
IndexRec->getValueAsBit("ReturnRange")));
797831
}
798832

799833
// Translate legacy tables.
@@ -848,7 +882,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
848882
std::string Name =
849883
(Twine("lookup") + Table->CppTypeName + "By" + Field).str();
850884
Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
851-
Name, {Field}, false));
885+
Name, {Field}, false, false));
852886
}
853887

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

0 commit comments

Comments
 (0)