summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/TableGen/LangIntro.rst18
-rw-r--r--llvm/docs/TableGen/LangRef.rst2
-rw-r--r--llvm/include/llvm/TableGen/Record.h2
-rw-r--r--llvm/lib/TableGen/Record.cpp25
-rw-r--r--llvm/lib/TableGen/TGLexer.cpp1
-rw-r--r--llvm/lib/TableGen/TGLexer.h2
-rw-r--r--llvm/lib/TableGen/TGParser.cpp39
-rw-r--r--llvm/test/TableGen/dag-functional.td95
8 files changed, 181 insertions, 3 deletions
diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst
index c4a7a34c025..a4b198b8958 100644
--- a/llvm/docs/TableGen/LangIntro.rst
+++ b/llvm/docs/TableGen/LangIntro.rst
@@ -165,6 +165,24 @@ supported include:
remaining elements in the list may be arbitrary other values, including
nested ```dag``' values.
+``!con(a, b, ...)``
+ Concatenate two or more DAG nodes. Their operations must equal.
+
+ Example: !con((op a1:$name1, a2:$name2), (op b1:$name3)) results in
+ the DAG node (op a1:$name1, a2:$name2, b1:$name3).
+
+``!dag(op, children, names)``
+ Generate a DAG node programmatically. 'children' and 'names' must be lists
+ of equal length or unset ('?'). 'names' must be a 'list<string>'.
+
+ Due to limitations of the type system, 'children' must be a list of items
+ of a common type. In practice, this means that they should either have the
+ same type or be records with a common superclass. Mixing dag and non-dag
+ items is not possible.
+
+ Example: !dag(op, [a1, a2], ["name1", "name2"]) results in
+ (op a1:$name1, a2:$name2).
+
``!listconcat(a, b, ...)``
A list value that is the result of concatenating the 'a' and 'b' lists.
The lists must have the same element type.
diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst
index 99bcad757fc..595505001d5 100644
--- a/llvm/docs/TableGen/LangRef.rst
+++ b/llvm/docs/TableGen/LangRef.rst
@@ -99,7 +99,7 @@ wide variety of meanings:
:!add !shl !sra !srl !and
:!or !empty !subst !foreach !strconcat
:!cast !listconcat !size !foldl
- :!isa
+ :!isa !dag
Syntax
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 0f2c26e59b7..411a7bd8c0b 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -856,7 +856,7 @@ public:
/// !op (X, Y, Z) - Combine two inits.
class TernOpInit : public OpInit, public FoldingSetNode {
public:
- enum TernaryOp : uint8_t { SUBST, FOREACH, IF };
+ enum TernaryOp : uint8_t { SUBST, FOREACH, IF, DAG };
private:
Init *LHS, *MHS, *RHS;
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 2fbe4cc493f..48197f04d11 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1114,6 +1114,30 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
}
break;
}
+
+ case DAG: {
+ ListInit *MHSl = dyn_cast<ListInit>(MHS);
+ ListInit *RHSl = dyn_cast<ListInit>(RHS);
+ bool MHSok = MHSl || isa<UnsetInit>(MHS);
+ bool RHSok = RHSl || isa<UnsetInit>(RHS);
+
+ if (isa<UnsetInit>(MHS) && isa<UnsetInit>(RHS))
+ break; // Typically prevented by the parser, but might happen with template args
+
+ if (MHSok && RHSok && (!MHSl || !RHSl || MHSl->size() == RHSl->size())) {
+ SmallVector<std::pair<Init *, StringInit *>, 8> Children;
+ unsigned Size = MHSl ? MHSl->size() : RHSl->size();
+ for (unsigned i = 0; i != Size; ++i) {
+ Init *Node = MHSl ? MHSl->getElement(i) : UnsetInit::get();
+ Init *Name = RHSl ? RHSl->getElement(i) : UnsetInit::get();
+ if (!isa<StringInit>(Name) && !isa<UnsetInit>(Name))
+ return const_cast<TernOpInit *>(this);
+ Children.emplace_back(Node, dyn_cast<StringInit>(Name));
+ }
+ return DagInit::get(LHS, nullptr, Children);
+ }
+ break;
+ }
}
return const_cast<TernOpInit *>(this);
@@ -1155,6 +1179,7 @@ std::string TernOpInit::getAsString() const {
case SUBST: Result = "!subst"; break;
case FOREACH: Result = "!foreach"; break;
case IF: Result = "!if"; break;
+ case DAG: Result = "!dag"; break;
}
return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " +
RHS->getAsString() + ")";
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index f833782e203..d4762a42191 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -473,6 +473,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("tail", tgtok::XTail)
.Case("size", tgtok::XSize)
.Case("con", tgtok::XConcat)
+ .Case("dag", tgtok::XDag)
.Case("add", tgtok::XADD)
.Case("and", tgtok::XAND)
.Case("or", tgtok::XOR)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 2ffc2efdc30..18559773d74 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -48,7 +48,7 @@ namespace tgtok {
// !keywords.
XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast,
- XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA,
+ XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag,
// Integer value.
IntVal,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 5d87bfdf19d..629320975a6 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1159,6 +1159,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
->Fold(CurRec, CurMultiClass);
}
+ case tgtok::XDag:
case tgtok::XIf:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
TernOpInit::TernaryOp Code;
@@ -1168,6 +1169,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
Lex.Lex(); // eat the operation
switch (LexCode) {
default: llvm_unreachable("Unhandled code!");
+ case tgtok::XDag:
+ Code = TernOpInit::DAG;
+ Type = DagRecTy::get();
+ ItemType = nullptr;
+ break;
case tgtok::XIf:
Code = TernOpInit::IF;
break;
@@ -1190,6 +1196,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
Lex.Lex(); // eat the ','
+ SMLoc MHSLoc = Lex.getLoc();
Init *MHS = ParseValue(CurRec, ItemType);
if (!MHS)
return nullptr;
@@ -1200,6 +1207,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
Lex.Lex(); // eat the ','
+ SMLoc RHSLoc = Lex.getLoc();
Init *RHS = ParseValue(CurRec, ItemType);
if (!RHS)
return nullptr;
@@ -1212,6 +1220,36 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
switch (LexCode) {
default: llvm_unreachable("Unhandled code!");
+ case tgtok::XDag: {
+ TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
+ if (!MHSt && !isa<UnsetInit>(MHS)) {
+ Error(MHSLoc, "could not determine type of the child list in !dag");
+ return nullptr;
+ }
+ if (MHSt && !isa<ListRecTy>(MHSt->getType())) {
+ Error(MHSLoc, Twine("expected list of children, got type '") +
+ MHSt->getType()->getAsString() + "'");
+ return nullptr;
+ }
+
+ TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
+ if (!RHSt && !isa<UnsetInit>(RHS)) {
+ Error(RHSLoc, "could not determine type of the name list in !dag");
+ return nullptr;
+ }
+ if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) {
+ Error(RHSLoc, Twine("expected list<string>, got type '") +
+ RHSt->getType()->getAsString() + "'");
+ return nullptr;
+ }
+
+ if (!MHSt && !RHSt) {
+ Error(MHSLoc,
+ "cannot have both unset children and unset names in !dag");
+ return nullptr;
+ }
+ break;
+ }
case tgtok::XIf: {
RecTy *MHSTy = nullptr;
RecTy *RHSTy = nullptr;
@@ -1728,6 +1766,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XCast: // Value ::= !unop '(' Value ')'
case tgtok::XIsA:
case tgtok::XConcat:
+ case tgtok::XDag:
case tgtok::XADD:
case tgtok::XAND:
case tgtok::XOR:
diff --git a/llvm/test/TableGen/dag-functional.td b/llvm/test/TableGen/dag-functional.td
new file mode 100644
index 00000000000..8a5fa8b4b02
--- /dev/null
+++ b/llvm/test/TableGen/dag-functional.td
@@ -0,0 +1,95 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: --- Defs ---
+
+// CHECK: def A0 {
+// CHECK: dag ret = (ops);
+// CHECK: }
+
+// CHECK: def A1 {
+// CHECK: dag ret = (ops 1:$a, 2:$b);
+// CHECK: }
+
+// CHECK: def A2 {
+// CHECK: dag ret = (ops (ops ?:$name):$a, (ops 1):$b, (ops "foo"):$c);
+// CHECK: }
+
+// CHECK: def A3 {
+// CHECK: dag ret = (ops NodeA0:$a, NodeB0:$b);
+// CHECK: }
+
+// CHECK: def A4 {
+// CHECK: dag ret = (ops NodeA0, NodeB0);
+// CHECK: }
+
+// CHECK: def B0 {
+// CHECK: dag ret = (ops);
+// CHECK: }
+
+// CHECK: def B1 {
+// CHECK: dag ret = (ops 1:$a, 2:$b);
+// CHECK: }
+
+// CHECK: def C0 {
+// CHECK: dag ret1 = (ops ?:$a, ?:$b);
+// CHECK: dag ret2 = (ops 1, 2);
+// CHECK: }
+
+def ops;
+
+class Node<int val, string name> {
+ int Val = val;
+ string Name = name;
+}
+
+class Aint<list<int> nodes, list<string> names> {
+ dag ret = !dag(ops, nodes, names);
+}
+
+class Adag<list<dag> nodes, list<string> names> {
+ dag ret = !dag(ops, nodes, names);
+}
+
+class NodeBase;
+
+class NodeA<int val> : NodeBase {
+ int x = val;
+}
+
+class NodeB<int val> : NodeBase {
+ int y = val;
+}
+
+class Anode<list<NodeBase> nodes, list<string> names> {
+ dag ret = !dag(ops, nodes, names);
+}
+
+class B<list<Node> nodes> {
+ dag ret = !foldl((ops), nodes, lhs, rhs, !con(lhs, !dag(ops, [rhs.Val], [rhs.Name])));
+}
+
+def A0 : Aint<[], []>;
+def A1 : Aint<[1, 2], ["a", "b"]>;
+
+def A2 : Adag<[(ops $name), (ops 1), (ops "foo")], ["a", "b", "c"]>;
+
+def NodeA0 : NodeA<0>;
+def NodeB0 : NodeB<0>;
+
+def A3 : Anode<[NodeA0, NodeB0], ["a", "b"]>;
+
+def A4 {
+ // Like A3, but with a literal list directly in the !dag.
+ dag ret = !dag(ops, [NodeA0, NodeB0], ?);
+}
+
+def B0 : B<[]>;
+def B1 : B<[Node<1, "a">, Node<2, "b">]>;
+
+class C<list<int> nodes, list<string> names> {
+ dag ret1 = !dag(ops, ?, names);
+ dag ret2 = !dag(ops, nodes, ?);
+}
+
+def C0 : C<[1, 2], ["a", "b"]>;
OpenPOWER on IntegriCloud