DAG operators
Directed Acyclic Graphs (DAGs) are used in compiler construction a lot to represent operation and type hierarchies along with other metadata in the form of Abstract Syntax Trees (AST). ASTs are a kind of a DAG with some constraints. Don't worry about the specifics right now. We will get plenty of practice in later chapters. For now just remember that a DAG unit (called a node) in TableGen consists of an Operator and zero or more Arguments. Arguments can be DAG nodes too so we can create hierarchies of nodes. I've used my excellent mermaid
skills to create this illustration for you (you know you're learning from the best):
Again, skim over the following operators. I have rarely used them in the context of writing compiler components but I have seen them being used in some library implementations, so just get a cursory idea for now. MLIR implicitly creates ASTs for your compiler, so you won't find yourself doing any sort of DAG manipulation in TableGen as you might expect.
#ifndef DAGOPS
#define DAGOPS
include "setup.td"
def DagOps {
dag binOp1 = !dag(addOp, [10, 20], ["op1", "op2"]);
assert !eq(!repr(binOp1), "(addOp 10:$op1, 20:$op2)"), errorStr;
int op1_v = !getdagarg<int>(binOp1, "op1");
assert !eq(op1_v, 10), errorStr;
int op2_v = !getdagarg<int>(binOp1, 1);
assert !eq(op2_v, 20), errorStr;
dag binOp2 = !setdagname(binOp1, "op2", "op3");
assert !eq(!repr(binOp2), "(addOp 10:$op1, 20:$op3)"), errorStr;
dag binOp3 = !setdagarg(binOp2, 0, 20);
assert !eq(!repr(binOp3), "(addOp 20:$op1, 20:$op3)"), errorStr;
dag binOp4 = !setdagop(binOp3, mulOp);
assert !eq(!repr(binOp4), "(mulOp 20:$op1, 20:$op3)"), errorStr;
list<int> op1s = !foreach(dg, [binOp1, binOp3], !getdagarg<int>(dg, "op1"));
assert !eq(!repr(op1s), "[10, 20]"), errorStr;
Op op = !getdagop<Op>(binOp1);
assert !eq(op, addOp), errorStr;
dag combinedOps = !con(binOp1, binOp3);
assert !eq(!repr(combinedOps), "(addOp 10:$op1, 20:$op2, 20:$op1, 20:$op3)"), errorStr;
int combined_op_v = !getdagarg<int>(combinedOps, "op1");
assert !eq(combined_op_v, 10), errorStr;
string name_v = !getdagname(binOp1, 0);
assert !eq(name_v, "op1"), errorStr;
int size_v = !size(binOp1);
assert !eq(size_v, 2), errorStr;
bit empty_f = !empty(binOp1);
assert !eq(empty_f, 0), errorStr;
dag emptyDag = !dag(addOp, []<int>, []<string>);
bit empty_t = !empty(emptyDag);
assert empty_t, errorStr;
dag binOp5 = !dag("myOp", [10, 20], ["op1", "op2"]);
assert !eq(!repr(binOp5), "(\"myOp\" 10:$op1, 20:$op2)"), errorStr;
dag binOp6 = !dag("myOp", [10, 20], ["op3", "op4"]);
}
#endif