blob: 9a86b85791005dad7fbe9f927eb9562306c6488a [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"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070030#include "mlir/IR/Statements.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070031#include "mlir/IR/Types.h"
32#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070033#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070034#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070035using namespace mlir;
36
37
Chris Lattner7121b802018-07-04 20:45:39 -070038void Identifier::print(raw_ostream &os) const {
39 os << str();
40}
41
42void Identifier::dump() const {
43 print(llvm::errs());
44}
45
Chris Lattner4c95a502018-06-23 16:03:42 -070046//===----------------------------------------------------------------------===//
47// Function printing
48//===----------------------------------------------------------------------===//
49
50static void printFunctionSignature(const Function *fn, raw_ostream &os) {
51 auto type = fn->getType();
52
53 os << "@" << fn->getName() << '(';
54 interleave(type->getInputs(),
55 [&](Type *eltType) { os << *eltType; },
56 [&]() { os << ", "; });
57 os << ')';
58
59 switch (type->getResults().size()) {
60 case 0: break;
61 case 1:
62 os << " -> " << *type->getResults()[0];
63 break;
64 default:
65 os << " -> (";
66 interleave(type->getResults(),
67 [&](Type *eltType) { os << *eltType; },
68 [&]() { os << ", "; });
69 os << ')';
70 break;
71 }
72}
73
74void ExtFunction::print(raw_ostream &os) const {
75 os << "extfunc ";
76 printFunctionSignature(this, os);
77 os << "\n";
78}
79
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -070080namespace {
81
82// FunctionState contains common functionality for printing
83// CFG and ML functions.
84class FunctionState {
85public:
86 FunctionState(MLIRContext *context, raw_ostream &os);
87
88 void printOperation(const Operation *op);
89
90protected:
91 raw_ostream &os;
92 const OperationSet &operationSet;
93};
94} // end anonymous namespace
95
96FunctionState::FunctionState(MLIRContext *context, raw_ostream &os)
97 : os(os), operationSet(OperationSet::get(context)) {}
98
99void FunctionState::printOperation(const Operation *op) {
100 // Check to see if this is a known operation. If so, use the registered
101 // custom printer hook.
102 if (auto opInfo = operationSet.lookup(op->getName().str())) {
103 os << " ";
104 opInfo->printAssembly(op, os);
105 return;
106 }
107
108 // TODO: escape name if necessary.
109 os << " \"" << op->getName().str() << "\"()";
110
111 auto attrs = op->getAttrs();
112 if (!attrs.empty()) {
113 os << '{';
114 interleave(
115 attrs,
116 [&](NamedAttribute attr) { os << attr.first << ": " << *attr.second; },
117 [&]() { os << ", "; });
118 os << '}';
119 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700120}
121
Chris Lattner4c95a502018-06-23 16:03:42 -0700122//===----------------------------------------------------------------------===//
123// CFG Function printing
124//===----------------------------------------------------------------------===//
125
126namespace {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700127class CFGFunctionState : public FunctionState {
Chris Lattner4c95a502018-06-23 16:03:42 -0700128public:
129 CFGFunctionState(const CFGFunction *function, raw_ostream &os);
130
131 const CFGFunction *getFunction() const { return function; }
132
133 void print();
134 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700135
136 void print(const Instruction *inst);
137 void print(const OperationInst *inst);
138 void print(const ReturnInst *inst);
139 void print(const BranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700140
141 unsigned getBBID(const BasicBlock *block) {
142 auto it = basicBlockIDs.find(block);
143 assert(it != basicBlockIDs.end() && "Block not in this function?");
144 return it->second;
145 }
146
147private:
148 const CFGFunction *function;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700149 DenseMap<const BasicBlock*, unsigned> basicBlockIDs;
Chris Lattner4c95a502018-06-23 16:03:42 -0700150};
151} // end anonymous namespace
152
153CFGFunctionState::CFGFunctionState(const CFGFunction *function, raw_ostream &os)
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700154 : FunctionState(function->getContext(), os), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700155 // Each basic block gets a unique ID per function.
156 unsigned blockID = 0;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700157 for (auto &block : *function)
158 basicBlockIDs[&block] = blockID++;
Chris Lattner4c95a502018-06-23 16:03:42 -0700159}
160
161void CFGFunctionState::print() {
162 os << "cfgfunc ";
163 printFunctionSignature(this->getFunction(), os);
164 os << " {\n";
165
Chris Lattner3a467cc2018-07-01 20:28:00 -0700166 for (auto &block : *function)
167 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700168 os << "}\n\n";
169}
170
171void CFGFunctionState::print(const BasicBlock *block) {
172 os << "bb" << getBBID(block) << ":\n";
173
Chris Lattnered65a732018-06-28 20:45:33 -0700174 // TODO Print arguments.
Jacques Pienaarb020c542018-07-15 00:06:54 -0700175 for (auto &inst : block->getOperations()) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700176 print(&inst);
Jacques Pienaarb020c542018-07-15 00:06:54 -0700177 os << "\n";
178 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700179
180 print(block->getTerminator());
Jacques Pienaarb020c542018-07-15 00:06:54 -0700181 os << "\n";
Chris Lattner4c95a502018-06-23 16:03:42 -0700182}
183
Chris Lattnered65a732018-06-28 20:45:33 -0700184void CFGFunctionState::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700185 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700186 case Instruction::Kind::Operation:
187 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700188 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700189 return print(cast<BranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700190 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700191 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700192 }
193}
194
Chris Lattnered65a732018-06-28 20:45:33 -0700195void CFGFunctionState::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700196 printOperation(inst);
Chris Lattnered65a732018-06-28 20:45:33 -0700197}
198
199void CFGFunctionState::print(const BranchInst *inst) {
Jacques Pienaarb020c542018-07-15 00:06:54 -0700200 os << " br bb" << getBBID(inst->getDest());
Chris Lattnered65a732018-06-28 20:45:33 -0700201}
202void CFGFunctionState::print(const ReturnInst *inst) {
Jacques Pienaarb020c542018-07-15 00:06:54 -0700203 os << " return";
Chris Lattnered65a732018-06-28 20:45:33 -0700204}
205
Chris Lattner4c95a502018-06-23 16:03:42 -0700206//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700207// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700208//===----------------------------------------------------------------------===//
209
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700210namespace {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700211class MLFunctionState : public FunctionState {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700212public:
213 MLFunctionState(const MLFunction *function, raw_ostream &os);
214
215 const MLFunction *getFunction() const { return function; }
216
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700217 // Prints ML function
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700218 void print();
219
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700220 // Methods to print ML function statements
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700221 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700222 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700223 void print(const ForStmt *stmt);
224 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700225 void print(const StmtBlock *block);
226
227 // Number of spaces used for indenting nested statements
228 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700229
230private:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700231 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700232 int numSpaces;
233};
234} // end anonymous namespace
235
236MLFunctionState::MLFunctionState(const MLFunction *function, raw_ostream &os)
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700237 : FunctionState(function->getContext(), os), function(function),
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700238 numSpaces(0) {}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700239
240void MLFunctionState::print() {
241 os << "mlfunc ";
242 // FIXME: should print argument names rather than just signature
243 printFunctionSignature(function, os);
244 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700245 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700246 os << " return\n";
247 os << "}\n\n";
248}
249
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700250void MLFunctionState::print(const StmtBlock *block) {
251 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -0700252 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700253 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -0700254 os << "\n";
255 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700256 numSpaces -= indentWidth;
257}
258
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700259void MLFunctionState::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700260 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700261 case Statement::Kind::Operation:
262 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700263 case Statement::Kind::For:
264 return print(cast<ForStmt>(stmt));
265 case Statement::Kind::If:
266 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700267 }
268}
269
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700270void MLFunctionState::print(const OperationStmt *stmt) {
271 printOperation(stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700272}
273
274void MLFunctionState::print(const ForStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700275 os.indent(numSpaces) << "for {\n";
276 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700277 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700278}
279
280void MLFunctionState::print(const IfStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700281 os.indent(numSpaces) << "if () {\n";
282 print(stmt->getThenClause());
283 os.indent(numSpaces) << "}";
284 if (stmt->hasElseClause()) {
285 os << " else {\n";
286 print(stmt->getElseClause());
287 os.indent(numSpaces) << "}";
288 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700289}
290
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700291//===----------------------------------------------------------------------===//
292// print and dump methods
293//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700294
295void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700296 CFGFunctionState state(getFunction(), os);
297 state.print(this);
298}
299
Chris Lattnered65a732018-06-28 20:45:33 -0700300void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700301 print(llvm::errs());
Jacques Pienaarb020c542018-07-15 00:06:54 -0700302 llvm::errs() << "\n";
Chris Lattner4c95a502018-06-23 16:03:42 -0700303}
304
MLIR Team718c82f2018-07-16 09:45:22 -0700305void AffineMap::dump() const {
306 print(llvm::errs());
307 llvm::errs() << "\n";
308}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700309
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()) {
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700398 return;
399 }
400
401 // Print range sizes for bounded affine maps.
402 os << " size (";
403 interleave(getRangeSizes(), [&](AffineExpr *expr) { os << *expr; },
404 [&]() { os << ", "; });
MLIR Team718c82f2018-07-16 09:45:22 -0700405 os << ")";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700406}
407
Chris Lattner4c95a502018-06-23 16:03:42 -0700408void BasicBlock::print(raw_ostream &os) const {
409 CFGFunctionState state(getFunction(), os);
410 state.print();
411}
412
413void BasicBlock::dump() const {
414 print(llvm::errs());
415}
416
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700417void Statement::print(raw_ostream &os) const {
418 MLFunctionState state(getFunction(), os);
419 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700420}
421
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700422void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700423 print(llvm::errs());
424}
Jacques Pienaarb020c542018-07-15 00:06:54 -0700425
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);
MLIR Team718c82f2018-07-16 09:45:22 -0700453 os << '\n';
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700454 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700455 for (auto *fn : functionList)
456 fn->print(os);
457}
458
459void Module::dump() const {
460 print(llvm::errs());
461}