blob: 68751200003de4f60f074cc16269e2f69bf75aee [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"
Chris Lattnerd4964212018-08-01 10:43:18 -070031#include "mlir/IR/StandardOps.h"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070032#include "mlir/IR/Statements.h"
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070033#include "mlir/IR/StmtVisitor.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070034#include "mlir/IR/Types.h"
35#include "mlir/Support/STLExtras.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070036#include "llvm/ADT/DenseMap.h"
Chris Lattnerd4964212018-08-01 10:43:18 -070037#include "llvm/ADT/SmallString.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/StringSet.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070040using namespace mlir;
41
MLIR Team54b55a22018-07-18 10:16:05 -070042void Identifier::print(raw_ostream &os) const { os << str(); }
Chris Lattner4c95a502018-06-23 16:03:42 -070043
MLIR Team54b55a22018-07-18 10:16:05 -070044void Identifier::dump() const { print(llvm::errs()); }
Chris Lattner7121b802018-07-04 20:45:39 -070045
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070046OpAsmPrinter::~OpAsmPrinter() {}
47
Chris Lattner4c95a502018-06-23 16:03:42 -070048//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -070049// ModuleState
MLIR Team4718bc92018-07-17 16:56:54 -070050//===----------------------------------------------------------------------===//
51
52namespace {
MLIR Team54b55a22018-07-18 10:16:05 -070053class ModuleState {
54public:
Chris Lattner4fd59b02018-07-20 09:35:47 -070055 /// This is the operation set for the current context if it is knowable (a
56 /// context could be determined), otherwise this is null.
57 OperationSet *const operationSet;
MLIR Team4718bc92018-07-17 16:56:54 -070058
Chris Lattner4fd59b02018-07-20 09:35:47 -070059 explicit ModuleState(MLIRContext *context)
60 : operationSet(context ? &OperationSet::get(context) : nullptr) {}
61
62 // Initializes module state, populating affine map state.
MLIR Team4718bc92018-07-17 16:56:54 -070063 void initialize(const Module *module);
64
MLIR Team54b55a22018-07-18 10:16:05 -070065 int getAffineMapId(const AffineMap *affineMap) const {
MLIR Team4718bc92018-07-17 16:56:54 -070066 auto it = affineMapIds.find(affineMap);
67 if (it == affineMapIds.end()) {
68 return -1;
69 }
70 return it->second;
71 }
72
James Molloyc4666722018-07-24 09:48:31 -070073 ArrayRef<const AffineMap *> getAffineMapIds() const { return affineMapsById; }
Chris Lattner4fd59b02018-07-20 09:35:47 -070074
MLIR Team54b55a22018-07-18 10:16:05 -070075private:
Chris Lattner4fd59b02018-07-20 09:35:47 -070076 void recordAffineMapReference(const AffineMap *affineMap) {
77 if (affineMapIds.count(affineMap) == 0) {
James Molloyc4666722018-07-24 09:48:31 -070078 affineMapIds[affineMap] = affineMapsById.size();
79 affineMapsById.push_back(affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -070080 }
81 }
82
MLIR Team4718bc92018-07-17 16:56:54 -070083 // Visit functions.
84 void visitFunction(const Function *fn);
85 void visitExtFunction(const ExtFunction *fn);
86 void visitCFGFunction(const CFGFunction *fn);
87 void visitMLFunction(const MLFunction *fn);
88 void visitType(const Type *type);
MLIR Teamb61885d2018-07-18 16:29:21 -070089 void visitAttribute(const Attribute *attr);
90 void visitOperation(const Operation *op);
91
MLIR Team54b55a22018-07-18 10:16:05 -070092 DenseMap<const AffineMap *, int> affineMapIds;
James Molloyc4666722018-07-24 09:48:31 -070093 std::vector<const AffineMap *> affineMapsById;
MLIR Team4718bc92018-07-17 16:56:54 -070094};
James Molloy87d81022018-07-23 11:44:40 -070095} // end anonymous namespace
MLIR Team4718bc92018-07-17 16:56:54 -070096
97// TODO Support visiting other types/instructions when implemented.
98void ModuleState::visitType(const Type *type) {
Chris Lattner3164ae62018-07-28 09:36:25 -070099 if (auto *funcType = dyn_cast<FunctionType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -0700100 // Visit input and result types for functions.
Chris Lattner3164ae62018-07-28 09:36:25 -0700101 for (auto *input : funcType->getInputs())
MLIR Team4718bc92018-07-17 16:56:54 -0700102 visitType(input);
Chris Lattner3164ae62018-07-28 09:36:25 -0700103 for (auto *result : funcType->getResults())
MLIR Team4718bc92018-07-17 16:56:54 -0700104 visitType(result);
Chris Lattner3164ae62018-07-28 09:36:25 -0700105 } else if (auto *memref = dyn_cast<MemRefType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -0700106 // Visit affine maps in memref type.
Chris Lattner3164ae62018-07-28 09:36:25 -0700107 for (auto *map : memref->getAffineMaps()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700108 recordAffineMapReference(map);
109 }
110 }
111}
112
MLIR Teamb61885d2018-07-18 16:29:21 -0700113void ModuleState::visitAttribute(const Attribute *attr) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700114 if (auto *mapAttr = dyn_cast<AffineMapAttr>(attr)) {
115 recordAffineMapReference(mapAttr->getValue());
116 } else if (auto *array = dyn_cast<ArrayAttr>(attr)) {
117 for (auto elt : array->getValue()) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700118 visitAttribute(elt);
119 }
120 }
121}
122
123void ModuleState::visitOperation(const Operation *op) {
Chris Lattnerca2ee872018-07-31 18:32:59 -0700124 // Visit all the types used in the operation.
125 for (auto *operand : op->getOperands())
126 visitType(operand->getType());
127 for (auto *result : op->getResults())
128 visitType(result->getType());
129
130 // Visit each of the attributes.
131 for (auto elt : op->getAttrs())
MLIR Teamb61885d2018-07-18 16:29:21 -0700132 visitAttribute(elt.second);
MLIR Teamb61885d2018-07-18 16:29:21 -0700133}
134
MLIR Team4718bc92018-07-17 16:56:54 -0700135void ModuleState::visitExtFunction(const ExtFunction *fn) {
136 visitType(fn->getType());
137}
138
139void ModuleState::visitCFGFunction(const CFGFunction *fn) {
140 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700141 for (auto &block : *fn) {
142 for (auto &op : block.getOperations()) {
143 visitOperation(&op);
144 }
145 }
MLIR Team4718bc92018-07-17 16:56:54 -0700146}
147
148void ModuleState::visitMLFunction(const MLFunction *fn) {
149 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700150 // TODO Visit function body statements (and attributes if required).
MLIR Team4718bc92018-07-17 16:56:54 -0700151}
152
153void ModuleState::visitFunction(const Function *fn) {
154 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700155 case Function::Kind::ExtFunc:
156 return visitExtFunction(cast<ExtFunction>(fn));
157 case Function::Kind::CFGFunc:
158 return visitCFGFunction(cast<CFGFunction>(fn));
159 case Function::Kind::MLFunc:
160 return visitMLFunction(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700161 }
162}
163
Chris Lattner4fd59b02018-07-20 09:35:47 -0700164// Initializes module state, populating affine map state.
165void ModuleState::initialize(const Module *module) {
Chris Lattnera8e47672018-07-25 14:08:16 -0700166 for (auto &fn : *module) {
167 visitFunction(&fn);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700168 }
169}
170
171//===----------------------------------------------------------------------===//
172// ModulePrinter
173//===----------------------------------------------------------------------===//
174
175namespace {
176class ModulePrinter {
177public:
178 ModulePrinter(raw_ostream &os, ModuleState &state) : os(os), state(state) {}
179 explicit ModulePrinter(const ModulePrinter &printer)
180 : os(printer.os), state(printer.state) {}
181
182 template <typename Container, typename UnaryFunctor>
183 inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
184 interleave(c.begin(), c.end(), each_fn, [&]() { os << ", "; });
185 }
186
187 void print(const Module *module);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700188 void printAttribute(const Attribute *attr);
189 void printType(const Type *type);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700190 void print(const Function *fn);
191 void print(const ExtFunction *fn);
192 void print(const CFGFunction *fn);
193 void print(const MLFunction *fn);
194
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700195 void printAffineMap(const AffineMap *map);
196 void printAffineExpr(const AffineExpr *expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700197
198protected:
199 raw_ostream &os;
200 ModuleState &state;
201
202 void printFunctionSignature(const Function *fn);
203 void printAffineMapId(int affineMapId) const;
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700204 void printAffineMapReference(const AffineMap *affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700205
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700206 /// This enum is used to represent the binding stength of the enclosing
207 /// context that an AffineExpr is being printed in, so we can intelligently
208 /// produce parens.
209 enum class BindingStrength {
210 Weak, // + and -
211 Strong, // All other binary operators.
212 };
213 void printAffineExprInternal(const AffineExpr *expr,
214 BindingStrength enclosingTightness);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700215};
216} // end anonymous namespace
217
MLIR Team4718bc92018-07-17 16:56:54 -0700218// Prints function with initialized module state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700219void ModulePrinter::print(const Function *fn) {
MLIR Team4718bc92018-07-17 16:56:54 -0700220 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700221 case Function::Kind::ExtFunc:
222 return print(cast<ExtFunction>(fn));
223 case Function::Kind::CFGFunc:
224 return print(cast<CFGFunction>(fn));
225 case Function::Kind::MLFunc:
226 return print(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700227 }
228}
229
230// Prints affine map identifier.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700231void ModulePrinter::printAffineMapId(int affineMapId) const {
MLIR Team4718bc92018-07-17 16:56:54 -0700232 os << "#map" << affineMapId;
233}
234
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700235void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700236 int mapId = state.getAffineMapId(affineMap);
MLIR Teamb61885d2018-07-18 16:29:21 -0700237 if (mapId >= 0) {
238 // Map will be printed at top of module so print reference to its id.
239 printAffineMapId(mapId);
240 } else {
241 // Map not in module state so print inline.
242 affineMap->print(os);
243 }
244}
245
Chris Lattner4fd59b02018-07-20 09:35:47 -0700246void ModulePrinter::print(const Module *module) {
James Molloyc4666722018-07-24 09:48:31 -0700247 for (const auto &map : state.getAffineMapIds()) {
248 printAffineMapId(state.getAffineMapId(map));
MLIR Team4718bc92018-07-17 16:56:54 -0700249 os << " = ";
James Molloyc4666722018-07-24 09:48:31 -0700250 map->print(os);
MLIR Team4718bc92018-07-17 16:56:54 -0700251 os << '\n';
252 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700253 for (auto const &fn : *module)
254 print(&fn);
MLIR Team4718bc92018-07-17 16:56:54 -0700255}
256
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700257void ModulePrinter::printAttribute(const Attribute *attr) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700258 switch (attr->getKind()) {
259 case Attribute::Kind::Bool:
260 os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
261 break;
262 case Attribute::Kind::Integer:
263 os << cast<IntegerAttr>(attr)->getValue();
264 break;
265 case Attribute::Kind::Float:
266 // FIXME: this isn't precise, we should print with a hex format.
267 os << cast<FloatAttr>(attr)->getValue();
268 break;
269 case Attribute::Kind::String:
270 // FIXME: should escape the string.
271 os << '"' << cast<StringAttr>(attr)->getValue() << '"';
272 break;
273 case Attribute::Kind::Array: {
274 auto elts = cast<ArrayAttr>(attr)->getValue();
275 os << '[';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700276 interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
MLIR Teamb61885d2018-07-18 16:29:21 -0700277 os << ']';
278 break;
279 }
280 case Attribute::Kind::AffineMap:
281 printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
282 break;
James Molloyf0d2f442018-08-03 01:54:46 -0700283 case Attribute::Kind::Type:
284 printType(cast<TypeAttr>(attr)->getValue());
285 break;
MLIR Teamb61885d2018-07-18 16:29:21 -0700286 }
287}
288
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700289void ModulePrinter::printType(const Type *type) {
MLIR Team4718bc92018-07-17 16:56:54 -0700290 switch (type->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700291 case Type::Kind::AffineInt:
292 os << "affineint";
293 return;
294 case Type::Kind::BF16:
295 os << "bf16";
296 return;
297 case Type::Kind::F16:
298 os << "f16";
299 return;
300 case Type::Kind::F32:
301 os << "f32";
302 return;
303 case Type::Kind::F64:
304 os << "f64";
305 return;
Jacques Pienaarc0d69302018-07-27 11:07:12 -0700306 case Type::Kind::TFControl:
307 os << "tf_control";
308 return;
James Molloy72b0cbe2018-08-01 12:55:27 -0700309 case Type::Kind::TFString:
310 os << "tf_string";
311 return;
MLIR Team4718bc92018-07-17 16:56:54 -0700312
313 case Type::Kind::Integer: {
314 auto *integer = cast<IntegerType>(type);
315 os << 'i' << integer->getWidth();
316 return;
317 }
318 case Type::Kind::Function: {
319 auto *func = cast<FunctionType>(type);
320 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700321 interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700322 os << ") -> ";
323 auto results = func->getResults();
324 if (results.size() == 1)
325 os << *results[0];
326 else {
327 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700328 interleaveComma(results, [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700329 os << ')';
330 }
331 return;
332 }
333 case Type::Kind::Vector: {
334 auto *v = cast<VectorType>(type);
335 os << "vector<";
James Molloy87d81022018-07-23 11:44:40 -0700336 for (auto dim : v->getShape())
337 os << dim << 'x';
MLIR Team4718bc92018-07-17 16:56:54 -0700338 os << *v->getElementType() << '>';
339 return;
340 }
341 case Type::Kind::RankedTensor: {
342 auto *v = cast<RankedTensorType>(type);
343 os << "tensor<";
344 for (auto dim : v->getShape()) {
345 if (dim < 0)
346 os << '?';
347 else
348 os << dim;
349 os << 'x';
350 }
351 os << *v->getElementType() << '>';
352 return;
353 }
354 case Type::Kind::UnrankedTensor: {
355 auto *v = cast<UnrankedTensorType>(type);
Chris Lattner413db6a2018-07-25 12:55:50 -0700356 os << "tensor<??";
357 printType(v->getElementType());
358 os << '>';
MLIR Team4718bc92018-07-17 16:56:54 -0700359 return;
360 }
361 case Type::Kind::MemRef: {
362 auto *v = cast<MemRefType>(type);
363 os << "memref<";
364 for (auto dim : v->getShape()) {
365 if (dim < 0)
366 os << '?';
367 else
368 os << dim;
369 os << 'x';
370 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700371 printType(v->getElementType());
MLIR Team4718bc92018-07-17 16:56:54 -0700372 for (auto map : v->getAffineMaps()) {
373 os << ", ";
MLIR Teamb61885d2018-07-18 16:29:21 -0700374 printAffineMapReference(map);
MLIR Team4718bc92018-07-17 16:56:54 -0700375 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700376 // Only print the memory space if it is the non-default one.
377 if (v->getMemorySpace())
378 os << ", " << v->getMemorySpace();
MLIR Team4718bc92018-07-17 16:56:54 -0700379 os << '>';
380 return;
381 }
382 }
383}
384
385//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -0700386// Affine expressions and maps
387//===----------------------------------------------------------------------===//
388
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700389void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700390 printAffineExprInternal(expr, BindingStrength::Weak);
391}
392
393void ModulePrinter::printAffineExprInternal(
394 const AffineExpr *expr, BindingStrength enclosingTightness) {
395 const char *binopSpelling = nullptr;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700396 switch (expr->getKind()) {
397 case AffineExpr::Kind::SymbolId:
398 os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
399 return;
400 case AffineExpr::Kind::DimId:
401 os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
402 return;
403 case AffineExpr::Kind::Constant:
404 os << cast<AffineConstantExpr>(expr)->getValue();
405 return;
406 case AffineExpr::Kind::Add:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700407 binopSpelling = " + ";
408 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700409 case AffineExpr::Kind::Mul:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700410 binopSpelling = " * ";
411 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700412 case AffineExpr::Kind::FloorDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700413 binopSpelling = " floordiv ";
414 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700415 case AffineExpr::Kind::CeilDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700416 binopSpelling = " ceildiv ";
417 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700418 case AffineExpr::Kind::Mod:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700419 binopSpelling = " mod ";
420 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700421 }
Chris Lattner4fd59b02018-07-20 09:35:47 -0700422
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700423 auto *binOp = cast<AffineBinaryOpExpr>(expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700424
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700425 // Handle tightly binding binary operators.
426 if (binOp->getKind() != AffineExpr::Kind::Add) {
427 if (enclosingTightness == BindingStrength::Strong)
428 os << '(';
429
430 printAffineExprInternal(binOp->getLHS(), BindingStrength::Strong);
431 os << binopSpelling;
432 printAffineExprInternal(binOp->getRHS(), BindingStrength::Strong);
433
434 if (enclosingTightness == BindingStrength::Strong)
435 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700436 return;
437 }
438
439 // Print out special "pretty" forms for add.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700440 if (enclosingTightness == BindingStrength::Strong)
441 os << '(';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700442
443 // Pretty print addition to a product that has a negative operand as a
444 // subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700445 if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700446 if (rhs->getKind() == AffineExpr::Kind::Mul) {
447 if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700448 if (rrhs->getValue() == -1) {
449 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
450 os << " - ";
451 printAffineExprInternal(rhs->getLHS(), BindingStrength::Weak);
452
453 if (enclosingTightness == BindingStrength::Strong)
454 os << ')';
455 return;
456 }
457
458 if (rrhs->getValue() < -1) {
459 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700460 os << " - ";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700461 printAffineExprInternal(rhs->getLHS(), BindingStrength::Strong);
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700462 os << " * " << -rrhs->getValue();
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700463 if (enclosingTightness == BindingStrength::Strong)
464 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700465 return;
466 }
467 }
468 }
469 }
470
471 // Pretty print addition to a negative number as a subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700472 if (auto *rhs = dyn_cast<AffineConstantExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700473 if (rhs->getValue() < 0) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700474 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
475 os << " - " << -rhs->getValue() << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700476 return;
477 }
478 }
479
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700480 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700481 os << " + ";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700482 printAffineExprInternal(binOp->getRHS(), BindingStrength::Weak);
483
484 if (enclosingTightness == BindingStrength::Strong)
485 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700486}
487
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700488void ModulePrinter::printAffineMap(const AffineMap *map) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700489 // Dimension identifiers.
490 os << '(';
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700491 for (int i = 0; i < (int)map->getNumDims() - 1; ++i)
492 os << 'd' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700493 if (map->getNumDims() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700494 os << 'd' << map->getNumDims() - 1;
495 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700496
497 // Symbolic identifiers.
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700498 if (map->getNumSymbols() != 0) {
499 os << '[';
500 for (unsigned i = 0; i < map->getNumSymbols() - 1; ++i)
501 os << 's' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700502 if (map->getNumSymbols() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700503 os << 's' << map->getNumSymbols() - 1;
504 os << ']';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700505 }
506
507 // AffineMap should have at least one result.
508 assert(!map->getResults().empty());
509 // Result affine expressions.
510 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700511 interleaveComma(map->getResults(),
512 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700513 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700514
515 if (!map->isBounded()) {
516 return;
517 }
518
519 // Print range sizes for bounded affine maps.
520 os << " size (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700521 interleaveComma(map->getRangeSizes(),
522 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700523 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700524}
525
526//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700527// Function printing
528//===----------------------------------------------------------------------===//
529
Chris Lattner4fd59b02018-07-20 09:35:47 -0700530void ModulePrinter::printFunctionSignature(const Function *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700531 auto type = fn->getType();
532
533 os << "@" << fn->getName() << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700534 interleaveComma(type->getInputs(),
535 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700536 os << ')';
537
538 switch (type->getResults().size()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700539 case 0:
540 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700541 case 1:
MLIR Team4718bc92018-07-17 16:56:54 -0700542 os << " -> ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700543 printType(type->getResults()[0]);
Chris Lattner4c95a502018-06-23 16:03:42 -0700544 break;
545 default:
546 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700547 interleaveComma(type->getResults(),
548 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700549 os << ')';
550 break;
551 }
552}
553
Chris Lattner4fd59b02018-07-20 09:35:47 -0700554void ModulePrinter::print(const ExtFunction *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700555 os << "extfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700556 printFunctionSignature(fn);
MLIR Team54b55a22018-07-18 10:16:05 -0700557 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700558}
559
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700560namespace {
561
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700562// FunctionPrinter contains common functionality for printing
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700563// CFG and ML functions.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700564class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700565public:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700566 FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700567
568 void printOperation(const Operation *op);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700569 void printDefaultOp(const Operation *op);
570
571 // Implement OpAsmPrinter.
572 raw_ostream &getStream() const { return os; }
573 void printType(const Type *type) { ModulePrinter::printType(type); }
574 void printAttribute(const Attribute *attr) {
575 ModulePrinter::printAttribute(attr);
576 }
577 void printAffineMap(const AffineMap *map) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700578 return ModulePrinter::printAffineMapReference(map);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700579 }
580 void printAffineExpr(const AffineExpr *expr) {
581 return ModulePrinter::printAffineExpr(expr);
582 }
583
584 void printOperand(const SSAValue *value) { printValueID(value); }
Tatiana Shpeismanc335d182018-08-03 11:12:34 -0700585
Chris Lattner85cf26d2018-08-02 16:54:36 -0700586 void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
587 ArrayRef<const char *> elidedAttrs = {}) override;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700588
Chris Lattnerd4964212018-08-01 10:43:18 -0700589 enum { nameSentinel = ~0U };
590
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700591protected:
Chris Lattnerf8cce872018-07-20 09:28:54 -0700592 void numberValueID(const SSAValue *value) {
593 assert(!valueIDs.count(value) && "Value numbered multiple times");
Chris Lattnerd4964212018-08-01 10:43:18 -0700594
595 SmallString<32> specialNameBuffer;
596 llvm::raw_svector_ostream specialName(specialNameBuffer);
597
598 // Give constant integers special names.
599 if (auto *op = value->getDefiningOperation()) {
600 if (auto intOp = op->getAs<ConstantIntOp>()) {
Chris Lattner384da8c2018-08-02 17:16:58 -0700601 // i1 constants get special names.
602 if (intOp->getType()->isInteger(1)) {
603 specialName << (intOp->getValue() ? "true" : "false");
604 } else {
605 specialName << 'c' << intOp->getValue();
606 if (!intOp->getType()->isAffineInt())
607 specialName << '_' << *intOp->getType();
608 }
Chris Lattnerd4964212018-08-01 10:43:18 -0700609 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700610 }
Chris Lattnerd4964212018-08-01 10:43:18 -0700611
612 if (specialNameBuffer.empty()) {
613 switch (value->getKind()) {
614 case SSAValueKind::BBArgument:
615 // If this is an argument to the function, give it an 'arg' name.
616 if (auto *bb = cast<BBArgument>(value)->getOwner())
617 if (auto *fn = bb->getFunction())
618 if (&fn->front() == bb) {
619 specialName << "arg" << nextArgumentID++;
620 break;
621 }
622 // Otherwise number it normally.
623 LLVM_FALLTHROUGH;
624 case SSAValueKind::InstResult:
625 case SSAValueKind::StmtResult:
626 // This is an uninteresting result, give it a boring number and be
627 // done with it.
628 valueIDs[value] = nextValueID++;
629 return;
630 case SSAValueKind::FnArgument:
631 specialName << "arg" << nextArgumentID++;
632 break;
633 case SSAValueKind::ForStmt:
634 specialName << 'i' << nextLoopID++;
635 break;
636 }
637 }
638
639 // Ok, this value had an interesting name. Remember it with a sentinel.
640 valueIDs[value] = nameSentinel;
641
642 // Remember that we've used this name, checking to see if we had a conflict.
643 auto insertRes = usedNames.insert(specialName.str());
644 if (insertRes.second) {
645 // If this is the first use of the name, then we're successful!
646 valueNames[value] = insertRes.first->first();
647 return;
648 }
649
650 // Otherwise, we had a conflict - probe until we find a unique name. This
651 // is guaranteed to terminate (and usually in a single iteration) because it
652 // generates new names by incrementing nextConflictID.
653 while (1) {
654 std::string probeName =
655 specialName.str().str() + "_" + llvm::utostr(nextConflictID++);
656 insertRes = usedNames.insert(probeName);
657 if (insertRes.second) {
658 // If this is the first use of the name, then we're successful!
659 valueNames[value] = insertRes.first->first();
660 return;
661 }
662 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700663 }
664
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700665 void printValueID(const SSAValue *value, bool printResultNo = true) const {
Chris Lattner6119d382018-07-20 18:41:34 -0700666 int resultNo = -1;
667 auto lookupValue = value;
668
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700669 // If this is a reference to the result of a multi-result instruction or
670 // statement, print out the # identifier and make sure to map our lookup
671 // to the first result of the instruction.
Chris Lattner6119d382018-07-20 18:41:34 -0700672 if (auto *result = dyn_cast<InstResult>(value)) {
673 if (result->getOwner()->getNumResults() != 1) {
674 resultNo = result->getResultNumber();
675 lookupValue = result->getOwner()->getResult(0);
676 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700677 } else if (auto *result = dyn_cast<StmtResult>(value)) {
678 if (result->getOwner()->getNumResults() != 1) {
679 resultNo = result->getResultNumber();
680 lookupValue = result->getOwner()->getResult(0);
681 }
Chris Lattner6119d382018-07-20 18:41:34 -0700682 }
683
684 auto it = valueIDs.find(lookupValue);
685 if (it == valueIDs.end()) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700686 os << "<<INVALID SSA VALUE>>";
Chris Lattner6119d382018-07-20 18:41:34 -0700687 return;
688 }
689
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700690 os << '%';
Chris Lattnerd4964212018-08-01 10:43:18 -0700691 if (it->second != nameSentinel) {
692 os << it->second;
693 } else {
694 auto nameIt = valueNames.find(lookupValue);
695 assert(nameIt != valueNames.end() && "Didn't have a name entry?");
696 os << nameIt->second;
697 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700698
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700699 if (resultNo != -1 && printResultNo)
Chris Lattner6119d382018-07-20 18:41:34 -0700700 os << '#' << resultNo;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700701 }
702
703private:
Chris Lattnerd4964212018-08-01 10:43:18 -0700704 /// This is the value ID for each SSA value in the current function. If this
705 /// returns ~0, then the valueID has an entry in valueNames.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700706 DenseMap<const SSAValue *, unsigned> valueIDs;
Chris Lattnerd4964212018-08-01 10:43:18 -0700707 DenseMap<const SSAValue *, StringRef> valueNames;
708
709 /// This keeps track of all of the non-numeric names that are in flight,
710 /// allowing us to check for duplicates.
711 llvm::StringSet<> usedNames;
712
713 /// This is the next value ID to assign in numbering.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700714 unsigned nextValueID = 0;
Chris Lattnerd4964212018-08-01 10:43:18 -0700715 /// This is the ID to assign to the next induction variable.
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700716 unsigned nextLoopID = 0;
Chris Lattnerd4964212018-08-01 10:43:18 -0700717 /// This is the next ID to assign to an MLFunction argument.
718 unsigned nextArgumentID = 0;
719
720 /// This is the next ID to assign when a name conflict is detected.
721 unsigned nextConflictID = 0;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700722};
James Molloy87d81022018-07-23 11:44:40 -0700723} // end anonymous namespace
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700724
Chris Lattner85cf26d2018-08-02 16:54:36 -0700725void FunctionPrinter::printOptionalAttrDict(
726 ArrayRef<NamedAttribute> attrs, ArrayRef<const char *> elidedAttrs) {
727 // If there are no attributes, then there is nothing to be done.
728 if (attrs.empty())
729 return;
730
731 // Filter out any attributes that shouldn't be included.
732 SmallVector<NamedAttribute, 8> filteredAttrs;
733 for (auto attr : attrs) {
734 auto attrName = attr.first.str();
735 // Never print attributes that start with a colon. These are internal
736 // attributes that represent location or other internal metadata.
737 if (attrName.startswith(":"))
738 continue;
739
740 // If the caller has requested that this attribute be ignored, then drop it.
741 bool ignore = false;
742 for (const char *elide : elidedAttrs)
743 ignore |= attrName == StringRef(elide);
744
745 // Otherwise add it to our filteredAttrs list.
746 if (!ignore)
747 filteredAttrs.push_back(attr);
748 }
749
750 // If there are no attributes left to print after filtering, then we're done.
751 if (filteredAttrs.empty())
752 return;
753
754 // Otherwise, print them all out in braces.
755 os << " {";
756 interleaveComma(filteredAttrs, [&](NamedAttribute attr) {
757 os << attr.first << ": ";
758 printAttribute(attr.second);
759 });
760 os << '}';
761}
762
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700763void FunctionPrinter::printOperation(const Operation *op) {
Chris Lattnerac591f12018-07-22 21:02:26 -0700764 if (op->getNumResults()) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700765 printValueID(op->getResult(0), /*printResultNo=*/false);
Chris Lattnerac591f12018-07-22 21:02:26 -0700766 os << " = ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700767 }
768
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700769 // Check to see if this is a known operation. If so, use the registered
770 // custom printer hook.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700771 if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700772 opInfo->printAssembly(op, this);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700773 return;
774 }
775
Chris Lattnerf8cce872018-07-20 09:28:54 -0700776 // Otherwise use the standard verbose printing approach.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700777 printDefaultOp(op);
778}
Chris Lattnerf8cce872018-07-20 09:28:54 -0700779
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700780void FunctionPrinter::printDefaultOp(const Operation *op) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700781 // TODO: escape name if necessary.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700782 os << "\"" << op->getName().str() << "\"(";
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700783
Chris Lattnerac591f12018-07-22 21:02:26 -0700784 interleaveComma(op->getOperands(),
785 [&](const SSAValue *value) { printValueID(value); });
Chris Lattner7f9cc272018-07-19 08:35:28 -0700786
Chris Lattnerf8cce872018-07-20 09:28:54 -0700787 os << ')';
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700788 auto attrs = op->getAttrs();
Chris Lattner85cf26d2018-08-02 16:54:36 -0700789 printOptionalAttrDict(attrs);
Chris Lattner3b2ef762018-07-18 15:31:25 -0700790
Chris Lattnerac591f12018-07-22 21:02:26 -0700791 // Print the type signature of the operation.
792 os << " : (";
793 interleaveComma(op->getOperands(),
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700794 [&](const SSAValue *value) { printType(value->getType()); });
Chris Lattnerac591f12018-07-22 21:02:26 -0700795 os << ") -> ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700796
Chris Lattnerac591f12018-07-22 21:02:26 -0700797 if (op->getNumResults() == 1) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700798 printType(op->getResult(0)->getType());
Chris Lattnerac591f12018-07-22 21:02:26 -0700799 } else {
800 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700801 interleaveComma(op->getResults(), [&](const SSAValue *result) {
802 printType(result->getType());
803 });
Chris Lattnerac591f12018-07-22 21:02:26 -0700804 os << ')';
Chris Lattnerf8cce872018-07-20 09:28:54 -0700805 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700806}
807
Chris Lattner4c95a502018-06-23 16:03:42 -0700808//===----------------------------------------------------------------------===//
809// CFG Function printing
810//===----------------------------------------------------------------------===//
811
812namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700813class CFGFunctionPrinter : public FunctionPrinter {
Chris Lattner4c95a502018-06-23 16:03:42 -0700814public:
Chris Lattner4fd59b02018-07-20 09:35:47 -0700815 CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
Chris Lattner4c95a502018-06-23 16:03:42 -0700816
817 const CFGFunction *getFunction() const { return function; }
818
819 void print();
820 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -0700821
822 void print(const Instruction *inst);
823 void print(const OperationInst *inst);
824 void print(const ReturnInst *inst);
825 void print(const BranchInst *inst);
James Molloy4f788372018-07-24 15:01:27 -0700826 void print(const CondBranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700827
828 unsigned getBBID(const BasicBlock *block) {
829 auto it = basicBlockIDs.find(block);
830 assert(it != basicBlockIDs.end() && "Block not in this function?");
831 return it->second;
832 }
833
834private:
835 const CFGFunction *function;
MLIR Team54b55a22018-07-18 10:16:05 -0700836 DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700837
Chris Lattner4fd59b02018-07-20 09:35:47 -0700838 void numberValuesInBlock(const BasicBlock *block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700839};
James Molloy87d81022018-07-23 11:44:40 -0700840} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -0700841
Chris Lattner4fd59b02018-07-20 09:35:47 -0700842CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
843 const ModulePrinter &other)
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700844 : FunctionPrinter(other), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700845 // Each basic block gets a unique ID per function.
846 unsigned blockID = 0;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700847 for (auto &block : *function) {
848 basicBlockIDs[&block] = blockID++;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700849 numberValuesInBlock(&block);
Chris Lattnerf8cce872018-07-20 09:28:54 -0700850 }
851}
852
853/// Number all of the SSA values in the specified basic block.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700854void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700855 for (auto *arg : block->getArguments()) {
856 numberValueID(arg);
857 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700858 for (auto &op : *block) {
859 // We number instruction that have results, and we only number the first
860 // result.
861 if (op.getNumResults() != 0)
862 numberValueID(op.getResult(0));
863 }
864
865 // Terminators do not define values.
Chris Lattner4c95a502018-06-23 16:03:42 -0700866}
867
Chris Lattner4fd59b02018-07-20 09:35:47 -0700868void CFGFunctionPrinter::print() {
Chris Lattner4c95a502018-06-23 16:03:42 -0700869 os << "cfgfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700870 printFunctionSignature(getFunction());
Chris Lattner4c95a502018-06-23 16:03:42 -0700871 os << " {\n";
872
James Molloy87d81022018-07-23 11:44:40 -0700873 for (auto &block : *function)
874 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700875 os << "}\n\n";
876}
877
Chris Lattner4fd59b02018-07-20 09:35:47 -0700878void CFGFunctionPrinter::print(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -0700879 os << "bb" << getBBID(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700880
James Molloy61a656c2018-07-22 15:45:24 -0700881 if (!block->args_empty()) {
882 os << '(';
883 interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
884 printValueID(arg);
885 os << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700886 printType(arg->getType());
James Molloy61a656c2018-07-22 15:45:24 -0700887 });
888 os << ')';
889 }
Chris Lattner25ce3062018-07-27 11:10:12 -0700890 os << ':';
891
892 // Print out some context information about the predecessors of this block.
893 if (!block->getFunction()) {
894 os << "\t// block is not in a function!";
895 } else if (block->hasNoPredecessors()) {
896 // Don't print "no predecessors" for the entry block.
897 if (block != &block->getFunction()->front())
898 os << "\t// no predecessors";
899 } else if (auto *pred = block->getSinglePredecessor()) {
900 os << "\t// pred: bb" << getBBID(pred);
901 } else {
902 // We want to print the predecessors in increasing numeric order, not in
903 // whatever order the use-list is in, so gather and sort them.
904 SmallVector<unsigned, 4> predIDs;
905 for (auto *pred : block->getPredecessors())
906 predIDs.push_back(getBBID(pred));
907 llvm::array_pod_sort(predIDs.begin(), predIDs.end());
908
909 os << "\t// " << predIDs.size() << " preds: ";
910
911 interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
912 }
913 os << '\n';
James Molloy61a656c2018-07-22 15:45:24 -0700914
Jacques Pienaarb020c542018-07-15 00:06:54 -0700915 for (auto &inst : block->getOperations()) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700916 os << " ";
Chris Lattner3a467cc2018-07-01 20:28:00 -0700917 print(&inst);
James Molloy61a656c2018-07-22 15:45:24 -0700918 os << '\n';
Jacques Pienaarb020c542018-07-15 00:06:54 -0700919 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700920
James Molloy6e4519b2018-08-03 03:51:38 -0700921 os << " ";
Chris Lattner4c95a502018-06-23 16:03:42 -0700922 print(block->getTerminator());
James Molloy61a656c2018-07-22 15:45:24 -0700923 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700924}
925
Chris Lattner4fd59b02018-07-20 09:35:47 -0700926void CFGFunctionPrinter::print(const Instruction *inst) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700927 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -0700928 case Instruction::Kind::Operation:
929 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700930 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -0700931 return print(cast<BranchInst>(inst));
James Molloy4f788372018-07-24 15:01:27 -0700932 case TerminatorInst::Kind::CondBranch:
933 return print(cast<CondBranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700934 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -0700935 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -0700936 }
937}
938
Chris Lattner4fd59b02018-07-20 09:35:47 -0700939void CFGFunctionPrinter::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700940 printOperation(inst);
Chris Lattner3b2ef762018-07-18 15:31:25 -0700941}
Chris Lattner1604e472018-07-23 08:42:19 -0700942
Chris Lattner4fd59b02018-07-20 09:35:47 -0700943void CFGFunctionPrinter::print(const BranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700944 os << "br bb" << getBBID(inst->getDest());
Chris Lattner1604e472018-07-23 08:42:19 -0700945
946 if (inst->getNumOperands() != 0) {
947 os << '(';
948 // TODO: Use getOperands() when we have it.
949 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
950 printValueID(operand.get());
951 });
952 os << ") : ";
953 interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700954 printType(operand.get()->getType());
Chris Lattner1604e472018-07-23 08:42:19 -0700955 });
956 }
Chris Lattnered65a732018-06-28 20:45:33 -0700957}
Chris Lattner1604e472018-07-23 08:42:19 -0700958
James Molloy4f788372018-07-24 15:01:27 -0700959void CFGFunctionPrinter::print(const CondBranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700960 os << "cond_br ";
James Molloy4f788372018-07-24 15:01:27 -0700961 printValueID(inst->getCondition());
962
963 os << ", bb" << getBBID(inst->getTrueDest());
964 if (inst->getNumTrueOperands() != 0) {
965 os << '(';
966 interleaveComma(inst->getTrueOperands(),
967 [&](const CFGValue *operand) { printValueID(operand); });
968 os << " : ";
969 interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700970 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700971 });
972 os << ")";
973 }
974
975 os << ", bb" << getBBID(inst->getFalseDest());
976 if (inst->getNumFalseOperands() != 0) {
977 os << '(';
978 interleaveComma(inst->getFalseOperands(),
979 [&](const CFGValue *operand) { printValueID(operand); });
980 os << " : ";
981 interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700982 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -0700983 });
984 os << ")";
985 }
986}
987
Chris Lattner40746442018-07-21 14:32:09 -0700988void CFGFunctionPrinter::print(const ReturnInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -0700989 os << "return";
Chris Lattner40746442018-07-21 14:32:09 -0700990
James Molloy6bf60c22018-08-02 08:28:20 -0700991 if (inst->getNumOperands() == 0)
992 return;
Chris Lattner40746442018-07-21 14:32:09 -0700993
James Molloy6bf60c22018-08-02 08:28:20 -0700994 os << ' ';
James Molloy4f788372018-07-24 15:01:27 -0700995 interleaveComma(inst->getOperands(),
996 [&](const CFGValue *operand) { printValueID(operand); });
997 os << " : ";
Chris Lattnerac591f12018-07-22 21:02:26 -0700998 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700999 printType(operand->getType());
Chris Lattner40746442018-07-21 14:32:09 -07001000 });
1001}
MLIR Team54b55a22018-07-18 10:16:05 -07001002
Chris Lattner4fd59b02018-07-20 09:35:47 -07001003void ModulePrinter::print(const CFGFunction *fn) {
1004 CFGFunctionPrinter(fn, *this).print();
Chris Lattnered65a732018-06-28 20:45:33 -07001005}
1006
Chris Lattner4c95a502018-06-23 16:03:42 -07001007//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001008// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -07001009//===----------------------------------------------------------------------===//
1010
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001011namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001012class MLFunctionPrinter : public FunctionPrinter {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001013public:
Chris Lattner4fd59b02018-07-20 09:35:47 -07001014 MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001015
1016 const MLFunction *getFunction() const { return function; }
1017
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001018 // Prints ML function
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001019 void print();
1020
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001021 // Methods to print ML function statements
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001022 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001023 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001024 void print(const ForStmt *stmt);
1025 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001026 void print(const StmtBlock *block);
1027
1028 // Number of spaces used for indenting nested statements
1029 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001030
1031private:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001032 void numberValues();
1033
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001034 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001035 int numSpaces;
1036};
James Molloy87d81022018-07-23 11:44:40 -07001037} // end anonymous namespace
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001038
Chris Lattner4fd59b02018-07-20 09:35:47 -07001039MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
1040 const ModulePrinter &other)
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001041 : FunctionPrinter(other), function(function), numSpaces(0) {
1042 numberValues();
1043}
1044
1045/// Number all of the SSA values in this ML function.
1046void MLFunctionPrinter::numberValues() {
1047 // Visits all operation statements and numbers the first result.
Uday Bondhugula081d9e72018-07-27 10:58:14 -07001048 struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001049 NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
1050 void visitOperationStmt(OperationStmt *stmt) {
1051 if (stmt->getNumResults() != 0)
1052 printer->numberValueID(stmt->getResult(0));
1053 }
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -07001054 void visitForStmt(ForStmt *stmt) { printer->numberValueID(stmt); }
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001055 MLFunctionPrinter *printer;
1056 };
1057
1058 NumberValuesPass pass(this);
1059 // TODO: it'd be cleaner to have constant visitor istead of using const_cast.
Uday Bondhugula081d9e72018-07-27 10:58:14 -07001060 pass.walk(const_cast<MLFunction *>(function));
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001061}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001062
Chris Lattner4fd59b02018-07-20 09:35:47 -07001063void MLFunctionPrinter::print() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001064 os << "mlfunc ";
1065 // FIXME: should print argument names rather than just signature
Chris Lattner4fd59b02018-07-20 09:35:47 -07001066 printFunctionSignature(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001067 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001068 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001069 os << " return\n";
1070 os << "}\n\n";
1071}
1072
Chris Lattner4fd59b02018-07-20 09:35:47 -07001073void MLFunctionPrinter::print(const StmtBlock *block) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001074 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -07001075 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001076 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -07001077 os << "\n";
1078 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001079 numSpaces -= indentWidth;
1080}
1081
Chris Lattner4fd59b02018-07-20 09:35:47 -07001082void MLFunctionPrinter::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001083 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001084 case Statement::Kind::Operation:
1085 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001086 case Statement::Kind::For:
1087 return print(cast<ForStmt>(stmt));
1088 case Statement::Kind::If:
1089 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001090 }
1091}
1092
Chris Lattner4fd59b02018-07-20 09:35:47 -07001093void MLFunctionPrinter::print(const OperationStmt *stmt) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001094 os.indent(numSpaces);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001095 printOperation(stmt);
1096}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001097
Chris Lattner4fd59b02018-07-20 09:35:47 -07001098void MLFunctionPrinter::print(const ForStmt *stmt) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -07001099 os.indent(numSpaces) << "for ";
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -07001100 printOperand(stmt);
Tatiana Shpeisman3838db72018-07-30 15:18:10 -07001101 os << " = " << *stmt->getLowerBound();
Tatiana Shpeisman1da50c42018-07-19 09:52:39 -07001102 os << " to " << *stmt->getUpperBound();
1103 if (stmt->getStep()->getValue() != 1)
1104 os << " step " << *stmt->getStep();
1105
1106 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001107 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001108 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001109}
1110
Chris Lattner4fd59b02018-07-20 09:35:47 -07001111void MLFunctionPrinter::print(const IfStmt *stmt) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001112 os.indent(numSpaces) << "if () {\n";
1113 print(stmt->getThenClause());
1114 os.indent(numSpaces) << "}";
1115 if (stmt->hasElseClause()) {
1116 os << " else {\n";
1117 print(stmt->getElseClause());
1118 os.indent(numSpaces) << "}";
1119 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001120}
1121
Chris Lattner4fd59b02018-07-20 09:35:47 -07001122void ModulePrinter::print(const MLFunction *fn) {
1123 MLFunctionPrinter(fn, *this).print();
MLIR Team4718bc92018-07-17 16:56:54 -07001124}
1125
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001126//===----------------------------------------------------------------------===//
1127// print and dump methods
1128//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -07001129
MLIR Teamb61885d2018-07-18 16:29:21 -07001130void Attribute::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001131 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001132 ModulePrinter(os, state).printAttribute(this);
MLIR Teamb61885d2018-07-18 16:29:21 -07001133}
1134
James Molloy87d81022018-07-23 11:44:40 -07001135void Attribute::dump() const { print(llvm::errs()); }
MLIR Teamb61885d2018-07-18 16:29:21 -07001136
MLIR Team4718bc92018-07-17 16:56:54 -07001137void Type::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001138 ModuleState state(getContext());
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001139 ModulePrinter(os, state).printType(this);
MLIR Team4718bc92018-07-17 16:56:54 -07001140}
1141
MLIR Team54b55a22018-07-18 10:16:05 -07001142void Type::dump() const { print(llvm::errs()); }
MLIR Team4718bc92018-07-17 16:56:54 -07001143
MLIR Team718c82f2018-07-16 09:45:22 -07001144void AffineMap::dump() const {
1145 print(llvm::errs());
1146 llvm::errs() << "\n";
1147}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001148
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001149void AffineExpr::dump() const {
1150 print(llvm::errs());
1151 llvm::errs() << "\n";
1152}
1153
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001154void AffineExpr::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001155 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001156 ModulePrinter(os, state).printAffineExpr(this);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001157}
1158
1159void AffineMap::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001160 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001161 ModulePrinter(os, state).printAffineMap(this);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001162}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001163
Chris Lattner384da8c2018-08-02 17:16:58 -07001164void SSAValue::print(raw_ostream &os) const {
1165 switch (getKind()) {
1166 case SSAValueKind::BBArgument:
1167 // TODO: Improve this.
1168 os << "<bb argument>\n";
1169 return;
1170 case SSAValueKind::InstResult:
1171 return getDefiningInst()->print(os);
1172 case SSAValueKind::FnArgument:
1173 // TODO: Improve this.
1174 os << "<function argument>\n";
1175 return;
1176 case SSAValueKind::StmtResult:
1177 return getDefiningStmt()->print(os);
1178 case SSAValueKind::ForStmt:
1179 return cast<ForStmt>(this)->print(os);
1180 }
1181}
1182
1183void SSAValue::dump() const { print(llvm::errs()); }
1184
Chris Lattner4fd59b02018-07-20 09:35:47 -07001185void Instruction::print(raw_ostream &os) const {
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001186 if (!getFunction()) {
1187 os << "<<UNLINKED INSTRUCTION>>\n";
1188 return;
1189 }
Chris Lattner4fd59b02018-07-20 09:35:47 -07001190 ModuleState state(getFunction()->getContext());
1191 ModulePrinter modulePrinter(os, state);
1192 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
1193}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001194
Chris Lattner4fd59b02018-07-20 09:35:47 -07001195void Instruction::dump() const {
1196 print(llvm::errs());
1197 llvm::errs() << "\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001198}
1199
Chris Lattner4c95a502018-06-23 16:03:42 -07001200void BasicBlock::print(raw_ostream &os) const {
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001201 if (!getFunction()) {
1202 os << "<<UNLINKED BLOCK>>\n";
1203 return;
1204 }
Chris Lattner4fd59b02018-07-20 09:35:47 -07001205 ModuleState state(getFunction()->getContext());
1206 ModulePrinter modulePrinter(os, state);
1207 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001208}
1209
MLIR Team54b55a22018-07-18 10:16:05 -07001210void BasicBlock::dump() const { print(llvm::errs()); }
Chris Lattner4c95a502018-06-23 16:03:42 -07001211
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001212void Statement::print(raw_ostream &os) const {
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001213 MLFunction *function = findFunction();
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001214 if (!function) {
1215 os << "<<UNLINKED STATEMENT>>\n";
1216 return;
1217 }
1218
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001219 ModuleState state(function->getContext());
Chris Lattner4fd59b02018-07-20 09:35:47 -07001220 ModulePrinter modulePrinter(os, state);
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001221 MLFunctionPrinter(function, modulePrinter).print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001222}
1223
MLIR Team54b55a22018-07-18 10:16:05 -07001224void Statement::dump() const { print(llvm::errs()); }
Jacques Pienaarb020c542018-07-15 00:06:54 -07001225
Uday Bondhugula84b80952018-08-03 13:22:26 -07001226void StmtBlock::print(raw_ostream &os) const {
1227 MLFunction *function = findFunction();
1228 ModuleState state(function->getContext());
1229 ModulePrinter modulePrinter(os, state);
1230 MLFunctionPrinter(function, modulePrinter).print(this);
1231}
1232
1233void StmtBlock::dump() const { print(llvm::errs()); }
1234
Chris Lattner4c95a502018-06-23 16:03:42 -07001235void Function::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001236 ModuleState state(getContext());
1237 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001238}
1239
MLIR Team54b55a22018-07-18 10:16:05 -07001240void Function::dump() const { print(llvm::errs()); }
1241
Chris Lattner4c95a502018-06-23 16:03:42 -07001242void Module::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001243 ModuleState state(getContext());
1244 state.initialize(this);
1245 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001246}
1247
MLIR Team54b55a22018-07-18 10:16:05 -07001248void Module::dump() const { print(llvm::errs()); }