blob: 28149fc7300459996f7c4403c9226a3cc20949c6 [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 Lattnerdd0c2ca2018-07-24 16:07:22 -070029#include "mlir/IR/OpImplementation.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070030#include "mlir/IR/OperationSet.h"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070031#include "mlir/IR/Statements.h"
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070032#include "mlir/IR/StmtVisitor.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070033#include "mlir/IR/Types.h"
34#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070035#include "llvm/ADT/DenseMap.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070036#include "llvm/Support/raw_ostream.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070037using namespace mlir;
38
MLIR Team54b55a22018-07-18 10:16:05 -070039void Identifier::print(raw_ostream &os) const { os << str(); }
Chris Lattner4c95a502018-06-23 16:03:42 -070040
MLIR Team54b55a22018-07-18 10:16:05 -070041void Identifier::dump() const { print(llvm::errs()); }
Chris Lattner7121b802018-07-04 20:45:39 -070042
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070043OpAsmPrinter::~OpAsmPrinter() {}
44
Chris Lattner4c95a502018-06-23 16:03:42 -070045//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -070046// ModuleState
MLIR Team4718bc92018-07-17 16:56:54 -070047//===----------------------------------------------------------------------===//
48
49namespace {
MLIR Team54b55a22018-07-18 10:16:05 -070050class ModuleState {
51public:
Chris Lattner4fd59b02018-07-20 09:35:47 -070052 /// This is the operation set for the current context if it is knowable (a
53 /// context could be determined), otherwise this is null.
54 OperationSet *const operationSet;
MLIR Team4718bc92018-07-17 16:56:54 -070055
Chris Lattner4fd59b02018-07-20 09:35:47 -070056 explicit ModuleState(MLIRContext *context)
57 : operationSet(context ? &OperationSet::get(context) : nullptr) {}
58
59 // Initializes module state, populating affine map state.
MLIR Team4718bc92018-07-17 16:56:54 -070060 void initialize(const Module *module);
61
MLIR Team54b55a22018-07-18 10:16:05 -070062 int getAffineMapId(const AffineMap *affineMap) const {
MLIR Team4718bc92018-07-17 16:56:54 -070063 auto it = affineMapIds.find(affineMap);
64 if (it == affineMapIds.end()) {
65 return -1;
66 }
67 return it->second;
68 }
69
James Molloyc4666722018-07-24 09:48:31 -070070 ArrayRef<const AffineMap *> getAffineMapIds() const { return affineMapsById; }
Chris Lattner4fd59b02018-07-20 09:35:47 -070071
MLIR Team54b55a22018-07-18 10:16:05 -070072private:
Chris Lattner4fd59b02018-07-20 09:35:47 -070073 void recordAffineMapReference(const AffineMap *affineMap) {
74 if (affineMapIds.count(affineMap) == 0) {
James Molloyc4666722018-07-24 09:48:31 -070075 affineMapIds[affineMap] = affineMapsById.size();
76 affineMapsById.push_back(affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -070077 }
78 }
79
MLIR Team4718bc92018-07-17 16:56:54 -070080 // Visit functions.
81 void visitFunction(const Function *fn);
82 void visitExtFunction(const ExtFunction *fn);
83 void visitCFGFunction(const CFGFunction *fn);
84 void visitMLFunction(const MLFunction *fn);
85 void visitType(const Type *type);
MLIR Teamb61885d2018-07-18 16:29:21 -070086 void visitAttribute(const Attribute *attr);
87 void visitOperation(const Operation *op);
88
MLIR Team54b55a22018-07-18 10:16:05 -070089 DenseMap<const AffineMap *, int> affineMapIds;
James Molloyc4666722018-07-24 09:48:31 -070090 std::vector<const AffineMap *> affineMapsById;
MLIR Team4718bc92018-07-17 16:56:54 -070091};
James Molloy87d81022018-07-23 11:44:40 -070092} // end anonymous namespace
MLIR Team4718bc92018-07-17 16:56:54 -070093
94// TODO Support visiting other types/instructions when implemented.
95void ModuleState::visitType(const Type *type) {
96 if (type->getKind() == Type::Kind::Function) {
97 // Visit input and result types for functions.
98 auto *funcType = cast<FunctionType>(type);
MLIR Team54b55a22018-07-18 10:16:05 -070099 for (auto *input : funcType->getInputs()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700100 visitType(input);
101 }
MLIR Team54b55a22018-07-18 10:16:05 -0700102 for (auto *result : funcType->getResults()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700103 visitType(result);
104 }
105 } else if (type->getKind() == Type::Kind::MemRef) {
106 // Visit affine maps in memref type.
107 auto *memref = cast<MemRefType>(type);
MLIR Team54b55a22018-07-18 10:16:05 -0700108 for (AffineMap *map : memref->getAffineMaps()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700109 recordAffineMapReference(map);
110 }
111 }
112}
113
MLIR Teamb61885d2018-07-18 16:29:21 -0700114void ModuleState::visitAttribute(const Attribute *attr) {
115 if (isa<AffineMapAttr>(attr)) {
116 recordAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
117 } else if (isa<ArrayAttr>(attr)) {
118 for (auto elt : cast<ArrayAttr>(attr)->getValue()) {
119 visitAttribute(elt);
120 }
121 }
122}
123
124void ModuleState::visitOperation(const Operation *op) {
125 for (auto elt : op->getAttrs()) {
126 visitAttribute(elt.second);
127 }
128}
129
MLIR Team4718bc92018-07-17 16:56:54 -0700130void ModuleState::visitExtFunction(const ExtFunction *fn) {
131 visitType(fn->getType());
132}
133
134void ModuleState::visitCFGFunction(const CFGFunction *fn) {
135 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700136 for (auto &block : *fn) {
137 for (auto &op : block.getOperations()) {
138 visitOperation(&op);
139 }
140 }
MLIR Team4718bc92018-07-17 16:56:54 -0700141}
142
143void ModuleState::visitMLFunction(const MLFunction *fn) {
144 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700145 // TODO Visit function body statements (and attributes if required).
MLIR Team4718bc92018-07-17 16:56:54 -0700146}
147
148void ModuleState::visitFunction(const Function *fn) {
149 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700150 case Function::Kind::ExtFunc:
151 return visitExtFunction(cast<ExtFunction>(fn));
152 case Function::Kind::CFGFunc:
153 return visitCFGFunction(cast<CFGFunction>(fn));
154 case Function::Kind::MLFunc:
155 return visitMLFunction(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700156 }
157}
158
Chris Lattner4fd59b02018-07-20 09:35:47 -0700159// Initializes module state, populating affine map state.
160void ModuleState::initialize(const Module *module) {
Chris Lattnera8e47672018-07-25 14:08:16 -0700161 for (auto &fn : *module) {
162 visitFunction(&fn);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700163 }
164}
165
166//===----------------------------------------------------------------------===//
167// ModulePrinter
168//===----------------------------------------------------------------------===//
169
170namespace {
171class ModulePrinter {
172public:
173 ModulePrinter(raw_ostream &os, ModuleState &state) : os(os), state(state) {}
174 explicit ModulePrinter(const ModulePrinter &printer)
175 : os(printer.os), state(printer.state) {}
176
177 template <typename Container, typename UnaryFunctor>
178 inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
179 interleave(c.begin(), c.end(), each_fn, [&]() { os << ", "; });
180 }
181
182 void print(const Module *module);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700183 void printAttribute(const Attribute *attr);
184 void printType(const Type *type);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700185 void print(const Function *fn);
186 void print(const ExtFunction *fn);
187 void print(const CFGFunction *fn);
188 void print(const MLFunction *fn);
189
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700190 void printAffineMap(const AffineMap *map);
191 void printAffineExpr(const AffineExpr *expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700192
193protected:
194 raw_ostream &os;
195 ModuleState &state;
196
197 void printFunctionSignature(const Function *fn);
198 void printAffineMapId(int affineMapId) const;
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700199 void printAffineMapReference(const AffineMap *affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700200
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700201 void printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700202};
203} // end anonymous namespace
204
MLIR Team4718bc92018-07-17 16:56:54 -0700205// Prints function with initialized module state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700206void ModulePrinter::print(const Function *fn) {
MLIR Team4718bc92018-07-17 16:56:54 -0700207 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700208 case Function::Kind::ExtFunc:
209 return print(cast<ExtFunction>(fn));
210 case Function::Kind::CFGFunc:
211 return print(cast<CFGFunction>(fn));
212 case Function::Kind::MLFunc:
213 return print(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700214 }
215}
216
217// Prints affine map identifier.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700218void ModulePrinter::printAffineMapId(int affineMapId) const {
MLIR Team4718bc92018-07-17 16:56:54 -0700219 os << "#map" << affineMapId;
220}
221
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700222void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700223 int mapId = state.getAffineMapId(affineMap);
MLIR Teamb61885d2018-07-18 16:29:21 -0700224 if (mapId >= 0) {
225 // Map will be printed at top of module so print reference to its id.
226 printAffineMapId(mapId);
227 } else {
228 // Map not in module state so print inline.
229 affineMap->print(os);
230 }
231}
232
Chris Lattner4fd59b02018-07-20 09:35:47 -0700233void ModulePrinter::print(const Module *module) {
James Molloyc4666722018-07-24 09:48:31 -0700234 for (const auto &map : state.getAffineMapIds()) {
235 printAffineMapId(state.getAffineMapId(map));
MLIR Team4718bc92018-07-17 16:56:54 -0700236 os << " = ";
James Molloyc4666722018-07-24 09:48:31 -0700237 map->print(os);
MLIR Team4718bc92018-07-17 16:56:54 -0700238 os << '\n';
239 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700240 for (auto const &fn : *module)
241 print(&fn);
MLIR Team4718bc92018-07-17 16:56:54 -0700242}
243
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700244void ModulePrinter::printAttribute(const Attribute *attr) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700245 switch (attr->getKind()) {
246 case Attribute::Kind::Bool:
247 os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
248 break;
249 case Attribute::Kind::Integer:
250 os << cast<IntegerAttr>(attr)->getValue();
251 break;
252 case Attribute::Kind::Float:
253 // FIXME: this isn't precise, we should print with a hex format.
254 os << cast<FloatAttr>(attr)->getValue();
255 break;
256 case Attribute::Kind::String:
257 // FIXME: should escape the string.
258 os << '"' << cast<StringAttr>(attr)->getValue() << '"';
259 break;
260 case Attribute::Kind::Array: {
261 auto elts = cast<ArrayAttr>(attr)->getValue();
262 os << '[';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700263 interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
MLIR Teamb61885d2018-07-18 16:29:21 -0700264 os << ']';
265 break;
266 }
267 case Attribute::Kind::AffineMap:
268 printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
269 break;
270 }
271}
272
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700273void ModulePrinter::printType(const Type *type) {
MLIR Team4718bc92018-07-17 16:56:54 -0700274 switch (type->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700275 case Type::Kind::AffineInt:
276 os << "affineint";
277 return;
278 case Type::Kind::BF16:
279 os << "bf16";
280 return;
281 case Type::Kind::F16:
282 os << "f16";
283 return;
284 case Type::Kind::F32:
285 os << "f32";
286 return;
287 case Type::Kind::F64:
288 os << "f64";
289 return;
Jacques Pienaarc0d69302018-07-27 11:07:12 -0700290 case Type::Kind::TFControl:
291 os << "tf_control";
292 return;
MLIR Team4718bc92018-07-17 16:56:54 -0700293
294 case Type::Kind::Integer: {
295 auto *integer = cast<IntegerType>(type);
296 os << 'i' << integer->getWidth();
297 return;
298 }
299 case Type::Kind::Function: {
300 auto *func = cast<FunctionType>(type);
301 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700302 interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700303 os << ") -> ";
304 auto results = func->getResults();
305 if (results.size() == 1)
306 os << *results[0];
307 else {
308 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700309 interleaveComma(results, [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700310 os << ')';
311 }
312 return;
313 }
314 case Type::Kind::Vector: {
315 auto *v = cast<VectorType>(type);
316 os << "vector<";
James Molloy87d81022018-07-23 11:44:40 -0700317 for (auto dim : v->getShape())
318 os << dim << 'x';
MLIR Team4718bc92018-07-17 16:56:54 -0700319 os << *v->getElementType() << '>';
320 return;
321 }
322 case Type::Kind::RankedTensor: {
323 auto *v = cast<RankedTensorType>(type);
324 os << "tensor<";
325 for (auto dim : v->getShape()) {
326 if (dim < 0)
327 os << '?';
328 else
329 os << dim;
330 os << 'x';
331 }
332 os << *v->getElementType() << '>';
333 return;
334 }
335 case Type::Kind::UnrankedTensor: {
336 auto *v = cast<UnrankedTensorType>(type);
Chris Lattner413db6a2018-07-25 12:55:50 -0700337 os << "tensor<??";
338 printType(v->getElementType());
339 os << '>';
MLIR Team4718bc92018-07-17 16:56:54 -0700340 return;
341 }
342 case Type::Kind::MemRef: {
343 auto *v = cast<MemRefType>(type);
344 os << "memref<";
345 for (auto dim : v->getShape()) {
346 if (dim < 0)
347 os << '?';
348 else
349 os << dim;
350 os << 'x';
351 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700352 printType(v->getElementType());
MLIR Team4718bc92018-07-17 16:56:54 -0700353 for (auto map : v->getAffineMaps()) {
354 os << ", ";
MLIR Teamb61885d2018-07-18 16:29:21 -0700355 printAffineMapReference(map);
MLIR Team4718bc92018-07-17 16:56:54 -0700356 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700357 // Only print the memory space if it is the non-default one.
358 if (v->getMemorySpace())
359 os << ", " << v->getMemorySpace();
MLIR Team4718bc92018-07-17 16:56:54 -0700360 os << '>';
361 return;
362 }
363 }
364}
365
366//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -0700367// Affine expressions and maps
368//===----------------------------------------------------------------------===//
369
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700370void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700371 switch (expr->getKind()) {
372 case AffineExpr::Kind::SymbolId:
373 os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
374 return;
375 case AffineExpr::Kind::DimId:
376 os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
377 return;
378 case AffineExpr::Kind::Constant:
379 os << cast<AffineConstantExpr>(expr)->getValue();
380 return;
381 case AffineExpr::Kind::Add:
382 case AffineExpr::Kind::Mul:
383 case AffineExpr::Kind::FloorDiv:
384 case AffineExpr::Kind::CeilDiv:
385 case AffineExpr::Kind::Mod:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700386 return printAffineBinaryOpExpr(cast<AffineBinaryOpExpr>(expr));
Chris Lattner4fd59b02018-07-20 09:35:47 -0700387 }
388}
389
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700390void ModulePrinter::printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700391 if (expr->getKind() != AffineExpr::Kind::Add) {
392 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700393 printAffineExpr(expr->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700394 switch (expr->getKind()) {
395 case AffineExpr::Kind::Mul:
396 os << " * ";
397 break;
398 case AffineExpr::Kind::FloorDiv:
399 os << " floordiv ";
400 break;
401 case AffineExpr::Kind::CeilDiv:
402 os << " ceildiv ";
403 break;
404 case AffineExpr::Kind::Mod:
405 os << " mod ";
406 break;
407 default:
408 llvm_unreachable("unexpected affine binary op expression");
409 }
410
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700411 printAffineExpr(expr->getRHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700412 os << ')';
413 return;
414 }
415
416 // Print out special "pretty" forms for add.
417 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700418 printAffineExpr(expr->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700419
420 // Pretty print addition to a product that has a negative operand as a
421 // subtraction.
422 if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(expr->getRHS())) {
423 if (rhs->getKind() == AffineExpr::Kind::Mul) {
424 if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
425 if (rrhs->getValue() < 0) {
426 os << " - (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700427 printAffineExpr(rhs->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700428 os << " * " << -rrhs->getValue() << "))";
429 return;
430 }
431 }
432 }
433 }
434
435 // Pretty print addition to a negative number as a subtraction.
436 if (auto *rhs = dyn_cast<AffineConstantExpr>(expr->getRHS())) {
437 if (rhs->getValue() < 0) {
438 os << " - " << -rhs->getValue() << ")";
439 return;
440 }
441 }
442
443 os << " + ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700444 printAffineExpr(expr->getRHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700445 os << ')';
446}
447
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700448void ModulePrinter::printAffineMap(const AffineMap *map) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700449 // Dimension identifiers.
450 os << '(';
451 for (int i = 0; i < (int)map->getNumDims() - 1; i++)
452 os << "d" << i << ", ";
453 if (map->getNumDims() >= 1)
454 os << "d" << map->getNumDims() - 1;
455 os << ")";
456
457 // Symbolic identifiers.
458 if (map->getNumSymbols() >= 1) {
459 os << " [";
460 for (int i = 0; i < (int)map->getNumSymbols() - 1; i++)
461 os << "s" << i << ", ";
462 if (map->getNumSymbols() >= 1)
463 os << "s" << map->getNumSymbols() - 1;
464 os << "]";
465 }
466
467 // AffineMap should have at least one result.
468 assert(!map->getResults().empty());
469 // Result affine expressions.
470 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700471 interleaveComma(map->getResults(),
472 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattner4fd59b02018-07-20 09:35:47 -0700473 os << ")";
474
475 if (!map->isBounded()) {
476 return;
477 }
478
479 // Print range sizes for bounded affine maps.
480 os << " size (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700481 interleaveComma(map->getRangeSizes(),
482 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattner4fd59b02018-07-20 09:35:47 -0700483 os << ")";
484}
485
486//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700487// Function printing
488//===----------------------------------------------------------------------===//
489
Chris Lattner4fd59b02018-07-20 09:35:47 -0700490void ModulePrinter::printFunctionSignature(const Function *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700491 auto type = fn->getType();
492
493 os << "@" << fn->getName() << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700494 interleaveComma(type->getInputs(),
495 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700496 os << ')';
497
498 switch (type->getResults().size()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700499 case 0:
500 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700501 case 1:
MLIR Team4718bc92018-07-17 16:56:54 -0700502 os << " -> ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700503 printType(type->getResults()[0]);
Chris Lattner4c95a502018-06-23 16:03:42 -0700504 break;
505 default:
506 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700507 interleaveComma(type->getResults(),
508 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700509 os << ')';
510 break;
511 }
512}
513
Chris Lattner4fd59b02018-07-20 09:35:47 -0700514void ModulePrinter::print(const ExtFunction *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700515 os << "extfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700516 printFunctionSignature(fn);
MLIR Team54b55a22018-07-18 10:16:05 -0700517 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700518}
519
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700520namespace {
521
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700522// FunctionPrinter contains common functionality for printing
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700523// CFG and ML functions.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700524class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700525public:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700526 FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700527
528 void printOperation(const Operation *op);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700529 void printDefaultOp(const Operation *op);
530
531 // Implement OpAsmPrinter.
532 raw_ostream &getStream() const { return os; }
533 void printType(const Type *type) { ModulePrinter::printType(type); }
534 void printAttribute(const Attribute *attr) {
535 ModulePrinter::printAttribute(attr);
536 }
537 void printAffineMap(const AffineMap *map) {
538 return ModulePrinter::printAffineMap(map);
539 }
540 void printAffineExpr(const AffineExpr *expr) {
541 return ModulePrinter::printAffineExpr(expr);
542 }
543
544 void printOperand(const SSAValue *value) { printValueID(value); }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700545
546protected:
Chris Lattnerf8cce872018-07-20 09:28:54 -0700547 void numberValueID(const SSAValue *value) {
548 assert(!valueIDs.count(value) && "Value numbered multiple times");
549 valueIDs[value] = nextValueID++;
550 }
551
Chris Lattner6119d382018-07-20 18:41:34 -0700552 void printValueID(const SSAValue *value,
553 bool dontPrintResultNo = false) const {
554 int resultNo = -1;
555 auto lookupValue = value;
556
557 // If this is a reference to the result of a multi-result instruction, print
558 // out the # identifier and make sure to map our lookup to the first result
559 // of the instruction.
560 if (auto *result = dyn_cast<InstResult>(value)) {
561 if (result->getOwner()->getNumResults() != 1) {
562 resultNo = result->getResultNumber();
563 lookupValue = result->getOwner()->getResult(0);
564 }
565 }
566
567 auto it = valueIDs.find(lookupValue);
568 if (it == valueIDs.end()) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700569 os << "<<INVALID SSA VALUE>>";
Chris Lattner6119d382018-07-20 18:41:34 -0700570 return;
571 }
572
573 os << '%' << it->getSecond();
574 if (resultNo != -1 && !dontPrintResultNo)
575 os << '#' << resultNo;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700576 }
577
578private:
579 /// This is the value ID for each SSA value in the current function.
580 DenseMap<const SSAValue *, unsigned> valueIDs;
581 unsigned nextValueID = 0;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700582};
James Molloy87d81022018-07-23 11:44:40 -0700583} // end anonymous namespace
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700584
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700585void FunctionPrinter::printOperation(const Operation *op) {
Chris Lattnerac591f12018-07-22 21:02:26 -0700586 if (op->getNumResults()) {
587 printValueID(op->getResult(0), /*dontPrintResultNo*/ true);
588 os << " = ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700589 }
590
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700591 // Check to see if this is a known operation. If so, use the registered
592 // custom printer hook.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700593 if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700594 opInfo->printAssembly(op, this);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700595 return;
596 }
597
Chris Lattnerf8cce872018-07-20 09:28:54 -0700598 // Otherwise use the standard verbose printing approach.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700599 printDefaultOp(op);
600}
Chris Lattnerf8cce872018-07-20 09:28:54 -0700601
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700602void FunctionPrinter::printDefaultOp(const Operation *op) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700603 // TODO: escape name if necessary.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700604 os << "\"" << op->getName().str() << "\"(";
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700605
Chris Lattnerac591f12018-07-22 21:02:26 -0700606 interleaveComma(op->getOperands(),
607 [&](const SSAValue *value) { printValueID(value); });
Chris Lattner7f9cc272018-07-19 08:35:28 -0700608
Chris Lattnerf8cce872018-07-20 09:28:54 -0700609 os << ')';
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700610 auto attrs = op->getAttrs();
611 if (!attrs.empty()) {
612 os << '{';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700613 interleaveComma(attrs, [&](NamedAttribute attr) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700614 os << attr.first << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700615 printAttribute(attr.second);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700616 });
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700617 os << '}';
618 }
Chris Lattner3b2ef762018-07-18 15:31:25 -0700619
Chris Lattnerac591f12018-07-22 21:02:26 -0700620 // Print the type signature of the operation.
621 os << " : (";
622 interleaveComma(op->getOperands(),
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700623 [&](const SSAValue *value) { printType(value->getType()); });
Chris Lattnerac591f12018-07-22 21:02:26 -0700624 os << ") -> ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700625
Chris Lattnerac591f12018-07-22 21:02:26 -0700626 if (op->getNumResults() == 1) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700627 printType(op->getResult(0)->getType());
Chris Lattnerac591f12018-07-22 21:02:26 -0700628 } else {
629 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700630 interleaveComma(op->getResults(), [&](const SSAValue *result) {
631 printType(result->getType());
632 });
Chris Lattnerac591f12018-07-22 21:02:26 -0700633 os << ')';
Chris Lattnerf8cce872018-07-20 09:28:54 -0700634 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700635}
636
Chris Lattner4c95a502018-06-23 16:03:42 -0700637//===----------------------------------------------------------------------===//
638// CFG Function printing
639//===----------------------------------------------------------------------===//
640
641namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700642class CFGFunctionPrinter : public FunctionPrinter {
Chris Lattner4c95a502018-06-23 16:03:42 -0700643public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700644 CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
Chris Lattner4c95a502018-06-23 16:03:42 -0700645
646 const CFGFunction *getFunction() const { return function; }
647
648 void print();
649 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700650
651 void print(const Instruction *inst);
652 void print(const OperationInst *inst);
653 void print(const ReturnInst *inst);
654 void print(const BranchInst *inst);
James Molloy4f788372018-07-24 15:01:27 -0700655 void print(const CondBranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700656
657 unsigned getBBID(const BasicBlock *block) {
658 auto it = basicBlockIDs.find(block);
659 assert(it != basicBlockIDs.end() && "Block not in this function?");
660 return it->second;
661 }
662
663private:
664 const CFGFunction *function;
MLIR Team54b55a22018-07-18 10:16:05 -0700665 DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700666
Chris Lattner4fd59b02018-07-20 09:35:47 -0700667 void numberValuesInBlock(const BasicBlock *block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700668};
James Molloy87d81022018-07-23 11:44:40 -0700669} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -0700670
Chris Lattner4fd59b02018-07-20 09:35:47 -0700671CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
672 const ModulePrinter &other)
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700673 : FunctionPrinter(other), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700674 // Each basic block gets a unique ID per function.
675 unsigned blockID = 0;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700676 for (auto &block : *function) {
677 basicBlockIDs[&block] = blockID++;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700678 numberValuesInBlock(&block);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700679 }
680}
681
682/// Number all of the SSA values in the specified basic block.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700683void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700684 for (auto *arg : block->getArguments()) {
685 numberValueID(arg);
686 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700687 for (auto &op : *block) {
688 // We number instruction that have results, and we only number the first
689 // result.
690 if (op.getNumResults() != 0)
691 numberValueID(op.getResult(0));
692 }
693
694 // Terminators do not define values.
Chris Lattner4c95a502018-06-23 16:03:42 -0700695}
696
Chris Lattner4fd59b02018-07-20 09:35:47 -0700697void CFGFunctionPrinter::print() {
Chris Lattner4c95a502018-06-23 16:03:42 -0700698 os << "cfgfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700699 printFunctionSignature(getFunction());
Chris Lattner4c95a502018-06-23 16:03:42 -0700700 os << " {\n";
701
James Molloy87d81022018-07-23 11:44:40 -0700702 for (auto &block : *function)
703 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700704 os << "}\n\n";
705}
706
Chris Lattner4fd59b02018-07-20 09:35:47 -0700707void CFGFunctionPrinter::print(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700708 os << "bb" << getBBID(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700709
James Molloy61a656c2018-07-22 15:45:24 -0700710 if (!block->args_empty()) {
711 os << '(';
712 interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
713 printValueID(arg);
714 os << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700715 printType(arg->getType());
James Molloy61a656c2018-07-22 15:45:24 -0700716 });
717 os << ')';
718 }
Chris Lattner25ce3062018-07-27 11:10:12 -0700719 os << ':';
720
721 // Print out some context information about the predecessors of this block.
722 if (!block->getFunction()) {
723 os << "\t// block is not in a function!";
724 } else if (block->hasNoPredecessors()) {
725 // Don't print "no predecessors" for the entry block.
726 if (block != &block->getFunction()->front())
727 os << "\t// no predecessors";
728 } else if (auto *pred = block->getSinglePredecessor()) {
729 os << "\t// pred: bb" << getBBID(pred);
730 } else {
731 // We want to print the predecessors in increasing numeric order, not in
732 // whatever order the use-list is in, so gather and sort them.
733 SmallVector<unsigned, 4> predIDs;
734 for (auto *pred : block->getPredecessors())
735 predIDs.push_back(getBBID(pred));
736 llvm::array_pod_sort(predIDs.begin(), predIDs.end());
737
738 os << "\t// " << predIDs.size() << " preds: ";
739
740 interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
741 }
742 os << '\n';
James Molloy61a656c2018-07-22 15:45:24 -0700743
Jacques Pienaarb020c542018-07-15 00:06:54 -0700744 for (auto &inst : block->getOperations()) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700745 os << " ";
Chris Lattner3a467cc2018-07-01 20:28:00 -0700746 print(&inst);
James Molloy61a656c2018-07-22 15:45:24 -0700747 os << '\n';
Jacques Pienaarb020c542018-07-15 00:06:54 -0700748 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700749
750 print(block->getTerminator());
James Molloy61a656c2018-07-22 15:45:24 -0700751 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700752}
753
Chris Lattner4fd59b02018-07-20 09:35:47 -0700754void CFGFunctionPrinter::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700755 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700756 case Instruction::Kind::Operation:
757 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700758 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700759 return print(cast<BranchInst>(inst));
James Molloy4f788372018-07-24 15:01:27 -0700760 case TerminatorInst::Kind::CondBranch:
761 return print(cast<CondBranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700762 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700763 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700764 }
765}
766
Chris Lattner4fd59b02018-07-20 09:35:47 -0700767void CFGFunctionPrinter::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700768 printOperation(inst);
Chris Lattner3b2ef762018-07-18 15:31:25 -0700769}
Chris Lattner1604e472018-07-23 08:42:19 -0700770
Chris Lattner4fd59b02018-07-20 09:35:47 -0700771void CFGFunctionPrinter::print(const BranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700772 os << "br bb" << getBBID(inst->getDest());
Chris Lattner1604e472018-07-23 08:42:19 -0700773
774 if (inst->getNumOperands() != 0) {
775 os << '(';
776 // TODO: Use getOperands() when we have it.
777 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
778 printValueID(operand.get());
779 });
780 os << ") : ";
781 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700782 printType(operand.get()->getType());
Chris Lattner1604e472018-07-23 08:42:19 -0700783 });
784 }
Chris Lattnered65a732018-06-28 20:45:33 -0700785}
Chris Lattner1604e472018-07-23 08:42:19 -0700786
James Molloy4f788372018-07-24 15:01:27 -0700787void CFGFunctionPrinter::print(const CondBranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700788 os << "cond_br ";
James Molloy4f788372018-07-24 15:01:27 -0700789 printValueID(inst->getCondition());
790
791 os << ", bb" << getBBID(inst->getTrueDest());
792 if (inst->getNumTrueOperands() != 0) {
793 os << '(';
794 interleaveComma(inst->getTrueOperands(),
795 [&](const CFGValue *operand) { printValueID(operand); });
796 os << " : ";
797 interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700798 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700799 });
800 os << ")";
801 }
802
803 os << ", bb" << getBBID(inst->getFalseDest());
804 if (inst->getNumFalseOperands() != 0) {
805 os << '(';
806 interleaveComma(inst->getFalseOperands(),
807 [&](const CFGValue *operand) { printValueID(operand); });
808 os << " : ";
809 interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700810 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700811 });
812 os << ")";
813 }
814}
815
Chris Lattner40746442018-07-21 14:32:09 -0700816void CFGFunctionPrinter::print(const ReturnInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700817 os << "return";
Chris Lattner40746442018-07-21 14:32:09 -0700818
819 if (inst->getNumOperands() != 0)
820 os << ' ';
821
James Molloy4f788372018-07-24 15:01:27 -0700822 interleaveComma(inst->getOperands(),
823 [&](const CFGValue *operand) { printValueID(operand); });
824 os << " : ";
Chris Lattnerac591f12018-07-22 21:02:26 -0700825 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700826 printType(operand->getType());
Chris Lattner40746442018-07-21 14:32:09 -0700827 });
828}
MLIR Team54b55a22018-07-18 10:16:05 -0700829
Chris Lattner4fd59b02018-07-20 09:35:47 -0700830void ModulePrinter::print(const CFGFunction *fn) {
831 CFGFunctionPrinter(fn, *this).print();
Chris Lattnered65a732018-06-28 20:45:33 -0700832}
833
Chris Lattner4c95a502018-06-23 16:03:42 -0700834//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700835// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700836//===----------------------------------------------------------------------===//
837
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700838namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700839class MLFunctionPrinter : public FunctionPrinter {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700840public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700841 MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700842
843 const MLFunction *getFunction() const { return function; }
844
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700845 // Prints ML function
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700846 void print();
847
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700848 // Methods to print ML function statements
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700849 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700850 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700851 void print(const ForStmt *stmt);
852 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700853 void print(const StmtBlock *block);
854
855 // Number of spaces used for indenting nested statements
856 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700857
858private:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700859 void numberValues();
860
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700861 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700862 int numSpaces;
863};
James Molloy87d81022018-07-23 11:44:40 -0700864} // end anonymous namespace
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700865
Chris Lattner4fd59b02018-07-20 09:35:47 -0700866MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
867 const ModulePrinter &other)
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700868 : FunctionPrinter(other), function(function), numSpaces(0) {
869 numberValues();
870}
871
872/// Number all of the SSA values in this ML function.
873void MLFunctionPrinter::numberValues() {
874 // Visits all operation statements and numbers the first result.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700875 struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700876 NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
877 void visitOperationStmt(OperationStmt *stmt) {
878 if (stmt->getNumResults() != 0)
879 printer->numberValueID(stmt->getResult(0));
880 }
881 MLFunctionPrinter *printer;
882 };
883
884 NumberValuesPass pass(this);
885 // TODO: it'd be cleaner to have constant visitor istead of using const_cast.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700886 pass.walk(const_cast<MLFunction *>(function));
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700887}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700888
Chris Lattner4fd59b02018-07-20 09:35:47 -0700889void MLFunctionPrinter::print() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700890 os << "mlfunc ";
891 // FIXME: should print argument names rather than just signature
Chris Lattner4fd59b02018-07-20 09:35:47 -0700892 printFunctionSignature(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700893 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700894 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700895 os << " return\n";
896 os << "}\n\n";
897}
898
Chris Lattner4fd59b02018-07-20 09:35:47 -0700899void MLFunctionPrinter::print(const StmtBlock *block) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700900 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -0700901 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700902 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -0700903 os << "\n";
904 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700905 numSpaces -= indentWidth;
906}
907
Chris Lattner4fd59b02018-07-20 09:35:47 -0700908void MLFunctionPrinter::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700909 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700910 case Statement::Kind::Operation:
911 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700912 case Statement::Kind::For:
913 return print(cast<ForStmt>(stmt));
914 case Statement::Kind::If:
915 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700916 }
917}
918
Chris Lattner4fd59b02018-07-20 09:35:47 -0700919void MLFunctionPrinter::print(const OperationStmt *stmt) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700920 os.indent(numSpaces);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700921 printOperation(stmt);
922}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700923
Chris Lattner4fd59b02018-07-20 09:35:47 -0700924void MLFunctionPrinter::print(const ForStmt *stmt) {
Tatiana Shpeisman1da50c42018-07-19 09:52:39 -0700925 os.indent(numSpaces) << "for x = " << *stmt->getLowerBound();
926 os << " to " << *stmt->getUpperBound();
927 if (stmt->getStep()->getValue() != 1)
928 os << " step " << *stmt->getStep();
929
930 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700931 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700932 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700933}
934
Chris Lattner4fd59b02018-07-20 09:35:47 -0700935void MLFunctionPrinter::print(const IfStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700936 os.indent(numSpaces) << "if () {\n";
937 print(stmt->getThenClause());
938 os.indent(numSpaces) << "}";
939 if (stmt->hasElseClause()) {
940 os << " else {\n";
941 print(stmt->getElseClause());
942 os.indent(numSpaces) << "}";
943 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700944}
945
Chris Lattner4fd59b02018-07-20 09:35:47 -0700946void ModulePrinter::print(const MLFunction *fn) {
947 MLFunctionPrinter(fn, *this).print();
MLIR Team4718bc92018-07-17 16:56:54 -0700948}
949
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700950//===----------------------------------------------------------------------===//
951// print and dump methods
952//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700953
MLIR Teamb61885d2018-07-18 16:29:21 -0700954void Attribute::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700955 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700956 ModulePrinter(os, state).printAttribute(this);
MLIR Teamb61885d2018-07-18 16:29:21 -0700957}
958
James Molloy87d81022018-07-23 11:44:40 -0700959void Attribute::dump() const { print(llvm::errs()); }
MLIR Teamb61885d2018-07-18 16:29:21 -0700960
MLIR Team4718bc92018-07-17 16:56:54 -0700961void Type::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700962 ModuleState state(getContext());
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700963 ModulePrinter(os, state).printType(this);
MLIR Team4718bc92018-07-17 16:56:54 -0700964}
965
MLIR Team54b55a22018-07-18 10:16:05 -0700966void Type::dump() const { print(llvm::errs()); }
MLIR Team4718bc92018-07-17 16:56:54 -0700967
MLIR Team718c82f2018-07-16 09:45:22 -0700968void AffineMap::dump() const {
969 print(llvm::errs());
970 llvm::errs() << "\n";
971}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700972
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700973void AffineExpr::dump() const {
974 print(llvm::errs());
975 llvm::errs() << "\n";
976}
977
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700978void AffineExpr::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700979 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700980 ModulePrinter(os, state).printAffineExpr(this);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700981}
982
983void AffineMap::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700984 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700985 ModulePrinter(os, state).printAffineMap(this);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700986}
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700987
Chris Lattner4fd59b02018-07-20 09:35:47 -0700988void Instruction::print(raw_ostream &os) const {
989 ModuleState state(getFunction()->getContext());
990 ModulePrinter modulePrinter(os, state);
991 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
992}
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700993
Chris Lattner4fd59b02018-07-20 09:35:47 -0700994void Instruction::dump() const {
995 print(llvm::errs());
996 llvm::errs() << "\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700997}
998
Chris Lattner4c95a502018-06-23 16:03:42 -0700999void BasicBlock::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001000 ModuleState state(getFunction()->getContext());
1001 ModulePrinter modulePrinter(os, state);
1002 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001003}
1004
MLIR Team54b55a22018-07-18 10:16:05 -07001005void BasicBlock::dump() const { print(llvm::errs()); }
Chris Lattner4c95a502018-06-23 16:03:42 -07001006
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001007void Statement::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001008 ModuleState state(getFunction()->getContext());
1009 ModulePrinter modulePrinter(os, state);
1010 MLFunctionPrinter(getFunction(), modulePrinter).print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001011}
1012
MLIR Team54b55a22018-07-18 10:16:05 -07001013void Statement::dump() const { print(llvm::errs()); }
Jacques Pienaarb020c542018-07-15 00:06:54 -07001014
Chris Lattner4c95a502018-06-23 16:03:42 -07001015void Function::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001016 ModuleState state(getContext());
1017 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001018}
1019
MLIR Team54b55a22018-07-18 10:16:05 -07001020void Function::dump() const { print(llvm::errs()); }
1021
Chris Lattner4c95a502018-06-23 16:03:42 -07001022void Module::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001023 ModuleState state(getContext());
1024 state.initialize(this);
1025 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001026}
1027
MLIR Team54b55a22018-07-18 10:16:05 -07001028void Module::dump() const { print(llvm::errs()); }