Skip to content
This repository was archived by the owner on Jan 1, 2023. It is now read-only.

Commit db875d5

Browse files
committed
TableGen: Add a defset statement
Allows capturing a list of concrete instantiated defs. This can be combined with foreach to create parallel sets of def instantiations with less repetition in the source. This purpose is largely also served by multiclasses, but in some cases multiclasses can't be used. The motivating example for this change is having a large set of intrinsics, which are generated from the IntrinsicsBackend.td file included by Intrinsics.td, and a corresponding set of instruction selection patterns, which are generated via the backend's .td files. Multiclasses cannot be used to eliminate the redundancy in this case, because a multiclass cannot span both LLVM's common .td files and the backend .td files at the same time. Change-Id: I879e35042dceea542a5e6776fad23c5e0e69e76b Differential revision: https://reviews.llvm.org/D44109 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@327121 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0afe174 commit db875d5

File tree

8 files changed

+205
-10
lines changed

8 files changed

+205
-10
lines changed

docs/TableGen/LangRef.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ TableGen's top-level production consists of "objects".
116116

117117
.. productionlist::
118118
TableGenFile: `Object`*
119-
Object: `Class` | `Def` | `Defm` | `Let` | `MultiClass` | `Foreach`
119+
Object: `Class` | `Def` | `Defm` | `Defset` | `Let` | `MultiClass` |
120+
`Foreach`
120121

121122
``class``\es
122123
------------
@@ -356,6 +357,21 @@ a ``foreach``.
356357
Note that in the :token:`BaseClassList`, all of the ``multiclass``'s must
357358
precede any ``class``'s that appear.
358359

360+
``defset``
361+
----------
362+
.. productionlist::
363+
Defset: "defset" `Type` `TokIdentifier` "=" "{" `Object`* "}"
364+
365+
All records defined inside the braces via ``def`` and ``defm`` are collected
366+
in a globally accessible list of the given name (in addition to being added
367+
to the global collection of records as usual). Anonymous records created inside
368+
initializier expressions using the ``Class<args...>`` syntax are never collected
369+
in a defset.
370+
371+
The given type must be ``list<A>``, where ``A`` is some class. It is an error
372+
to define a record (via ``def`` or ``defm``) inside the braces which doesn't
373+
derive from ``A``.
374+
359375
``foreach``
360376
-----------
361377

