16#include "llvm/ADT/STLExtras.h"
17#include "llvm/Support/Format.h"
18#include "llvm/Support/GraphWriter.h"
24#define GEN_PASS_DEF_VIEWOPGRAPHPASS
25#include "mlir/Transforms/Passes.h.inc"
38 if (std::optional<int64_t> limit =
47 llvm::raw_string_ostream os(buf);
54 return "\"" + str +
"\"";
62 llvm::raw_string_ostream os(buf);
64 if (llvm::is_contained({
'{',
'|',
'<',
'}',
'>',
'\n',
'"'}, c))
84 Node(
int id = 0, std::optional<int> clusterId = std::nullopt)
85 : id(
id), clusterId(clusterId) {}
88 std::optional<int> clusterId;
102 PrintOpPass() : os(llvm::errs()) {}
107 PrintOpPass(
const PrintOpPass &o) : PrintOpPass(o.os.
getOStream()) {}
109 void runOnOperation()
override {
110 initColorMapping(*getOperation());
112 processOperation(getOperation());
115 markAllAnalysesPreserved();
119 void emitRegionCFG(
Region ®ion) {
120 printControlFlowEdges =
true;
121 printDataFlowEdges =
false;
122 initColorMapping(region);
123 emitGraph([&]() { processRegion(region); });
130 template <
typename T>
131 void initColorMapping(T &irEntity) {
132 backgroundColors.clear();
135 auto &entry = backgroundColors[op->
getName()];
136 if (entry.first == 0)
140 for (
auto indexedOps : llvm::enumerate(ops)) {
141 double hue = ((double)indexedOps.index()) / ops.size();
144 backgroundColors[indexedOps.value()->getName()].second =
145 std::to_string(hue) +
" 0.3 0.95";
151 void emitAllEdgeStmts() {
152 if (printDataFlowEdges) {
153 for (
const auto &e : dataFlowEdges) {
158 for (
const std::string &edge : edges)
166 const std::string &label =
"") {
167 int clusterId = ++counter;
168 os <<
"subgraph cluster_" << clusterId <<
" {\n";
171 Node anchorNode = emitNodeStmt(
" ",
kShapeNone);
172 os << attrStmt(
"label",
quoteString(label)) <<
";\n";
176 return Node(anchorNode.id, clusterId);
180 std::string attrStmt(
const Twine &key,
const Twine &value) {
181 return (key +
" = " + value).str();
187 interleaveComma(map, os, [&](
const auto &it) {
188 os << this->attrStmt(it.first, it.second);
199 if (isa<SplatElementsAttr>(attr)) {
206 auto elements = dyn_cast<ElementsAttr>(attr);
207 if (elements && elements.getNumElements() > largeAttrLimit) {
208 os << std::string(elements.getShapedType().getRank(),
'[') <<
"..."
209 << std::string(elements.getShapedType().getRank(),
']') <<
" : ";
210 emitMlirType(os, elements.getType());
214 auto array = dyn_cast<ArrayAttr>(attr);
215 if (array &&
static_cast<int64_t>(array.size()) > largeAttrLimit) {
222 llvm::raw_string_ostream ss(buf);
230 llvm::raw_string_ostream ss(buf);
242 void emitEdgeStmt(Node n1, Node n2, std::string port, StringRef style) {
244 attrs[
"style"] = style.str();
247 attrs[
"ltail"] =
"cluster_" + std::to_string(*n1.clusterId);
249 attrs[
"lhead"] =
"cluster_" + std::to_string(*n2.clusterId);
253 if (!port.empty() && !n1.clusterId)
255 os <<
":res" << port <<
":s";
258 if (!port.empty() && !n2.clusterId)
260 os <<
":arg" << port <<
":n";
261 emitAttrList(os, attrs);
267 os <<
"digraph G {\n";
270 os << attrStmt(
"compound",
"true") <<
";\n";
277 Node emitNodeStmt(
const std::string &label, StringRef
shape =
kShapeNode,
278 StringRef background =
"") {
279 int nodeId = ++counter;
282 attrs[
"shape"] =
shape.str();
283 if (!background.empty()) {
284 attrs[
"style"] =
"filled";
285 attrs[
"fillcolor"] =
quoteString(background.str());
287 os << llvm::format(
"v%i ", nodeId);
288 emitAttrList(os, attrs);
293 std::string getValuePortName(
Value operand) {
299 llvm::replace(str,
'%',
'_');
300 llvm::replace(str,
'#',
'_');
304 std::string getClusterLabel(
Operation *op) {
308 if (printResultTypes) {
311 llvm::raw_string_ostream ss(buf);
313 os << truncateString(buf) <<
")";
321 emitMlirAttr(os, attr.getValue());
329 std::string getRecordLabel(
Operation *op) {
336 auto operandToPort = [&](
Value operand) {
337 os <<
"<arg" << getValuePortName(operand) <<
"> ";
338 emitMlirOperand(os, operand);
340 interleave(op->
getOperands(), os, operandToPort,
"|");
347 if (printAttrs && !op->
getAttrs().empty()) {
351 os << attr.getName().getValue() <<
": ";
352 emitMlirAttr(os, attr.getValue());
360 os <<
"<res" << getValuePortName(
result) <<
"> ";
361 emitMlirOperand(os,
result);
362 if (printResultTypes) {
364 emitMlirType(os,
result.getType());
367 interleave(op->
getResults(), os, resultToPort,
"|");
378 os <<
"<res" << getValuePortName(arg) <<
"> ";
380 if (printResultTypes) {
382 emitMlirType(os, arg.
getType());
389 void processBlock(
Block &block) {
390 emitClusterStmt([&]() {
392 valueToNode[blockArg] = emitNodeStmt(getLabel(blockArg));
394 std::optional<Node> prevNode;
396 Node nextNode = processOperation(&op);
397 if (printControlFlowEdges && prevNode)
410 node = emitClusterStmt(
413 processRegion(region);
415 getClusterLabel(op));
417 node = emitNodeStmt(getRecordLabel(op),
kShapeNode,
418 backgroundColors[op->
getName()].second);
422 if (printDataFlowEdges) {
424 for (
unsigned i = 0; i < numOperands; i++) {
426 dataFlowEdges.push_back({operand, node, getValuePortName(operand)});
431 valueToNode[
result] = node;
437 void processRegion(
Region ®ion) {
443 std::string truncateString(std::string str) {
444 if (str.length() <= maxLabelLen)
446 return str.substr(0, maxLabelLen) +
"...";
453 std::vector<std::string> edges;
457 std::vector<DataFlowEdge> dataFlowEdges;
467 return std::make_unique<PrintOpPass>(os);
473 std::string filename = llvm::createGraphFilename(name.str(), fd);
475 llvm::raw_fd_ostream os(fd,
true);
477 llvm::errs() <<
"error opening file '" << filename <<
"' for writing\n";
480 PrintOpPass pass(os);
481 pass.emitRegionCFG(region);
483 llvm::DisplayGraph(filename,
false, llvm::GraphProgram::DOT);
MemRefDependenceGraph::Node Node
static llvm::ManagedStatic< PassManagerOptions > options
static std::string quoteString(const std::string &str)
Put quotation marks around a given string.
static std::string escapeLabelString(const std::string &str)
For Graphviz record nodes: " Braces, vertical bars and angle brackets must be escaped with a backslas...
static const StringRef kLineStyleDataFlow
static const StringRef kLineStyleControlFlow
static int64_t getLargeAttributeSizeLimit()
Return the size limits for eliding large attributes.
std::map< std::string, std::string > AttributeMap
static const StringRef kShapeNone
static const StringRef kShapeNode
static void llvmViewGraph(Region ®ion, const Twine &name)
Generate a CFG for a region and show it in a window.
static std::string strFromOs(function_ref< void(raw_ostream &)> func)
Return all values printed onto a stream as a string.
Attributes are known-constant values of operations.
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgListType getArguments()
NamedAttribute represents a combination of a name and an Attribute value.
Set of flags used to control the behavior of the various IR print methods (e.g.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
unsigned getNumOperands()
OperationName getName()
The name of an operation is the key identifier for it.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
void viewGraph(const Twine ®ionName)
Displays the CFG in a window.
BlockListType & getBlocks()
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
void print(raw_ostream &os) const
Print the current type.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
raw_ostream subclass that simplifies indention a sequence of code.
raw_ostream & getOStream() const
Returns the underlying (unindented) raw_ostream.
Include the generated interface declarations.
std::unique_ptr<::mlir::Pass > createViewOpGraphPass()
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref