blob: 1102559f9b2b91b4fe2b79194ba4f2bf229a579a [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) {
Chris Lattner3164ae62018-07-28 09:36:25 -070096 if (auto *funcType = dyn_cast<FunctionType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -070097 // Visit input and result types for functions.
Chris Lattner3164ae62018-07-28 09:36:25 -070098 for (auto *input : funcType->getInputs())
MLIR Team4718bc92018-07-17 16:56:54 -070099 visitType(input);
Chris Lattner3164ae62018-07-28 09:36:25 -0700100 for (auto *result : funcType->getResults())
MLIR Team4718bc92018-07-17 16:56:54 -0700101 visitType(result);
Chris Lattner3164ae62018-07-28 09:36:25 -0700102 } else if (auto *memref = dyn_cast<MemRefType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -0700103 // Visit affine maps in memref type.
Chris Lattner3164ae62018-07-28 09:36:25 -0700104 for (auto *map : memref->getAffineMaps()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700105 recordAffineMapReference(map);
106 }
107 }
108}
109
MLIR Teamb61885d2018-07-18 16:29:21 -0700110void ModuleState::visitAttribute(const Attribute *attr) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700111 if (auto *mapAttr = dyn_cast<AffineMapAttr>(attr)) {
112 recordAffineMapReference(mapAttr->getValue());
113 } else if (auto *array = dyn_cast<ArrayAttr>(attr)) {
114 for (auto elt : array->getValue()) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700115 visitAttribute(elt);
116 }
117 }
118}
119
120void ModuleState::visitOperation(const Operation *op) {
121 for (auto elt : op->getAttrs()) {
122 visitAttribute(elt.second);
123 }
124}
125
MLIR Team4718bc92018-07-17 16:56:54 -0700126void ModuleState::visitExtFunction(const ExtFunction *fn) {
127 visitType(fn->getType());
128}
129
130void ModuleState::visitCFGFunction(const CFGFunction *fn) {
131 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700132 for (auto &block : *fn) {
133 for (auto &op : block.getOperations()) {
134 visitOperation(&op);
135 }
136 }
MLIR Team4718bc92018-07-17 16:56:54 -0700137}
138
139void ModuleState::visitMLFunction(const MLFunction *fn) {
140 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700141 // TODO Visit function body statements (and attributes if required).
MLIR Team4718bc92018-07-17 16:56:54 -0700142}
143
144void ModuleState::visitFunction(const Function *fn) {
145 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700146 case Function::Kind::ExtFunc:
147 return visitExtFunction(cast<ExtFunction>(fn));
148 case Function::Kind::CFGFunc:
149 return visitCFGFunction(cast<CFGFunction>(fn));
150 case Function::Kind::MLFunc:
151 return visitMLFunction(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700152 }
153}
154
Chris Lattner4fd59b02018-07-20 09:35:47 -0700155// Initializes module state, populating affine map state.
156void ModuleState::initialize(const Module *module) {
Chris Lattnera8e47672018-07-25 14:08:16 -0700157 for (auto &fn : *module) {
158 visitFunction(&fn);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700159 }
160}
161
162//===----------------------------------------------------------------------===//
163// ModulePrinter
164//===----------------------------------------------------------------------===//
165
166namespace {
167class ModulePrinter {
168public:
169 ModulePrinter(raw_ostream &os, ModuleState &state) : os(os), state(state) {}
170 explicit ModulePrinter(const ModulePrinter &printer)
171 : os(printer.os), state(printer.state) {}
172
173 template <typename Container, typename UnaryFunctor>
174 inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
175 interleave(c.begin(), c.end(), each_fn, [&]() { os << ", "; });
176 }
177
178 void print(const Module *module);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700179 void printAttribute(const Attribute *attr);
180 void printType(const Type *type);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700181 void print(const Function *fn);
182 void print(const ExtFunction *fn);
183 void print(const CFGFunction *fn);
184 void print(const MLFunction *fn);
185
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700186 void printAffineMap(const AffineMap *map);
187 void printAffineExpr(const AffineExpr *expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700188
189protected:
190 raw_ostream &os;
191 ModuleState &state;
192
193 void printFunctionSignature(const Function *fn);
194 void printAffineMapId(int affineMapId) const;
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700195 void printAffineMapReference(const AffineMap *affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700196
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700197 void printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700198};
199} // end anonymous namespace
200
MLIR Team4718bc92018-07-17 16:56:54 -0700201// Prints function with initialized module state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700202void ModulePrinter::print(const Function *fn) {
MLIR Team4718bc92018-07-17 16:56:54 -0700203 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700204 case Function::Kind::ExtFunc:
205 return print(cast<ExtFunction>(fn));
206 case Function::Kind::CFGFunc:
207 return print(cast<CFGFunction>(fn));
208 case Function::Kind::MLFunc:
209 return print(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700210 }
211}
212
213// Prints affine map identifier.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700214void ModulePrinter::printAffineMapId(int affineMapId) const {
MLIR Team4718bc92018-07-17 16:56:54 -0700215 os << "#map" << affineMapId;
216}
217
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700218void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700219 int mapId = state.getAffineMapId(affineMap);
MLIR Teamb61885d2018-07-18 16:29:21 -0700220 if (mapId >= 0) {
221 // Map will be printed at top of module so print reference to its id.
222 printAffineMapId(mapId);
223 } else {
224 // Map not in module state so print inline.
225 affineMap->print(os);
226 }
227}
228
Chris Lattner4fd59b02018-07-20 09:35:47 -0700229void ModulePrinter::print(const Module *module) {
James Molloyc4666722018-07-24 09:48:31 -0700230 for (const auto &map : state.getAffineMapIds()) {
231 printAffineMapId(state.getAffineMapId(map));
MLIR Team4718bc92018-07-17 16:56:54 -0700232 os << " = ";
James Molloyc4666722018-07-24 09:48:31 -0700233 map->print(os);
MLIR Team4718bc92018-07-17 16:56:54 -0700234 os << '\n';
235 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700236 for (auto const &fn : *module)
237 print(&fn);
MLIR Team4718bc92018-07-17 16:56:54 -0700238}
239
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700240void ModulePrinter::printAttribute(const Attribute *attr) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700241 switch (attr->getKind()) {
242 case Attribute::Kind::Bool:
243 os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
244 break;
245 case Attribute::Kind::Integer:
246 os << cast<IntegerAttr>(attr)->getValue();
247 break;
248 case Attribute::Kind::Float:
249 // FIXME: this isn't precise, we should print with a hex format.
250 os << cast<FloatAttr>(attr)->getValue();
251 break;
252 case Attribute::Kind::String:
253 // FIXME: should escape the string.
254 os << '"' << cast<StringAttr>(attr)->getValue() << '"';
255 break;
256 case Attribute::Kind::Array: {
257 auto elts = cast<ArrayAttr>(attr)->getValue();
258 os << '[';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700259 interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
MLIR Teamb61885d2018-07-18 16:29:21 -0700260 os << ']';
261 break;
262 }
263 case Attribute::Kind::AffineMap:
264 printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
265 break;
266 }
267}
268
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700269void ModulePrinter::printType(const Type *type) {
MLIR Team4718bc92018-07-17 16:56:54 -0700270 switch (type->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700271 case Type::Kind::AffineInt:
272 os << "affineint";
273 return;
274 case Type::Kind::BF16:
275 os << "bf16";
276 return;
277 case Type::Kind::F16:
278 os << "f16";
279 return;
280 case Type::Kind::F32:
281 os << "f32";
282 return;
283 case Type::Kind::F64:
284 os << "f64";
285 return;
Jacques Pienaarc0d69302018-07-27 11:07:12 -0700286 case Type::Kind::TFControl:
287 os << "tf_control";
288 return;
MLIR Team4718bc92018-07-17 16:56:54 -0700289
290 case Type::Kind::Integer: {
291 auto *integer = cast<IntegerType>(type);
292 os << 'i' << integer->getWidth();
293 return;
294 }
295 case Type::Kind::Function: {
296 auto *func = cast<FunctionType>(type);
297 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700298 interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700299 os << ") -> ";
300 auto results = func->getResults();
301 if (results.size() == 1)
302 os << *results[0];
303 else {
304 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700305 interleaveComma(results, [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700306 os << ')';
307 }
308 return;
309 }
310 case Type::Kind::Vector: {
311 auto *v = cast<VectorType>(type);
312 os << "vector<";
James Molloy87d81022018-07-23 11:44:40 -0700313 for (auto dim : v->getShape())
314 os << dim << 'x';
MLIR Team4718bc92018-07-17 16:56:54 -0700315 os << *v->getElementType() << '>';
316 return;
317 }
318 case Type::Kind::RankedTensor: {
319 auto *v = cast<RankedTensorType>(type);
320 os << "tensor<";
321 for (auto dim : v->getShape()) {
322 if (dim < 0)
323 os << '?';
324 else
325 os << dim;
326 os << 'x';
327 }
328 os << *v->getElementType() << '>';
329 return;
330 }
331 case Type::Kind::UnrankedTensor: {
332 auto *v = cast<UnrankedTensorType>(type);
Chris Lattner413db6a2018-07-25 12:55:50 -0700333 os << "tensor<??";
334 printType(v->getElementType());
335 os << '>';
MLIR Team4718bc92018-07-17 16:56:54 -0700336 return;
337 }
338 case Type::Kind::MemRef: {
339 auto *v = cast<MemRefType>(type);
340 os << "memref<";
341 for (auto dim : v->getShape()) {
342 if (dim < 0)
343 os << '?';
344 else
345 os << dim;
346 os << 'x';
347 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700348 printType(v->getElementType());
MLIR Team4718bc92018-07-17 16:56:54 -0700349 for (auto map : v->getAffineMaps()) {
350 os << ", ";
MLIR Teamb61885d2018-07-18 16:29:21 -0700351 printAffineMapReference(map);
MLIR Team4718bc92018-07-17 16:56:54 -0700352 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700353 // Only print the memory space if it is the non-default one.
354 if (v->getMemorySpace())
355 os << ", " << v->getMemorySpace();
MLIR Team4718bc92018-07-17 16:56:54 -0700356 os << '>';
357 return;
358 }
359 }
360}
361
362//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -0700363// Affine expressions and maps
364//===----------------------------------------------------------------------===//
365
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700366void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700367 switch (expr->getKind()) {
368 case AffineExpr::Kind::SymbolId:
369 os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
370 return;
371 case AffineExpr::Kind::DimId:
372 os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
373 return;
374 case AffineExpr::Kind::Constant:
375 os << cast<AffineConstantExpr>(expr)->getValue();
376 return;
377 case AffineExpr::Kind::Add:
378 case AffineExpr::Kind::Mul:
379 case AffineExpr::Kind::FloorDiv:
380 case AffineExpr::Kind::CeilDiv:
381 case AffineExpr::Kind::Mod:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700382 return printAffineBinaryOpExpr(cast<AffineBinaryOpExpr>(expr));
Chris Lattner4fd59b02018-07-20 09:35:47 -0700383 }
384}
385
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700386void ModulePrinter::printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700387 if (expr->getKind() != AffineExpr::Kind::Add) {
388 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700389 printAffineExpr(expr->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700390 switch (expr->getKind()) {
391 case AffineExpr::Kind::Mul:
392 os << " * ";
393 break;
394 case AffineExpr::Kind::FloorDiv:
395 os << " floordiv ";
396 break;
397 case AffineExpr::Kind::CeilDiv:
398 os << " ceildiv ";
399 break;
400 case AffineExpr::Kind::Mod:
401 os << " mod ";
402 break;
403 default:
404 llvm_unreachable("unexpected affine binary op expression");
405 }
406
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700407 printAffineExpr(expr->getRHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700408 os << ')';
409 return;
410 }
411
412 // Print out special "pretty" forms for add.
413 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700414 printAffineExpr(expr->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700415
416 // Pretty print addition to a product that has a negative operand as a
417 // subtraction.
418 if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(expr->getRHS())) {
419 if (rhs->getKind() == AffineExpr::Kind::Mul) {
420 if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
421 if (rrhs->getValue() < 0) {
422 os << " - (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700423 printAffineExpr(rhs->getLHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700424 os << " * " << -rrhs->getValue() << "))";
425 return;
426 }
427 }
428 }
429 }
430
431 // Pretty print addition to a negative number as a subtraction.
432 if (auto *rhs = dyn_cast<AffineConstantExpr>(expr->getRHS())) {
433 if (rhs->getValue() < 0) {
434 os << " - " << -rhs->getValue() << ")";
435 return;
436 }
437 }
438
439 os << " + ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700440 printAffineExpr(expr->getRHS());
Chris Lattner4fd59b02018-07-20 09:35:47 -0700441 os << ')';
442}
443
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700444void ModulePrinter::printAffineMap(const AffineMap *map) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700445 // Dimension identifiers.
446 os << '(';
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700447 for (int i = 0; i < (int)map->getNumDims() - 1; ++i)
448 os << 'd' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700449 if (map->getNumDims() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700450 os << 'd' << map->getNumDims() - 1;
451 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700452
453 // Symbolic identifiers.
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700454 if (map->getNumSymbols() != 0) {
455 os << '[';
456 for (unsigned i = 0; i < map->getNumSymbols() - 1; ++i)
457 os << 's' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700458 if (map->getNumSymbols() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700459 os << 's' << map->getNumSymbols() - 1;
460 os << ']';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700461 }
462
463 // AffineMap should have at least one result.
464 assert(!map->getResults().empty());
465 // Result affine expressions.
466 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700467 interleaveComma(map->getResults(),
468 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700469 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700470
471 if (!map->isBounded()) {
472 return;
473 }
474
475 // Print range sizes for bounded affine maps.
476 os << " size (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700477 interleaveComma(map->getRangeSizes(),
478 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700479 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700480}
481
482//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700483// Function printing
484//===----------------------------------------------------------------------===//
485
Chris Lattner4fd59b02018-07-20 09:35:47 -0700486void ModulePrinter::printFunctionSignature(const Function *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700487 auto type = fn->getType();
488
489 os << "@" << fn->getName() << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700490 interleaveComma(type->getInputs(),
491 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700492 os << ')';
493
494 switch (type->getResults().size()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700495 case 0:
496 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700497 case 1:
MLIR Team4718bc92018-07-17 16:56:54 -0700498 os << " -> ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700499 printType(type->getResults()[0]);
Chris Lattner4c95a502018-06-23 16:03:42 -0700500 break;
501 default:
502 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700503 interleaveComma(type->getResults(),
504 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700505 os << ')';
506 break;
507 }
508}
509
Chris Lattner4fd59b02018-07-20 09:35:47 -0700510void ModulePrinter::print(const ExtFunction *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700511 os << "extfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700512 printFunctionSignature(fn);
MLIR Team54b55a22018-07-18 10:16:05 -0700513 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700514}
515
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700516namespace {
517
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700518// FunctionPrinter contains common functionality for printing
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700519// CFG and ML functions.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700520class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700521public:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700522 FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700523
524 void printOperation(const Operation *op);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700525 void printDefaultOp(const Operation *op);
526
527 // Implement OpAsmPrinter.
528 raw_ostream &getStream() const { return os; }
529 void printType(const Type *type) { ModulePrinter::printType(type); }
530 void printAttribute(const Attribute *attr) {
531 ModulePrinter::printAttribute(attr);
532 }
533 void printAffineMap(const AffineMap *map) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700534 return ModulePrinter::printAffineMapReference(map);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700535 }
536 void printAffineExpr(const AffineExpr *expr) {
537 return ModulePrinter::printAffineExpr(expr);
538 }
539
540 void printOperand(const SSAValue *value) { printValueID(value); }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700541
542protected:
Chris Lattnerf8cce872018-07-20 09:28:54 -0700543 void numberValueID(const SSAValue *value) {
544 assert(!valueIDs.count(value) && "Value numbered multiple times");
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700545 unsigned id;
546 switch (value->getKind()) {
547 case SSAValueKind::BBArgument:
548 case SSAValueKind::InstResult:
549 case SSAValueKind::StmtResult:
550 id = nextValueID++;
551 break;
552 case SSAValueKind::FnArgument:
553 id = nextFnArgumentID++;
554 break;
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700555 case SSAValueKind::ForStmt:
556 id = nextLoopID++;
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700557 break;
558 }
559 valueIDs[value] = id;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700560 }
561
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700562 void printValueID(const SSAValue *value, bool printResultNo = true) const {
Chris Lattner6119d382018-07-20 18:41:34 -0700563 int resultNo = -1;
564 auto lookupValue = value;
565
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700566 // If this is a reference to the result of a multi-result instruction or
567 // statement, print out the # identifier and make sure to map our lookup
568 // to the first result of the instruction.
Chris Lattner6119d382018-07-20 18:41:34 -0700569 if (auto *result = dyn_cast<InstResult>(value)) {
570 if (result->getOwner()->getNumResults() != 1) {
571 resultNo = result->getResultNumber();
572 lookupValue = result->getOwner()->getResult(0);
573 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700574 } else if (auto *result = dyn_cast<StmtResult>(value)) {
575 if (result->getOwner()->getNumResults() != 1) {
576 resultNo = result->getResultNumber();
577 lookupValue = result->getOwner()->getResult(0);
578 }
Chris Lattner6119d382018-07-20 18:41:34 -0700579 }
580
581 auto it = valueIDs.find(lookupValue);
582 if (it == valueIDs.end()) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700583 os << "<<INVALID SSA VALUE>>";
Chris Lattner6119d382018-07-20 18:41:34 -0700584 return;
585 }
586
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700587 os << '%';
588 if (isa<ForStmt>(value))
589
590 os << 'i';
591 else if (isa<FnArgument>(value))
592 os << "arg";
593 os << it->getSecond();
594 if (resultNo != -1 && printResultNo)
Chris Lattner6119d382018-07-20 18:41:34 -0700595 os << '#' << resultNo;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700596 }
597
598private:
599 /// This is the value ID for each SSA value in the current function.
600 DenseMap<const SSAValue *, unsigned> valueIDs;
601 unsigned nextValueID = 0;
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700602 unsigned nextLoopID = 0;
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700603 unsigned nextFnArgumentID = 0;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700604};
James Molloy87d81022018-07-23 11:44:40 -0700605} // end anonymous namespace
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700606
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700607void FunctionPrinter::printOperation(const Operation *op) {
Chris Lattnerac591f12018-07-22 21:02:26 -0700608 if (op->getNumResults()) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700609 printValueID(op->getResult(0), /*printResultNo=*/false);
Chris Lattnerac591f12018-07-22 21:02:26 -0700610 os << " = ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700611 }
612
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700613 // Check to see if this is a known operation. If so, use the registered
614 // custom printer hook.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700615 if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700616 opInfo->printAssembly(op, this);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700617 return;
618 }
619
Chris Lattnerf8cce872018-07-20 09:28:54 -0700620 // Otherwise use the standard verbose printing approach.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700621 printDefaultOp(op);
622}
Chris Lattnerf8cce872018-07-20 09:28:54 -0700623
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700624void FunctionPrinter::printDefaultOp(const Operation *op) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700625 // TODO: escape name if necessary.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700626 os << "\"" << op->getName().str() << "\"(";
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700627
Chris Lattnerac591f12018-07-22 21:02:26 -0700628 interleaveComma(op->getOperands(),
629 [&](const SSAValue *value) { printValueID(value); });
Chris Lattner7f9cc272018-07-19 08:35:28 -0700630
Chris Lattnerf8cce872018-07-20 09:28:54 -0700631 os << ')';
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700632 auto attrs = op->getAttrs();
633 if (!attrs.empty()) {
634 os << '{';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700635 interleaveComma(attrs, [&](NamedAttribute attr) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700636 os << attr.first << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700637 printAttribute(attr.second);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700638 });
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700639 os << '}';
640 }
Chris Lattner3b2ef762018-07-18 15:31:25 -0700641
Chris Lattnerac591f12018-07-22 21:02:26 -0700642 // Print the type signature of the operation.
643 os << " : (";
644 interleaveComma(op->getOperands(),
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700645 [&](const SSAValue *value) { printType(value->getType()); });
Chris Lattnerac591f12018-07-22 21:02:26 -0700646 os << ") -> ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700647
Chris Lattnerac591f12018-07-22 21:02:26 -0700648 if (op->getNumResults() == 1) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700649 printType(op->getResult(0)->getType());
Chris Lattnerac591f12018-07-22 21:02:26 -0700650 } else {
651 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700652 interleaveComma(op->getResults(), [&](const SSAValue *result) {
653 printType(result->getType());
654 });
Chris Lattnerac591f12018-07-22 21:02:26 -0700655 os << ')';
Chris Lattnerf8cce872018-07-20 09:28:54 -0700656 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700657}
658
Chris Lattner4c95a502018-06-23 16:03:42 -0700659//===----------------------------------------------------------------------===//
660// CFG Function printing
661//===----------------------------------------------------------------------===//
662
663namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700664class CFGFunctionPrinter : public FunctionPrinter {
Chris Lattner4c95a502018-06-23 16:03:42 -0700665public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700666 CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
Chris Lattner4c95a502018-06-23 16:03:42 -0700667
668 const CFGFunction *getFunction() const { return function; }
669
670 void print();
671 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700672
673 void print(const Instruction *inst);
674 void print(const OperationInst *inst);
675 void print(const ReturnInst *inst);
676 void print(const BranchInst *inst);
James Molloy4f788372018-07-24 15:01:27 -0700677 void print(const CondBranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700678
679 unsigned getBBID(const BasicBlock *block) {
680 auto it = basicBlockIDs.find(block);
681 assert(it != basicBlockIDs.end() && "Block not in this function?");
682 return it->second;
683 }
684
685private:
686 const CFGFunction *function;
MLIR Team54b55a22018-07-18 10:16:05 -0700687 DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700688
Chris Lattner4fd59b02018-07-20 09:35:47 -0700689 void numberValuesInBlock(const BasicBlock *block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700690};
James Molloy87d81022018-07-23 11:44:40 -0700691} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -0700692
Chris Lattner4fd59b02018-07-20 09:35:47 -0700693CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
694 const ModulePrinter &other)
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700695 : FunctionPrinter(other), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700696 // Each basic block gets a unique ID per function.
697 unsigned blockID = 0;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700698 for (auto &block : *function) {
699 basicBlockIDs[&block] = blockID++;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700700 numberValuesInBlock(&block);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700701 }
702}
703
704/// Number all of the SSA values in the specified basic block.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700705void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700706 for (auto *arg : block->getArguments()) {
707 numberValueID(arg);
708 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700709 for (auto &op : *block) {
710 // We number instruction that have results, and we only number the first
711 // result.
712 if (op.getNumResults() != 0)
713 numberValueID(op.getResult(0));
714 }
715
716 // Terminators do not define values.
Chris Lattner4c95a502018-06-23 16:03:42 -0700717}
718
Chris Lattner4fd59b02018-07-20 09:35:47 -0700719void CFGFunctionPrinter::print() {
Chris Lattner4c95a502018-06-23 16:03:42 -0700720 os << "cfgfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700721 printFunctionSignature(getFunction());
Chris Lattner4c95a502018-06-23 16:03:42 -0700722 os << " {\n";
723
James Molloy87d81022018-07-23 11:44:40 -0700724 for (auto &block : *function)
725 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700726 os << "}\n\n";
727}
728
Chris Lattner4fd59b02018-07-20 09:35:47 -0700729void CFGFunctionPrinter::print(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700730 os << "bb" << getBBID(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700731
James Molloy61a656c2018-07-22 15:45:24 -0700732 if (!block->args_empty()) {
733 os << '(';
734 interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
735 printValueID(arg);
736 os << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700737 printType(arg->getType());
James Molloy61a656c2018-07-22 15:45:24 -0700738 });
739 os << ')';
740 }
Chris Lattner25ce3062018-07-27 11:10:12 -0700741 os << ':';
742
743 // Print out some context information about the predecessors of this block.
744 if (!block->getFunction()) {
745 os << "\t// block is not in a function!";
746 } else if (block->hasNoPredecessors()) {
747 // Don't print "no predecessors" for the entry block.
748 if (block != &block->getFunction()->front())
749 os << "\t// no predecessors";
750 } else if (auto *pred = block->getSinglePredecessor()) {
751 os << "\t// pred: bb" << getBBID(pred);
752 } else {
753 // We want to print the predecessors in increasing numeric order, not in
754 // whatever order the use-list is in, so gather and sort them.
755 SmallVector<unsigned, 4> predIDs;
756 for (auto *pred : block->getPredecessors())
757 predIDs.push_back(getBBID(pred));
758 llvm::array_pod_sort(predIDs.begin(), predIDs.end());
759
760 os << "\t// " << predIDs.size() << " preds: ";
761
762 interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
763 }
764 os << '\n';
James Molloy61a656c2018-07-22 15:45:24 -0700765
Jacques Pienaarb020c542018-07-15 00:06:54 -0700766 for (auto &inst : block->getOperations()) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700767 os << " ";
Chris Lattner3a467cc2018-07-01 20:28:00 -0700768 print(&inst);
James Molloy61a656c2018-07-22 15:45:24 -0700769 os << '\n';
Jacques Pienaarb020c542018-07-15 00:06:54 -0700770 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700771
772 print(block->getTerminator());
James Molloy61a656c2018-07-22 15:45:24 -0700773 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700774}
775
Chris Lattner4fd59b02018-07-20 09:35:47 -0700776void CFGFunctionPrinter::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700777 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700778 case Instruction::Kind::Operation:
779 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700780 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700781 return print(cast<BranchInst>(inst));
James Molloy4f788372018-07-24 15:01:27 -0700782 case TerminatorInst::Kind::CondBranch:
783 return print(cast<CondBranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700784 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700785 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700786 }
787}
788
Chris Lattner4fd59b02018-07-20 09:35:47 -0700789void CFGFunctionPrinter::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700790 printOperation(inst);
Chris Lattner3b2ef762018-07-18 15:31:25 -0700791}
Chris Lattner1604e472018-07-23 08:42:19 -0700792
Chris Lattner4fd59b02018-07-20 09:35:47 -0700793void CFGFunctionPrinter::print(const BranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700794 os << "br bb" << getBBID(inst->getDest());
Chris Lattner1604e472018-07-23 08:42:19 -0700795
796 if (inst->getNumOperands() != 0) {
797 os << '(';
798 // TODO: Use getOperands() when we have it.
799 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
800 printValueID(operand.get());
801 });
802 os << ") : ";
803 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700804 printType(operand.get()->getType());
Chris Lattner1604e472018-07-23 08:42:19 -0700805 });
806 }
Chris Lattnered65a732018-06-28 20:45:33 -0700807}
Chris Lattner1604e472018-07-23 08:42:19 -0700808
James Molloy4f788372018-07-24 15:01:27 -0700809void CFGFunctionPrinter::print(const CondBranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700810 os << "cond_br ";
James Molloy4f788372018-07-24 15:01:27 -0700811 printValueID(inst->getCondition());
812
813 os << ", bb" << getBBID(inst->getTrueDest());
814 if (inst->getNumTrueOperands() != 0) {
815 os << '(';
816 interleaveComma(inst->getTrueOperands(),
817 [&](const CFGValue *operand) { printValueID(operand); });
818 os << " : ";
819 interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700820 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700821 });
822 os << ")";
823 }
824
825 os << ", bb" << getBBID(inst->getFalseDest());
826 if (inst->getNumFalseOperands() != 0) {
827 os << '(';
828 interleaveComma(inst->getFalseOperands(),
829 [&](const CFGValue *operand) { printValueID(operand); });
830 os << " : ";
831 interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700832 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700833 });
834 os << ")";
835 }
836}
837
Chris Lattner40746442018-07-21 14:32:09 -0700838void CFGFunctionPrinter::print(const ReturnInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700839 os << "return";
Chris Lattner40746442018-07-21 14:32:09 -0700840
841 if (inst->getNumOperands() != 0)
842 os << ' ';
843
James Molloy4f788372018-07-24 15:01:27 -0700844 interleaveComma(inst->getOperands(),
845 [&](const CFGValue *operand) { printValueID(operand); });
846 os << " : ";
Chris Lattnerac591f12018-07-22 21:02:26 -0700847 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700848 printType(operand->getType());
Chris Lattner40746442018-07-21 14:32:09 -0700849 });
850}
MLIR Team54b55a22018-07-18 10:16:05 -0700851
Chris Lattner4fd59b02018-07-20 09:35:47 -0700852void ModulePrinter::print(const CFGFunction *fn) {
853 CFGFunctionPrinter(fn, *this).print();
Chris Lattnered65a732018-06-28 20:45:33 -0700854}
855
Chris Lattner4c95a502018-06-23 16:03:42 -0700856//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700857// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700858//===----------------------------------------------------------------------===//
859
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700860namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700861class MLFunctionPrinter : public FunctionPrinter {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700862public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700863 MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700864
865 const MLFunction *getFunction() const { return function; }
866
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700867 // Prints ML function
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700868 void print();
869
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700870 // Methods to print ML function statements
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700871 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700872 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700873 void print(const ForStmt *stmt);
874 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700875 void print(const StmtBlock *block);
876
877 // Number of spaces used for indenting nested statements
878 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700879
880private:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700881 void numberValues();
882
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700883 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700884 int numSpaces;
885};
James Molloy87d81022018-07-23 11:44:40 -0700886} // end anonymous namespace
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700887
Chris Lattner4fd59b02018-07-20 09:35:47 -0700888MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
889 const ModulePrinter &other)
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700890 : FunctionPrinter(other), function(function), numSpaces(0) {
891 numberValues();
892}
893
894/// Number all of the SSA values in this ML function.
895void MLFunctionPrinter::numberValues() {
896 // Visits all operation statements and numbers the first result.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700897 struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700898 NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
899 void visitOperationStmt(OperationStmt *stmt) {
900 if (stmt->getNumResults() != 0)
901 printer->numberValueID(stmt->getResult(0));
902 }
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700903 void visitForStmt(ForStmt *stmt) { printer->numberValueID(stmt); }
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700904 MLFunctionPrinter *printer;
905 };
906
907 NumberValuesPass pass(this);
908 // TODO: it'd be cleaner to have constant visitor istead of using const_cast.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700909 pass.walk(const_cast<MLFunction *>(function));
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700910}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700911
Chris Lattner4fd59b02018-07-20 09:35:47 -0700912void MLFunctionPrinter::print() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700913 os << "mlfunc ";
914 // FIXME: should print argument names rather than just signature
Chris Lattner4fd59b02018-07-20 09:35:47 -0700915 printFunctionSignature(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700916 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700917 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700918 os << " return\n";
919 os << "}\n\n";
920}
921
Chris Lattner4fd59b02018-07-20 09:35:47 -0700922void MLFunctionPrinter::print(const StmtBlock *block) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700923 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -0700924 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700925 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -0700926 os << "\n";
927 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700928 numSpaces -= indentWidth;
929}
930
Chris Lattner4fd59b02018-07-20 09:35:47 -0700931void MLFunctionPrinter::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700932 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700933 case Statement::Kind::Operation:
934 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700935 case Statement::Kind::For:
936 return print(cast<ForStmt>(stmt));
937 case Statement::Kind::If:
938 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700939 }
940}
941
Chris Lattner4fd59b02018-07-20 09:35:47 -0700942void MLFunctionPrinter::print(const OperationStmt *stmt) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700943 os.indent(numSpaces);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700944 printOperation(stmt);
945}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700946
Chris Lattner4fd59b02018-07-20 09:35:47 -0700947void MLFunctionPrinter::print(const ForStmt *stmt) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700948 os.indent(numSpaces) << "for ";
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700949 printOperand(stmt);
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700950 os << " = " << *stmt->getLowerBound();
Tatiana Shpeisman1da50c42018-07-19 09:52:39 -0700951 os << " to " << *stmt->getUpperBound();
952 if (stmt->getStep()->getValue() != 1)
953 os << " step " << *stmt->getStep();
954
955 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700956 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700957 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700958}
959
Chris Lattner4fd59b02018-07-20 09:35:47 -0700960void MLFunctionPrinter::print(const IfStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700961 os.indent(numSpaces) << "if () {\n";
962 print(stmt->getThenClause());
963 os.indent(numSpaces) << "}";
964 if (stmt->hasElseClause()) {
965 os << " else {\n";
966 print(stmt->getElseClause());
967 os.indent(numSpaces) << "}";
968 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700969}
970
Chris Lattner4fd59b02018-07-20 09:35:47 -0700971void ModulePrinter::print(const MLFunction *fn) {
972 MLFunctionPrinter(fn, *this).print();
MLIR Team4718bc92018-07-17 16:56:54 -0700973}
974
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700975//===----------------------------------------------------------------------===//
976// print and dump methods
977//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -0700978
MLIR Teamb61885d2018-07-18 16:29:21 -0700979void Attribute::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700980 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700981 ModulePrinter(os, state).printAttribute(this);
MLIR Teamb61885d2018-07-18 16:29:21 -0700982}
983
James Molloy87d81022018-07-23 11:44:40 -0700984void Attribute::dump() const { print(llvm::errs()); }
MLIR Teamb61885d2018-07-18 16:29:21 -0700985
MLIR Team4718bc92018-07-17 16:56:54 -0700986void Type::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700987 ModuleState state(getContext());
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700988 ModulePrinter(os, state).printType(this);
MLIR Team4718bc92018-07-17 16:56:54 -0700989}
990
MLIR Team54b55a22018-07-18 10:16:05 -0700991void Type::dump() const { print(llvm::errs()); }
MLIR Team4718bc92018-07-17 16:56:54 -0700992
MLIR Team718c82f2018-07-16 09:45:22 -0700993void AffineMap::dump() const {
994 print(llvm::errs());
995 llvm::errs() << "\n";
996}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700997
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700998void AffineExpr::dump() const {
999 print(llvm::errs());
1000 llvm::errs() << "\n";
1001}
1002
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001003void AffineExpr::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001004 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001005 ModulePrinter(os, state).printAffineExpr(this);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001006}
1007
1008void AffineMap::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001009 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001010 ModulePrinter(os, state).printAffineMap(this);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001011}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001012
Chris Lattner4fd59b02018-07-20 09:35:47 -07001013void Instruction::print(raw_ostream &os) const {
1014 ModuleState state(getFunction()->getContext());
1015 ModulePrinter modulePrinter(os, state);
1016 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
1017}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001018
Chris Lattner4fd59b02018-07-20 09:35:47 -07001019void Instruction::dump() const {
1020 print(llvm::errs());
1021 llvm::errs() << "\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001022}
1023
Chris Lattner4c95a502018-06-23 16:03:42 -07001024void BasicBlock::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001025 ModuleState state(getFunction()->getContext());
1026 ModulePrinter modulePrinter(os, state);
1027 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001028}
1029
MLIR Team54b55a22018-07-18 10:16:05 -07001030void BasicBlock::dump() const { print(llvm::errs()); }
Chris Lattner4c95a502018-06-23 16:03:42 -07001031
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001032void Statement::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001033 ModuleState state(getFunction()->getContext());
1034 ModulePrinter modulePrinter(os, state);
1035 MLFunctionPrinter(getFunction(), modulePrinter).print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001036}
1037
MLIR Team54b55a22018-07-18 10:16:05 -07001038void Statement::dump() const { print(llvm::errs()); }
Jacques Pienaarb020c542018-07-15 00:06:54 -07001039
Chris Lattner4c95a502018-06-23 16:03:42 -07001040void Function::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001041 ModuleState state(getContext());
1042 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001043}
1044
MLIR Team54b55a22018-07-18 10:16:05 -07001045void Function::dump() const { print(llvm::errs()); }
1046
Chris Lattner4c95a502018-06-23 16:03:42 -07001047void Module::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001048 ModuleState state(getContext());
1049 state.initialize(this);
1050 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001051}
1052
MLIR Team54b55a22018-07-18 10:16:05 -07001053void Module::dump() const { print(llvm::errs()); }