Skip to content

Commit d6c0956

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 d6c0956

File tree

3 files changed

+211
-36
lines changed

3 files changed

+211
-36
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 an
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.

llvm/test/TableGen/ReturnRange.td

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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 List : 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+
def lookupSysRegByName : SearchIndex {
23+
let Table = List;
24+
let Key = [ "Name" ];
25+
let ReturnRange = true;
26+
}
27+
28+
let FeaturesRequired = [{ {Feature1} }] in {
29+
def : SysReg<"csr1", 0x7C0>;
30+
}
31+
32+
let FeaturesRequired = [{ {Feature2} }] in {
33+
def : SysReg<"csr2", 0x7C0>;
34+
}
35+
36+
let FeaturesRequired = [{ {Feature1} }] in {
37+
def : SysReg<"aabbc", 0x7C1>;
38+
}
39+
40+
let FeaturesRequired = [{ {Feature2} }] in {
41+
def : SysReg<"aaabb", 0x7C2>;
42+
}
43+
44+
// CHECK: #ifdef GET_List_DECL
45+
// CHECK-NEXT: llvm::iterator_range<const SysReg *>
46+
// CHECK-NEXT: lookupSysRegByEncoding(uint16_t Encoding);
47+
// CHECK-NEXT: llvm::iterator_range<const SysReg *>
48+
// CHECK-NEXT: lookupSysRegByName(StringRef Name);
49+
// CHECK-NEXT: #endif
50+
51+
// CHECK: #ifdef GET_List_IMPL
52+
// CHECK-NEXT: constexpr SysReg List[] = {
53+
// CHECK-NEXT: { "csr1", 0x7C0, {Feature1} }, // 0
54+
// CHECK-NEXT: { "csr2", 0x7C0, {Feature2} }, // 1
55+
// CHECK-NEXT: { "aabbc", 0x7C1, {Feature1} }, // 2
56+
// CHECK-NEXT: { "aaabb", 0x7C2, {Feature2} }, // 3
57+
// CHECK-NEXT: };
58+
// CHECK-NEXT: constexpr SysReg ListforlookupSysRegByName[] = {
59+
// CHECK-NEXT: { "aaabb", 0x7C2, {Feature2} },
60+
// CHECK-NEXT: { "aabbc", 0x7C1, {Feature1} },
61+
// CHECK-NEXT: { "csr1", 0x7C0, {Feature1} },
62+
// CHECK-NEXT: { "csr2", 0x7C0, {Feature2} },
63+
// CHECK-NEXT: };
64+
65+
// CHECK: llvm::iterator_range<const SysReg *>
66+
// CHECK-NEXT: lookupSysRegByEncoding(uint16_t Encoding) {
67+
// CHECK-NEXT: SysReg Key;
68+
// CHECK-NEXT: Key.Encoding = Encoding;
69+
// CHECK-NEXT: auto Table = ArrayRef(List);
70+
// CHECK-NEXT: auto It = std::equal_range(Table.begin(), Table.end(), Key,
71+
// CHECK-NEXT: [](const SysReg &LHS, const SysReg &RHS) {
72+
// CHECK-NEXT: if (LHS.Encoding < RHS.Encoding)
73+
// CHECK-NEXT: return true;
74+
// CHECK-NEXT: if (LHS.Encoding > RHS.Encoding)
75+
// CHECK-NEXT: return false;
76+
// CHECK-NEXT: return false;
77+
// CHECK-NEXT: });
78+
79+
// CHECK: return llvm::make_range(It.first, It.second);
80+
// CHECK-NEXT: }
81+
82+
// CHECK: llvm::iterator_range<const SysReg *>
83+
// CHECK-NEXT: lookupSysRegByName(StringRef Name) {
84+
// CHECK-NEXT: SysReg Key;
85+
// CHECK-NEXT: Key.Name = Name.data();
86+
// CHECK-NEXT: auto Table = ArrayRef(ListforlookupSysRegByName);
87+
// CHECK-NEXT: auto It = std::equal_range(Table.begin(), Table.end(), Key,
88+
// CHECK-NEXT: [](const SysReg &LHS, const SysReg &RHS) {
89+
// CHECK-NEXT: int CmpName = StringRef(LHS.Name).compare(RHS.Name);
90+
// CHECK-NEXT: if (CmpName < 0) return true;
91+
// CHECK-NEXT: if (CmpName > 0) return false;
92+
// CHECK-NEXT: return false;
93+
// CHECK-NEXT: });
94+
95+
// CHECK: return llvm::make_range(It.first, It.second);
96+
// CHECK-NEXT: }
97+
// CHECK-NEXT: #endif
98+
99+
// CHECK: #undef GET_List_DECL
100+
// CHECK-NEXT: #undef GET_List_IMPL

