Skip to content

Commit f19b276

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 f19b276

File tree

3 files changed

+194
-41
lines changed

3 files changed

+194
-41
lines changed

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

llvm/utils/TableGen/SearchableTableEmitter.cpp

Lines changed: 77 additions & 41 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);
@@ -320,6 +322,12 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
320322
const SearchIndex &Index,
321323
bool IsPrimary,
322324
raw_ostream &OS) {
325+
bool ShouldReturnRange = Index.ReturnRange;
326+
if (ShouldReturnRange && !IsPrimary)
327+
PrintFatalError(Index.Loc,
328+
"Emitting different signature for returning a range of "
329+
"results is only supported for Primary Key.");
330+
323331
OS << "\n";
324332
emitLookupDeclaration(Table, Index, OS);
325333
OS << " {\n";
@@ -448,55 +456,80 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
448456
}
449457
OS << "};\n";
450458

451-
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";
459+
OS << " struct Comp {\n";
460+
OS << " bool operator()(const " << IndexTypeName
461+
<< " &LHS, const KeyType &RHS) const {\n";
454462

455-
for (const auto &Field : Index.Fields) {
456-
if (isa<StringRecTy>(Field.RecType)) {
457-
OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
458-
<< ").compare(RHS." << Field.Name << ");\n";
459-
OS << " if (Cmp" << Field.Name << " < 0) return true;\n";
460-
OS << " if (Cmp" << Field.Name << " > 0) return false;\n";
461-
} else if (Field.Enum) {
462-
// Explicitly cast to unsigned, because the signedness of enums is
463-
// compiler-dependent.
464-
OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
465-
<< Field.Name << ")\n";
466-
OS << " return true;\n";
467-
OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
468-
<< Field.Name << ")\n";
469-
OS << " return false;\n";
470-
} else {
471-
OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
472-
OS << " return true;\n";
473-
OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
474-
OS << " return false;\n";
463+
auto emitComparator = [&]() {
464+
for (const auto &Field : Index.Fields) {
465+
if (isa<StringRecTy>(Field.RecType)) {
466+
OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
467+
<< ").compare(RHS." << Field.Name << ");\n";
468+
OS << " if (Cmp" << Field.Name << " < 0) return true;\n";
469+
OS << " if (Cmp" << Field.Name << " > 0) return false;\n";
470+
} else if (Field.Enum) {
471+
// Explicitly cast to unsigned, because the signedness of enums is
472+
// compiler-dependent.
473+
OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
474+
<< Field.Name << ")\n";
475+
OS << " return true;\n";
476+
OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
477+
<< Field.Name << ")\n";
478+
OS << " return false;\n";
479+
} else {
480+
OS << " if (LHS." << Field.Name << " < RHS." << Field.Name
481+
<< ")\n";
482+
OS << " return true;\n";
483+
OS << " if (LHS." << Field.Name << " > RHS." << Field.Name
484+
<< ")\n";
485+
OS << " return false;\n";
486+
}
475487
}
488+
OS << " return false;\n";
489+
OS << " }\n";
490+
};
491+
emitComparator();
492+
if (ShouldReturnRange) {
493+
OS << " bool operator()(const KeyType &LHS, const " << IndexTypeName
494+
<< " &RHS) const {\n";
495+
emitComparator();
476496
}
477497

478-
OS << " return false;\n";
479-
OS << " });\n\n";
480-
481-
OS << " if (Idx == Table.end()";
498+
OS << " };\n";
499+
OS << " auto Table = ArrayRef(" << IndexName << ");\n";
500+
if (ShouldReturnRange)
501+
OS << " auto It = std::equal_range(Table.begin(), Table.end(), Key, ";
502+
else
503+
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key, ";
504+
OS << "Comp());\n";
482505

483-
for (const auto &Field : Index.Fields)
484-
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
485-
OS << ")\n return nullptr;\n";
506+
if (!ShouldReturnRange) {
507+
OS << " if (Idx == Table.end()";
508+
for (const auto &Field : Index.Fields)
509+
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
510+
}
486511

487-
if (IsPrimary)
512+
if (ShouldReturnRange)
513+
OS << " return llvm::make_range(It.first, It.second);\n";
514+
else if (IsPrimary) {
515+
OS << ")\n return nullptr;\n\n";
488516
OS << " return &*Idx;\n";
489-
else
517+
} else {
518+
OS << ")\n return nullptr;\n\n";
490519
OS << " return &" << Table.Name << "[Idx->_index];\n";
520+
}
491521

492522
OS << "}\n";
493523
}
494524

495525
void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
496526
const SearchIndex &Index,
497527
raw_ostream &OS) {
498-
OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
499-
528+
if (Index.ReturnRange)
529+
OS << "llvm::iterator_range<const " << Table.CppTypeName << " *> ";
530+
else
531+
OS << "const " << Table.CppTypeName << " *";
532+
OS << Index.Name << "(";
500533
ListSeparator LS;
501534
for (const auto &Field : Index.Fields)
502535
OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
@@ -541,9 +574,9 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
541574
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
542575
// search can be performed by "Thing".
543576
if (Table.PrimaryKey)
544-
emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
577+
emitLookupFunction(Table, *Table.PrimaryKey, /*IsPrimary=*/true, OS);
545578
for (const auto &Index : Table.Indices)
546-
emitLookupFunction(Table, *Index, false, OS);
579+
emitLookupFunction(Table, *Index, /*IsPrimary=*/false, OS);
547580

548581
OS << "#endif\n\n";
549582
}
@@ -569,11 +602,12 @@ bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
569602

570603
std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
571604
GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
572-
const std::vector<StringRef> &Key, bool EarlyOut) {
605+
const std::vector<StringRef> &Key, bool EarlyOut, bool ReturnRange) {
573606
auto Index = std::make_unique<SearchIndex>();
574607
Index->Name = std::string(Name);
575608
Index->Loc = KeyRecVal->getLoc();
576609
Index->EarlyOut = EarlyOut;
610+
Index->ReturnRange = ReturnRange;
577611

578612
for (const auto &FieldName : Key) {
579613
const GenericField *Field = Table.getFieldByName(FieldName);
@@ -769,7 +803,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
769803
parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
770804
TableRec->getValueAsString("PrimaryKeyName"),
771805
TableRec->getValueAsListOfStrings("PrimaryKey"),
772-
TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
806+
TableRec->getValueAsBit("PrimaryKeyEarlyOut"),
807+
TableRec->getValueAsBit("PrimaryKeyReturnRange"));
773808

774809
llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
775810
return compareBy(LHS, RHS, *Table->PrimaryKey);
@@ -793,7 +828,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
793828
Table.Indices.push_back(
794829
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
795830
IndexRec->getValueAsListOfStrings("Key"),
796-
IndexRec->getValueAsBit("EarlyOut")));
831+
IndexRec->getValueAsBit("EarlyOut"),
832+
IndexRec->getValueAsBit("ReturnRange")));
797833
}
798834

799835
// Translate legacy tables.
@@ -848,7 +884,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
848884
std::string Name =
849885
(Twine("lookup") + Table->CppTypeName + "By" + Field).str();
850886
Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
851-
Name, {Field}, false));
887+
Name, {Field}, false, false));
852888
}
853889

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

0 commit comments

Comments
 (0)