blob: 61d1698d520b58babbfd56e1f554c7965de1f908 [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"
Chris Lattner4c95a502018-06-23 16:03:42 -070030#include "mlir/IR/Types.h"
31#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070032#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070033#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070034using namespace mlir;
35
36
Chris Lattner7121b802018-07-04 20:45:39 -070037void Identifier::print(raw_ostream &os) const {
38 os << str();
39}
40
41void Identifier::dump() const {
42 print(llvm::errs());
43}
44
Chris Lattner4c95a502018-06-23 16:03:42 -070045//===----------------------------------------------------------------------===//
46// Function printing
47//===----------------------------------------------------------------------===//
48
49static void printFunctionSignature(const Function *fn, raw_ostream &os) {
50 auto type = fn->getType();
51
52 os << "@" << fn->getName() << '(';
53 interleave(type->getInputs(),
54 [&](Type *eltType) { os << *eltType; },
55 [&]() { os << ", "; });
56 os << ')';
57
58 switch (type->getResults().size()) {
59 case 0: break;
60 case 1:
61 os << " -> " << *type->getResults()[0];
62 break;
63 default:
64 os << " -> (";
65 interleave(type->getResults(),
66 [&](Type *eltType) { os << *eltType; },
67 [&]() { os << ", "; });
68 os << ')';
69 break;
70 }
71}
72
73void ExtFunction::print(raw_ostream &os) const {
74 os << "extfunc ";
75 printFunctionSignature(this, os);
76 os << "\n";
77}
78
79//===----------------------------------------------------------------------===//
80// CFG Function printing
81//===----------------------------------------------------------------------===//
82
83namespace {
84class CFGFunctionState {
85public:
86 CFGFunctionState(const CFGFunction *function, raw_ostream &os);
87
88 const CFGFunction *getFunction() const { return function; }
89
90 void print();
91 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -070092
93 void print(const Instruction *inst);
94 void print(const OperationInst *inst);
95 void print(const ReturnInst *inst);
96 void print(const BranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -070097
98 unsigned getBBID(const BasicBlock *block) {
99 auto it = basicBlockIDs.find(block);
100 assert(it != basicBlockIDs.end() && "Block not in this function?");
101 return it->second;
102 }
103
104private:
105 const CFGFunction *function;
106 raw_ostream &os;
Chris Lattnerff0d5902018-07-05 09:12:11 -0700107 const OperationSet &operationSet;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700108 DenseMap<const BasicBlock*, unsigned> basicBlockIDs;
Chris Lattner4c95a502018-06-23 16:03:42 -0700109};
110} // end anonymous namespace
111
112CFGFunctionState::CFGFunctionState(const CFGFunction *function, raw_ostream &os)
Chris Lattnerff0d5902018-07-05 09:12:11 -0700113 : function(function), os(os),
114 operationSet(OperationSet::get(function->getContext())) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700115
116 // Each basic block gets a unique ID per function.
117 unsigned blockID = 0;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700118 for (auto &block : *function)
119 basicBlockIDs[&block] = blockID++;
Chris Lattner4c95a502018-06-23 16:03:42 -0700120}
121
122void CFGFunctionState::print() {
123 os << "cfgfunc ";
124 printFunctionSignature(this->getFunction(), os);
125 os << " {\n";
126
Chris Lattner3a467cc2018-07-01 20:28:00 -0700127 for (auto &block : *function)
128 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700129 os << "}\n\n";
130}
131
132void CFGFunctionState::print(const BasicBlock *block) {
133 os << "bb" << getBBID(block) << ":\n";
134
Chris Lattnered65a732018-06-28 20:45:33 -0700135 // TODO Print arguments.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700136 for (auto &inst : block->getOperations())
137 print(&inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700138
139 print(block->getTerminator());
140}
141
Chris Lattnered65a732018-06-28 20:45:33 -0700142void CFGFunctionState::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700143 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700144 case Instruction::Kind::Operation:
145 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700146 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700147 return print(cast<BranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700148 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700149 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700150 }
151}
152
Chris Lattnered65a732018-06-28 20:45:33 -0700153void CFGFunctionState::print(const OperationInst *inst) {
Chris Lattnerff0d5902018-07-05 09:12:11 -0700154 // Check to see if this is a known operation. If so, use the registered
155 // custom printer hook.
156 if (auto opInfo = operationSet.lookup(inst->getName().str())) {
157 os << " ";
158 opInfo->printAssembly(inst, os);
159 return;
160 }
161
Chris Lattnered65a732018-06-28 20:45:33 -0700162 // TODO: escape name if necessary.
Chris Lattner7121b802018-07-04 20:45:39 -0700163 os << " \"" << inst->getName().str() << "\"()";
164
165 auto attrs = inst->getAttrs();
166 if (!attrs.empty()) {
167 os << '{';
168 interleave(attrs, [&](NamedAttribute attr) {
169 os << attr.first << ": " << *attr.second;
170 }, [&]() { os << ", "; });
171 os << '}';
172 }
173
174 os << '\n';
Chris Lattnered65a732018-06-28 20:45:33 -0700175}
176
177void CFGFunctionState::print(const BranchInst *inst) {
178 os << " br bb" << getBBID(inst->getDest()) << "\n";
179}
180void CFGFunctionState::print(const ReturnInst *inst) {
181 os << " return\n";
182}
183
Chris Lattner4c95a502018-06-23 16:03:42 -0700184//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700185// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700186//===----------------------------------------------------------------------===//
187
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700188namespace {
189class MLFunctionState {
190public:
191 MLFunctionState(const MLFunction *function, raw_ostream &os);
192
193 const MLFunction *getFunction() const { return function; }
194
195 void print();
196
197 void print(const Statement *stmt);
198 void print(const ForStmt *stmt);
199 void print(const IfStmt *stmt);
200 void print(const ElseClause *stmt, bool isLast);
201
202private:
203 // Print statements nested within this node statement.
204 void printNestedStatements(const NodeStmt *stmt);
205
206 const MLFunction *function;
207 raw_ostream &os;
208 int numSpaces;
209};
210} // end anonymous namespace
211
212MLFunctionState::MLFunctionState(const MLFunction *function, raw_ostream &os)
213 : function(function), os(os), numSpaces(2) {}
214
215void MLFunctionState::print() {
216 os << "mlfunc ";
217 // FIXME: should print argument names rather than just signature
218 printFunctionSignature(function, os);
219 os << " {\n";
220 for (auto *stmt : function->stmtList)
221 print(stmt);
222 os << " return\n";
223 os << "}\n\n";
224}
225
226void MLFunctionState::print(const Statement *stmt) {
227 os.indent(numSpaces);
228 switch (stmt->getKind()) {
229 case Statement::Kind::Operation: // TODO
230 assert(0 && "Operation statement is not yet implemented");
231 case Statement::Kind::For:
232 return print(cast<ForStmt>(stmt));
233 case Statement::Kind::If:
234 return print(cast<IfStmt>(stmt));
235 case Statement::Kind::Else:
236 return print(cast<ElseClause>(stmt));
237 }
238}
239
240void MLFunctionState::printNestedStatements(const NodeStmt *stmt) {
241 os << "{\n";
242 numSpaces += 2;
243 for (auto * nestedStmt : stmt->children)
244 print(nestedStmt);
245 numSpaces -= 2;
246 os.indent(numSpaces) << "}";
247}
248
249void MLFunctionState::print(const ForStmt *stmt) {
250 os << "for ";
251 printNestedStatements(stmt);
252 os << "\n";
253}
254
255void MLFunctionState::print(const IfStmt *stmt) {
256 os << "if ";
257 printNestedStatements(stmt);
258
259 int numClauses = stmt->elseClauses.size();
260 for (auto e : stmt->elseClauses)
261 print(e, e->getClauseNumber() == numClauses - 1);
262 os << "\n";
263}
264
265void MLFunctionState::print(const ElseClause *stmt, bool isLast) {
266 if (!isLast)
267 os << " if";
268 os << " else ";;
269 printNestedStatements(stmt);
270}
271
272//===----------------------------------------------------------------------===//
273// print and dump methods
274//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700275
276void Instruction::print(raw_ostream &os) const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700277 CFGFunctionState state(getFunction(), os);
278 state.print(this);
279}
280
Chris Lattnered65a732018-06-28 20:45:33 -0700281void Instruction::dump() const {
Chris Lattner4c95a502018-06-23 16:03:42 -0700282 print(llvm::errs());
283}
284
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700285void AffineExpr::dump() const {
286 print(llvm::errs());
287 llvm::errs() << "\n";
288}
289
290void AffineAddExpr::print(raw_ostream &os) const {
291 os << "(" << *getLeftOperand() << " + " << *getRightOperand() << ")";
292}
293
294void AffineSubExpr::print(raw_ostream &os) const {
295 os << "(" << *getLeftOperand() << " - " << *getRightOperand() << ")";
296}
297
298void AffineMulExpr::print(raw_ostream &os) const {
299 os << "(" << *getLeftOperand() << " * " << *getRightOperand() << ")";
300}
301
302void AffineModExpr::print(raw_ostream &os) const {
303 os << "(" << *getLeftOperand() << " mod " << *getRightOperand() << ")";
304}
305
306void AffineFloorDivExpr::print(raw_ostream &os) const {
307 os << "(" << *getLeftOperand() << " floordiv " << *getRightOperand() << ")";
308}
309
310void AffineCeilDivExpr::print(raw_ostream &os) const {
311 os << "(" << *getLeftOperand() << " ceildiv " << *getRightOperand() << ")";
312}
313
314void AffineSymbolExpr::print(raw_ostream &os) const {
315 os << "s" << getPosition();
316}
317
318void AffineDimExpr::print(raw_ostream &os) const { os << "d" << getPosition(); }
319
320void AffineConstantExpr::print(raw_ostream &os) const { os << getValue(); }
321
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700322void AffineExpr::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700323 switch (getKind()) {
324 case Kind::SymbolId:
325 return cast<AffineSymbolExpr>(this)->print(os);
326 case Kind::DimId:
327 return cast<AffineDimExpr>(this)->print(os);
328 case Kind::Constant:
329 return cast<AffineConstantExpr>(this)->print(os);
330 case Kind::Add:
331 return cast<AffineAddExpr>(this)->print(os);
332 case Kind::Sub:
333 return cast<AffineSubExpr>(this)->print(os);
334 case Kind::Mul:
335 return cast<AffineMulExpr>(this)->print(os);
336 case Kind::FloorDiv:
337 return cast<AffineFloorDivExpr>(this)->print(os);
338 case Kind::CeilDiv:
339 return cast<AffineCeilDivExpr>(this)->print(os);
340 case Kind::Mod:
341 return cast<AffineModExpr>(this)->print(os);
342 default:
343 os << "<unimplemented expr>";
344 return;
345 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700346}
347
348void AffineMap::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700349 // Dimension identifiers.
350 os << "(";
351 for (int i = 0; i < (int)getNumDims() - 1; i++)
352 os << "d" << i << ", ";
353 if (getNumDims() >= 1)
354 os << "d" << getNumDims() - 1;
355 os << ")";
356
357 // Symbolic identifiers.
358 if (getNumSymbols() >= 1) {
359 os << " [";
360 for (int i = 0; i < (int)getNumSymbols() - 1; i++)
361 os << "s" << i << ", ";
362 if (getNumSymbols() >= 1)
363 os << "s" << getNumSymbols() - 1;
364 os << "]";
365 }
366
367 // AffineMap should have at least one result.
368 assert(!getResults().empty());
369 // Result affine expressions.
370 os << " -> (";
371 interleave(getResults(), [&](AffineExpr *expr) { os << *expr; },
372 [&]() { os << ", "; });
373 os << ")\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700374}
375
Chris Lattner4c95a502018-06-23 16:03:42 -0700376void BasicBlock::print(raw_ostream &os) const {
377 CFGFunctionState state(getFunction(), os);
378 state.print();
379}
380
381void BasicBlock::dump() const {
382 print(llvm::errs());
383}
384
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700385void Statement::print(raw_ostream &os) const {
386 MLFunctionState state(getFunction(), os);
387 state.print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700388}
389
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700390void Statement::dump() const {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700391 print(llvm::errs());
392}
Chris Lattner4c95a502018-06-23 16:03:42 -0700393void Function::print(raw_ostream &os) const {
394 switch (getKind()) {
395 case Kind::ExtFunc: return cast<ExtFunction>(this)->print(os);
396 case Kind::CFGFunc: return cast<CFGFunction>(this)->print(os);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700397 case Kind::MLFunc: return cast<MLFunction>(this)->print(os);
Chris Lattner4c95a502018-06-23 16:03:42 -0700398 }
399}
400
401void Function::dump() const {
402 print(llvm::errs());
403}
404
405void CFGFunction::print(raw_ostream &os) const {
406 CFGFunctionState state(this, os);
407 state.print();
408}
409
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700410void MLFunction::print(raw_ostream &os) const {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700411 MLFunctionState state(this, os);
412 state.print();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700413}
414
Chris Lattner4c95a502018-06-23 16:03:42 -0700415void Module::print(raw_ostream &os) const {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700416 unsigned id = 0;
417 for (auto *map : affineMapList) {
418 os << "#" << id++ << " = ";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700419 map->print(os);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700420 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700421 for (auto *fn : functionList)
422 fn->print(os);
423}
424
425void Module::dump() const {
426 print(llvm::errs());
427}