blob: b24eb2f0ad480f072f8ec34a558402ecfceb202b [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 Lattner4c95a502018-06-23 16:03:42 -070025#include "mlir/IR/CFGFunction.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070026#include "mlir/IR/MLFunction.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070027#include "mlir/IR/Module.h"
28#include "mlir/IR/Types.h"
29#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070030#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070031#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070032using namespace mlir;
33
34
35//===----------------------------------------------------------------------===//
36// Function printing
37//===----------------------------------------------------------------------===//
38
39static void printFunctionSignature(const Function *fn, raw_ostream &os) {
40 auto type = fn->getType();
41
42 os << "@" << fn->getName() << '(';
43 interleave(type->getInputs(),
44 [&](Type *eltType) { os << *eltType; },
45 [&]() { os << ", "; });
46 os << ')';
47
48 switch (type->getResults().size()) {
49 case 0: break;
50 case 1:
51 os << " -> " << *type->getResults()[0];
52 break;
53 default:
54 os << " -> (";
55 interleave(type->getResults(),
56 [&](Type *eltType) { os << *eltType; },
57 [&]() { os << ", "; });
58 os << ')';
59 break;
60 }
61}
62
63void ExtFunction::print(raw_ostream &os) const {
64 os << "extfunc ";
65 printFunctionSignature(this, os);
66 os << "\n";
67}
68
69//===----------------------------------------------------------------------===//
70// CFG Function printing
71//===----------------------------------------------------------------------===//
72
73namespace {
74class CFGFunctionState {
75public:
76 CFGFunctionState(const CFGFunction *function, raw_ostream &os);
77
78 const CFGFunction *getFunction() const { return function; }
79
80 void print();
81 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -070082
83 void print(const Instruction *inst);
84 void print(const OperationInst *inst);
85 void print(const ReturnInst *inst);
86 void print(const BranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -070087
88 unsigned getBBID(const BasicBlock *block) {
89 auto it = basicBlockIDs.find(block);
90 assert(it != basicBlockIDs.end() && "Block not in this function?");
91 return it->second;
92 }
93
94private:
95 const CFGFunction *function;
96 raw_ostream &os;
Chris Lattner3a467cc2018-07-01 20:28:00 -070097 DenseMap<const BasicBlock*, unsigned> basicBlockIDs;
Chris Lattner4c95a502018-06-23 16:03:42 -070098};
99} // end anonymous namespace
100
101CFGFunctionState::CFGFunctionState(const CFGFunction *function, raw_ostream &os)
102 : function(function), os(os) {
103
104 // Each basic block gets a unique ID per function.
105 unsigned blockID = 0;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700106 for (auto &block : *function)
107 basicBlockIDs[&block] = blockID++;
Chris Lattner4c95a502018-06-23 16:03:42 -0700108}
109
110void CFGFunctionState::print() {
111 os << "cfgfunc ";
112 printFunctionSignature(this->getFunction(), os);
113 os << " {\n";
114
Chris Lattner3a467cc2018-07-01 20:28:00 -0700115 for (auto &block : *function)
116 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700117 os << "}\n\n";
118}
119
120void CFGFunctionState::print(const BasicBlock *block) {
121 os << "bb" << getBBID(block) << ":\n";
122
Chris Lattnered65a732018-06-28 20:45:33 -0700123 // TODO Print arguments.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700124 for (auto &inst : block->getOperations())
125 print(&inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700126
127 print(block->getTerminator());
128}
129
Chris Lattnered65a732018-06-28 20:45:33 -0700130void CFGFunctionState::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700131 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700132 case Instruction::Kind::Operation:
133 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700134 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700135 return print(cast<BranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700136 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700137 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700138 }
139}
140
Chris Lattnered65a732018-06-28 20:45:33 -0700141void CFGFunctionState::print(const OperationInst *inst) {
142 // TODO: escape name if necessary.
143 os << " \"" << inst->getName().str() << "\"()\n";
144}
145
146void CFGFunctionState::print(const BranchInst *inst) {
147 os << " br bb" << getBBID(inst->getDest()) << "\n";
148}
149void CFGFunctionState::print(const ReturnInst *inst) {
150 os << " return\n";
151}
152
Chris Lattner4c95a502018-06-23 16:03:42 -0700153//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700154// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700155//===----------------------------------------------------------------------===//
156
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700157namespace {
158class MLFunctionState {
159public:
160 MLFunctionState(const MLFunction *function, raw_ostream &os);
161
162 const MLFunction *getFunction() const { return function; }
163
164 void print();
165
166 void print(const Statement *stmt);
167 void print(const ForStmt *stmt);
168 void print(const IfStmt *stmt);
169 void print(const ElseClause *stmt, bool isLast);
170
171private:
172 // Print statements nested within this node statement.
173 void printNestedStatements(const NodeStmt *stmt);
174
175 const MLFunction *function;
176 raw_ostream &os;
177 int numSpaces;
178};
179} // end anonymous namespace
180
181MLFunctionState::MLFunctionState(const MLFunction *function, raw_ostream &os)
182 : function(function), os(os), numSpaces(2) {}
183
184void MLFunctionState::print() {
185 os << "mlfunc ";
186 // FIXME: should print argument names rather than just signature
187 printFunctionSignature(function, os);
188 os << " {\n";
189 for (auto *stmt : function->stmtList)
190 print(stmt);
191 os << " return\n";
192 os << "}\n\n";
193}
194
195void MLFunctionState::print(const Statement *stmt) {
196 os.indent(numSpaces);
197 switch (stmt->getKind()) {
198 case Statement::Kind::Operation: // TODO
199 assert(0 && "Operation statement is not yet implemented");
200 case Statement::Kind::For:
201 return print(cast<ForStmt>(stmt));
202 case Statement::Kind::If:
203 return print(cast<IfStmt>(stmt));
204 case Statement::Kind::Else:
205 return print(cast<ElseClause>(stmt));
206 }
207}
208
209void MLFunctionState::printNestedStatements(const NodeStmt *stmt) {
210 os << "{\n";
211 numSpaces += 2;
212 for (auto * nestedStmt : stmt->children)
213 print(nestedStmt);
214 numSpaces -= 2;
215 os.indent(numSpaces) << "}";
216}
217
218void MLFunctionState::print(const ForStmt *stmt) {
219 os << "for ";
220 printNestedStatements(stmt);
221 os << "\n";
222}
223
224void MLFunctionState::print(const IfStmt *stmt) {
225 os << "if ";
226 printNestedStatements(stmt);
227
228 int numClauses = stmt->elseClauses.size();
229 for (auto e : stmt->elseClauses)
230 print(e, e->getClauseNumber() == numClauses - 1);
231 os << "\n";
232}
233
234void MLFunctionState::print(const ElseClause *stmt, bool isLast) {
235 if (!isLast)
236 os << " if";
237 os << " else ";;
238 printNestedStatements(stmt);
239}
240
241//===----------------------------------------------------------------------===//
242// print and dump methods
243//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700244
245void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700246 CFGFunctionState state(getFunction(), os);
247 state.print(this);
248}
249
Chris Lattnered65a732018-06-28 20:45:33 -0700250void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700251 print(llvm::errs());
252}
253
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700254void AffineExpr::dump() const {
255 print(llvm::errs());
256 llvm::errs() << "\n";
257}
258
259void AffineAddExpr::print(raw_ostream &os) const {
260 os << "(" << *getLeftOperand() << " + " << *getRightOperand() << ")";
261}
262
263void AffineSubExpr::print(raw_ostream &os) const {
264 os << "(" << *getLeftOperand() << " - " << *getRightOperand() << ")";
265}
266
267void AffineMulExpr::print(raw_ostream &os) const {
268 os << "(" << *getLeftOperand() << " * " << *getRightOperand() << ")";
269}
270
271void AffineModExpr::print(raw_ostream &os) const {
272 os << "(" << *getLeftOperand() << " mod " << *getRightOperand() << ")";
273}
274
275void AffineFloorDivExpr::print(raw_ostream &os) const {
276 os << "(" << *getLeftOperand() << " floordiv " << *getRightOperand() << ")";
277}
278
279void AffineCeilDivExpr::print(raw_ostream &os) const {
280 os << "(" << *getLeftOperand() << " ceildiv " << *getRightOperand() << ")";
281}
282
283void AffineSymbolExpr::print(raw_ostream &os) const {
284 os << "s" << getPosition();
285}
286
287void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
288
289void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
290
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700291void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700292 switch (getKind()) {
293 case Kind::SymbolId:
294 return cast<AffineSymbolExpr>(this)->print(os);
295 case Kind::DimId:
296 return cast<AffineDimExpr>(this)->print(os);
297 case Kind::Constant:
298 return cast<AffineConstantExpr>(this)->print(os);
299 case Kind::Add:
300 return cast<AffineAddExpr>(this)->print(os);
301 case Kind::Sub:
302 return cast<AffineSubExpr>(this)->print(os);
303 case Kind::Mul:
304 return cast<AffineMulExpr>(this)->print(os);
305 case Kind::FloorDiv:
306 return cast<AffineFloorDivExpr>(this)->print(os);
307 case Kind::CeilDiv:
308 return cast<AffineCeilDivExpr>(this)->print(os);
309 case Kind::Mod:
310 return cast<AffineModExpr>(this)->print(os);
311 default:
312 os << "<unimplemented expr>";
313 return;
314 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700315}
316
317void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700318 // Dimension identifiers.
319 os << "(";
320 for (int i = 0; i < (int)getNumDims() - 1; i++)
321 os << "d" << i << ", ";
322 if (getNumDims() >= 1)
323 os << "d" << getNumDims() - 1;
324 os << ")";
325
326 // Symbolic identifiers.
327 if (getNumSymbols() >= 1) {
328 os << " [";
329 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
330 os << "s" << i << ", ";
331 if (getNumSymbols() >= 1)
332 os << "s" << getNumSymbols() - 1;
333 os << "]";
334 }
335
336 // AffineMap should have at least one result.
337 assert(!getResults().empty());
338 // Result affine expressions.
339 os << " -> (";
340 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
341 [&]() { os << ", "; });
342 os << ")\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700343}
344
Chris Lattner4c95a502018-06-23 16:03:42 -0700345void BasicBlock::print(raw_ostream &os) const {
346 CFGFunctionState state(getFunction(), os);
347 state.print();
348}
349
350void BasicBlock::dump() const {
351 print(llvm::errs());
352}
353
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700354void Statement::print(raw_ostream &os) const {
355 MLFunctionState state(getFunction(), os);
356 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700357}
358
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700359void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700360 print(llvm::errs());
361}
Chris Lattner4c95a502018-06-23 16:03:42 -0700362void Function::print(raw_ostream &os) const {
363 switch (getKind()) {
364 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
365 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700366 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700367 }
368}
369
370void Function::dump() const {
371 print(llvm::errs());
372}
373
374void CFGFunction::print(raw_ostream &os) const {
375 CFGFunctionState state(this, os);
376 state.print();
377}
378
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700379void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700380 MLFunctionState state(this, os);
381 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700382}
383
Chris Lattner4c95a502018-06-23 16:03:42 -0700384void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700385 unsigned id = 0;
386 for (auto *map : affineMapList) {
387 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700388 map->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700389 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700390 for (auto *fn : functionList)
391 fn->print(os);
392}
393
394void Module::dump() const {
395 print(llvm::errs());
396}