blob: 1cefc0a74fae9e6476cd1bb3f2c1613d1af1966b [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"
29#include "mlir/IR/Types.h"
30#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070031#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070032#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070033using namespace mlir;
34
35
Chris Lattner7121b802018-07-04 20:45:39 -070036void Identifier::print(raw_ostream &os) const {
37 os << str();
38}
39
40void Identifier::dump() const {
41 print(llvm::errs());
42}
43
Chris Lattner4c95a502018-06-23 16:03:42 -070044//===----------------------------------------------------------------------===//
45// Function printing
46//===----------------------------------------------------------------------===//
47
48static void printFunctionSignature(const Function *fn, raw_ostream &os) {
49 auto type = fn->getType();
50
51 os << "@" << fn->getName() << '(';
52 interleave(type->getInputs(),
53 [&](Type *eltType) { os << *eltType; },
54 [&]() { os << ", "; });
55 os << ')';
56
57 switch (type->getResults().size()) {
58 case 0: break;
59 case 1:
60 os << " -> " << *type->getResults()[0];
61 break;
62 default:
63 os << " -> (";
64 interleave(type->getResults(),
65 [&](Type *eltType) { os << *eltType; },
66 [&]() { os << ", "; });
67 os << ')';
68 break;
69 }
70}
71
72void ExtFunction::print(raw_ostream &os) const {
73 os << "extfunc ";
74 printFunctionSignature(this, os);
75 os << "\n";
76}
77
78//===----------------------------------------------------------------------===//
79// CFG Function printing
80//===----------------------------------------------------------------------===//
81
82namespace {
83class CFGFunctionState {
84public:
85 CFGFunctionState(const CFGFunction *function, raw_ostream &os);
86
87 const CFGFunction *getFunction() const { return function; }
88
89 void print();
90 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -070091
92 void print(const Instruction *inst);
93 void print(const OperationInst *inst);
94 void print(const ReturnInst *inst);
95 void print(const BranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -070096
97 unsigned getBBID(const BasicBlock *block) {
98 auto it = basicBlockIDs.find(block);
99 assert(it != basicBlockIDs.end() && "Block not in this function?");
100 return it->second;
101 }
102
103private:
104 const CFGFunction *function;
105 raw_ostream &os;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700106 DenseMap<const BasicBlock*, unsigned> basicBlockIDs;
Chris Lattner4c95a502018-06-23 16:03:42 -0700107};
108} // end anonymous namespace
109
110CFGFunctionState::CFGFunctionState(const CFGFunction *function, raw_ostream &os)
111 : function(function), os(os) {
112
113 // Each basic block gets a unique ID per function.
114 unsigned blockID = 0;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700115 for (auto &block : *function)
116 basicBlockIDs[&block] = blockID++;
Chris Lattner4c95a502018-06-23 16:03:42 -0700117}
118
119void CFGFunctionState::print() {
120 os << "cfgfunc ";
121 printFunctionSignature(this->getFunction(), os);
122 os << " {\n";
123
Chris Lattner3a467cc2018-07-01 20:28:00 -0700124 for (auto &block : *function)
125 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700126 os << "}\n\n";
127}
128
129void CFGFunctionState::print(const BasicBlock *block) {
130 os << "bb" << getBBID(block) << ":\n";
131
Chris Lattnered65a732018-06-28 20:45:33 -0700132 // TODO Print arguments.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700133 for (auto &inst : block->getOperations())
134 print(&inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700135
136 print(block->getTerminator());
137}
138
Chris Lattnered65a732018-06-28 20:45:33 -0700139void CFGFunctionState::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700140 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700141 case Instruction::Kind::Operation:
142 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700143 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700144 return print(cast<BranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700145 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700146 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700147 }
148}
149
Chris Lattnered65a732018-06-28 20:45:33 -0700150void CFGFunctionState::print(const OperationInst *inst) {
151 // TODO: escape name if necessary.
Chris Lattner7121b802018-07-04 20:45:39 -0700152 os << " \"" << inst->getName().str() << "\"()";
153
154 auto attrs = inst->getAttrs();
155 if (!attrs.empty()) {
156 os << '{';
157 interleave(attrs, [&](NamedAttribute attr) {
158 os << attr.first << ": " << *attr.second;
159 }, [&]() { os << ", "; });
160 os << '}';
161 }
162
163 os << '\n';
Chris Lattnered65a732018-06-28 20:45:33 -0700164}
165
166void CFGFunctionState::print(const BranchInst *inst) {
167 os << " br bb" << getBBID(inst->getDest()) << "\n";
168}
169void CFGFunctionState::print(const ReturnInst *inst) {
170 os << " return\n";
171}
172
Chris Lattner4c95a502018-06-23 16:03:42 -0700173//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700174// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700175//===----------------------------------------------------------------------===//
176
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700177namespace {
178class MLFunctionState {
179public:
180 MLFunctionState(const MLFunction *function, raw_ostream &os);
181
182 const MLFunction *getFunction() const { return function; }
183
184 void print();
185
186 void print(const Statement *stmt);
187 void print(const ForStmt *stmt);
188 void print(const IfStmt *stmt);
189 void print(const ElseClause *stmt, bool isLast);
190
191private:
192 // Print statements nested within this node statement.
193 void printNestedStatements(const NodeStmt *stmt);
194
195 const MLFunction *function;
196 raw_ostream &os;
197 int numSpaces;
198};
199} // end anonymous namespace
200
201MLFunctionState::MLFunctionState(const MLFunction *function, raw_ostream &os)
202 : function(function), os(os), numSpaces(2) {}
203
204void MLFunctionState::print() {
205 os << "mlfunc ";
206 // FIXME: should print argument names rather than just signature
207 printFunctionSignature(function, os);
208 os << " {\n";
209 for (auto *stmt : function->stmtList)
210 print(stmt);
211 os << " return\n";
212 os << "}\n\n";
213}
214
215void MLFunctionState::print(const Statement *stmt) {
216 os.indent(numSpaces);
217 switch (stmt->getKind()) {
218 case Statement::Kind::Operation: // TODO
219 assert(0 && "Operation statement is not yet implemented");
220 case Statement::Kind::For:
221 return print(cast<ForStmt>(stmt));
222 case Statement::Kind::If:
223 return print(cast<IfStmt>(stmt));
224 case Statement::Kind::Else:
225 return print(cast<ElseClause>(stmt));
226 }
227}
228
229void MLFunctionState::printNestedStatements(const NodeStmt *stmt) {
230 os << "{\n";
231 numSpaces += 2;
232 for (auto * nestedStmt : stmt->children)
233 print(nestedStmt);
234 numSpaces -= 2;
235 os.indent(numSpaces) << "}";
236}
237
238void MLFunctionState::print(const ForStmt *stmt) {
239 os << "for ";
240 printNestedStatements(stmt);
241 os << "\n";
242}
243
244void MLFunctionState::print(const IfStmt *stmt) {
245 os << "if ";
246 printNestedStatements(stmt);
247
248 int numClauses = stmt->elseClauses.size();
249 for (auto e : stmt->elseClauses)
250 print(e, e->getClauseNumber() == numClauses - 1);
251 os << "\n";
252}
253
254void MLFunctionState::print(const ElseClause *stmt, bool isLast) {
255 if (!isLast)
256 os << " if";
257 os << " else ";;
258 printNestedStatements(stmt);
259}
260
261//===----------------------------------------------------------------------===//
262// print and dump methods
263//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700264
265void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700266 CFGFunctionState state(getFunction(), os);
267 state.print(this);
268}
269
Chris Lattnered65a732018-06-28 20:45:33 -0700270void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700271 print(llvm::errs());
272}
273
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700274void AffineExpr::dump() const {
275 print(llvm::errs());
276 llvm::errs() << "\n";
277}
278
279void AffineAddExpr::print(raw_ostream &os) const {
280 os << "(" << *getLeftOperand() << " + " << *getRightOperand() << ")";
281}
282
283void AffineSubExpr::print(raw_ostream &os) const {
284 os << "(" << *getLeftOperand() << " - " << *getRightOperand() << ")";
285}
286
287void AffineMulExpr::print(raw_ostream &os) const {
288 os << "(" << *getLeftOperand() << " * " << *getRightOperand() << ")";
289}
290
291void AffineModExpr::print(raw_ostream &os) const {
292 os << "(" << *getLeftOperand() << " mod " << *getRightOperand() << ")";
293}
294
295void AffineFloorDivExpr::print(raw_ostream &os) const {
296 os << "(" << *getLeftOperand() << " floordiv " << *getRightOperand() << ")";
297}
298
299void AffineCeilDivExpr::print(raw_ostream &os) const {
300 os << "(" << *getLeftOperand() << " ceildiv " << *getRightOperand() << ")";
301}
302
303void AffineSymbolExpr::print(raw_ostream &os) const {
304 os << "s" << getPosition();
305}
306
307void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
308
309void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
310
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700311void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700312 switch (getKind()) {
313 case Kind::SymbolId:
314 return cast<AffineSymbolExpr>(this)->print(os);
315 case Kind::DimId:
316 return cast<AffineDimExpr>(this)->print(os);
317 case Kind::Constant:
318 return cast<AffineConstantExpr>(this)->print(os);
319 case Kind::Add:
320 return cast<AffineAddExpr>(this)->print(os);
321 case Kind::Sub:
322 return cast<AffineSubExpr>(this)->print(os);
323 case Kind::Mul:
324 return cast<AffineMulExpr>(this)->print(os);
325 case Kind::FloorDiv:
326 return cast<AffineFloorDivExpr>(this)->print(os);
327 case Kind::CeilDiv:
328 return cast<AffineCeilDivExpr>(this)->print(os);
329 case Kind::Mod:
330 return cast<AffineModExpr>(this)->print(os);
331 default:
332 os << "<unimplemented expr>";
333 return;
334 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700335}
336
337void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700338 // Dimension identifiers.
339 os << "(";
340 for (int i = 0; i < (int)getNumDims() - 1; i++)
341 os << "d" << i << ", ";
342 if (getNumDims() >= 1)
343 os << "d" << getNumDims() - 1;
344 os << ")";
345
346 // Symbolic identifiers.
347 if (getNumSymbols() >= 1) {
348 os << " [";
349 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
350 os << "s" << i << ", ";
351 if (getNumSymbols() >= 1)
352 os << "s" << getNumSymbols() - 1;
353 os << "]";
354 }
355
356 // AffineMap should have at least one result.
357 assert(!getResults().empty());
358 // Result affine expressions.
359 os << " -> (";
360 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
361 [&]() { os << ", "; });
362 os << ")\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700363}
364
Chris Lattner4c95a502018-06-23 16:03:42 -0700365void BasicBlock::print(raw_ostream &os) const {
366 CFGFunctionState state(getFunction(), os);
367 state.print();
368}
369
370void BasicBlock::dump() const {
371 print(llvm::errs());
372}
373
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700374void Statement::print(raw_ostream &os) const {
375 MLFunctionState state(getFunction(), os);
376 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700377}
378
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700379void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700380 print(llvm::errs());
381}
Chris Lattner4c95a502018-06-23 16:03:42 -0700382void Function::print(raw_ostream &os) const {
383 switch (getKind()) {
384 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
385 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700386 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700387 }
388}
389
390void Function::dump() const {
391 print(llvm::errs());
392}
393
394void CFGFunction::print(raw_ostream &os) const {
395 CFGFunctionState state(this, os);
396 state.print();
397}
398
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700399void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700400 MLFunctionState state(this, os);
401 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700402}
403
Chris Lattner4c95a502018-06-23 16:03:42 -0700404void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700405 unsigned id = 0;
406 for (auto *map : affineMapList) {
407 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700408 map->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700409 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700410 for (auto *fn : functionList)
411 fn->print(os);
412}
413
414void Module::dump() const {
415 print(llvm::errs());
416}