[Mlir-commits] [mlir] 1f67070 - [ViewOpGraph] Improve GraphViz output (#125509)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Feb 7 07:45:51 PST 2025
Author: Eric Hein
Date: 2025-02-07T10:45:47-05:00
New Revision: 1f67070a3f6ca8d0bf5fdca90ceb6b607422c899
URL: https://github.com/llvm/llvm-project/commit/1f67070a3f6ca8d0bf5fdca90ceb6b607422c899
DIFF: https://github.com/llvm/llvm-project/commit/1f67070a3f6ca8d0bf5fdca90ceb6b607422c899.diff
LOG: [ViewOpGraph] Improve GraphViz output (#125509)
This patch improves the GraphViz output of ViewOpGraph
(--view-op-graph).
- Switch to rectangular record-based nodes, inspired by a similar
visualization in [Glow](https://github.com/pytorch/glow). Rectangles
make more efficient use of space when printing text.
- Add input and output ports for each operand and result, and remove
edge labels.
- Switch to a muted color palette to reduce eye strain.
Added:
Modified:
mlir/lib/Transforms/ViewOpGraph.cpp
mlir/test/Transforms/print-op-graph-back-edges.mlir
mlir/test/Transforms/print-op-graph-cycles.mlir
mlir/test/Transforms/print-op-graph.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp
index fa0af7665ba4c4c..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>
@@ -29,7 +30,7 @@ using namespace mlir;
static const StringRef kLineStyleControlFlow = "dashed";
static const StringRef kLineStyleDataFlow = "solid";
-static const StringRef kShapeNode = "ellipse";
+static const StringRef kShapeNode = "Mrecord";
static const StringRef kShapeNone = "plain";
/// Return the size limits for eliding large attributes.
@@ -49,16 +50,25 @@ 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 + "\"";
}
+/// 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 "
+std::string escapeLabelString(const std::string &str) {
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ for (char c : str) {
+ if (llvm::is_contained({'{', '|', '<', '}', '>', '\n', '"'}, c))
+ os << '\\';
+ os << c;
+ }
+ return buf;
+}
+
using AttributeMap = std::map<std::string, std::string>;
namespace {
@@ -79,6 +89,12 @@ struct Node {
std::optional<int> clusterId;
};
+struct DataFlowEdge {
+ Value value;
+ Node node;
+ std::string port;
+};
+
/// 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.
@@ -107,7 +123,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();
@@ -120,8 +136,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";
}
}
@@ -129,8 +147,8 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
/// emitted.
void emitAllEdgeStmts() {
if (printDataFlowEdges) {
- for (const auto &[value, node, label] : dataFlowEdges) {
- emitEdgeStmt(valueToNode[value], node, label, kLineStyleDataFlow);
+ for (const auto &e : dataFlowEdges) {
+ emitEdgeStmt(valueToNode[e.value], e.node, e.port, kLineStyleDataFlow);
}
}
@@ -147,8 +165,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";
@@ -176,7 +193,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;
}
@@ -184,8 +202,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;
}
@@ -199,19 +217,27 @@ 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));
+ }
+
+ // 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 label, StringRef style) {
+ void emitEdgeStmt(Node n1, Node n2, std::string port, 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);
@@ -219,7 +245,15 @@ 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 (!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() && !n2.clusterId)
+ // Attach edge to north compass point of the operand
+ os << ":arg" << port << ":n";
emitAttrList(os, attrs);
}));
}
@@ -240,11 +274,11 @@ 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";
- attrs["fillcolor"] = ("\"" + background + "\"").str();
+ attrs["fillcolor"] = quoteString(background.str());
}
os << llvm::format("v%i ", nodeId);
emitAttrList(os, attrs);
@@ -252,8 +286,18 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
return Node(nodeId);
}
- /// Generate a label for an operation.
- std::string getLabel(Operation *op) {
+ 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());
+ });
+ // Replace % and # with _
+ std::replace(str.begin(), str.end(), '%', '_');
+ std::replace(str.begin(), str.end(), '#', '_');
+ return str;
+ }
+
+ std::string getClusterLabel(Operation *op) {
return strFromOs([&](raw_ostream &os) {
// Print operation name and type.
os << op->getName();
@@ -267,18 +311,73 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
// Print attributes.
if (printAttrs) {
- os << "\n";
+ os << "\\l";
+ for (const NamedAttribute &attr : op->getAttrs()) {
+ os << escapeLabelString(attr.getName().getValue().str()) << ": ";
+ emitMlirAttr(os, attr.getValue());
+ os << "\\l";
+ }
+ }
+ });
+ }
+
+ /// Generate a label for an operation.
+ std::string getRecordLabel(Operation *op) {
+ return strFromOs([&](raw_ostream &os) {
+ os << "{";
+
+ // Print operation inputs.
+ if (op->getNumOperands() > 0) {
+ os << "{";
+ auto operandToPort = [&](Value operand) {
+ os << "<arg" << getValuePortName(operand) << "> ";
+ emitMlirOperand(os, operand);
+ };
+ interleave(op->getOperands(), os, operandToPort, "|");
+ os << "}|";
+ }
+ // Print operation name and type.
+ os << op->getName() << "\\l";
+
+ // Print attributes.
+ if (printAttrs && !op->getAttrs().empty()) {
+ // 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";
}
}
+
+ if (op->getNumResults() > 0) {
+ os << "|{";
+ auto resultToPort = [&](Value result) {
+ os << "<res" << getValuePortName(result) << "> ";
+ emitMlirOperand(os, result);
+ if (printResultTypes) {
+ os << " ";
+ emitMlirType(os, result.getType());
+ }
+ };
+ interleave(op->getResults(), os, resultToPort, "|");
+ os << "}";
+ }
+
+ os << "}";
});
}
/// 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 << "<res" << getValuePortName(arg) << "> ";
+ arg.printAsOperand(os, OpPrintingFlags());
+ if (printResultTypes) {
+ os << " ";
+ emitMlirType(os, arg.getType());
+ }
+ });
}
/// Process a block. Emit a cluster and one node per block argument and
@@ -287,14 +386,12 @@ class PrintOpPass : public impl::ViewOpGraphBase<PrintOpPass> {
emitClusterStmt([&]() {
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, /*port=*/"", kLineStyleControlFlow);
prevNode = nextNode;
}
});
@@ -311,18 +408,19 @@ 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);
}
// 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);
+ dataFlowEdges.push_back({operand, node, getValuePortName(operand)});
+ }
}
for (Value result : op->getResults())
@@ -352,7 +450,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;
diff --git a/mlir/test/Transforms/print-op-graph-back-edges.mlir b/mlir/test/Transforms/print-op-graph-back-edges.mlir
index ed922dd7cb13bda..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 : ()\n";
-// 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: }
-// DFG: }
-// DFG: v6 -> v5 [label = "0", style = solid];
-// DFG: v7 -> v5 [label = "1", 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 7e4eb5616a28b39..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 : ()\n";
-// 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: 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: subgraph cluster_10 {
-// DFG: v11 [label = " ", shape = plain];
-// DFG: label = "test.ssacfg_region : (i32)\n";
-// 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: }
-// 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: }
-// 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: }
+// 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
diff --git a/mlir/test/Transforms/print-op-graph.mlir b/mlir/test/Transforms/print-op-graph.mlir
index df03194a663d95f..440b037d780921b 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]] -> 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 {{.*}} {
// 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>
More information about the Mlir-commits
mailing list