llvm/utils/TableGen/SearchableTableEmitter.cpp

Lines changed: 103 additions & 36 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);
@@ -328,8 +330,9 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
328330
ArrayRef<Record *> IndexRows;
329331
StringRef IndexTypeName;
330332
StringRef IndexName;
333+
bool ShouldReturnRange = Index.ReturnRange;
331334

332-
if (IsPrimary) {
335+
if (IsPrimary || ShouldReturnRange) {
333336
IndexTypeName = Table.CppTypeName;
334337
IndexName = Table.Name;
335338
IndexRows = Table.Entries;
@@ -426,31 +429,55 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
426429
OS << " return nullptr;\n\n";
427430
}
428431

429-
OS << " struct KeyType {\n";
430-
for (const auto &Field : Index.Fields) {
431-
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
432-
<< " " << Field.Name << ";\n";
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;
439-
if (isa<StringRecTy>(Field.RecType)) {
440-
OS << ".upper()";
441-
if (IsPrimary)
442-
PrintFatalError(Index.Loc,
443-
Twine("In table '") + Table.Name +
444-
"', use a secondary lookup method for "
445-
"case-insensitive comparison of field '" +
446-
Field.Name + "'");
446+
if (ShouldReturnRange) {
447+
OS << " Key." << Field.Name << " = " << Field.Name;
448+
if (isa<StringRecTy>(Field.RecType))
449+
OS << ".data()";
450+
OS << ";\n";
451+
} else {
452+
OS << LS << Field.Name;
453+
if (isa<StringRecTy>(Field.RecType)) {
454+
OS << ".upper()";
455+
if (IsPrimary)
456+
PrintFatalError(Index.Loc,
457+
Twine("In table '") + Table.Name +
458+
"', use a secondary lookup method for "
459+
"case-insensitive comparison of field '" +
460+
Field.Name + "'");
461+
}
447462
}
448463
}
449-
OS << "};\n";
450464

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";
465+
if (!ShouldReturnRange)
466+
OS << "};\n";
467+
468+
OS << " auto Table = ArrayRef(" << IndexName;
469+
if (ShouldReturnRange) {
470+
if (!IsPrimary)
471+
OS << "for" << Index.Name;
472+
OS << ");\n";
473+
OS << " auto It = std::equal_range(Table.begin(), Table.end(), Key,\n";
474+
OS << " [](const " << IndexTypeName << " &LHS, const " << IndexTypeName
475+
<< " &RHS) {\n";
476+
} else {
477+
OS << ");\n";
478+
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
479+
OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
480+
}
454481

455482
for (const auto &Field : Index.Fields) {
456483
if (isa<StringRecTy>(Field.RecType)) {
@@ -478,25 +505,33 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
478505
OS << " return false;\n";
479506
OS << " });\n\n";
480507

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";
508+
if (!ShouldReturnRange) {
509+
OS << " if (Idx == Table.end()";
510+
for (const auto &Field : Index.Fields)
511+
OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
512+
}
486513

487-
if (IsPrimary)
514+
if (ShouldReturnRange)
515+
OS << " return llvm::make_range(It.first, It.second);\n";
516+
else if (IsPrimary) {
517+
OS << ")\n return nullptr;\n\n";
488518
OS << " return &*Idx;\n";
489-
else
519+
} else {
520+
OS << ")\n return nullptr;\n\n";
490521
OS << " return &" << Table.Name << "[Idx->_index];\n";
522+
}
491523

492524
OS << "}\n";
493525
}
494526

495527
void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
496528
const SearchIndex &Index,
497529
raw_ostream &OS) {
498-
OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
499-
530+
if (Index.ReturnRange)
531+
OS << "llvm::iterator_range<const " << Table.CppTypeName << " *>\n";
532+
else
533+
OS << "const " << Table.CppTypeName << " *";
534+
OS << Index.Name << "(";
500535
ListSeparator LS;
501536
for (const auto &Field : Index.Fields)
502537
OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
@@ -538,12 +573,41 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
538573
}
539574
OS << " };\n";
540575

576+
// Emit Table for all those indices which will return a range instead of a
577+
// single record
578+
for (const auto &Index : Table.Indices) {
579+
if (Index->ReturnRange) {
580+
std::vector<Record *> Entries;
581+
Entries.reserve(Table.Entries.size());
582+
for (unsigned i = 0; i < Table.Entries.size(); ++i)
583+
Entries.emplace_back(Table.Entries[i]);
584+
585+
llvm::stable_sort(Entries, [&](Record *LHS, Record *RHS) {
586+
return compareBy(LHS, RHS, *Index);
587+
});
588+
589+
OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "for"
590+
<< Index->Name << "[] = {\n";
591+
for (const auto &Entry : Entries) {
592+
OS << " { ";
593+
ListSeparator LS;
594+
for (const auto &Field : Table.Fields)
595+
OS << LS
596+
<< primaryRepresentation(Table.Locs[0], Field,
597+
Entry->getValueInit(Field.Name));
598+
599+
OS << " },\n";
600+
}
601+
OS << " };\n";
602+
}
603+
}
604+
541605
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
542606
// search can be performed by "Thing".
543607
if (Table.PrimaryKey)
544-
emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
608+
emitLookupFunction(Table, *Table.PrimaryKey, /*IsPrimary=*/true, OS);
545609
for (const auto &Index : Table.Indices)
546-
emitLookupFunction(Table, *Index, false, OS);
610+
emitLookupFunction(Table, *Index, /*IsPrimary=*/false, OS);
547611

548612
OS << "#endif\n\n";
549613
}
@@ -569,11 +633,12 @@ bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
569633

570634
std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
571635
GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
572-
const std::vector<StringRef> &Key, bool EarlyOut) {
636+
const std::vector<StringRef> &Key, bool EarlyOut, bool ReturnRange) {
573637
auto Index = std::make_unique<SearchIndex>();
574638
Index->Name = std::string(Name);
575639
Index->Loc = KeyRecVal->getLoc();
576640
Index->EarlyOut = EarlyOut;
641+
Index->ReturnRange = ReturnRange;
577642

578643
for (const auto &FieldName : Key) {
579644
const GenericField *Field = Table.getFieldByName(FieldName);
@@ -769,7 +834,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
769834
parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
770835
TableRec->getValueAsString("PrimaryKeyName"),
771836
TableRec->getValueAsListOfStrings("PrimaryKey"),
772-
TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
837+
TableRec->getValueAsBit("PrimaryKeyEarlyOut"),
838+
TableRec->getValueAsBit("PrimaryKeyReturnRange"));
773839

774840
llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
775841
return compareBy(LHS, RHS, *Table->PrimaryKey);
@@ -793,7 +859,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
793859
Table.Indices.push_back(
794860
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
795861
IndexRec->getValueAsListOfStrings("Key"),
796-
IndexRec->getValueAsBit("EarlyOut")));
862+
IndexRec->getValueAsBit("EarlyOut"),
863+
IndexRec->getValueAsBit("ReturnRange")));
797864
}
798865

799866
// Translate legacy tables.
@@ -848,7 +915,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
848915
std::string Name =
849916
(Twine("lookup") + Table->CppTypeName + "By" + Field).str();
850917
Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
851-
Name, {Field}, false));
918+
Name, {Field}, false, false));
852919
}
853920

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

0 commit comments

Comments
 (0)