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.
:!add !shl !sra !srl !and
:!or !empty !subst !foreach !strconcat
:!cast !listconcat !size !foldl
- :!isa
+ :!isa !dag
Syntax
/// !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;
}
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);
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() + ")";
.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)
// !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,
->Fold(CurRec, CurMultiClass);
}
+ case tgtok::XDag:
case tgtok::XIf:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
TernOpInit::TernaryOp Code;
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;
}
Lex.Lex(); // eat the ','
+ SMLoc MHSLoc = Lex.getLoc();
Init *MHS = ParseValue(CurRec, ItemType);
if (!MHS)
return nullptr;
}
Lex.Lex(); // eat the ','
+ SMLoc RHSLoc = Lex.getLoc();
Init *RHS = ParseValue(CurRec, ItemType);
if (!RHS)
return nullptr;
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;
case tgtok::XCast: // Value ::= !unop '(' Value ')'
case tgtok::XIsA:
case tgtok::XConcat:
+ case tgtok::XDag:
case tgtok::XADD:
case tgtok::XAND:
case tgtok::XOR:
--- /dev/null
+// 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"]>;