blob: 0bc573b3e3d344c8936cb423241f831280a6ea40 [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 Lattner7d3b77c2018-07-31 16:21:36 -0700197 /// This enum is used to represent the binding stength of the enclosing
198 /// context that an AffineExpr is being printed in, so we can intelligently
199 /// produce parens.
200 enum class BindingStrength {
201 Weak, // + and -
202 Strong, // All other binary operators.
203 };
204 void printAffineExprInternal(const AffineExpr *expr,
205 BindingStrength enclosingTightness);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700206};
207} // end anonymous namespace
208
MLIR Team4718bc92018-07-17 16:56:54 -0700209// Prints function with initialized module state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700210void ModulePrinter::print(const Function *fn) {
MLIR Team4718bc92018-07-17 16:56:54 -0700211 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700212 case Function::Kind::ExtFunc:
213 return print(cast<ExtFunction>(fn));
214 case Function::Kind::CFGFunc:
215 return print(cast<CFGFunction>(fn));
216 case Function::Kind::MLFunc:
217 return print(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700218 }
219}
220
221// Prints affine map identifier.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700222void ModulePrinter::printAffineMapId(int affineMapId) const {
MLIR Team4718bc92018-07-17 16:56:54 -0700223 os << "#map" << affineMapId;
224}
225
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700226void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700227 int mapId = state.getAffineMapId(affineMap);
MLIR Teamb61885d2018-07-18 16:29:21 -0700228 if (mapId >= 0) {
229 // Map will be printed at top of module so print reference to its id.
230 printAffineMapId(mapId);
231 } else {
232 // Map not in module state so print inline.
233 affineMap->print(os);
234 }
235}
236
Chris Lattner4fd59b02018-07-20 09:35:47 -0700237void ModulePrinter::print(const Module *module) {
James Molloyc4666722018-07-24 09:48:31 -0700238 for (const auto &map : state.getAffineMapIds()) {
239 printAffineMapId(state.getAffineMapId(map));
MLIR Team4718bc92018-07-17 16:56:54 -0700240 os << " = ";
James Molloyc4666722018-07-24 09:48:31 -0700241 map->print(os);
MLIR Team4718bc92018-07-17 16:56:54 -0700242 os << '\n';
243 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700244 for (auto const &fn : *module)
245 print(&fn);
MLIR Team4718bc92018-07-17 16:56:54 -0700246}
247
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700248void ModulePrinter::printAttribute(const Attribute *attr) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700249 switch (attr->getKind()) {
250 case Attribute::Kind::Bool:
251 os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
252 break;
253 case Attribute::Kind::Integer:
254 os << cast<IntegerAttr>(attr)->getValue();
255 break;
256 case Attribute::Kind::Float:
257 // FIXME: this isn't precise, we should print with a hex format.
258 os << cast<FloatAttr>(attr)->getValue();
259 break;
260 case Attribute::Kind::String:
261 // FIXME: should escape the string.
262 os << '"' << cast<StringAttr>(attr)->getValue() << '"';
263 break;
264 case Attribute::Kind::Array: {
265 auto elts = cast<ArrayAttr>(attr)->getValue();
266 os << '[';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700267 interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
MLIR Teamb61885d2018-07-18 16:29:21 -0700268 os << ']';
269 break;
270 }
271 case Attribute::Kind::AffineMap:
272 printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
273 break;
274 }
275}
276
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700277void ModulePrinter::printType(const Type *type) {
MLIR Team4718bc92018-07-17 16:56:54 -0700278 switch (type->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700279 case Type::Kind::AffineInt:
280 os << "affineint";
281 return;
282 case Type::Kind::BF16:
283 os << "bf16";
284 return;
285 case Type::Kind::F16:
286 os << "f16";
287 return;
288 case Type::Kind::F32:
289 os << "f32";
290 return;
291 case Type::Kind::F64:
292 os << "f64";
293 return;
Jacques Pienaarc0d69302018-07-27 11:07:12 -0700294 case Type::Kind::TFControl:
295 os << "tf_control";
296 return;
MLIR Team4718bc92018-07-17 16:56:54 -0700297
298 case Type::Kind::Integer: {
299 auto *integer = cast<IntegerType>(type);
300 os << 'i' << integer->getWidth();
301 return;
302 }
303 case Type::Kind::Function: {
304 auto *func = cast<FunctionType>(type);
305 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700306 interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700307 os << ") -> ";
308 auto results = func->getResults();
309 if (results.size() == 1)
310 os << *results[0];
311 else {
312 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700313 interleaveComma(results, [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700314 os << ')';
315 }
316 return;
317 }
318 case Type::Kind::Vector: {
319 auto *v = cast<VectorType>(type);
320 os << "vector<";
James Molloy87d81022018-07-23 11:44:40 -0700321 for (auto dim : v->getShape())
322 os << dim << 'x';
MLIR Team4718bc92018-07-17 16:56:54 -0700323 os << *v->getElementType() << '>';
324 return;
325 }
326 case Type::Kind::RankedTensor: {
327 auto *v = cast<RankedTensorType>(type);
328 os << "tensor<";
329 for (auto dim : v->getShape()) {
330 if (dim < 0)
331 os << '?';
332 else
333 os << dim;
334 os << 'x';
335 }
336 os << *v->getElementType() << '>';
337 return;
338 }
339 case Type::Kind::UnrankedTensor: {
340 auto *v = cast<UnrankedTensorType>(type);
Chris Lattner413db6a2018-07-25 12:55:50 -0700341 os << "tensor<??";
342 printType(v->getElementType());
343 os << '>';
MLIR Team4718bc92018-07-17 16:56:54 -0700344 return;
345 }
346 case Type::Kind::MemRef: {
347 auto *v = cast<MemRefType>(type);
348 os << "memref<";
349 for (auto dim : v->getShape()) {
350 if (dim < 0)
351 os << '?';
352 else
353 os << dim;
354 os << 'x';
355 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700356 printType(v->getElementType());
MLIR Team4718bc92018-07-17 16:56:54 -0700357 for (auto map : v->getAffineMaps()) {
358 os << ", ";
MLIR Teamb61885d2018-07-18 16:29:21 -0700359 printAffineMapReference(map);
MLIR Team4718bc92018-07-17 16:56:54 -0700360 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700361 // Only print the memory space if it is the non-default one.
362 if (v->getMemorySpace())
363 os << ", " << v->getMemorySpace();
MLIR Team4718bc92018-07-17 16:56:54 -0700364 os << '>';
365 return;
366 }
367 }
368}
369
370//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -0700371// Affine expressions and maps
372//===----------------------------------------------------------------------===//
373
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700374void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700375 printAffineExprInternal(expr, BindingStrength::Weak);
376}
377
378void ModulePrinter::printAffineExprInternal(
379 const AffineExpr *expr, BindingStrength enclosingTightness) {
380 const char *binopSpelling = nullptr;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700381 switch (expr->getKind()) {
382 case AffineExpr::Kind::SymbolId:
383 os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
384 return;
385 case AffineExpr::Kind::DimId:
386 os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
387 return;
388 case AffineExpr::Kind::Constant:
389 os << cast<AffineConstantExpr>(expr)->getValue();
390 return;
391 case AffineExpr::Kind::Add:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700392 binopSpelling = " + ";
393 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700394 case AffineExpr::Kind::Mul:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700395 binopSpelling = " * ";
396 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700397 case AffineExpr::Kind::FloorDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700398 binopSpelling = " floordiv ";
399 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700400 case AffineExpr::Kind::CeilDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700401 binopSpelling = " ceildiv ";
402 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700403 case AffineExpr::Kind::Mod:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700404 binopSpelling = " mod ";
405 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700406 }
Chris Lattner4fd59b02018-07-20 09:35:47 -0700407
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700408 auto *binOp = cast<AffineBinaryOpExpr>(expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700409
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700410 // Handle tightly binding binary operators.
411 if (binOp->getKind() != AffineExpr::Kind::Add) {
412 if (enclosingTightness == BindingStrength::Strong)
413 os << '(';
414
415 printAffineExprInternal(binOp->getLHS(), BindingStrength::Strong);
416 os << binopSpelling;
417 printAffineExprInternal(binOp->getRHS(), BindingStrength::Strong);
418
419 if (enclosingTightness == BindingStrength::Strong)
420 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700421 return;
422 }
423
424 // Print out special "pretty" forms for add.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700425 if (enclosingTightness == BindingStrength::Strong)
426 os << '(';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700427
428 // Pretty print addition to a product that has a negative operand as a
429 // subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700430 if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700431 if (rhs->getKind() == AffineExpr::Kind::Mul) {
432 if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700433 if (rrhs->getValue() == -1) {
434 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
435 os << " - ";
436 printAffineExprInternal(rhs->getLHS(), BindingStrength::Weak);
437
438 if (enclosingTightness == BindingStrength::Strong)
439 os << ')';
440 return;
441 }
442
443 if (rrhs->getValue() < -1) {
444 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700445 os << " - (";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700446 printAffineExprInternal(rhs->getLHS(), BindingStrength::Strong);
447 os << " * " << -rrhs->getValue() << ')';
448 if (enclosingTightness == BindingStrength::Strong)
449 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700450 return;
451 }
452 }
453 }
454 }
455
456 // Pretty print addition to a negative number as a subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700457 if (auto *rhs = dyn_cast<AffineConstantExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700458 if (rhs->getValue() < 0) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700459 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
460 os << " - " << -rhs->getValue() << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700461 return;
462 }
463 }
464
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700465 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700466 os << " + ";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700467 printAffineExprInternal(binOp->getRHS(), BindingStrength::Weak);
468
469 if (enclosingTightness == BindingStrength::Strong)
470 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700471}
472
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700473void ModulePrinter::printAffineMap(const AffineMap *map) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700474 // Dimension identifiers.
475 os << '(';
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700476 for (int i = 0; i < (int)map->getNumDims() - 1; ++i)
477 os << 'd' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700478 if (map->getNumDims() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700479 os << 'd' << map->getNumDims() - 1;
480 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700481
482 // Symbolic identifiers.
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700483 if (map->getNumSymbols() != 0) {
484 os << '[';
485 for (unsigned i = 0; i < map->getNumSymbols() - 1; ++i)
486 os << 's' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700487 if (map->getNumSymbols() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700488 os << 's' << map->getNumSymbols() - 1;
489 os << ']';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700490 }
491
492 // AffineMap should have at least one result.
493 assert(!map->getResults().empty());
494 // Result affine expressions.
495 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700496 interleaveComma(map->getResults(),
497 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700498 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700499
500 if (!map->isBounded()) {
501 return;
502 }
503
504 // Print range sizes for bounded affine maps.
505 os << " size (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700506 interleaveComma(map->getRangeSizes(),
507 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700508 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700509}
510
511//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700512// Function printing
513//===----------------------------------------------------------------------===//
514
Chris Lattner4fd59b02018-07-20 09:35:47 -0700515void ModulePrinter::printFunctionSignature(const Function *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700516 auto type = fn->getType();
517
518 os << "@" << fn->getName() << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700519 interleaveComma(type->getInputs(),
520 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700521 os << ')';
522
523 switch (type->getResults().size()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700524 case 0:
525 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700526 case 1:
MLIR Team4718bc92018-07-17 16:56:54 -0700527 os << " -> ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700528 printType(type->getResults()[0]);
Chris Lattner4c95a502018-06-23 16:03:42 -0700529 break;
530 default:
531 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700532 interleaveComma(type->getResults(),
533 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700534 os << ')';
535 break;
536 }
537}
538
Chris Lattner4fd59b02018-07-20 09:35:47 -0700539void ModulePrinter::print(const ExtFunction *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700540 os << "extfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700541 printFunctionSignature(fn);
MLIR Team54b55a22018-07-18 10:16:05 -0700542 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700543}
544
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700545namespace {
546
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700547// FunctionPrinter contains common functionality for printing
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700548// CFG and ML functions.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700549class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700550public:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700551 FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700552
553 void printOperation(const Operation *op);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700554 void printDefaultOp(const Operation *op);
555
556 // Implement OpAsmPrinter.
557 raw_ostream &getStream() const { return os; }
558 void printType(const Type *type) { ModulePrinter::printType(type); }
559 void printAttribute(const Attribute *attr) {
560 ModulePrinter::printAttribute(attr);
561 }
562 void printAffineMap(const AffineMap *map) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700563 return ModulePrinter::printAffineMapReference(map);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700564 }
565 void printAffineExpr(const AffineExpr *expr) {
566 return ModulePrinter::printAffineExpr(expr);
567 }
568
569 void printOperand(const SSAValue *value) { printValueID(value); }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700570
571protected:
Chris Lattnerf8cce872018-07-20 09:28:54 -0700572 void numberValueID(const SSAValue *value) {
573 assert(!valueIDs.count(value) && "Value numbered multiple times");
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700574 unsigned id;
575 switch (value->getKind()) {
576 case SSAValueKind::BBArgument:
577 case SSAValueKind::InstResult:
578 case SSAValueKind::StmtResult:
579 id = nextValueID++;
580 break;
581 case SSAValueKind::FnArgument:
582 id = nextFnArgumentID++;
583 break;
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700584 case SSAValueKind::ForStmt:
585 id = nextLoopID++;
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700586 break;
587 }
588 valueIDs[value] = id;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700589 }
590
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700591 void printValueID(const SSAValue *value, bool printResultNo = true) const {
Chris Lattner6119d382018-07-20 18:41:34 -0700592 int resultNo = -1;
593 auto lookupValue = value;
594
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700595 // If this is a reference to the result of a multi-result instruction or
596 // statement, print out the # identifier and make sure to map our lookup
597 // to the first result of the instruction.
Chris Lattner6119d382018-07-20 18:41:34 -0700598 if (auto *result = dyn_cast<InstResult>(value)) {
599 if (result->getOwner()->getNumResults() != 1) {
600 resultNo = result->getResultNumber();
601 lookupValue = result->getOwner()->getResult(0);
602 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700603 } else if (auto *result = dyn_cast<StmtResult>(value)) {
604 if (result->getOwner()->getNumResults() != 1) {
605 resultNo = result->getResultNumber();
606 lookupValue = result->getOwner()->getResult(0);
607 }
Chris Lattner6119d382018-07-20 18:41:34 -0700608 }
609
610 auto it = valueIDs.find(lookupValue);
611 if (it == valueIDs.end()) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700612 os << "<<INVALID SSA VALUE>>";
Chris Lattner6119d382018-07-20 18:41:34 -0700613 return;
614 }
615
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700616 os << '%';
617 if (isa<ForStmt>(value))
618
619 os << 'i';
620 else if (isa<FnArgument>(value))
621 os << "arg";
622 os << it->getSecond();
623 if (resultNo != -1 && printResultNo)
Chris Lattner6119d382018-07-20 18:41:34 -0700624 os << '#' << resultNo;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700625 }
626
627private:
628 /// This is the value ID for each SSA value in the current function.
629 DenseMap<const SSAValue *, unsigned> valueIDs;
630 unsigned nextValueID = 0;
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700631 unsigned nextLoopID = 0;
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700632 unsigned nextFnArgumentID = 0;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700633};
James Molloy87d81022018-07-23 11:44:40 -0700634} // end anonymous namespace
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700635
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700636void FunctionPrinter::printOperation(const Operation *op) {
Chris Lattnerac591f12018-07-22 21:02:26 -0700637 if (op->getNumResults()) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700638 printValueID(op->getResult(0), /*printResultNo=*/false);
Chris Lattnerac591f12018-07-22 21:02:26 -0700639 os << " = ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700640 }
641
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700642 // Check to see if this is a known operation. If so, use the registered
643 // custom printer hook.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700644 if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700645 opInfo->printAssembly(op, this);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700646 return;
647 }
648
Chris Lattnerf8cce872018-07-20 09:28:54 -0700649 // Otherwise use the standard verbose printing approach.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700650 printDefaultOp(op);
651}
Chris Lattnerf8cce872018-07-20 09:28:54 -0700652
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700653void FunctionPrinter::printDefaultOp(const Operation *op) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700654 // TODO: escape name if necessary.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700655 os << "\"" << op->getName().str() << "\"(";
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700656
Chris Lattnerac591f12018-07-22 21:02:26 -0700657 interleaveComma(op->getOperands(),
658 [&](const SSAValue *value) { printValueID(value); });
Chris Lattner7f9cc272018-07-19 08:35:28 -0700659
Chris Lattnerf8cce872018-07-20 09:28:54 -0700660 os << ')';
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700661 auto attrs = op->getAttrs();
662 if (!attrs.empty()) {
663 os << '{';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700664 interleaveComma(attrs, [&](NamedAttribute attr) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700665 os << attr.first << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700666 printAttribute(attr.second);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700667 });
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700668 os << '}';
669 }
Chris Lattner3b2ef762018-07-18 15:31:25 -0700670
Chris Lattnerac591f12018-07-22 21:02:26 -0700671 // Print the type signature of the operation.
672 os << " : (";
673 interleaveComma(op->getOperands(),
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700674 [&](const SSAValue *value) { printType(value->getType()); });
Chris Lattnerac591f12018-07-22 21:02:26 -0700675 os << ") -> ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700676
Chris Lattnerac591f12018-07-22 21:02:26 -0700677 if (op->getNumResults() == 1) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700678 printType(op->getResult(0)->getType());
Chris Lattnerac591f12018-07-22 21:02:26 -0700679 } else {
680 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700681 interleaveComma(op->getResults(), [&](const SSAValue *result) {
682 printType(result->getType());
683 });
Chris Lattnerac591f12018-07-22 21:02:26 -0700684 os << ')';
Chris Lattnerf8cce872018-07-20 09:28:54 -0700685 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700686}
687
Chris Lattner4c95a502018-06-23 16:03:42 -0700688//===----------------------------------------------------------------------===//
689// CFG Function printing
690//===----------------------------------------------------------------------===//
691
692namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700693class CFGFunctionPrinter : public FunctionPrinter {
Chris Lattner4c95a502018-06-23 16:03:42 -0700694public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700695 CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
Chris Lattner4c95a502018-06-23 16:03:42 -0700696
697 const CFGFunction *getFunction() const { return function; }
698
699 void print();
700 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700701
702 void print(const Instruction *inst);
703 void print(const OperationInst *inst);
704 void print(const ReturnInst *inst);
705 void print(const BranchInst *inst);
James Molloy4f788372018-07-24 15:01:27 -0700706 void print(const CondBranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700707
708 unsigned getBBID(const BasicBlock *block) {
709 auto it = basicBlockIDs.find(block);
710 assert(it != basicBlockIDs.end() && "Block not in this function?");
711 return it->second;
712 }
713
714private:
715 const CFGFunction *function;
MLIR Team54b55a22018-07-18 10:16:05 -0700716 DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700717
Chris Lattner4fd59b02018-07-20 09:35:47 -0700718 void numberValuesInBlock(const BasicBlock *block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700719};
James Molloy87d81022018-07-23 11:44:40 -0700720} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -0700721
Chris Lattner4fd59b02018-07-20 09:35:47 -0700722CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
723 const ModulePrinter &other)
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700724 : FunctionPrinter(other), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700725 // Each basic block gets a unique ID per function.
726 unsigned blockID = 0;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700727 for (auto &block : *function) {
728 basicBlockIDs[&block] = blockID++;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700729 numberValuesInBlock(&block);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700730 }
731}
732
733/// Number all of the SSA values in the specified basic block.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700734void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700735 for (auto *arg : block->getArguments()) {
736 numberValueID(arg);
737 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700738 for (auto &op : *block) {
739 // We number instruction that have results, and we only number the first
740 // result.
741 if (op.getNumResults() != 0)
742 numberValueID(op.getResult(0));
743 }
744
745 // Terminators do not define values.
Chris Lattner4c95a502018-06-23 16:03:42 -0700746}
747
Chris Lattner4fd59b02018-07-20 09:35:47 -0700748void CFGFunctionPrinter::print() {
Chris Lattner4c95a502018-06-23 16:03:42 -0700749 os << "cfgfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700750 printFunctionSignature(getFunction());
Chris Lattner4c95a502018-06-23 16:03:42 -0700751 os << " {\n";
752
James Molloy87d81022018-07-23 11:44:40 -0700753 for (auto &block : *function)
754 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700755 os << "}\n\n";
756}
757
Chris Lattner4fd59b02018-07-20 09:35:47 -0700758void CFGFunctionPrinter::print(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700759 os << "bb" << getBBID(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700760
James Molloy61a656c2018-07-22 15:45:24 -0700761 if (!block->args_empty()) {
762 os << '(';
763 interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
764 printValueID(arg);
765 os << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700766 printType(arg->getType());
James Molloy61a656c2018-07-22 15:45:24 -0700767 });
768 os << ')';
769 }
Chris Lattner25ce3062018-07-27 11:10:12 -0700770 os << ':';
771
772 // Print out some context information about the predecessors of this block.
773 if (!block->getFunction()) {
774 os << "\t// block is not in a function!";
775 } else if (block->hasNoPredecessors()) {
776 // Don't print "no predecessors" for the entry block.
777 if (block != &block->getFunction()->front())
778 os << "\t// no predecessors";
779 } else if (auto *pred = block->getSinglePredecessor()) {
780 os << "\t// pred: bb" << getBBID(pred);
781 } else {
782 // We want to print the predecessors in increasing numeric order, not in
783 // whatever order the use-list is in, so gather and sort them.
784 SmallVector<unsigned, 4> predIDs;
785 for (auto *pred : block->getPredecessors())
786 predIDs.push_back(getBBID(pred));
787 llvm::array_pod_sort(predIDs.begin(), predIDs.end());
788
789 os << "\t// " << predIDs.size() << " preds: ";
790
791 interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
792 }
793 os << '\n';
James Molloy61a656c2018-07-22 15:45:24 -0700794
Jacques Pienaarb020c542018-07-15 00:06:54 -0700795 for (auto &inst : block->getOperations()) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700796 os << " ";
Chris Lattner3a467cc2018-07-01 20:28:00 -0700797 print(&inst);
James Molloy61a656c2018-07-22 15:45:24 -0700798 os << '\n';
Jacques Pienaarb020c542018-07-15 00:06:54 -0700799 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700800
801 print(block->getTerminator());
James Molloy61a656c2018-07-22 15:45:24 -0700802 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700803}
804
Chris Lattner4fd59b02018-07-20 09:35:47 -0700805void CFGFunctionPrinter::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700806 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700807 case Instruction::Kind::Operation:
808 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700809 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700810 return print(cast<BranchInst>(inst));
James Molloy4f788372018-07-24 15:01:27 -0700811 case TerminatorInst::Kind::CondBranch:
812 return print(cast<CondBranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700813 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700814 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700815 }
816}
817
Chris Lattner4fd59b02018-07-20 09:35:47 -0700818void CFGFunctionPrinter::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700819 printOperation(inst);
Chris Lattner3b2ef762018-07-18 15:31:25 -0700820}
Chris Lattner1604e472018-07-23 08:42:19 -0700821
Chris Lattner4fd59b02018-07-20 09:35:47 -0700822void CFGFunctionPrinter::print(const BranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700823 os << "br bb" << getBBID(inst->getDest());
Chris Lattner1604e472018-07-23 08:42:19 -0700824
825 if (inst->getNumOperands() != 0) {
826 os << '(';
827 // TODO: Use getOperands() when we have it.
828 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
829 printValueID(operand.get());
830 });
831 os << ") : ";
832 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700833 printType(operand.get()->getType());
Chris Lattner1604e472018-07-23 08:42:19 -0700834 });
835 }
Chris Lattnered65a732018-06-28 20:45:33 -0700836}
Chris Lattner1604e472018-07-23 08:42:19 -0700837
James Molloy4f788372018-07-24 15:01:27 -0700838void CFGFunctionPrinter::print(const CondBranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700839 os << "cond_br ";
James Molloy4f788372018-07-24 15:01:27 -0700840 printValueID(inst->getCondition());
841
842 os << ", bb" << getBBID(inst->getTrueDest());
843 if (inst->getNumTrueOperands() != 0) {
844 os << '(';
845 interleaveComma(inst->getTrueOperands(),
846 [&](const CFGValue *operand) { printValueID(operand); });
847 os << " : ";
848 interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700849 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700850 });
851 os << ")";
852 }
853
854 os << ", bb" << getBBID(inst->getFalseDest());
855 if (inst->getNumFalseOperands() != 0) {
856 os << '(';
857 interleaveComma(inst->getFalseOperands(),
858 [&](const CFGValue *operand) { printValueID(operand); });
859 os << " : ";
860 interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700861 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700862 });
863 os << ")";
864 }
865}
866
Chris Lattner40746442018-07-21 14:32:09 -0700867void CFGFunctionPrinter::print(const ReturnInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700868 os << "return";
Chris Lattner40746442018-07-21 14:32:09 -0700869
870 if (inst->getNumOperands() != 0)
871 os << ' ';
872
James Molloy4f788372018-07-24 15:01:27 -0700873 interleaveComma(inst->getOperands(),
874 [&](const CFGValue *operand) { printValueID(operand); });
875 os << " : ";
Chris Lattnerac591f12018-07-22 21:02:26 -0700876 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700877 printType(operand->getType());
Chris Lattner40746442018-07-21 14:32:09 -0700878 });
879}
MLIR Team54b55a22018-07-18 10:16:05 -0700880
Chris Lattner4fd59b02018-07-20 09:35:47 -0700881void ModulePrinter::print(const CFGFunction *fn) {
882 CFGFunctionPrinter(fn, *this).print();
Chris Lattnered65a732018-06-28 20:45:33 -0700883}
884
Chris Lattner4c95a502018-06-23 16:03:42 -0700885//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700886// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -0700887//===----------------------------------------------------------------------===//
888
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700889namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700890class MLFunctionPrinter : public FunctionPrinter {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700891public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700892 MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700893
894 const MLFunction *getFunction() const { return function; }
895
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700896 // Prints ML function
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700897 void print();
898
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700899 // Methods to print ML function statements
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700900 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700901 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700902 void print(const ForStmt *stmt);
903 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700904 void print(const StmtBlock *block);
905
906 // Number of spaces used for indenting nested statements
907 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700908
909private:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700910 void numberValues();
911
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700912 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700913 int numSpaces;
914};
James Molloy87d81022018-07-23 11:44:40 -0700915} // end anonymous namespace
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700916
Chris Lattner4fd59b02018-07-20 09:35:47 -0700917MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
918 const ModulePrinter &other)
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700919 : FunctionPrinter(other), function(function), numSpaces(0) {
920 numberValues();
921}
922
923/// Number all of the SSA values in this ML function.
924void MLFunctionPrinter::numberValues() {
925 // Visits all operation statements and numbers the first result.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700926 struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700927 NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
928 void visitOperationStmt(OperationStmt *stmt) {
929 if (stmt->getNumResults() != 0)
930 printer->numberValueID(stmt->getResult(0));
931 }
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700932 void visitForStmt(ForStmt *stmt) { printer->numberValueID(stmt); }
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700933 MLFunctionPrinter *printer;
934 };
935
936 NumberValuesPass pass(this);
937 // TODO: it'd be cleaner to have constant visitor istead of using const_cast.
Uday Bondhugula081d9e72018-07-27 10:58:14 -0700938 pass.walk(const_cast<MLFunction *>(function));
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700939}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700940
Chris Lattner4fd59b02018-07-20 09:35:47 -0700941void MLFunctionPrinter::print() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700942 os << "mlfunc ";
943 // FIXME: should print argument names rather than just signature
Chris Lattner4fd59b02018-07-20 09:35:47 -0700944 printFunctionSignature(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700945 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700946 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700947 os << " return\n";
948 os << "}\n\n";
949}
950
Chris Lattner4fd59b02018-07-20 09:35:47 -0700951void MLFunctionPrinter::print(const StmtBlock *block) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700952 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -0700953 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700954 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -0700955 os << "\n";
956 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700957 numSpaces -= indentWidth;
958}
959
Chris Lattner4fd59b02018-07-20 09:35:47 -0700960void MLFunctionPrinter::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700961 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700962 case Statement::Kind::Operation:
963 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700964 case Statement::Kind::For:
965 return print(cast<ForStmt>(stmt));
966 case Statement::Kind::If:
967 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700968 }
969}
970
Chris Lattner4fd59b02018-07-20 09:35:47 -0700971void MLFunctionPrinter::print(const OperationStmt *stmt) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700972 os.indent(numSpaces);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700973 printOperation(stmt);
974}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700975
Chris Lattner4fd59b02018-07-20 09:35:47 -0700976void MLFunctionPrinter::print(const ForStmt *stmt) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700977 os.indent(numSpaces) << "for ";
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700978 printOperand(stmt);
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700979 os << " = " << *stmt->getLowerBound();
Tatiana Shpeisman1da50c42018-07-19 09:52:39 -0700980 os << " to " << *stmt->getUpperBound();
981 if (stmt->getStep()->getValue() != 1)
982 os << " step " << *stmt->getStep();
983
984 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700985 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700986 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700987}
988
Chris Lattner4fd59b02018-07-20 09:35:47 -0700989void MLFunctionPrinter::print(const IfStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -0700990 os.indent(numSpaces) << "if () {\n";
991 print(stmt->getThenClause());
992 os.indent(numSpaces) << "}";
993 if (stmt->hasElseClause()) {
994 os << " else {\n";
995 print(stmt->getElseClause());
996 os.indent(numSpaces) << "}";
997 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700998}
999
Chris Lattner4fd59b02018-07-20 09:35:47 -07001000void ModulePrinter::print(const MLFunction *fn) {
1001 MLFunctionPrinter(fn, *this).print();
MLIR Team4718bc92018-07-17 16:56:54 -07001002}
1003
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001004//===----------------------------------------------------------------------===//
1005// print and dump methods
1006//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -07001007
MLIR Teamb61885d2018-07-18 16:29:21 -07001008void Attribute::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).printAttribute(this);
MLIR Teamb61885d2018-07-18 16:29:21 -07001011}
1012
James Molloy87d81022018-07-23 11:44:40 -07001013void Attribute::dump() const { print(llvm::errs()); }
MLIR Teamb61885d2018-07-18 16:29:21 -07001014
MLIR Team4718bc92018-07-17 16:56:54 -07001015void Type::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001016 ModuleState state(getContext());
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001017 ModulePrinter(os, state).printType(this);
MLIR Team4718bc92018-07-17 16:56:54 -07001018}
1019
MLIR Team54b55a22018-07-18 10:16:05 -07001020void Type::dump() const { print(llvm::errs()); }
MLIR Team4718bc92018-07-17 16:56:54 -07001021
MLIR Team718c82f2018-07-16 09:45:22 -07001022void AffineMap::dump() const {
1023 print(llvm::errs());
1024 llvm::errs() << "\n";
1025}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001026
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001027void AffineExpr::dump() const {
1028 print(llvm::errs());
1029 llvm::errs() << "\n";
1030}
1031
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001032void AffineExpr::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001033 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001034 ModulePrinter(os, state).printAffineExpr(this);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001035}
1036
1037void AffineMap::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001038 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001039 ModulePrinter(os, state).printAffineMap(this);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001040}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001041
Chris Lattner4fd59b02018-07-20 09:35:47 -07001042void Instruction::print(raw_ostream &os) const {
1043 ModuleState state(getFunction()->getContext());
1044 ModulePrinter modulePrinter(os, state);
1045 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
1046}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001047
Chris Lattner4fd59b02018-07-20 09:35:47 -07001048void Instruction::dump() const {
1049 print(llvm::errs());
1050 llvm::errs() << "\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001051}
1052
Chris Lattner4c95a502018-06-23 16:03:42 -07001053void BasicBlock::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001054 ModuleState state(getFunction()->getContext());
1055 ModulePrinter modulePrinter(os, state);
1056 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001057}
1058
MLIR Team54b55a22018-07-18 10:16:05 -07001059void BasicBlock::dump() const { print(llvm::errs()); }
Chris Lattner4c95a502018-06-23 16:03:42 -07001060
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001061void Statement::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001062 ModuleState state(getFunction()->getContext());
1063 ModulePrinter modulePrinter(os, state);
1064 MLFunctionPrinter(getFunction(), modulePrinter).print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001065}
1066
MLIR Team54b55a22018-07-18 10:16:05 -07001067void Statement::dump() const { print(llvm::errs()); }
Jacques Pienaarb020c542018-07-15 00:06:54 -07001068
Chris Lattner4c95a502018-06-23 16:03:42 -07001069void Function::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001070 ModuleState state(getContext());
1071 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001072}
1073
MLIR Team54b55a22018-07-18 10:16:05 -07001074void Function::dump() const { print(llvm::errs()); }
1075
Chris Lattner4c95a502018-06-23 16:03:42 -07001076void Module::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001077 ModuleState state(getContext());
1078 state.initialize(this);
1079 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001080}
1081
MLIR Team54b55a22018-07-18 10:16:05 -07001082void Module::dump() const { print(llvm::errs()); }