include/llvm/TableGen/Record.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,7 @@ class RecordKeeper {
16121612
using RecordMap = std::map<std::string, std::unique_ptr<Record>>;
16131613
RecordMap Classes, Defs;
16141614
FoldingSet<RecordRecTy> RecordTypePool;
1615+
std::map<std::string, Init *> ExtraGlobals;
16151616
unsigned AnonCounter = 0;
16161617

16171618
public:
@@ -1628,6 +1629,13 @@ class RecordKeeper {
16281629
return I == Defs.end() ? nullptr : I->second.get();
16291630
}
16301631

1632+
Init *getGlobal(StringRef Name) const {
1633+
if (Record *R = getDef(Name))
1634+
return R->getDefInit();
1635+
auto It = ExtraGlobals.find(Name);
1636+
return It == ExtraGlobals.end() ? nullptr : It->second;
1637+
}
1638+
16311639
void addClass(std::unique_ptr<Record> R) {
16321640
bool Ins = Classes.insert(std::make_pair(R->getName(),
16331641
std::move(R))).second;
@@ -1642,6 +1650,13 @@ class RecordKeeper {
16421650
assert(Ins && "Record already exists");
16431651
}
16441652

1653+
void addExtraGlobal(StringRef Name, Init *I) {
1654+
bool Ins = ExtraGlobals.insert(std::make_pair(Name, I)).second;
1655+
(void)Ins;
1656+
assert(!getDef(Name));
1657+
assert(Ins && "Global already exists");
1658+
}
1659+
16451660
Init *getNewAnonymousName();
16461661

16471662
//===--------------------------------------------------------------------===//

lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
276276
.Case("def", tgtok::Def)
277277
.Case("foreach", tgtok::Foreach)
278278
.Case("defm", tgtok::Defm)
279+
.Case("defset", tgtok::Defset)
279280
.Case("multiclass", tgtok::MultiClass)
280281
.Case("field", tgtok::Field)
281282
.Case("let", tgtok::Let)

lib/TableGen/TGLexer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace tgtok {
4444

4545
// Keywords.
4646
Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List,
47-
MultiClass, String,
47+
MultiClass, String, Defset,
4848

4949
// !keywords.
5050
XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast,

lib/TableGen/TGParser.cpp

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){
413413
Records.addDef(std::move(IterRec));
414414
IterRecSave->resolveReferences();
415415
checkConcrete(*IterRecSave);
416+
if (addToDefsets(*IterRecSave))
417+
return true;
416418
return false;
417419
}
418420

@@ -422,9 +424,9 @@ bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){
422424

423425
/// isObjectStart - Return true if this is a valid first token for an Object.
424426
static bool isObjectStart(tgtok::TokKind K) {
425-
return K == tgtok::Class || K == tgtok::Def ||
426-
K == tgtok::Defm || K == tgtok::Let ||
427-
K == tgtok::MultiClass || K == tgtok::Foreach;
427+
return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm ||
428+
K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach ||
429+
K == tgtok::Defset;
428430
}
429431

430432
/// ParseObjectName - If an object name is specified, return it. Otherwise,
@@ -724,6 +726,7 @@ RecTy *TGParser::ParseType() {
724726
case tgtok::Dag: Lex.Lex(); return DagRecTy::get();
725727
case tgtok::Id:
726728
if (Record *R = ParseClassID()) return RecordRecTy::get(R);
729+
TokError("unknown class name");
727730
return nullptr;
728731
case tgtok::Bits: {
729732
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
@@ -805,8 +808,8 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
805808
if (Mode == ParseNameMode)
806809
return Name;
807810

808-
if (Record *D = Records.getDef(Name->getValue()))
809-
return DefInit::get(D);
811+
if (Init *I = Records.getGlobal(Name->getValue()))
812+
return I;
810813

811814
if (Mode == ParseValueMode) {
812815
Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
@@ -2323,8 +2326,11 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
23232326
// for the def that might have been created when resolving
23242327
// inheritance, values and arguments above.
23252328
CurRec->resolveReferences();
2326-
if (Loops.empty())
2329+
if (Loops.empty()) {
23272330
checkConcrete(*CurRec);
2331+
if (addToDefsets(*CurRec))
2332+
return true;
2333+
}
23282334
}
23292335

23302336
// If ObjectBody has template arguments, it's an error.
@@ -2346,6 +2352,68 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
23462352
return false;
23472353
}
23482354

2355+
bool TGParser::addToDefsets(Record &R) {
2356+
for (DefsetRecord *Defset : Defsets) {
2357+
DefInit *I = R.getDefInit();
2358+
if (!I->getType()->typeIsA(Defset->EltTy)) {
2359+
PrintError(R.getLoc(),
2360+
Twine("adding record of incompatible type '") +
2361+
I->getType()->getAsString() + "' to defset");
2362+
PrintNote(Defset->Loc, "to this defset");
2363+
return true;
2364+
}
2365+
Defset->Elements.push_back(I);
2366+
}
2367+
return false;
2368+
}
2369+
2370+
/// ParseDefset - Parse a defset statement.
2371+
///
2372+
/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}'
2373+
///
2374+
bool TGParser::ParseDefset() {
2375+
assert(Lex.getCode() == tgtok::Defset);
2376+
Lex.Lex(); // Eat the 'defset' token
2377+
2378+
DefsetRecord Defset;
2379+
Defset.Loc = Lex.getLoc();
2380+
RecTy *Type = ParseType();
2381+
if (!Type)
2382+
return true;
2383+
if (!isa<ListRecTy>(Type))
2384+
return Error(Defset.Loc, "expected list type");
2385+
Defset.EltTy = cast<ListRecTy>(Type)->getElementType();
2386+
2387+
if (Lex.getCode() != tgtok::Id)
2388+
return TokError("expected identifier");
2389+
StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
2390+
if (Records.getGlobal(DeclName->getValue()))
2391+
return TokError("def or global variable of this name already exists");
2392+
2393+
if (Lex.Lex() != tgtok::equal) // Eat the identifier
2394+
return TokError("expected '='");
2395+
if (Lex.Lex() != tgtok::l_brace) // Eat the '='
2396+
return TokError("expected '{'");
2397+
SMLoc BraceLoc = Lex.getLoc();
2398+
Lex.Lex(); // Eat the '{'
2399+
2400+
Defsets.push_back(&Defset);
2401+
bool Err = ParseObjectList(nullptr);
2402+
Defsets.pop_back();
2403+
if (Err)
2404+
return true;
2405+
2406+
if (Lex.getCode() != tgtok::r_brace) {
2407+
TokError("expected '}' at end of defset");
2408+
return Error(BraceLoc, "to match this '{'");
2409+
}
2410+
Lex.Lex(); // Eat the '}'
2411+
2412+
Records.addExtraGlobal(DeclName->getValue(),
2413+
ListInit::get(Defset.Elements, Defset.EltTy));
2414+
return false;
2415+
}
2416+
23492417
/// ParseForeach - Parse a for statement. Return the record corresponding
23502418
/// to it. This returns true on error.
23512419
///
@@ -2598,7 +2666,8 @@ bool TGParser::ParseMultiClass() {
25982666
while (Lex.getCode() != tgtok::r_brace) {
25992667
switch (Lex.getCode()) {
26002668
default:
2601-
return TokError("expected 'let', 'def' or 'defm' in multiclass body");
2669+
return TokError("expected 'let', 'def', 'defm' or 'foreach' in "
2670+
"multiclass body");
26022671
case tgtok::Let:
26032672
case tgtok::Def:
26042673
case tgtok::Defm:
@@ -2919,6 +2988,8 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
29192988
// inheritance, values and arguments above.
29202989
CurRec->resolveReferences();
29212990
checkConcrete(*CurRec);
2991+
if (addToDefsets(*CurRec))
2992+
return true;
29222993
}
29232994
}
29242995

@@ -2939,11 +3010,16 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
29393010
bool TGParser::ParseObject(MultiClass *MC) {
29403011
switch (Lex.getCode()) {
29413012
default:
2942-
return TokError("Expected class, def, defm, multiclass or let definition");
3013+
return TokError("Expected class, def, defm, defset, multiclass, let or "
3014+
"foreach");
29433015
case tgtok::Let: return ParseTopLevelLet(MC);
29443016
case tgtok::Def: return ParseDef(MC);
29453017
case tgtok::Foreach: return ParseForeach(MC);
29463018
case tgtok::Defm: return ParseDefm(MC);
3019+
case tgtok::Defset:
3020+
if (MC)
3021+
return TokError("defset is not allowed inside multiclass");
3022+
return ParseDefset();
29473023
case tgtok::Class: return ParseClass();
29483024
case tgtok::MultiClass: return ParseMultiClass();
29493025
}

lib/TableGen/TGParser.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ namespace llvm {
5151
: IterVar(IVar), ListValue(LValue) {}
5252
};
5353

54+
struct DefsetRecord {
55+
SMLoc Loc;
56+
RecTy *EltTy;
57+
SmallVector<Init *, 16> Elements;
58+
};
59+
5460
class TGParser {
5561
TGLexer Lex;
5662
std::vector<SmallVector<LetRecord, 4>> LetStack;
@@ -61,6 +67,8 @@ class TGParser {
6167
typedef std::vector<ForeachLoop> LoopVector;
6268
LoopVector Loops;
6369

70+
SmallVector<DefsetRecord *, 2> Defsets;
71+
6472
/// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
6573
/// current value.
6674
MultiClass *CurMultiClass;
@@ -121,6 +129,8 @@ class TGParser {
121129
bool ProcessForeachDefs(Record *CurRec, SMLoc Loc);
122130
bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals);
123131

132+
bool addToDefsets(Record &R);
133+
124134
private: // Parser methods.
125135
bool ParseObjectList(MultiClass *MC = nullptr);
126136
bool ParseObject(MultiClass *MC);
@@ -140,6 +150,7 @@ class TGParser {
140150
SMLoc DefmPrefixLoc);
141151
bool ParseDefm(MultiClass *CurMultiClass);
142152
bool ParseDef(MultiClass *CurMultiClass);
153+
bool ParseDefset();
143154
bool ParseForeach(MultiClass *CurMultiClass);
144155
bool ParseTopLevelLet(MultiClass *CurMultiClass);
145156
void ParseLetList(SmallVectorImpl<LetRecord> &Result);

test/TableGen/defset-typeerror.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
2+
// XFAIL: vg_leak
3+
4+
// CHECK: error: adding record of incompatible type 'A' to defset
5+
6+
class A<int a> {
7+
int Num = a;
8+
}
9+
10+
class B<int a> : A<a>;
11+
12+
defset list<B> Bs = {
13+
def A0 : A<1>;
14+
}

test/TableGen/defset.td

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
// XFAIL: vg_leak
3+
4+
// CHECK: --- Defs ---
5+
6+
// CHECK: def Sum {
7+
// CHECK: int x = 712;
8+
// CHECK: }
9+
10+
// CHECK: def yyy_A0
11+
// CHECK: def yyy_A1
12+
// CHECK: def yyy_A2
13+
// CHECK: def yyy_B0A0
14+
// CHECK: def yyy_B0A1
15+
// CHECK: def yyy_C0B0A0
16+
// CHECK: def yyy_C0B0A1
17+
// CHECK: def yyy_C0B1A0
18+
// CHECK: def yyy_C0B1A1
19+
// CHECK-NOT: def zzz_A0
20+
// CHECK: def zzz_B0A0
21+
// CHECK: def zzz_B0A1
22+
// CHECK: def zzz_C0B0A0
23+
// CHECK: def zzz_C0B0A1
24+
// CHECK: def zzz_C0B1A0
25+
// CHECK: def zzz_C0B1A1
26+
27+
class A<int a> {
28+
int Num = a;
29+
}
30+
31+
multiclass B<int b> {
32+
def A0 : A<!add(10, b)>;
33+
def A1 : A<!add(20, b)>;
34+
}
35+
36+
multiclass C<int c> {
37+
defm B0 : B<!add(100, c)>;
38+
defm B1 : B<!add(200, c)>;
39+
}
40+
41+
defset list<A> As = {
42+
def A0 : A<1>;
43+
foreach i = 1-2 in {
44+
def A#i : A<!add(i, 1)>;
45+
}
46+
defset list<A> SubAs = {
47+
defm B0 : B<2>;
48+
defm C0 : C<3>;
49+
}
50+
}
51+
52+
def Sum {
53+
int x = !foldl(0, As, a, b, !add(a, b.Num));
54+
}
55+
56+
foreach a = As in {
57+
def yyy_ # !cast<string>(a);
58+
}
59+
60+
foreach a = SubAs in {
61+
def zzz_ # !cast<string>(a);
62+
}

0 commit comments

Comments
 (0)