summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/TableGen/LangRef.rst18
-rw-r--r--llvm/include/llvm/TableGen/Record.h15
-rw-r--r--llvm/lib/TableGen/TGLexer.cpp1
-rw-r--r--llvm/lib/TableGen/TGLexer.h2
-rw-r--r--llvm/lib/TableGen/TGParser.cpp92
-rw-r--r--llvm/lib/TableGen/TGParser.h11
-rw-r--r--llvm/test/TableGen/defset-typeerror.td14
-rw-r--r--llvm/test/TableGen/defset.td62
8 files changed, 205 insertions, 10 deletions
diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst
index 702b40c9011..99bcad757fc 100644
--- a/llvm/docs/TableGen/LangRef.rst
+++ b/llvm/docs/TableGen/LangRef.rst
@@ -116,7 +116,8 @@ TableGen's top-level production consists of "objects".
.. productionlist::
TableGenFile: `Object`*
- Object: `Class` | `Def` | `Defm` | `Let` | `MultiClass` | `Foreach`
+ Object: `Class` | `Def` | `Defm` | `Defset` | `Let` | `MultiClass` |
+ `Foreach`
``class``\es
------------
@@ -356,6 +357,21 @@ a ``foreach``.
Note that in the :token:`BaseClassList`, all of the ``multiclass``'s must
precede any ``class``'s that appear.
+``defset``
+----------
+.. productionlist::
+ Defset: "defset" `Type` `TokIdentifier` "=" "{" `Object`* "}"
+
+All records defined inside the braces via ``def`` and ``defm`` are collected
+in a globally accessible list of the given name (in addition to being added
+to the global collection of records as usual). Anonymous records created inside
+initializier expressions using the ``Class<args...>`` syntax are never collected
+in a defset.
+
+The given type must be ``list<A>``, where ``A`` is some class. It is an error
+to define a record (via ``def`` or ``defm``) inside the braces which doesn't
+derive from ``A``.
+
``foreach``
-----------
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index cf955662463..0f2c26e59b7 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -1612,6 +1612,7 @@ class RecordKeeper {
using RecordMap = std::map<std::string, std::unique_ptr<Record>>;
RecordMap Classes, Defs;
FoldingSet<RecordRecTy> RecordTypePool;
+ std::map<std::string, Init *> ExtraGlobals;
unsigned AnonCounter = 0;
public:
@@ -1628,6 +1629,13 @@ public:
return I == Defs.end() ? nullptr : I->second.get();
}
+ Init *getGlobal(StringRef Name) const {
+ if (Record *R = getDef(Name))
+ return R->getDefInit();
+ auto It = ExtraGlobals.find(Name);
+ return It == ExtraGlobals.end() ? nullptr : It->second;
+ }
+
void addClass(std::unique_ptr<Record> R) {
bool Ins = Classes.insert(std::make_pair(R->getName(),
std::move(R))).second;
@@ -1642,6 +1650,13 @@ public:
assert(Ins && "Record already exists");
}
+ void addExtraGlobal(StringRef Name, Init *I) {
+ bool Ins = ExtraGlobals.insert(std::make_pair(Name, I)).second;
+ (void)Ins;
+ assert(!getDef(Name));
+ assert(Ins && "Global already exists");
+ }
+
Init *getNewAnonymousName();
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 222aac25f9d..d3dd27cbbb3 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -276,6 +276,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
.Case("def", tgtok::Def)
.Case("foreach", tgtok::Foreach)
.Case("defm", tgtok::Defm)
+ .Case("defset", tgtok::Defset)
.Case("multiclass", tgtok::MultiClass)
.Case("field", tgtok::Field)
.Case("let", tgtok::Let)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index bebe3176d7b..c2222472195 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -44,7 +44,7 @@ namespace tgtok {
// Keywords.
Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List,
- MultiClass, String,
+ MultiClass, String, Defset,
// !keywords.
XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index a60fa90c190..5d87bfdf19d 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -413,6 +413,8 @@ bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){
Records.addDef(std::move(IterRec));
IterRecSave->resolveReferences();
checkConcrete(*IterRecSave);
+ if (addToDefsets(*IterRecSave))
+ return true;
return false;
}
@@ -422,9 +424,9 @@ bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){
/// isObjectStart - Return true if this is a valid first token for an Object.
static bool isObjectStart(tgtok::TokKind K) {
- return K == tgtok::Class || K == tgtok::Def ||
- K == tgtok::Defm || K == tgtok::Let ||
- K == tgtok::MultiClass || K == tgtok::Foreach;
+ return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm ||
+ K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach ||
+ K == tgtok::Defset;
}
/// ParseObjectName - If an object name is specified, return it. Otherwise,
@@ -724,6 +726,7 @@ RecTy *TGParser::ParseType() {
case tgtok::Dag: Lex.Lex(); return DagRecTy::get();
case tgtok::Id:
if (Record *R = ParseClassID()) return RecordRecTy::get(R);
+ TokError("unknown class name");
return nullptr;
case tgtok::Bits: {
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
@@ -805,8 +808,8 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
if (Mode == ParseNameMode)
return Name;
- if (Record *D = Records.getDef(Name->getValue()))
- return DefInit::get(D);
+ if (Init *I = Records.getGlobal(Name->getValue()))
+ return I;
if (Mode == ParseValueMode) {
Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
@@ -2323,8 +2326,11 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
// for the def that might have been created when resolving
// inheritance, values and arguments above.
CurRec->resolveReferences();
- if (Loops.empty())
+ if (Loops.empty()) {
checkConcrete(*CurRec);
+ if (addToDefsets(*CurRec))
+ return true;
+ }
}
// If ObjectBody has template arguments, it's an error.
@@ -2346,6 +2352,68 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
return false;
}
+bool TGParser::addToDefsets(Record &R) {
+ for (DefsetRecord *Defset : Defsets) {
+ DefInit *I = R.getDefInit();
+ if (!I->getType()->typeIsA(Defset->EltTy)) {
+ PrintError(R.getLoc(),
+ Twine("adding record of incompatible type '") +
+ I->getType()->getAsString() + "' to defset");
+ PrintNote(Defset->Loc, "to this defset");
+ return true;
+ }
+ Defset->Elements.push_back(I);
+ }
+ return false;
+}
+
+/// ParseDefset - Parse a defset statement.
+///
+/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}'
+///
+bool TGParser::ParseDefset() {
+ assert(Lex.getCode() == tgtok::Defset);
+ Lex.Lex(); // Eat the 'defset' token
+
+ DefsetRecord Defset;
+ Defset.Loc = Lex.getLoc();
+ RecTy *Type = ParseType();
+ if (!Type)
+ return true;
+ if (!isa<ListRecTy>(Type))
+ return Error(Defset.Loc, "expected list type");
+ Defset.EltTy = cast<ListRecTy>(Type)->getElementType();
+
+ if (Lex.getCode() != tgtok::Id)
+ return TokError("expected identifier");
+ StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
+ if (Records.getGlobal(DeclName->getValue()))
+ return TokError("def or global variable of this name already exists");
+
+ if (Lex.Lex() != tgtok::equal) // Eat the identifier
+ return TokError("expected '='");
+ if (Lex.Lex() != tgtok::l_brace) // Eat the '='
+ return TokError("expected '{'");
+ SMLoc BraceLoc = Lex.getLoc();
+ Lex.Lex(); // Eat the '{'
+
+ Defsets.push_back(&Defset);
+ bool Err = ParseObjectList(nullptr);
+ Defsets.pop_back();
+ if (Err)
+ return true;
+
+ if (Lex.getCode() != tgtok::r_brace) {
+ TokError("expected '}' at end of defset");
+ return Error(BraceLoc, "to match this '{'");
+ }
+ Lex.Lex(); // Eat the '}'
+
+ Records.addExtraGlobal(DeclName->getValue(),
+ ListInit::get(Defset.Elements, Defset.EltTy));
+ return false;
+}
+
/// ParseForeach - Parse a for statement. Return the record corresponding
/// to it. This returns true on error.
///
@@ -2598,7 +2666,8 @@ bool TGParser::ParseMultiClass() {
while (Lex.getCode() != tgtok::r_brace) {
switch (Lex.getCode()) {
default:
- return TokError("expected 'let', 'def' or 'defm' in multiclass body");
+ return TokError("expected 'let', 'def', 'defm' or 'foreach' in "
+ "multiclass body");
case tgtok::Let:
case tgtok::Def:
case tgtok::Defm:
@@ -2919,6 +2988,8 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
// inheritance, values and arguments above.
CurRec->resolveReferences();
checkConcrete(*CurRec);
+ if (addToDefsets(*CurRec))
+ return true;
}
}
@@ -2939,11 +3010,16 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
bool TGParser::ParseObject(MultiClass *MC) {
switch (Lex.getCode()) {
default:
- return TokError("Expected class, def, defm, multiclass or let definition");
+ return TokError("Expected class, def, defm, defset, multiclass, let or "
+ "foreach");
case tgtok::Let: return ParseTopLevelLet(MC);
case tgtok::Def: return ParseDef(MC);
case tgtok::Foreach: return ParseForeach(MC);
case tgtok::Defm: return ParseDefm(MC);
+ case tgtok::Defset:
+ if (MC)
+ return TokError("defset is not allowed inside multiclass");
+ return ParseDefset();
case tgtok::Class: return ParseClass();
case tgtok::MultiClass: return ParseMultiClass();
}
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index 03fbc14047e..d4ee5be5d98 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -51,6 +51,12 @@ namespace llvm {
: IterVar(IVar), ListValue(LValue) {}
};
+ struct DefsetRecord {
+ SMLoc Loc;
+ RecTy *EltTy;
+ SmallVector<Init *, 16> Elements;
+ };
+
class TGParser {
TGLexer Lex;
std::vector<SmallVector<LetRecord, 4>> LetStack;
@@ -61,6 +67,8 @@ class TGParser {
typedef std::vector<ForeachLoop> LoopVector;
LoopVector Loops;
+ SmallVector<DefsetRecord *, 2> Defsets;
+
/// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
/// current value.
MultiClass *CurMultiClass;
@@ -121,6 +129,8 @@ private: // Semantic analysis methods.
bool ProcessForeachDefs(Record *CurRec, SMLoc Loc);
bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals);
+ bool addToDefsets(Record &R);
+
private: // Parser methods.
bool ParseObjectList(MultiClass *MC = nullptr);
bool ParseObject(MultiClass *MC);
@@ -140,6 +150,7 @@ private: // Parser methods.
SMLoc DefmPrefixLoc);
bool ParseDefm(MultiClass *CurMultiClass);
bool ParseDef(MultiClass *CurMultiClass);
+ bool ParseDefset();
bool ParseForeach(MultiClass *CurMultiClass);
bool ParseTopLevelLet(MultiClass *CurMultiClass);
void ParseLetList(SmallVectorImpl<LetRecord> &Result);
diff --git a/llvm/test/TableGen/defset-typeerror.td b/llvm/test/TableGen/defset-typeerror.td
new file mode 100644
index 00000000000..cdc7833fa3a
--- /dev/null
+++ b/llvm/test/TableGen/defset-typeerror.td
@@ -0,0 +1,14 @@
+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: error: adding record of incompatible type 'A' to defset
+
+class A<int a> {
+ int Num = a;
+}
+
+class B<int a> : A<a>;
+
+defset list<B> Bs = {
+ def A0 : A<1>;
+}
diff --git a/llvm/test/TableGen/defset.td b/llvm/test/TableGen/defset.td
new file mode 100644
index 00000000000..3c5fb68ea7e
--- /dev/null
+++ b/llvm/test/TableGen/defset.td
@@ -0,0 +1,62 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: --- Defs ---
+
+// CHECK: def Sum {
+// CHECK: int x = 712;
+// CHECK: }
+
+// CHECK: def yyy_A0
+// CHECK: def yyy_A1
+// CHECK: def yyy_A2
+// CHECK: def yyy_B0A0
+// CHECK: def yyy_B0A1
+// CHECK: def yyy_C0B0A0
+// CHECK: def yyy_C0B0A1
+// CHECK: def yyy_C0B1A0
+// CHECK: def yyy_C0B1A1
+// CHECK-NOT: def zzz_A0
+// CHECK: def zzz_B0A0
+// CHECK: def zzz_B0A1
+// CHECK: def zzz_C0B0A0
+// CHECK: def zzz_C0B0A1
+// CHECK: def zzz_C0B1A0
+// CHECK: def zzz_C0B1A1
+
+class A<int a> {
+ int Num = a;
+}
+
+multiclass B<int b> {
+ def A0 : A<!add(10, b)>;
+ def A1 : A<!add(20, b)>;
+}
+
+multiclass C<int c> {
+ defm B0 : B<!add(100, c)>;
+ defm B1 : B<!add(200, c)>;
+}
+
+defset list<A> As = {
+ def A0 : A<1>;
+ foreach i = 1-2 in {
+ def A#i : A<!add(i, 1)>;
+ }
+ defset list<A> SubAs = {
+ defm B0 : B<2>;
+ defm C0 : C<3>;
+ }
+}
+
+def Sum {
+ int x = !foldl(0, As, a, b, !add(a, b.Num));
+}
+
+foreach a = As in {
+ def yyy_ # !cast<string>(a);
+}
+
+foreach a = SubAs in {
+ def zzz_ # !cast<string>(a);
+}
OpenPOWER on IntegriCloud