blob: 27ed3e4421d077a6c59682c843e40ffcbf790e29 [file] [log] [blame]
Chris Lattner4c95a502018-06-23 16:03:42 -07001//===- AsmPrinter.cpp - MLIR Assembly Printer Implementation --------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the MLIR AsmPrinter class, which is used to implement
19// the various print() methods on the core IR objects.
20//
21//===----------------------------------------------------------------------===//
22
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070023#include "mlir/IR/AffineExpr.h"
24#include "mlir/IR/AffineMap.h"
Chris Lattner7121b802018-07-04 20:45:39 -070025#include "mlir/IR/Attributes.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070026#include "mlir/IR/CFGFunction.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070027#include "mlir/IR/MLFunction.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070028#include "mlir/IR/Module.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070029#include "mlir/IR/OperationSet.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070030#include "mlir/IR/Types.h"
31#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070032#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070033#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070034using namespace mlir;
35
36
Chris Lattner7121b802018-07-04 20:45:39 -070037void Identifier::print(raw_ostream &os) const {
38 os << str();
39}
40
41void Identifier::dump() const {
42 print(llvm::errs());
43}
44
Chris Lattner4c95a502018-06-23 16:03:42 -070045//===----------------------------------------------------------------------===//
46// Function printing
47//===----------------------------------------------------------------------===//
48
49static void printFunctionSignature(const Function *fn, raw_ostream &os) {
50 auto type = fn->getType();
51
52 os << "@" << fn->getName() << '(';
53 interleave(type->getInputs(),
54 [&](Type *eltType) { os << *eltType; },
55 [&]() { os << ", "; });
56 os << ')';
57
58 switch (type->getResults().size()) {
59 case 0: break;
60 case 1:
61 os << " -> " << *type->getResults()[0];
62 break;
63 default:
64 os << " -> (";
65 interleave(type->getResults(),
66 [&](Type *eltType) { os << *eltType; },
67 [&]() { os << ", "; });
68 os << ')';
69 break;
70 }
71}
72
73void ExtFunction::print(raw_ostream &os) const {
74 os << "extfunc ";
75 printFunctionSignature(this, os);
76 os << "\n";
77}
78
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -070079namespace {
80
81// FunctionState contains common functionality for printing
82// CFG and ML functions.
83class FunctionState {
84public:
85 FunctionState(MLIRContext *context, raw_ostream &os);
86
87 void printOperation(const Operation *op);
88
89protected:
90 raw_ostream &os;
91 const OperationSet &operationSet;
92};
93} // end anonymous namespace
94
95FunctionState::FunctionState(MLIRContext *context, raw_ostream &os)
96 : os(os), operationSet(OperationSet::get(context)) {}
97
98void FunctionState::printOperation(const Operation *op) {
99 // Check to see if this is a known operation. If so, use the registered
100 // custom printer hook.
101 if (auto opInfo = operationSet.lookup(op->getName().str())) {
102 os << " ";
103 opInfo->printAssembly(op, os);
104 return;
105 }
106
107 // TODO: escape name if necessary.
108 os << " \"" << op->getName().str() << "\"()";
109
110 auto attrs = op->getAttrs();
111 if (!attrs.empty()) {
112 os << '{';
113 interleave(
114 attrs,
115 [&](NamedAttribute attr) { os << attr.first << ": " << *attr.second; },
116 [&]() { os << ", "; });
117 os << '}';
118 }
119
120 os << '\n';
121}
122
Chris Lattner4c95a502018-06-23 16:03:42 -0700123//===----------------------------------------------------------------------===//
124// CFG Function printing
125//===----------------------------------------------------------------------===//
126
127namespace {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700128class CFGFunctionState : public FunctionState {
Chris Lattner4c95a502018-06-23 16:03:42 -0700129public:
130 CFGFunctionState(const CFGFunction *function, raw_ostream &os);
131
132 const CFGFunction *getFunction() const { return function; }
133
134 void print();
135 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700136
137 void print(const Instruction *inst);
138 void print(const OperationInst *inst);
139 void print(const ReturnInst *inst);
140 void print(const BranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700141
142 unsigned getBBID(const BasicBlock *block) {
143 auto it = basicBlockIDs.find(block);
144 assert(it != basicBlockIDs.end() && "Block not in this function?");
145 return it->second;
146 }
147
148private:
149 const CFGFunction *function;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700150 DenseMap<const BasicBlock*, unsigned> basicBlockIDs;
Chris Lattner4c95a502018-06-23 16:03:42 -0700151};
152} // end anonymous namespace
153
154CFGFunctionState::CFGFunctionState(const CFGFunction *function, raw_ostream &os)
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700155 : FunctionState(function->getContext(), os), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700156 // Each basic block gets a unique ID per function.
157 unsigned blockID = 0;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700158 for (auto &block : *function)
159 basicBlockIDs[&block] = blockID++;
Chris Lattner4c95a502018-06-23 16:03:42 -0700160}
161
162void CFGFunctionState::print() {
163 os << "cfgfunc ";
164 printFunctionSignature(this->getFunction(), os);
165 os << " {\n";
166
Chris Lattner3a467cc2018-07-01 20:28:00 -0700167 for (auto &block : *function)
168 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700169 os << "}\n\n";
170}
171
172void CFGFunctionState::print(const BasicBlock *block) {
173 os << "bb" << getBBID(block) << ":\n";
174
Chris Lattnered65a732018-06-28 20:45:33 -0700175 // TODO Print arguments.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700176 for (auto &inst : block->getOperations())
177 print(&inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700178
179 print(block->getTerminator());
180}
181
Chris Lattnered65a732018-06-28 20:45:33 -0700182void CFGFunctionState::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700183 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700184 case Instruction::Kind::Operation:
185 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700186 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700187 return print(cast<BranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700188 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700189 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700190 }
191}
192
Chris Lattnered65a732018-06-28 20:45:33 -0700193void CFGFunctionState::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700194 printOperation(inst);
Chris Lattnered65a732018-06-28 20:45:33 -0700195}
196
197void CFGFunctionState::print(const BranchInst *inst) {
198 os << " br bb" << getBBID(inst->getDest()) << "\n";
199}
200void CFGFunctionState::print(const ReturnInst *inst) {
201 os << " return\n";
202}
203
Chris Lattner4c95a502018-06-23 16:03:42 -0700204//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700205// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700206//===----------------------------------------------------------------------===//
207
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700208namespace {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700209class MLFunctionState : public FunctionState {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700210public:
211 MLFunctionState(const MLFunction *function, raw_ostream &os);
212
213 const MLFunction *getFunction() const { return function; }
214
215 void print();
216
217 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700218 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700219 void print(const ForStmt *stmt);
220 void print(const IfStmt *stmt);
221 void print(const ElseClause *stmt, bool isLast);
222
223private:
224 // Print statements nested within this node statement.
225 void printNestedStatements(const NodeStmt *stmt);
226
227 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700228 int numSpaces;
229};
230} // end anonymous namespace
231
232MLFunctionState::MLFunctionState(const MLFunction *function, raw_ostream &os)
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700233 : FunctionState(function->getContext(), os), function(function),
234 numSpaces(2) {}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700235
236void MLFunctionState::print() {
237 os << "mlfunc ";
238 // FIXME: should print argument names rather than just signature
239 printFunctionSignature(function, os);
240 os << " {\n";
241 for (auto *stmt : function->stmtList)
242 print(stmt);
243 os << " return\n";
244 os << "}\n\n";
245}
246
247void MLFunctionState::print(const Statement *stmt) {
248 os.indent(numSpaces);
249 switch (stmt->getKind()) {
250 case Statement::Kind::Operation: // TODO
Jacques Pienaar16916002018-07-07 15:48:05 -0700251 llvm_unreachable("Operation statement is not yet implemented");
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700252 case Statement::Kind::For:
253 return print(cast<ForStmt>(stmt));
254 case Statement::Kind::If:
255 return print(cast<IfStmt>(stmt));
256 case Statement::Kind::Else:
257 return print(cast<ElseClause>(stmt));
258 }
259}
260
261void MLFunctionState::printNestedStatements(const NodeStmt *stmt) {
262 os << "{\n";
263 numSpaces += 2;
264 for (auto * nestedStmt : stmt->children)
265 print(nestedStmt);
266 numSpaces -= 2;
267 os.indent(numSpaces) << "}";
268}
269
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700270void MLFunctionState::print(const OperationStmt *stmt) { printOperation(stmt); }
271
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700272void MLFunctionState::print(const ForStmt *stmt) {
273 os << "for ";
274 printNestedStatements(stmt);
275 os << "\n";
276}
277
278void MLFunctionState::print(const IfStmt *stmt) {
279 os << "if ";
280 printNestedStatements(stmt);
281
282 int numClauses = stmt->elseClauses.size();
283 for (auto e : stmt->elseClauses)
284 print(e, e->getClauseNumber() == numClauses - 1);
285 os << "\n";
286}
287
288void MLFunctionState::print(const ElseClause *stmt, bool isLast) {
289 if (!isLast)
290 os << " if";
291 os << " else ";;
292 printNestedStatements(stmt);
293}
294
295//===----------------------------------------------------------------------===//
296// print and dump methods
297//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700298
299void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700300 CFGFunctionState state(getFunction(), os);
301 state.print(this);
302}
303
Chris Lattnered65a732018-06-28 20:45:33 -0700304void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700305 print(llvm::errs());
306}
307
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700308void AffineMap::dump() const { print(llvm::errs()); }
309
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700310void AffineExpr::dump() const {
311 print(llvm::errs());
312 llvm::errs() << "\n";
313}
314
315void AffineAddExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700316 os << "(" << *getLHS() << " + " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700317}
318
319void AffineSubExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700320 os << "(" << *getLHS() << " - " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700321}
322
323void AffineMulExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700324 os << "(" << *getLHS() << " * " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700325}
326
327void AffineModExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700328 os << "(" << *getLHS() << " mod " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700329}
330
331void AffineFloorDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700332 os << "(" << *getLHS() << " floordiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700333}
334
335void AffineCeilDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700336 os << "(" << *getLHS() << " ceildiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700337}
338
339void AffineSymbolExpr::print(raw_ostream &os) const {
340 os << "s" << getPosition();
341}
342
343void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
344
345void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
346
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700347void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700348 switch (getKind()) {
349 case Kind::SymbolId:
350 return cast<AffineSymbolExpr>(this)->print(os);
351 case Kind::DimId:
352 return cast<AffineDimExpr>(this)->print(os);
353 case Kind::Constant:
354 return cast<AffineConstantExpr>(this)->print(os);
355 case Kind::Add:
356 return cast<AffineAddExpr>(this)->print(os);
357 case Kind::Sub:
358 return cast<AffineSubExpr>(this)->print(os);
359 case Kind::Mul:
360 return cast<AffineMulExpr>(this)->print(os);
361 case Kind::FloorDiv:
362 return cast<AffineFloorDivExpr>(this)->print(os);
363 case Kind::CeilDiv:
364 return cast<AffineCeilDivExpr>(this)->print(os);
365 case Kind::Mod:
366 return cast<AffineModExpr>(this)->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700367 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700368}
369
370void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700371 // Dimension identifiers.
372 os << "(";
373 for (int i = 0; i < (int)getNumDims() - 1; i++)
374 os << "d" << i << ", ";
375 if (getNumDims() >= 1)
376 os << "d" << getNumDims() - 1;
377 os << ")";
378
379 // Symbolic identifiers.
380 if (getNumSymbols() >= 1) {
381 os << " [";
382 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
383 os << "s" << i << ", ";
384 if (getNumSymbols() >= 1)
385 os << "s" << getNumSymbols() - 1;
386 os << "]";
387 }
388
389 // AffineMap should have at least one result.
390 assert(!getResults().empty());
391 // Result affine expressions.
392 os << " -> (";
393 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
394 [&]() { os << ", "; });
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700395 os << ")";
396
397 if (!isBounded()) {
398 os << "\n";
399 return;
400 }
401
402 // Print range sizes for bounded affine maps.
403 os << " size (";
404 interleave(getRangeSizes(), [&](AffineExpr *expr) { os << *expr; },
405 [&]() { os << ", "; });
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700406 os << ")\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700407}
408
Chris Lattner4c95a502018-06-23 16:03:42 -0700409void BasicBlock::print(raw_ostream &os) const {
410 CFGFunctionState state(getFunction(), os);
411 state.print();
412}
413
414void BasicBlock::dump() const {
415 print(llvm::errs());
416}
417
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700418void Statement::print(raw_ostream &os) const {
419 MLFunctionState state(getFunction(), os);
420 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700421}
422
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700423void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700424 print(llvm::errs());
425}
Chris Lattner4c95a502018-06-23 16:03:42 -0700426void Function::print(raw_ostream &os) const {
427 switch (getKind()) {
428 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
429 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700430 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700431 }
432}
433
434void Function::dump() const {
435 print(llvm::errs());
436}
437
438void CFGFunction::print(raw_ostream &os) const {
439 CFGFunctionState state(this, os);
440 state.print();
441}
442
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700443void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700444 MLFunctionState state(this, os);
445 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700446}
447
Chris Lattner4c95a502018-06-23 16:03:42 -0700448void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700449 unsigned id = 0;
450 for (auto *map : affineMapList) {
451 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700452 map->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700453 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700454 for (auto *fn : functionList)
455 fn->print(os);
456}
457
458void Module::dump() const {
459 print(llvm::errs());
460}