[Mlir-commits] [mlir] [ViewOpGraph] Improve GraphViz output (PR #125509)
Eric Hein
llvmlistbot at llvm.org
Thu Feb 6 09:34:24 PST 2025
https://github.com/ehein6 updated https://github.com/llvm/llvm-project/pull/125509
>From 645f70e82350be4d995a07a50c734ba4ee76360c Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 14:47:36 +0000
Subject: [PATCH 01/24] [WIP] Improve graphviz output
---
mlir/lib/Transforms/ViewOpGraph.cpp | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index fa0af7665ba4c4c..920de8b22f1ac97 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -29,7 +29,7 @@ using namespace mlir;
static const StringRef kLineStyleControlFlow = "dashed";
static const StringRef kLineStyleDataFlow = "solid";
-static const StringRef kShapeNode = "ellipse";
+static const StringRef kShapeNode = "record";
static const StringRef kShapeNone = "plain";
/// Return the size limits for eliding large attributes.
@@ -59,6 +59,21 @@ static std::string quoteString(const std::string &str) {
return "\"" + str + "\"";
}
+/// For Graphviz record nodes:
+/// " Braces, vertical bars and angle brackets must be escaped with a backslash
+/// character if you wish them to appear as a literal character "
+static std::string escapeLabelString(const std::string &str) {
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ for (char c : str) {
+ if (c == '{' || c == '|' || c == '<' || c == '}' || c == '>') {
+ os << "\\\\";
+ }
+ os << c;
+ }
+ return buf;
+}
+
using AttributeMap = std::map<std::string, std::string>;
namespace {
@@ -240,7 +255,8 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
StringRef background = "") {
int nodeId = ++counter;
AttributeMap attrs;
- attrs["label"] = quoteString(escapeString(std::move(label)));
+ attrs["label"] =
+ quoteString(escapeString(escapeLabelString(std::move(label))));
attrs["shape"] = shape.str();
if (!background.empty()) {
attrs["style"] = "filled";
>From efbff2b2b43fc9220faa12b8525af1e55cb17fe4 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 13:26:14 -0500
Subject: [PATCH 02/24] Moving to record nodes and port-based edges.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 43 ++++++++++++++++++-----------
1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 920de8b22f1ac97..53e4bcfaa57f6e9 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -62,12 +62,12 @@ static std::string quoteString(const std::string &str) {
/// For Graphviz record nodes:
/// " Braces, vertical bars and angle brackets must be escaped with a backslash
/// character if you wish them to appear as a literal character "
-static std::string escapeLabelString(const std::string &str) {
+std::string escapeLabelString(const std::string &str) {
std::string buf;
llvm::raw_string_ostream os(buf);
for (char c : str) {
if (c == '{' || c == '|' || c == '<' || c == '}' || c == '>') {
- os << "\\\\";
+ os << '\\';
}
os << c;
}
@@ -145,7 +145,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
void emitAllEdgeStmts() {
if (printDataFlowEdges) {
for (const auto &[value, node, label] : dataFlowEdges) {
- emitEdgeStmt(valueToNode[value], node, label, kLineStyleDataFlow);
+ emitEdgeStmt(valueToNode[value], "", node, "", kLineStyleDataFlow);
}
}
@@ -219,14 +219,10 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Append an edge to the list of edges.
/// Note: Edges are written to the output stream via `emitAllEdgeStmts`.
- void emitEdgeStmt(Node n1, Node n2, std::string label, StringRef style) {
+ void emitEdgeStmt(Node n1, std::string outPort, Node n2, std::string inPort,
+ StringRef style) {
AttributeMap attrs;
attrs["style"] = style.str();
- // Do not label edges that start/end at a cluster boundary. Such edges are
- // clipped at the boundary, but labels are not. This can lead to labels
- // floating around without any edge next to them.
- if (!n1.clusterId && !n2.clusterId)
- attrs["label"] = quoteString(escapeString(std::move(label)));
// Use `ltail` and `lhead` to draw edges between clusters.
if (n1.clusterId)
attrs["ltail"] = "cluster_" + std::to_string(*n1.clusterId);
@@ -234,7 +230,13 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
attrs["lhead"] = "cluster_" + std::to_string(*n2.clusterId);
edges.push_back(strFromOs([&](raw_ostream &os) {
- os << llvm::format("v%i -> v%i ", n1.id, n2.id);
+ os << "v" << n1.id;
+ if (!outPort.empty())
+ os << ":" << outPort;
+ os << " -> ";
+ os << "v" << n2.id;
+ if (!inPort.empty())
+ os << ":" << inPort;
emitAttrList(os, attrs);
}));
}
@@ -255,8 +257,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
StringRef background = "") {
int nodeId = ++counter;
AttributeMap attrs;
- attrs["label"] =
- quoteString(escapeString(escapeLabelString(std::move(label))));
+ attrs["label"] = quoteString(escapeString(std::move(label)));
attrs["shape"] = shape.str();
if (!background.empty()) {
attrs["style"] = "filled";
@@ -271,6 +272,16 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Generate a label for an operation.
std::string getLabel(Operation *op) {
return strFromOs([&](raw_ostream &os) {
+ os << "{{";
+ // Print operation inputs.
+ interleave(
+ op->getOperands(), os,
+ [&](Value operand) {
+ OpPrintingFlags flags;
+ operand.printAsOperand(os, flags);
+ },
+ "|");
+ os << "}|";
// Print operation name and type.
os << op->getName();
if (printResultTypes) {
@@ -289,6 +300,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
emitMlirAttr(os, attr.getValue());
}
}
+ os << "}";
});
}
@@ -301,16 +313,15 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// operation inside the cluster.
void processBlock(Block &block) {
emitClusterStmt([&]() {
- for (BlockArgument &blockArg : block.getArguments())
+ for (BlockArgument &blockArg : block.getArguments()) {
valueToNode[blockArg] = emitNodeStmt(getLabel(blockArg));
-
+ }
// Emit a node for each operation.
std::optional<Node> prevNode;
for (Operation &op : block) {
Node nextNode = processOperation(&op);
if (printControlFlowEdges && prevNode)
- emitEdgeStmt(*prevNode, nextNode, /*label=*/"",
- kLineStyleControlFlow);
+ emitEdgeStmt(*prevNode, "", nextNode, "", kLineStyleControlFlow);
prevNode = nextNode;
}
});
>From 8f229f862988866818adf5439d5cb2ff76f2b1c6 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 14:44:13 -0500
Subject: [PATCH 03/24] Fix input port linking
---
mlir/lib/Transforms/ViewOpGraph.cpp | 54 +++++++++++++++++++++--------
1 file changed, 39 insertions(+), 15 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 53e4bcfaa57f6e9..88ec22d88109525 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -94,6 +94,13 @@ struct Node {
std::optional<int> clusterId;
};
+struct DataFlowEdge {
+ Value value;
+ std::string outPort;
+ Node node;
+ std::string inPort;
+};
+
/// This pass generates a Graphviz dataflow visualization of an MLIR operation.
/// Note: See https://www.graphviz.org/doc/info/lang.html for more information
/// about the Graphviz DOT language.
@@ -144,8 +151,9 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// emitted.
void emitAllEdgeStmts() {
if (printDataFlowEdges) {
- for (const auto &[value, node, label] : dataFlowEdges) {
- emitEdgeStmt(valueToNode[value], "", node, "", kLineStyleDataFlow);
+ for (const auto &e : dataFlowEdges) {
+ emitEdgeStmt(valueToNode[e.value], e.outPort, e.node, e.inPort,
+ kLineStyleDataFlow);
}
}
@@ -269,19 +277,33 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
return Node(nodeId);
}
+ std::string getOperandPortName(Value operand) {
+ // Print value as an operand and omit the leading '%' character.
+ return strFromOs([&](raw_ostream &os) {
+ operand.printAsOperand(os, OpPrintingFlags());
+ })
+ .substr(1, std::string::npos);
+ }
+
/// Generate a label for an operation.
std::string getLabel(Operation *op) {
return strFromOs([&](raw_ostream &os) {
- os << "{{";
+ os << "{";
+
// Print operation inputs.
- interleave(
- op->getOperands(), os,
- [&](Value operand) {
- OpPrintingFlags flags;
- operand.printAsOperand(os, flags);
- },
- "|");
- os << "}|";
+ if (op->getNumOperands() > 0) {
+ os << "{";
+ interleave(
+ op->getOperands(), os,
+ [&](Value operand) {
+ os << "<";
+ os << getOperandPortName(operand);
+ os << "> ";
+ operand.printAsOperand(os, OpPrintingFlags());
+ },
+ "|");
+ os << "}|";
+ }
// Print operation name and type.
os << op->getName();
if (printResultTypes) {
@@ -347,9 +369,11 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
// Insert data flow edges originating from each operand.
if (printDataFlowEdges) {
unsigned numOperands = op->getNumOperands();
- for (unsigned i = 0; i < numOperands; i++)
- dataFlowEdges.push_back({op->getOperand(i), node,
- numOperands == 1 ? "" : std::to_string(i)});
+ for (unsigned i = 0; i < numOperands; i++) {
+ auto operand = op->getOperand(i);
+ auto inPort = getOperandPortName(operand);
+ dataFlowEdges.push_back({operand, "", node, inPort});
+ }
}
for (Value result : op->getResults())
@@ -379,7 +403,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Mapping of SSA values to Graphviz nodes/clusters.
DenseMap<Value, Node> valueToNode;
/// Output for data flow edges is delayed until the end to handle cycles
- std::vector<std::tuple<Value, Node, std::string>> dataFlowEdges;
+ std::vector<DataFlowEdge> dataFlowEdges;
/// Counter for generating unique node/subgraph identifiers.
int counter = 0;
>From ca0c74057f67b5f71c73b0bc9cc5a4119ecc3bb1 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 15:04:46 -0500
Subject: [PATCH 04/24] Fix result type printing
---
mlir/lib/Transforms/ViewOpGraph.cpp | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 88ec22d88109525..bf8e2a845751b89 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -265,7 +265,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
StringRef background = "") {
int nodeId = ++counter;
AttributeMap attrs;
- attrs["label"] = quoteString(escapeString(std::move(label)));
+ attrs["label"] = quoteString(label);
attrs["shape"] = shape.str();
if (!background.empty()) {
attrs["style"] = "filled";
@@ -306,12 +306,19 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
}
// Print operation name and type.
os << op->getName();
- if (printResultTypes) {
- os << " : (";
+ if (printResultTypes && op->getNumResults() > 0) {
+ os << "|{";
std::string buf;
llvm::raw_string_ostream ss(buf);
- interleaveComma(op->getResultTypes(), ss);
- os << truncateString(buf) << ")";
+ interleave(
+ op->getResultTypes(), ss,
+ [&](Type type) {
+ ss << escapeLabelString(
+ strFromOs([&](raw_ostream &os) { os << type; }));
+ },
+ "|");
+ // TODO: how to truncate string without breaking the layout?
+ os << buf << "}";
}
// Print attributes.
>From 87dd5c98b333da2e0c406452a42a8e024c6ae229 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 15:22:33 -0500
Subject: [PATCH 05/24] Fix attribute printing
---
mlir/lib/Transforms/ViewOpGraph.cpp | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index bf8e2a845751b89..2ddefe971f38a19 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -66,7 +66,7 @@ std::string escapeLabelString(const std::string &str) {
std::string buf;
llvm::raw_string_ostream os(buf);
for (char c : str) {
- if (c == '{' || c == '|' || c == '<' || c == '}' || c == '>') {
+ if (c == '{' || c == '|' || c == '<' || c == '}' || c == '>' || c == '\n') {
os << '\\';
}
os << c;
@@ -222,7 +222,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
std::string buf;
llvm::raw_string_ostream ss(buf);
attr.print(ss);
- os << truncateString(buf);
+ os << escapeLabelString(truncateString(buf));
}
/// Append an edge to the list of edges.
@@ -306,6 +306,16 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
}
// Print operation name and type.
os << op->getName();
+
+ // Print attributes.
+ if (printAttrs && !op->getAttrs().empty()) {
+ os << "\\n";
+ for (const NamedAttribute &attr : op->getAttrs()) {
+ os << "\\n" << attr.getName().getValue() << ": ";
+ emitMlirAttr(os, attr.getValue());
+ }
+ }
+
if (printResultTypes && op->getNumResults() > 0) {
os << "|{";
std::string buf;
@@ -321,14 +331,6 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << buf << "}";
}
- // Print attributes.
- if (printAttrs) {
- os << "\n";
- for (const NamedAttribute &attr : op->getAttrs()) {
- os << '\n' << attr.getName().getValue() << ": ";
- emitMlirAttr(os, attr.getValue());
- }
- }
os << "}";
});
}
>From 2ad44fca3ecdb0d9adab7ebeb0c25a4c258ac192 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 15:41:02 -0500
Subject: [PATCH 06/24] Switch to Mrecord shape (rounded rectangle)
---
mlir/lib/Transforms/ViewOpGraph.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 2ddefe971f38a19..7493eab592f8ec9 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -29,7 +29,7 @@ using namespace mlir;
static const StringRef kLineStyleControlFlow = "dashed";
static const StringRef kLineStyleDataFlow = "solid";
-static const StringRef kShapeNode = "record";
+static const StringRef kShapeNode = "Mrecord";
static const StringRef kShapeNone = "plain";
/// Return the size limits for eliding large attributes.
>From 96b42e840a003954d3b21c34adacf6f9c27e1aec Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Fri, 31 Jan 2025 15:41:27 -0500
Subject: [PATCH 07/24] Handle more special characters in node labels
---
mlir/lib/Transforms/ViewOpGraph.cpp | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 7493eab592f8ec9..246aa88a045b581 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -65,8 +65,9 @@ static std::string quoteString(const std::string &str) {
std::string escapeLabelString(const std::string &str) {
std::string buf;
llvm::raw_string_ostream os(buf);
+ llvm::DenseSet<char> shouldEscape = {'{', '|', '<', '}', '>', '\n', '"'};
for (char c : str) {
- if (c == '{' || c == '|' || c == '<' || c == '}' || c == '>' || c == '\n') {
+ if (shouldEscape.contains(c)) {
os << '\\';
}
os << c;
@@ -279,10 +280,13 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
std::string getOperandPortName(Value operand) {
// Print value as an operand and omit the leading '%' character.
- return strFromOs([&](raw_ostream &os) {
- operand.printAsOperand(os, OpPrintingFlags());
- })
- .substr(1, std::string::npos);
+ auto str = strFromOs([&](raw_ostream &os) {
+ operand.printAsOperand(os, OpPrintingFlags());
+ });
+ // Replace % and # with _
+ std::replace(str.begin(), str.end(), '%', '_');
+ std::replace(str.begin(), str.end(), '#', '_');
+ return str;
}
/// Generate a label for an operation.
>From 4ac25aa8483ffa6b32757b6956d951bdfd3879c3 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sat, 1 Feb 2025 14:30:55 -0500
Subject: [PATCH 08/24] Fix output port names
---
mlir/lib/Transforms/ViewOpGraph.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 246aa88a045b581..27d7131543c454f 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -320,19 +320,19 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
}
}
- if (printResultTypes && op->getNumResults() > 0) {
+ if (op->getNumResults() > 0) {
os << "|{";
- std::string buf;
- llvm::raw_string_ostream ss(buf);
interleave(
- op->getResultTypes(), ss,
- [&](Type type) {
- ss << escapeLabelString(
- strFromOs([&](raw_ostream &os) { os << type; }));
+ op->getResults(), os,
+ [&](Value result) {
+ os << "<" << getOperandPortName(result) << "> ";
+ if (printResultTypes)
+ os << truncateString(escapeLabelString(strFromOs(
+ [&](raw_ostream &os) { os << result.getType(); })));
},
"|");
// TODO: how to truncate string without breaking the layout?
- os << buf << "}";
+ os << "}";
}
os << "}";
@@ -385,7 +385,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
for (unsigned i = 0; i < numOperands; i++) {
auto operand = op->getOperand(i);
auto inPort = getOperandPortName(operand);
- dataFlowEdges.push_back({operand, "", node, inPort});
+ dataFlowEdges.push_back({operand, inPort, node, inPort});
}
}
>From 8a62b0582383b2fdcdc90388456ebfa7e1382148 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sat, 1 Feb 2025 15:16:34 -0500
Subject: [PATCH 09/24] Clean up port generation code
---
mlir/lib/Transforms/ViewOpGraph.cpp | 37 +++++++++++++----------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 27d7131543c454f..af8095583de5a88 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -278,7 +278,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
return Node(nodeId);
}
- std::string getOperandPortName(Value operand) {
+ std::string getValuePortName(Value operand) {
// Print value as an operand and omit the leading '%' character.
auto str = strFromOs([&](raw_ostream &os) {
operand.printAsOperand(os, OpPrintingFlags());
@@ -297,15 +297,11 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
// Print operation inputs.
if (op->getNumOperands() > 0) {
os << "{";
- interleave(
- op->getOperands(), os,
- [&](Value operand) {
- os << "<";
- os << getOperandPortName(operand);
- os << "> ";
- operand.printAsOperand(os, OpPrintingFlags());
- },
- "|");
+ auto operandToPort = [&](Value operand) {
+ os << "<" << getValuePortName(operand) << "> ";
+ operand.printAsOperand(os, OpPrintingFlags());
+ };
+ interleave(op->getOperands(), os, operandToPort, "|");
os << "}|";
}
// Print operation name and type.
@@ -322,16 +318,15 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
if (op->getNumResults() > 0) {
os << "|{";
- interleave(
- op->getResults(), os,
- [&](Value result) {
- os << "<" << getOperandPortName(result) << "> ";
- if (printResultTypes)
- os << truncateString(escapeLabelString(strFromOs(
- [&](raw_ostream &os) { os << result.getType(); })));
- },
- "|");
- // TODO: how to truncate string without breaking the layout?
+ auto resultToPort = [&](Value result) {
+ os << "<" << getValuePortName(result) << "> ";
+ if (printResultTypes)
+ os << truncateString(escapeLabelString(
+ strFromOs([&](raw_ostream &os) { os << result.getType(); })));
+ else
+ result.printAsOperand(os, OpPrintingFlags());
+ };
+ interleave(op->getResults(), os, resultToPort, "|");
os << "}";
}
@@ -384,7 +379,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
unsigned numOperands = op->getNumOperands();
for (unsigned i = 0; i < numOperands; i++) {
auto operand = op->getOperand(i);
- auto inPort = getOperandPortName(operand);
+ auto inPort = getValuePortName(operand);
dataFlowEdges.push_back({operand, inPort, node, inPort});
}
}
>From a51de257110715811d99bbb4d3d95e9d90732854 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sat, 1 Feb 2025 15:40:45 -0500
Subject: [PATCH 10/24] Left-justify the label text.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index af8095583de5a88..3bc6a460d01ed7a 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -305,14 +305,16 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << "}|";
}
// Print operation name and type.
- os << op->getName();
+ os << op->getName() << "\\l";
// Print attributes.
if (printAttrs && !op->getAttrs().empty()) {
- os << "\\n";
+ // Extra line break to separate attributes from the operation name.
+ os << "\\l";
for (const NamedAttribute &attr : op->getAttrs()) {
- os << "\\n" << attr.getName().getValue() << ": ";
+ os << attr.getName().getValue() << ": ";
emitMlirAttr(os, attr.getValue());
+ os << "\\l";
}
}
>From fc069edfa994187da0552f8060e50f525318bffa Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sat, 1 Feb 2025 15:41:09 -0500
Subject: [PATCH 11/24] Always print result short name.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 3bc6a460d01ed7a..3576ed601843707 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -322,11 +322,11 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << "|{";
auto resultToPort = [&](Value result) {
os << "<" << getValuePortName(result) << "> ";
+ result.printAsOperand(os, OpPrintingFlags());
if (printResultTypes)
- os << truncateString(escapeLabelString(
- strFromOs([&](raw_ostream &os) { os << result.getType(); })));
- else
- result.printAsOperand(os, OpPrintingFlags());
+ os << " "
+ << truncateString(escapeLabelString(strFromOs(
+ [&](raw_ostream &os) { os << result.getType(); })));
};
interleave(op->getResults(), os, resultToPort, "|");
os << "}";
>From 1398fe919c3e9c222a27a69aab4dc43a38b32604 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sat, 1 Feb 2025 15:58:31 -0500
Subject: [PATCH 12/24] Fix edge attachment points.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 3576ed601843707..ac9ce6b0c641cfe 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -241,11 +241,11 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
edges.push_back(strFromOs([&](raw_ostream &os) {
os << "v" << n1.id;
if (!outPort.empty())
- os << ":" << outPort;
+ os << ":" << outPort << ":s";
os << " -> ";
os << "v" << n2.id;
if (!inPort.empty())
- os << ":" << inPort;
+ os << ":" << inPort << ":n";
emitAttrList(os, attrs);
}));
}
>From c681a203068209ee9c4db7a4c012d02339764386 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sun, 2 Feb 2025 13:30:47 -0500
Subject: [PATCH 13/24] Merge in and out ports into a single port attribute.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index ac9ce6b0c641cfe..43949ca289590bd 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -97,9 +97,8 @@ struct Node {
struct DataFlowEdge {
Value value;
- std::string outPort;
Node node;
- std::string inPort;
+ std::string port;
};
/// This pass generates a Graphviz dataflow visualization of an MLIR operation.
@@ -153,8 +152,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
void emitAllEdgeStmts() {
if (printDataFlowEdges) {
for (const auto &e : dataFlowEdges) {
- emitEdgeStmt(valueToNode[e.value], e.outPort, e.node, e.inPort,
- kLineStyleDataFlow);
+ emitEdgeStmt(valueToNode[e.value], e.node, e.port, kLineStyleDataFlow);
}
}
@@ -228,8 +226,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Append an edge to the list of edges.
/// Note: Edges are written to the output stream via `emitAllEdgeStmts`.
- void emitEdgeStmt(Node n1, std::string outPort, Node n2, std::string inPort,
- StringRef style) {
+ void emitEdgeStmt(Node n1, Node n2, std::string port, StringRef style) {
AttributeMap attrs;
attrs["style"] = style.str();
// Use `ltail` and `lhead` to draw edges between clusters.
@@ -240,12 +237,14 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
edges.push_back(strFromOs([&](raw_ostream &os) {
os << "v" << n1.id;
- if (!outPort.empty())
- os << ":" << outPort << ":s";
+ if (!port.empty())
+ // Attach edge to south compass point of the result
+ os << ":" << port << ":s";
os << " -> ";
os << "v" << n2.id;
- if (!inPort.empty())
- os << ":" << inPort << ":n";
+ if (!port.empty())
+ // Attach edge to north compass point of the operand
+ os << ":" << port << ":n";
emitAttrList(os, attrs);
}));
}
@@ -353,7 +352,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
for (Operation &op : block) {
Node nextNode = processOperation(&op);
if (printControlFlowEdges && prevNode)
- emitEdgeStmt(*prevNode, "", nextNode, "", kLineStyleControlFlow);
+ emitEdgeStmt(*prevNode, nextNode, /*port=*/"", kLineStyleControlFlow);
prevNode = nextNode;
}
});
@@ -381,8 +380,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
unsigned numOperands = op->getNumOperands();
for (unsigned i = 0; i < numOperands; i++) {
auto operand = op->getOperand(i);
- auto inPort = getValuePortName(operand);
- dataFlowEdges.push_back({operand, inPort, node, inPort});
+ dataFlowEdges.push_back({operand, node, getValuePortName(operand)});
}
}
>From da400cc7452b9b9f3c56c085198eb65480467e1b Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sun, 2 Feb 2025 21:16:49 -0500
Subject: [PATCH 14/24] Fix formatting of cluster labels
---
mlir/lib/Transforms/ViewOpGraph.cpp | 38 +++++++++++++++++++++--------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 43949ca289590bd..2fef6aa4d9a082d 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -49,11 +49,6 @@ static std::string strFromOs(function_ref<void(raw_ostream &)> func) {
return buf;
}
-/// Escape special characters such as '\n' and quotation marks.
-static std::string escapeString(std::string str) {
- return strFromOs([&](raw_ostream &os) { os.write_escaped(str); });
-}
-
/// Put quotation marks around a given string.
static std::string quoteString(const std::string &str) {
return "\"" + str + "\"";
@@ -169,8 +164,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os.indent();
// Emit invisible anchor node from/to which arrows can be drawn.
Node anchorNode = emitNodeStmt(" ", kShapeNone);
- os << attrStmt("label", quoteString(escapeString(std::move(label))))
- << ";\n";
+ os << attrStmt("label", quoteString(label)) << ";\n";
builder();
os.unindent();
os << "}\n";
@@ -288,8 +282,32 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
return str;
}
+ std::string getClusterLabel(Operation *op) {
+ return strFromOs([&](raw_ostream &os) {
+ // Print operation name and type.
+ os << op->getName();
+ if (printResultTypes) {
+ os << " : (";
+ std::string buf;
+ llvm::raw_string_ostream ss(buf);
+ interleaveComma(op->getResultTypes(), ss);
+ os << truncateString(buf) << ")";
+ }
+
+ // Print attributes.
+ if (printAttrs) {
+ os << "\\l";
+ for (const NamedAttribute &attr : op->getAttrs()) {
+ os << attr.getName().getValue() << ": ";
+ emitMlirAttr(os, attr.getValue());
+ os << "\\l";
+ }
+ }
+ });
+ }
+
/// Generate a label for an operation.
- std::string getLabel(Operation *op) {
+ std::string getRecordLabel(Operation *op) {
return strFromOs([&](raw_ostream &os) {
os << "{";
@@ -369,9 +387,9 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
for (Region ®ion : op->getRegions())
processRegion(region);
},
- getLabel(op));
+ getClusterLabel(op));
} else {
- node = emitNodeStmt(getLabel(op), kShapeNode,
+ node = emitNodeStmt(getRecordLabel(op), kShapeNode,
backgroundColors[op->getName()].second);
}
>From 464880325ecfae2fc7123b0b96d8c47499926f76 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Sun, 2 Feb 2025 21:32:26 -0500
Subject: [PATCH 15/24] Print result types in block arguments
---
mlir/lib/Transforms/ViewOpGraph.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 2fef6aa4d9a082d..abf0d8e36bc5ca7 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -355,7 +355,14 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Generate a label for a block argument.
std::string getLabel(BlockArgument arg) {
- return "arg" + std::to_string(arg.getArgNumber());
+ return strFromOs([&](raw_ostream &os) {
+ os << "<" << getValuePortName(arg) << "> ";
+ arg.printAsOperand(os, OpPrintingFlags());
+ if (printResultTypes)
+ os << " "
+ << truncateString(escapeLabelString(
+ strFromOs([&](raw_ostream &os) { os << arg.getType(); })));
+ });
}
/// Process a block. Emit a cluster and one node per block argument and
>From 566c8a6b1e3eb843ff944786c0f2208847cf03dc Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Mon, 3 Feb 2025 09:13:16 -0500
Subject: [PATCH 16/24] Improved node fill color choices
---
mlir/lib/Transforms/ViewOpGraph.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index abf0d8e36bc5ca7..065b4da568b588d 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -124,7 +124,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
private:
/// Generate a color mapping that will color every operation with the same
/// name the same way. It'll interpolate the hue in the HSV color-space,
- /// attempting to keep the contrast suitable for black text.
+ /// using muted colors that provide good contrast for black text.
template <typename T>
void initColorMapping(T &irEntity) {
backgroundColors.clear();
@@ -137,8 +137,10 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
});
for (auto indexedOps : llvm::enumerate(ops)) {
double hue = ((double)indexedOps.index()) / ops.size();
+ // Use lower saturation (0.3) and higher value (0.95) for better
+ // readability
backgroundColors[indexedOps.value()->getName()].second =
- std::to_string(hue) + " 1.0 1.0";
+ std::to_string(hue) + " 0.3 0.95";
}
}
@@ -263,7 +265,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
attrs["shape"] = shape.str();
if (!background.empty()) {
attrs["style"] = "filled";
- attrs["fillcolor"] = ("\"" + background + "\"").str();
+ attrs["fillcolor"] = quoteString(background.str());
}
os << llvm::format("v%i ", nodeId);
emitAttrList(os, attrs);
>From 9afe4113dccb20f0722774e6f1463d5c0265bf03 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Mon, 3 Feb 2025 20:48:20 -0500
Subject: [PATCH 17/24] Add helpers for printing MLIR types and operands
---
mlir/lib/Transforms/ViewOpGraph.cpp | 33 ++++++++++++++++++++---------
1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 065b4da568b588d..c11255e22cc9575 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -220,6 +220,19 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << escapeLabelString(truncateString(buf));
}
+ // Print a truncated and escaped MLIR type to `os`.
+ void emitMlirType(raw_ostream &os, Type type) {
+ std::string buf;
+ llvm::raw_string_ostream ss(buf);
+ type.print(ss);
+ os << escapeLabelString(truncateString(buf));
+ }
+
+ // Print a truncated and escaped MLIR operand to `os`.
+ void emitMlirOperand(raw_ostream &os, Value operand) {
+ operand.printAsOperand(os, OpPrintingFlags());
+ }
+
/// Append an edge to the list of edges.
/// Note: Edges are written to the output stream via `emitAllEdgeStmts`.
void emitEdgeStmt(Node n1, Node n2, std::string port, StringRef style) {
@@ -318,7 +331,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << "{";
auto operandToPort = [&](Value operand) {
os << "<" << getValuePortName(operand) << "> ";
- operand.printAsOperand(os, OpPrintingFlags());
+ emitMlirOperand(os, operand);
};
interleave(op->getOperands(), os, operandToPort, "|");
os << "}|";
@@ -341,11 +354,11 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << "|{";
auto resultToPort = [&](Value result) {
os << "<" << getValuePortName(result) << "> ";
- result.printAsOperand(os, OpPrintingFlags());
- if (printResultTypes)
- os << " "
- << truncateString(escapeLabelString(strFromOs(
- [&](raw_ostream &os) { os << result.getType(); })));
+ emitMlirOperand(os, result);
+ if (printResultTypes) {
+ os << " ";
+ emitMlirType(os, result.getType());
+ }
};
interleave(op->getResults(), os, resultToPort, "|");
os << "}";
@@ -360,10 +373,10 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
return strFromOs([&](raw_ostream &os) {
os << "<" << getValuePortName(arg) << "> ";
arg.printAsOperand(os, OpPrintingFlags());
- if (printResultTypes)
- os << " "
- << truncateString(escapeLabelString(
- strFromOs([&](raw_ostream &os) { os << arg.getType(); })));
+ if (printResultTypes) {
+ os << " ";
+ emitMlirType(os, arg.getType());
+ }
});
}
>From 76ab77fea852d6759c6bbbd65e4e934f7324976b Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Tue, 4 Feb 2025 10:10:48 -0500
Subject: [PATCH 18/24] Update print-op-graph unit tests
---
.../Transforms/print-op-graph-back-edges.mlir | 12 +++----
.../Transforms/print-op-graph-cycles.mlir | 32 +++++++++----------
mlir/test/Transforms/print-op-graph.mlir | 32 +++++++++----------
3 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/mlir/test/Transforms/print-op-graph-back-edges.mlir b/mlir/test/Transforms/print-op-graph-back-edges.mlir
index ed922dd7cb13bda..71eda7f1b1be22c 100644
--- a/mlir/test/Transforms/print-op-graph-back-edges.mlir
+++ b/mlir/test/Transforms/print-op-graph-back-edges.mlir
@@ -4,17 +4,17 @@
// DFG: compound = true;
// DFG: subgraph cluster_1 {
// DFG: v2 [label = " ", shape = plain];
-// DFG: label = "builtin.module : ()\n";
+// DFG: label = "builtin.module : ()\l";
// DFG: subgraph cluster_3 {
// DFG: v4 [label = " ", shape = plain];
// DFG: label = "";
-// DFG: v5 [fillcolor = "0.000000 1.0 1.0", label = "arith.addi : (index)\n\noverflowFlags: #arith.overflow<none...", shape = ellipse, style = filled];
-// DFG: v6 [fillcolor = "0.333333 1.0 1.0", label = "arith.constant : (index)\n\nvalue: 0 : index", shape = ellipse, style = filled];
-// DFG: v7 [fillcolor = "0.333333 1.0 1.0", label = "arith.constant : (index)\n\nvalue: 1 : index", shape = ellipse, style = filled];
+// DFG: v5 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_c0> %c0|<arg_c1> %c1}|arith.addi\l\loverflowFlags: #arith.overflow\<none...\l|{<res_0> %0 index}}", shape = Mrecord, style = filled];
+// DFG: v6 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 0 : index\l|{<res_c0> %c0 index}}", shape = Mrecord, style = filled];
+// DFG: v7 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 1 : index\l|{<res_c1> %c1 index}}", shape = Mrecord, style = filled];
// DFG: }
// DFG: }
-// DFG: v6 -> v5 [label = "0", style = solid];
-// DFG: v7 -> v5 [label = "1", style = solid];
+// DFG: v6:res_c0:s -> v5:arg_c0:n[style = solid];
+// DFG: v7:res_c1:s -> v5:arg_c1:n[style = solid];
// DFG: }
module {
diff --git a/mlir/test/Transforms/print-op-graph-cycles.mlir b/mlir/test/Transforms/print-op-graph-cycles.mlir
index 7e4eb5616a28b39..760867802753b08 100644
--- a/mlir/test/Transforms/print-op-graph-cycles.mlir
+++ b/mlir/test/Transforms/print-op-graph-cycles.mlir
@@ -4,41 +4,41 @@
// DFG: compound = true;
// DFG: subgraph cluster_1 {
// DFG: v2 [label = " ", shape = plain];
-// DFG: label = "builtin.module : ()\n";
+// DFG: label = "builtin.module : ()\l";
// DFG: subgraph cluster_3 {
// DFG: v4 [label = " ", shape = plain];
// DFG: label = "";
// DFG: subgraph cluster_5 {
// DFG: v6 [label = " ", shape = plain];
-// DFG: label = "test.graph_region : ()\n";
+// DFG: label = "test.graph_region : ()\l";
// DFG: subgraph cluster_7 {
// DFG: v8 [label = " ", shape = plain];
// DFG: label = "";
-// DFG: v9 [fillcolor = "0.000000 1.0 1.0", label = "op1 : (i32)\n", shape = ellipse, style = filled];
+// DFG: v9 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_2> %2}|op1\l|{<res_0> %0 i32}}", shape = Mrecord, style = filled];
// DFG: subgraph cluster_10 {
// DFG: v11 [label = " ", shape = plain];
-// DFG: label = "test.ssacfg_region : (i32)\n";
+// DFG: label = "test.ssacfg_region : (i32)\l";
// DFG: subgraph cluster_12 {
// DFG: v13 [label = " ", shape = plain];
// DFG: label = "";
-// DFG: v14 [fillcolor = "0.166667 1.0 1.0", label = "op2 : (i32)\n", shape = ellipse, style = filled];
+// DFG: v14 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_1> %1|<arg_2> %2|<arg_3> %3}|op2\l|{<res_4> %4 i32}}", shape = Mrecord, style = filled];
// DFG: }
// DFG: }
-// DFG: v15 [fillcolor = "0.166667 1.0 1.0", label = "op2 : (i32)\n", shape = ellipse, style = filled];
-// DFG: v16 [fillcolor = "0.500000 1.0 1.0", label = "op3 : (i32)\n", shape = ellipse, style = filled];
+// DFG: v15 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_3> %3}|op2\l|{<res_2> %2 i32}}", shape = Mrecord, style = filled];
+// DFG: v16 [fillcolor = "0.500000 0.3 0.95", label = "{{\{\{}}<arg_0> %0}|op3\l|{<res_3> %3 i32}}", shape = Mrecord, style = filled];
// DFG: }
// DFG: }
// DFG: }
// DFG: }
-// DFG: v9 -> v9 [label = "0", style = solid];
-// DFG: v15 -> v9 [label = "1", style = solid];
-// DFG: v9 -> v14 [label = "0", style = solid];
-// DFG: v11 -> v14 [ltail = cluster_10, style = solid];
-// DFG: v15 -> v14 [label = "2", style = solid];
-// DFG: v16 -> v14 [label = "3", style = solid];
-// DFG: v9 -> v15 [label = "0", style = solid];
-// DFG: v16 -> v15 [label = "1", style = solid];
-// DFG: v9 -> v16 [label = "", style = solid];
+// DFG: v9:res_0:s -> v9:arg_0:n[style = solid];
+// DFG: v15:res_2:s -> v9:arg_2:n[style = solid];
+// DFG: v9:res_0:s -> v14:arg_0:n[style = solid];
+// DFG: v11:res_1:s -> v14:arg_1:n[ltail = cluster_10, style = solid];
+// DFG: v15:res_2:s -> v14:arg_2:n[style = solid];
+// DFG: v16:res_3:s -> v14:arg_3:n[style = solid];
+// DFG: v9:res_0:s -> v15:arg_0:n[style = solid];
+// DFG: v16:res_3:s -> v15:arg_3:n[style = solid];
+// DFG: v9:res_0:s -> v16:arg_0:n[style = solid];
// DFG: }
"test.graph_region"() ({ // A Graph region
diff --git a/mlir/test/Transforms/print-op-graph.mlir b/mlir/test/Transforms/print-op-graph.mlir
index df03194a663d95f..430ed6299c89c3f 100644
--- a/mlir/test/Transforms/print-op-graph.mlir
+++ b/mlir/test/Transforms/print-op-graph.mlir
@@ -6,49 +6,49 @@
// DFG: subgraph {{.*}}
// DFG: label = "func.func{{.*}}merge_blocks
// DFG: subgraph {{.*}} {
-// DFG: v[[ARG0:.*]] [label = "arg0"
+// DFG: v[[ARG0:.*]] [label = "<res_arg0> %arg0 i32"
// DFG: v[[CONST10:.*]] [{{.*}}label ={{.*}}10 : i32
// DFG: subgraph [[CLUSTER_MERGE_BLOCKS:.*]] {
// DFG: v[[ANCHOR:.*]] [label = " ", shape = plain]
// DFG: label = "test.merge_blocks
// DFG: subgraph {{.*}} {
-// DFG: v[[TEST_BR:.*]] [{{.*}}label = "test.br
+// DFG: v[[TEST_BR:.*]] [{{.*}}label = "{{.*}}test.br
// DFG: }
// DFG: subgraph {{.*}} {
// DFG: }
// DFG: }
-// DFG: v[[TEST_RET:.*]] [{{.*}}label = "test.return
-// DFG: v[[ARG0]] -> v[[TEST_BR]]
-// DFG: v[[CONST10]] -> v[[TEST_BR]]
-// DFG: v[[ANCHOR]] -> v[[TEST_RET]] [ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
-// DFG: v[[ANCHOR]] -> v[[TEST_RET]] [ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
+// DFG: v[[TEST_RET:.*]] [{{.*}}label = "{{.*}}test.return
+// DFG: v[[ARG0]]:res_arg0:s -> v[[TEST_BR]]:arg_arg0:n
+// DFG: v[[CONST10]]:res_c10_i32:s -> v[[TEST_BR]]
+// DFG: v[[ANCHOR]]:res_1_0:s -> v[[TEST_RET]]:arg_1_0:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
+// DFG: v[[ANCHOR]]:res_1_1:s -> v[[TEST_RET]]:arg_1_1:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
// CFG-LABEL: digraph G {
// CFG: subgraph {{.*}} {
// CFG: subgraph {{.*}}
// CFG: label = "func.func{{.*}}merge_blocks
// CFG: subgraph {{.*}} {
-// CFG: v[[C1:.*]] [{{.*}}label = "arith.constant
-// CFG: v[[C2:.*]] [{{.*}}label = "arith.constant
-// CFG: v[[C3:.*]] [{{.*}}label = "arith.constant
-// CFG: v[[C4:.*]] [{{.*}}label = "arith.constant
-// CFG: v[[TEST_FUNC:.*]] [{{.*}}label = "test.func
+// CFG: v[[C1:.*]] [{{.*}}label = "{arith.constant
+// CFG: v[[C2:.*]] [{{.*}}label = "{arith.constant
+// CFG: v[[C3:.*]] [{{.*}}label = "{arith.constant
+// CFG: v[[C4:.*]] [{{.*}}label = "{arith.constant
+// CFG: v[[TEST_FUNC:.*]] [{{.*}}label = "{test.func
// CFG: subgraph [[CLUSTER_MERGE_BLOCKS:.*]] {
// CFG: v[[ANCHOR:.*]] [label = " ", shape = plain]
// CFG: label = "test.merge_blocks
// CFG: subgraph {{.*}} {
-// CFG: v[[TEST_BR:.*]] [{{.*}}label = "test.br
+// CFG: v[[TEST_BR:.*]] [{{.*}}label = "{{.*}}test.br
// CFG: }
// CFG: subgraph {{.*}} {
// CFG: }
// CFG: }
-// CFG: v[[TEST_RET:.*]] [{{.*}}label = "test.return
+// CFG: v[[TEST_RET:.*]] [{{.*}}label = "{{.*}}test.return
// CFG: v[[C1]] -> v[[C2]]
// CFG: v[[C2]] -> v[[C3]]
// CFG: v[[C3]] -> v[[C4]]
// CFG: v[[C4]] -> v[[TEST_FUNC]]
-// CFG: v[[TEST_FUNC]] -> v[[ANCHOR]] [lhead = [[CLUSTER_MERGE_BLOCKS]], style = dashed];
-// CFG: v[[ANCHOR]] -> v[[TEST_RET]] [ltail = [[CLUSTER_MERGE_BLOCKS]], style = dashed];
+// CFG: v[[TEST_FUNC]] -> v[[ANCHOR]][lhead = [[CLUSTER_MERGE_BLOCKS]], style = dashed];
+// CFG: v[[ANCHOR]] -> v[[TEST_RET]][ltail = [[CLUSTER_MERGE_BLOCKS]], style = dashed];
func.func @merge_blocks(%arg0: i32, %arg1 : i32) -> () {
%0 = arith.constant dense<[[0, 1], [2, 3]]> : tensor<2x2xi32>
>From 47b9ae60ca021866bfa209a1e147e1c5fef3eb20 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Tue, 4 Feb 2025 10:26:12 -0500
Subject: [PATCH 19/24] Uniquely identify input and output ports.
Turns out we can use the same value in both input and result slots
of an MLIR operation.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index c11255e22cc9575..d6dfea1db546b90 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -248,12 +248,12 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
os << "v" << n1.id;
if (!port.empty())
// Attach edge to south compass point of the result
- os << ":" << port << ":s";
+ os << ":res" << port << ":s";
os << " -> ";
os << "v" << n2.id;
if (!port.empty())
// Attach edge to north compass point of the operand
- os << ":" << port << ":n";
+ os << ":arg" << port << ":n";
emitAttrList(os, attrs);
}));
}
@@ -330,7 +330,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
if (op->getNumOperands() > 0) {
os << "{";
auto operandToPort = [&](Value operand) {
- os << "<" << getValuePortName(operand) << "> ";
+ os << "<arg" << getValuePortName(operand) << "> ";
emitMlirOperand(os, operand);
};
interleave(op->getOperands(), os, operandToPort, "|");
@@ -353,7 +353,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
if (op->getNumResults() > 0) {
os << "|{";
auto resultToPort = [&](Value result) {
- os << "<" << getValuePortName(result) << "> ";
+ os << "<res" << getValuePortName(result) << "> ";
emitMlirOperand(os, result);
if (printResultTypes) {
os << " ";
@@ -371,7 +371,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// Generate a label for a block argument.
std::string getLabel(BlockArgument arg) {
return strFromOs([&](raw_ostream &os) {
- os << "<" << getValuePortName(arg) << "> ";
+ os << "<res" << getValuePortName(arg) << "> ";
arg.printAsOperand(os, OpPrintingFlags());
if (printResultTypes) {
os << " ";
>From 768d032e1ceeee33c3fbf2c8e4359a31e41af204 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Tue, 4 Feb 2025 11:39:33 -0500
Subject: [PATCH 20/24] Fix escaping of some attributes.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index d6dfea1db546b90..e6d3fc3e414656a 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -194,7 +194,8 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
// Always emit splat attributes.
if (isa<SplatElementsAttr>(attr)) {
- attr.print(os);
+ os << escapeLabelString(
+ strFromOs([&](raw_ostream &os) { attr.print(os); }));
return;
}
@@ -202,8 +203,8 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
auto elements = dyn_cast<ElementsAttr>(attr);
if (elements && elements.getNumElements() > largeAttrLimit) {
os << std::string(elements.getShapedType().getRank(), '[') << "..."
- << std::string(elements.getShapedType().getRank(), ']') << " : "
- << elements.getType();
+ << std::string(elements.getShapedType().getRank(), ']') << " : ";
+ emitMlirType(os, elements.getType());
return;
}
@@ -313,7 +314,7 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
if (printAttrs) {
os << "\\l";
for (const NamedAttribute &attr : op->getAttrs()) {
- os << attr.getName().getValue() << ": ";
+ os << escapeLabelString(attr.getName().getValue().str()) << ": ";
emitMlirAttr(os, attr.getValue());
os << "\\l";
}
>From 35806adde44b96cd15e96cfacc40bbcde9a53d66 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Tue, 4 Feb 2025 11:46:57 -0500
Subject: [PATCH 21/24] Don't use ports when edges attach to clusters.
---
mlir/lib/Transforms/ViewOpGraph.cpp | 4 ++--
mlir/test/Transforms/print-op-graph-cycles.mlir | 2 +-
mlir/test/Transforms/print-op-graph.mlir | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index e6d3fc3e414656a..2d274a00d078ed3 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -247,12 +247,12 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
edges.push_back(strFromOs([&](raw_ostream &os) {
os << "v" << n1.id;
- if (!port.empty())
+ if (!port.empty() && !n1.clusterId)
// Attach edge to south compass point of the result
os << ":res" << port << ":s";
os << " -> ";
os << "v" << n2.id;
- if (!port.empty())
+ if (!port.empty() && !n2.clusterId)
// Attach edge to north compass point of the operand
os << ":arg" << port << ":n";
emitAttrList(os, attrs);
diff --git a/mlir/test/Transforms/print-op-graph-cycles.mlir b/mlir/test/Transforms/print-op-graph-cycles.mlir
index 760867802753b08..4058078fc8f0269 100644
--- a/mlir/test/Transforms/print-op-graph-cycles.mlir
+++ b/mlir/test/Transforms/print-op-graph-cycles.mlir
@@ -33,7 +33,7 @@
// DFG: v9:res_0:s -> v9:arg_0:n[style = solid];
// DFG: v15:res_2:s -> v9:arg_2:n[style = solid];
// DFG: v9:res_0:s -> v14:arg_0:n[style = solid];
-// DFG: v11:res_1:s -> v14:arg_1:n[ltail = cluster_10, style = solid];
+// DFG: v11 -> v14:arg_1:n[ltail = cluster_10, style = solid];
// DFG: v15:res_2:s -> v14:arg_2:n[style = solid];
// DFG: v16:res_3:s -> v14:arg_3:n[style = solid];
// DFG: v9:res_0:s -> v15:arg_0:n[style = solid];
diff --git a/mlir/test/Transforms/print-op-graph.mlir b/mlir/test/Transforms/print-op-graph.mlir
index 430ed6299c89c3f..440b037d780921b 100644
--- a/mlir/test/Transforms/print-op-graph.mlir
+++ b/mlir/test/Transforms/print-op-graph.mlir
@@ -20,8 +20,8 @@
// DFG: v[[TEST_RET:.*]] [{{.*}}label = "{{.*}}test.return
// DFG: v[[ARG0]]:res_arg0:s -> v[[TEST_BR]]:arg_arg0:n
// DFG: v[[CONST10]]:res_c10_i32:s -> v[[TEST_BR]]
-// DFG: v[[ANCHOR]]:res_1_0:s -> v[[TEST_RET]]:arg_1_0:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
-// DFG: v[[ANCHOR]]:res_1_1:s -> v[[TEST_RET]]:arg_1_1:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
+// DFG: v[[ANCHOR]] -> v[[TEST_RET]]:arg_1_0:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
+// DFG: v[[ANCHOR]] -> v[[TEST_RET]]:arg_1_1:n[ltail = [[CLUSTER_MERGE_BLOCKS]], style = solid];
// CFG-LABEL: digraph G {
// CFG: subgraph {{.*}} {
>From 5bc34e795db4a53c894702f4f9f9a8fa53649449 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Tue, 4 Feb 2025 13:01:12 -0500
Subject: [PATCH 22/24] Drop one-line braces for style
---
mlir/lib/Transforms/ViewOpGraph.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index 2d274a00d078ed3..b53be32f2f6a3e9 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -385,9 +385,8 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// operation inside the cluster.
void processBlock(Block &block) {
emitClusterStmt([&]() {
- for (BlockArgument &blockArg : block.getArguments()) {
+ for (BlockArgument &blockArg : block.getArguments())
valueToNode[blockArg] = emitNodeStmt(getLabel(blockArg));
- }
// Emit a node for each operation.
std::optional<Node> prevNode;
for (Operation &op : block) {
>From 78a8188d259507ae510ba14eed768de354cc8913 Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Wed, 5 Feb 2025 12:57:56 -0500
Subject: [PATCH 23/24] Review feedback: use llvm::is_contained
---
mlir/lib/Transforms/ViewOpGraph.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index b53be32f2f6a3e9..75ee3ed74db5edf 100644
--- a/mlir/lib/Transforms/ViewOpGraph.cpp
+++ b/mlir/lib/Transforms/ViewOpGraph.cpp
@@ -14,6 +14,7 @@
#include "mlir/IR/Operation.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/IndentedOstream.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/GraphWriter.h"
#include <map>
@@ -60,11 +61,9 @@ static std::string quoteString(const std::string &str) {
std::string escapeLabelString(const std::string &str) {
std::string buf;
llvm::raw_string_ostream os(buf);
- llvm::DenseSet<char> shouldEscape = {'{', '|', '<', '}', '>', '\n', '"'};
for (char c : str) {
- if (shouldEscape.contains(c)) {
+ if (llvm::is_contained({'{', '|', '<', '}', '>', '\n', '"'}, c))
os << '\\';
- }
os << c;
}
return buf;
>From 7a2f24a7493d00db258eb363f10fc2344e00539e Mon Sep 17 00:00:00 2001
From: Eric Hein <ehein at modular.com>
Date: Thu, 6 Feb 2025 12:33:26 -0500
Subject: [PATCH 24/24] Use CHECK-NEXT for tests with exact output
---
.../Transforms/print-op-graph-back-edges.mlir | 30 +++----
.../Transforms/print-op-graph-cycles.mlir | 78 +++++++++----------
2 files changed, 54 insertions(+), 54 deletions(-)
diff --git a/mlir/test/Transforms/print-op-graph-back-edges.mlir b/mlir/test/Transforms/print-op-graph-back-edges.mlir
index 71eda7f1b1be22c..7950125e2f73546 100644
--- a/mlir/test/Transforms/print-op-graph-back-edges.mlir
+++ b/mlir/test/Transforms/print-op-graph-back-edges.mlir
@@ -1,21 +1,21 @@
// RUN: mlir-opt -view-op-graph %s -o %t 2>&1 | FileCheck -check-prefix=DFG %s
// DFG-LABEL: digraph G {
-// DFG: compound = true;
-// DFG: subgraph cluster_1 {
-// DFG: v2 [label = " ", shape = plain];
-// DFG: label = "builtin.module : ()\l";
-// DFG: subgraph cluster_3 {
-// DFG: v4 [label = " ", shape = plain];
-// DFG: label = "";
-// DFG: v5 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_c0> %c0|<arg_c1> %c1}|arith.addi\l\loverflowFlags: #arith.overflow\<none...\l|{<res_0> %0 index}}", shape = Mrecord, style = filled];
-// DFG: v6 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 0 : index\l|{<res_c0> %c0 index}}", shape = Mrecord, style = filled];
-// DFG: v7 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 1 : index\l|{<res_c1> %c1 index}}", shape = Mrecord, style = filled];
-// DFG: }
-// DFG: }
-// DFG: v6:res_c0:s -> v5:arg_c0:n[style = solid];
-// DFG: v7:res_c1:s -> v5:arg_c1:n[style = solid];
-// DFG: }
+// DFG-NEXT: compound = true;
+// DFG-NEXT: subgraph cluster_1 {
+// DFG-NEXT: v2 [label = " ", shape = plain];
+// DFG-NEXT: label = "builtin.module : ()\l";
+// DFG-NEXT: subgraph cluster_3 {
+// DFG-NEXT: v4 [label = " ", shape = plain];
+// DFG-NEXT: label = "";
+// DFG-NEXT: v5 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_c0> %c0|<arg_c1> %c1}|arith.addi\l\loverflowFlags: #arith.overflow\<none...\l|{<res_0> %0 index}}", shape = Mrecord, style = filled];
+// DFG-NEXT: v6 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 0 : index\l|{<res_c0> %c0 index}}", shape = Mrecord, style = filled];
+// DFG-NEXT: v7 [fillcolor = "0.333333 0.3 0.95", label = "{arith.constant\l\lvalue: 1 : index\l|{<res_c1> %c1 index}}", shape = Mrecord, style = filled];
+// DFG-NEXT: }
+// DFG-NEXT: }
+// DFG-NEXT: v6:res_c0:s -> v5:arg_c0:n[style = solid];
+// DFG-NEXT: v7:res_c1:s -> v5:arg_c1:n[style = solid];
+// DFG-NEXT: }
module {
%add = arith.addi %c0, %c1 : index
diff --git a/mlir/test/Transforms/print-op-graph-cycles.mlir b/mlir/test/Transforms/print-op-graph-cycles.mlir
index 4058078fc8f0269..ba989544419f33b 100644
--- a/mlir/test/Transforms/print-op-graph-cycles.mlir
+++ b/mlir/test/Transforms/print-op-graph-cycles.mlir
@@ -1,45 +1,45 @@
// RUN: mlir-opt -view-op-graph -allow-unregistered-dialect %s -o %t 2>&1 | FileCheck -check-prefix=DFG %s
// DFG-LABEL: digraph G {
-// DFG: compound = true;
-// DFG: subgraph cluster_1 {
-// DFG: v2 [label = " ", shape = plain];
-// DFG: label = "builtin.module : ()\l";
-// DFG: subgraph cluster_3 {
-// DFG: v4 [label = " ", shape = plain];
-// DFG: label = "";
-// DFG: subgraph cluster_5 {
-// DFG: v6 [label = " ", shape = plain];
-// DFG: label = "test.graph_region : ()\l";
-// DFG: subgraph cluster_7 {
-// DFG: v8 [label = " ", shape = plain];
-// DFG: label = "";
-// DFG: v9 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_2> %2}|op1\l|{<res_0> %0 i32}}", shape = Mrecord, style = filled];
-// DFG: subgraph cluster_10 {
-// DFG: v11 [label = " ", shape = plain];
-// DFG: label = "test.ssacfg_region : (i32)\l";
-// DFG: subgraph cluster_12 {
-// DFG: v13 [label = " ", shape = plain];
-// DFG: label = "";
-// DFG: v14 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_1> %1|<arg_2> %2|<arg_3> %3}|op2\l|{<res_4> %4 i32}}", shape = Mrecord, style = filled];
-// DFG: }
-// DFG: }
-// DFG: v15 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_3> %3}|op2\l|{<res_2> %2 i32}}", shape = Mrecord, style = filled];
-// DFG: v16 [fillcolor = "0.500000 0.3 0.95", label = "{{\{\{}}<arg_0> %0}|op3\l|{<res_3> %3 i32}}", shape = Mrecord, style = filled];
-// DFG: }
-// DFG: }
-// DFG: }
-// DFG: }
-// DFG: v9:res_0:s -> v9:arg_0:n[style = solid];
-// DFG: v15:res_2:s -> v9:arg_2:n[style = solid];
-// DFG: v9:res_0:s -> v14:arg_0:n[style = solid];
-// DFG: v11 -> v14:arg_1:n[ltail = cluster_10, style = solid];
-// DFG: v15:res_2:s -> v14:arg_2:n[style = solid];
-// DFG: v16:res_3:s -> v14:arg_3:n[style = solid];
-// DFG: v9:res_0:s -> v15:arg_0:n[style = solid];
-// DFG: v16:res_3:s -> v15:arg_3:n[style = solid];
-// DFG: v9:res_0:s -> v16:arg_0:n[style = solid];
-// DFG: }
+// DFG-NEXT: compound = true;
+// DFG-NEXT: subgraph cluster_1 {
+// DFG-NEXT: v2 [label = " ", shape = plain];
+// DFG-NEXT: label = "builtin.module : ()\l";
+// DFG-NEXT: subgraph cluster_3 {
+// DFG-NEXT: v4 [label = " ", shape = plain];
+// DFG-NEXT: label = "";
+// DFG-NEXT: subgraph cluster_5 {
+// DFG-NEXT: v6 [label = " ", shape = plain];
+// DFG-NEXT: label = "test.graph_region : ()\l";
+// DFG-NEXT: subgraph cluster_7 {
+// DFG-NEXT: v8 [label = " ", shape = plain];
+// DFG-NEXT: label = "";
+// DFG-NEXT: v9 [fillcolor = "0.000000 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_2> %2}|op1\l|{<res_0> %0 i32}}", shape = Mrecord, style = filled];
+// DFG-NEXT: subgraph cluster_10 {
+// DFG-NEXT: v11 [label = " ", shape = plain];
+// DFG-NEXT: label = "test.ssacfg_region : (i32)\l";
+// DFG-NEXT: subgraph cluster_12 {
+// DFG-NEXT: v13 [label = " ", shape = plain];
+// DFG-NEXT: label = "";
+// DFG-NEXT: v14 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_1> %1|<arg_2> %2|<arg_3> %3}|op2\l|{<res_4> %4 i32}}", shape = Mrecord, style = filled];
+// DFG-NEXT: }
+// DFG-NEXT: }
+// DFG-NEXT: v15 [fillcolor = "0.166667 0.3 0.95", label = "{{\{\{}}<arg_0> %0|<arg_3> %3}|op2\l|{<res_2> %2 i32}}", shape = Mrecord, style = filled];
+// DFG-NEXT: v16 [fillcolor = "0.500000 0.3 0.95", label = "{{\{\{}}<arg_0> %0}|op3\l|{<res_3> %3 i32}}", shape = Mrecord, style = filled];
+// DFG-NEXT: }
+// DFG-NEXT: }
+// DFG-NEXT: }
+// DFG-NEXT: }
+// DFG-NEXT: v9:res_0:s -> v9:arg_0:n[style = solid];
+// DFG-NEXT: v15:res_2:s -> v9:arg_2:n[style = solid];
+// DFG-NEXT: v9:res_0:s -> v14:arg_0:n[style = solid];
+// DFG-NEXT: v11 -> v14:arg_1:n[ltail = cluster_10, style = solid];
+// DFG-NEXT: v15:res_2:s -> v14:arg_2:n[style = solid];
+// DFG-NEXT: v16:res_3:s -> v14:arg_3:n[style = solid];
+// DFG-NEXT: v9:res_0:s -> v15:arg_0:n[style = solid];
+// DFG-NEXT: v16:res_3:s -> v15:arg_3:n[style = solid];
+// DFG-NEXT: v9:res_0:s -> v16:arg_0:n[style = solid];
+// DFG-NEXT: }
"test.graph_region"() ({ // A Graph region
%1 = "op1"(%1, %3) : (i32, i32) -> (i32) // OK: %1, %3 allowed here
More information about the Mlir-commits
mailing list