blob: 2dd2a3b77596a3c2156c2fc230dccfb9dbcf219c [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()) {
261 case Statement::Kind::Operation: // TODO
Jacques Pienaar16916002018-07-07 15:48:05 -0700262 llvm_unreachable("Operation statement is not yet implemented");
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));
277 os.indent(numSpaces) << "}\n";
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 os << "\n";
290}
291
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700292//===----------------------------------------------------------------------===//
293// print and dump methods
294//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700295
296void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700297 CFGFunctionState state(getFunction(), os);
298 state.print(this);
299}
300
Chris Lattnered65a732018-06-28 20:45:33 -0700301void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700302 print(llvm::errs());
Jacques Pienaarb020c542018-07-15 00:06:54 -0700303 llvm::errs() << "\n";
Chris Lattner4c95a502018-06-23 16:03:42 -0700304}
305
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700306void AffineMap::dump() const { print(llvm::errs()); }
307
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700308void AffineExpr::dump() const {
309 print(llvm::errs());
310 llvm::errs() << "\n";
311}
312
313void AffineAddExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700314 os << "(" << *getLHS() << " + " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700315}
316
317void AffineSubExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700318 os << "(" << *getLHS() << " - " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700319}
320
321void AffineMulExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700322 os << "(" << *getLHS() << " * " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700323}
324
325void AffineModExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700326 os << "(" << *getLHS() << " mod " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700327}
328
329void AffineFloorDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700330 os << "(" << *getLHS() << " floordiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700331}
332
333void AffineCeilDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700334 os << "(" << *getLHS() << " ceildiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700335}
336
337void AffineSymbolExpr::print(raw_ostream &os) const {
338 os << "s" << getPosition();
339}
340
341void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
342
343void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
344
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700345void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700346 switch (getKind()) {
347 case Kind::SymbolId:
348 return cast<AffineSymbolExpr>(this)->print(os);
349 case Kind::DimId:
350 return cast<AffineDimExpr>(this)->print(os);
351 case Kind::Constant:
352 return cast<AffineConstantExpr>(this)->print(os);
353 case Kind::Add:
354 return cast<AffineAddExpr>(this)->print(os);
355 case Kind::Sub:
356 return cast<AffineSubExpr>(this)->print(os);
357 case Kind::Mul:
358 return cast<AffineMulExpr>(this)->print(os);
359 case Kind::FloorDiv:
360 return cast<AffineFloorDivExpr>(this)->print(os);
361 case Kind::CeilDiv:
362 return cast<AffineCeilDivExpr>(this)->print(os);
363 case Kind::Mod:
364 return cast<AffineModExpr>(this)->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700365 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700366}
367
368void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700369 // Dimension identifiers.
370 os << "(";
371 for (int i = 0; i < (int)getNumDims() - 1; i++)
372 os << "d" << i << ", ";
373 if (getNumDims() >= 1)
374 os << "d" << getNumDims() - 1;
375 os << ")";
376
377 // Symbolic identifiers.
378 if (getNumSymbols() >= 1) {
379 os << " [";
380 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
381 os << "s" << i << ", ";
382 if (getNumSymbols() >= 1)
383 os << "s" << getNumSymbols() - 1;
384 os << "]";
385 }
386
387 // AffineMap should have at least one result.
388 assert(!getResults().empty());
389 // Result affine expressions.
390 os << " -> (";
391 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
392 [&]() { os << ", "; });
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700393 os << ")";
394
395 if (!isBounded()) {
396 os << "\n";
397 return;
398 }
399
400 // Print range sizes for bounded affine maps.
401 os << " size (";
402 interleave(getRangeSizes(), [&](AffineExpr *expr) { os << *expr; },
403 [&]() { os << ", "; });
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700404 os << ")\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700405}
406
Chris Lattner4c95a502018-06-23 16:03:42 -0700407void BasicBlock::print(raw_ostream &os) const {
408 CFGFunctionState state(getFunction(), os);
409 state.print();
410}
411
412void BasicBlock::dump() const {
413 print(llvm::errs());
414}
415
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700416void Statement::print(raw_ostream &os) const {
417 MLFunctionState state(getFunction(), os);
418 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700419}
420
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700421void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700422 print(llvm::errs());
423}
Jacques Pienaarb020c542018-07-15 00:06:54 -0700424
Chris Lattner4c95a502018-06-23 16:03:42 -0700425void Function::print(raw_ostream &os) const {
426 switch (getKind()) {
427 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
428 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700429 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700430 }
431}
432
433void Function::dump() const {
434 print(llvm::errs());
435}
436
437void CFGFunction::print(raw_ostream &os) const {
438 CFGFunctionState state(this, os);
439 state.print();
440}
441
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700442void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700443 MLFunctionState state(this, os);
444 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700445}
446
Chris Lattner4c95a502018-06-23 16:03:42 -0700447void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700448 unsigned id = 0;
449 for (auto *map : affineMapList) {
450 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700451 map->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700452 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700453 for (auto *fn : functionList)
454 fn->print(os);
455}
456
457void Module::dump() const {
458 print(llvm::errs());
459}