10 #include "PassDetail.h" 15 #include "llvm/Support/Format.h" 16 #include "llvm/Support/GraphWriter.h" 37 llvm::raw_string_ostream os(buf);
44 return strFromOs([&](raw_ostream &os) { os.write_escaped(str); });
49 return "\"" + str +
"\"";
66 : id(
id), clusterId(clusterId) {}
75 class PrintOpPass :
public ViewOpGraphBase<PrintOpPass> {
77 PrintOpPass(raw_ostream &os) : os(os) {}
78 PrintOpPass(
const PrintOpPass &o) : PrintOpPass(o.os.getOStream()) {}
80 void runOnOperation()
override {
82 processOperation(getOperation());
88 void emitRegionCFG(
Region ®ion) {
89 printControlFlowEdges =
true;
90 printDataFlowEdges =
false;
91 emitGraph([&]() { processRegion(region); });
97 void emitAllEdgeStmts() {
98 for (
const std::string &edge : edges)
105 Node emitClusterStmt(
function_ref<
void()> builder, std::string label =
"") {
106 int clusterId = ++counter;
107 os <<
"subgraph cluster_" << clusterId <<
" {\n";
110 Node anchorNode = emitNodeStmt(
" ",
kShapeNone);
116 return Node(anchorNode.id, clusterId);
120 std::string attrStmt(
const Twine &key,
const Twine &
value) {
121 return (key +
" = " + value).str();
125 void emitAttrList(raw_ostream &os,
const AttributeMap &map) {
127 interleaveComma(map, os, [&](
const auto &it) {
128 os << this->attrStmt(it.getKey(), it.getValue());
134 void emitMlirAttr(raw_ostream &os,
Attribute attr) {
145 auto elements = attr.
dyn_cast<ElementsAttr>();
146 if (elements && elements.getNumElements() > largeAttrLimit) {
147 os << std::string(elements.getType().getRank(),
'[') <<
"..." 148 << std::string(elements.getType().getRank(),
']') <<
" : " 149 << elements.getType();
153 auto array = attr.
dyn_cast<ArrayAttr>();
154 if (array && static_cast<int64_t>(array.size()) > largeAttrLimit) {
161 llvm::raw_string_ostream ss(buf);
163 os << truncateString(ss.str());
168 void emitEdgeStmt(Node n1, Node n2, std::string label, StringRef style) {
170 attrs[
"style"] = style.str();
174 if (!n1.clusterId && !n2.clusterId)
178 attrs[
"ltail"] =
"cluster_" + std::to_string(*n1.clusterId);
180 attrs[
"lhead"] =
"cluster_" + std::to_string(*n2.clusterId);
182 edges.push_back(
strFromOs([&](raw_ostream &os) {
183 os << llvm::format(
"v%i -> v%i ", n1.id, n2.id);
184 emitAttrList(os, attrs);
190 os <<
"digraph G {\n";
193 os << attrStmt(
"compound",
"true") <<
";\n";
200 Node emitNodeStmt(std::string label, StringRef shape =
kShapeNode) {
201 int nodeId = ++counter;
204 attrs[
"shape"] = shape.str();
205 os << llvm::format(
"v%i ", nodeId);
206 emitAttrList(os, attrs);
216 if (printResultTypes) {
219 llvm::raw_string_ostream ss(buf);
221 os << truncateString(ss.str()) <<
")";
229 os <<
'\n' << attr.getName().getValue() <<
": ";
230 emitMlirAttr(os, attr.getValue());
243 void processBlock(
Block &block) {
244 emitClusterStmt([&]() {
246 valueToNode[blockArg] = emitNodeStmt(getLabel(blockArg));
251 Node nextNode = processOperation(&op);
252 if (printControlFlowEdges && prevNode)
253 emitEdgeStmt(*prevNode, nextNode,
"",
266 node = emitClusterStmt(
269 processRegion(region);
273 node = emitNodeStmt(getLabel(op));
277 if (printDataFlowEdges) {
279 for (
unsigned i = 0; i < numOperands; i++)
280 emitEdgeStmt(valueToNode[op->
getOperand(i)], node,
281 numOperands == 1 ?
"" : std::to_string(i),
286 valueToNode[result] = node;
292 void processRegion(
Region ®ion) {
298 std::string truncateString(std::string str) {
299 if (str.length() <= maxLabelLen)
301 return str.substr(0, maxLabelLen) +
"...";
308 std::vector<std::string> edges;
318 return std::make_unique<PrintOpPass>(os);
324 std::string filename = llvm::createGraphFilename(name.str(), fd);
326 llvm::raw_fd_ostream os(fd,
true);
328 llvm::errs() <<
"error opening file '" << filename <<
"' for writing\n";
331 PrintOpPass pass(os);
332 pass.emitRegionCFG(region);
334 llvm::DisplayGraph(filename,
false, llvm::GraphProgram::DOT);
Include the generated interface declarations.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
static void llvmViewGraph(Region ®ion, const Twine &name)
Generate a CFG for a region and show it in a window.
Operation is a basic unit of execution within MLIR.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
BlockListType & getBlocks()
unsigned getNumRegions()
Returns the number of regions held by this operation.
std::unique_ptr< Pass > createPrintOpGraphPass(raw_ostream &os=llvm::errs())
Creates a pass to print op graphs.
Block represents an ordered list of Operations.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Value getOperand(unsigned idx)
static std::string strFromOs(function_ref< void(raw_ostream &)> func)
Return all values printed onto a stream as a string.
unsigned getNumOperands()
unsigned getArgNumber() const
Returns the number of this argument.
static constexpr const bool value
NamedAttribute represents a combination of a name and an Attribute value.
Attributes are known-constant values of operations.
static const StringRef kShapeNone
static int64_t getLargeAttributeSizeLimit()
Return the size limits for eliding large attributes.
BlockArgListType getArguments()
This class represents an argument of a Block.
void print(raw_ostream &os) const
Print the attribute.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
An attribute that represents a reference to a splat vector or tensor constant, meaning all of the ele...
Set of flags used to control the behavior of the various IR print methods (e.g.
llvm::StringMap< std::string > AttributeMap
static std::string escapeString(std::string str)
Escape special characters such as ' ' and quotation marks.
static const StringRef kLineStyleDataFlow
OperationName getName()
The name of an operation is the key identifier for it.
static const StringRef kLineStyleControlFlow
raw_ostream subclass that simplifies indention a sequence of code.
result_range getResults()
result_type_range getResultTypes()
static std::string quoteString(const std::string &str)
Put quotation marks around a given string.
static const StringRef kShapeNode