blob: 7347a812476cbc46139a2b3252859baac4789b8a [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
MLIR Team718c82f2018-07-16 09:45:22 -0700306void AffineMap::dump() const {
307 print(llvm::errs());
308 llvm::errs() << "\n";
309}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700310
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700311void AffineExpr::dump() const {
312 print(llvm::errs());
313 llvm::errs() << "\n";
314}
315
316void AffineAddExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700317 os << "(" << *getLHS() << " + " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700318}
319
320void AffineSubExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700321 os << "(" << *getLHS() << " - " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700322}
323
324void AffineMulExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700325 os << "(" << *getLHS() << " * " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700326}
327
328void AffineModExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700329 os << "(" << *getLHS() << " mod " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700330}
331
332void AffineFloorDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700333 os << "(" << *getLHS() << " floordiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700334}
335
336void AffineCeilDivExpr::print(raw_ostream &os) const {
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700337 os << "(" << *getLHS() << " ceildiv " << *getRHS() << ")";
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700338}
339
340void AffineSymbolExpr::print(raw_ostream &os) const {
341 os << "s" << getPosition();
342}
343
344void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
345
346void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
347
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700348void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700349 switch (getKind()) {
350 case Kind::SymbolId:
351 return cast<AffineSymbolExpr>(this)->print(os);
352 case Kind::DimId:
353 return cast<AffineDimExpr>(this)->print(os);
354 case Kind::Constant:
355 return cast<AffineConstantExpr>(this)->print(os);
356 case Kind::Add:
357 return cast<AffineAddExpr>(this)->print(os);
358 case Kind::Sub:
359 return cast<AffineSubExpr>(this)->print(os);
360 case Kind::Mul:
361 return cast<AffineMulExpr>(this)->print(os);
362 case Kind::FloorDiv:
363 return cast<AffineFloorDivExpr>(this)->print(os);
364 case Kind::CeilDiv:
365 return cast<AffineCeilDivExpr>(this)->print(os);
366 case Kind::Mod:
367 return cast<AffineModExpr>(this)->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700368 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700369}
370
371void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700372 // Dimension identifiers.
373 os << "(";
374 for (int i = 0; i < (int)getNumDims() - 1; i++)
375 os << "d" << i << ", ";
376 if (getNumDims() >= 1)
377 os << "d" << getNumDims() - 1;
378 os << ")";
379
380 // Symbolic identifiers.
381 if (getNumSymbols() >= 1) {
382 os << " [";
383 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
384 os << "s" << i << ", ";
385 if (getNumSymbols() >= 1)
386 os << "s" << getNumSymbols() - 1;
387 os << "]";
388 }
389
390 // AffineMap should have at least one result.
391 assert(!getResults().empty());
392 // Result affine expressions.
393 os << " -> (";
394 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
395 [&]() { os << ", "; });
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700396 os << ")";
397
398 if (!isBounded()) {
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700399 return;
400 }
401
402 // Print range sizes for bounded affine maps.
403 os << " size (";
404 interleave(getRangeSizes(), [&](AffineExpr *expr) { os << *expr; },
405 [&]() { os << ", "; });
MLIR Team718c82f2018-07-16 09:45:22 -0700406 os << ")";
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}
Jacques Pienaarb020c542018-07-15 00:06:54 -0700426
Chris Lattner4c95a502018-06-23 16:03:42 -0700427void Function::print(raw_ostream &os) const {
428 switch (getKind()) {
429 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
430 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700431 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700432 }
433}
434
435void Function::dump() const {
436 print(llvm::errs());
437}
438
439void CFGFunction::print(raw_ostream &os) const {
440 CFGFunctionState state(this, os);
441 state.print();
442}
443
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700444void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700445 MLFunctionState state(this, os);
446 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700447}
448
Chris Lattner4c95a502018-06-23 16:03:42 -0700449void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700450 unsigned id = 0;
451 for (auto *map : affineMapList) {
452 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700453 map->print(os);
MLIR Team718c82f2018-07-16 09:45:22 -0700454 os << '\n';
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700455 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700456 for (auto *fn : functionList)
457 fn->print(os);
458}
459
460void Module::dump() const {
461 print(llvm::errs());
462}