blob: 83b9493f9c4132ab63900f583294d73477ef32f6 [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"
Uday Bondhugulabc535622018-08-07 14:24:38 -070027#include "mlir/IR/IntegerSet.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070028#include "mlir/IR/MLFunction.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070029#include "mlir/IR/Module.h"
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070030#include "mlir/IR/OpImplementation.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070031#include "mlir/IR/OperationSet.h"
Chris Lattnerd4964212018-08-01 10:43:18 -070032#include "mlir/IR/StandardOps.h"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070033#include "mlir/IR/Statements.h"
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070034#include "mlir/IR/StmtVisitor.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070035#include "mlir/IR/Types.h"
36#include "mlir/Support/STLExtras.h"
Chris Lattner0497c4b2018-08-15 09:09:54 -070037#include "llvm/ADT/APFloat.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070038#include "llvm/ADT/DenseMap.h"
Chris Lattnerd4964212018-08-01 10:43:18 -070039#include "llvm/ADT/SmallString.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/StringSet.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070042using namespace mlir;
43
MLIR Team54b55a22018-07-18 10:16:05 -070044void Identifier::print(raw_ostream &os) const { os << str(); }
Chris Lattner4c95a502018-06-23 16:03:42 -070045
MLIR Team54b55a22018-07-18 10:16:05 -070046void Identifier::dump() const { print(llvm::errs()); }
Chris Lattner7121b802018-07-04 20:45:39 -070047
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -070048OpAsmPrinter::~OpAsmPrinter() {}
49
Chris Lattner4c95a502018-06-23 16:03:42 -070050//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -070051// ModuleState
MLIR Team4718bc92018-07-17 16:56:54 -070052//===----------------------------------------------------------------------===//
53
54namespace {
MLIR Team54b55a22018-07-18 10:16:05 -070055class ModuleState {
56public:
Chris Lattner4fd59b02018-07-20 09:35:47 -070057 /// This is the operation set for the current context if it is knowable (a
58 /// context could be determined), otherwise this is null.
59 OperationSet *const operationSet;
MLIR Team4718bc92018-07-17 16:56:54 -070060
Chris Lattner4fd59b02018-07-20 09:35:47 -070061 explicit ModuleState(MLIRContext *context)
62 : operationSet(context ? &OperationSet::get(context) : nullptr) {}
63
64 // Initializes module state, populating affine map state.
MLIR Team4718bc92018-07-17 16:56:54 -070065 void initialize(const Module *module);
66
MLIR Team54b55a22018-07-18 10:16:05 -070067 int getAffineMapId(const AffineMap *affineMap) const {
MLIR Team4718bc92018-07-17 16:56:54 -070068 auto it = affineMapIds.find(affineMap);
69 if (it == affineMapIds.end()) {
70 return -1;
71 }
72 return it->second;
73 }
74
James Molloyc4666722018-07-24 09:48:31 -070075 ArrayRef<const AffineMap *> getAffineMapIds() const { return affineMapsById; }
Chris Lattner4fd59b02018-07-20 09:35:47 -070076
Uday Bondhugulabc535622018-08-07 14:24:38 -070077 int getIntegerSetId(const IntegerSet *integerSet) const {
78 auto it = integerSetIds.find(integerSet);
79 if (it == integerSetIds.end()) {
80 return -1;
81 }
82 return it->second;
83 }
84
85 ArrayRef<const IntegerSet *> getIntegerSetIds() const {
86 return integerSetsById;
87 }
88
MLIR Team54b55a22018-07-18 10:16:05 -070089private:
Chris Lattner4fd59b02018-07-20 09:35:47 -070090 void recordAffineMapReference(const AffineMap *affineMap) {
91 if (affineMapIds.count(affineMap) == 0) {
James Molloyc4666722018-07-24 09:48:31 -070092 affineMapIds[affineMap] = affineMapsById.size();
93 affineMapsById.push_back(affineMap);
Chris Lattner4fd59b02018-07-20 09:35:47 -070094 }
95 }
96
Uday Bondhugulabc535622018-08-07 14:24:38 -070097 void recordIntegerSetReference(const IntegerSet *integerSet) {
98 if (integerSetIds.count(integerSet) == 0) {
99 integerSetIds[integerSet] = integerSetsById.size();
100 integerSetsById.push_back(integerSet);
101 }
102 }
103
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700104 // Return true if this map could be printed using the shorthand form.
105 static bool hasShorthandForm(const AffineMap *boundMap) {
106 if (boundMap->isSingleConstant())
107 return true;
108
109 // Check if the affine map is single dim id or single symbol identity -
110 // (i)->(i) or ()[s]->(i)
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700111 return boundMap->getNumInputs() == 1 && boundMap->getNumResults() == 1 &&
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700112 (isa<AffineDimExpr>(boundMap->getResult(0)) ||
113 isa<AffineSymbolExpr>(boundMap->getResult(0)));
114 }
115
MLIR Team4718bc92018-07-17 16:56:54 -0700116 // Visit functions.
117 void visitFunction(const Function *fn);
118 void visitExtFunction(const ExtFunction *fn);
119 void visitCFGFunction(const CFGFunction *fn);
120 void visitMLFunction(const MLFunction *fn);
Uday Bondhugulabc535622018-08-07 14:24:38 -0700121 void visitStatement(const Statement *stmt);
122 void visitForStmt(const ForStmt *forStmt);
123 void visitIfStmt(const IfStmt *ifStmt);
124 void visitOperationStmt(const OperationStmt *opStmt);
MLIR Team4718bc92018-07-17 16:56:54 -0700125 void visitType(const Type *type);
MLIR Teamb61885d2018-07-18 16:29:21 -0700126 void visitAttribute(const Attribute *attr);
127 void visitOperation(const Operation *op);
128
MLIR Team54b55a22018-07-18 10:16:05 -0700129 DenseMap<const AffineMap *, int> affineMapIds;
James Molloyc4666722018-07-24 09:48:31 -0700130 std::vector<const AffineMap *> affineMapsById;
Uday Bondhugulabc535622018-08-07 14:24:38 -0700131
132 DenseMap<const IntegerSet *, int> integerSetIds;
133 std::vector<const IntegerSet *> integerSetsById;
MLIR Team4718bc92018-07-17 16:56:54 -0700134};
James Molloy87d81022018-07-23 11:44:40 -0700135} // end anonymous namespace
MLIR Team4718bc92018-07-17 16:56:54 -0700136
137// TODO Support visiting other types/instructions when implemented.
138void ModuleState::visitType(const Type *type) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700139 if (auto *funcType = dyn_cast<FunctionType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -0700140 // Visit input and result types for functions.
Chris Lattner3164ae62018-07-28 09:36:25 -0700141 for (auto *input : funcType->getInputs())
MLIR Team4718bc92018-07-17 16:56:54 -0700142 visitType(input);
Chris Lattner3164ae62018-07-28 09:36:25 -0700143 for (auto *result : funcType->getResults())
MLIR Team4718bc92018-07-17 16:56:54 -0700144 visitType(result);
Chris Lattner3164ae62018-07-28 09:36:25 -0700145 } else if (auto *memref = dyn_cast<MemRefType>(type)) {
MLIR Team4718bc92018-07-17 16:56:54 -0700146 // Visit affine maps in memref type.
Chris Lattner3164ae62018-07-28 09:36:25 -0700147 for (auto *map : memref->getAffineMaps()) {
MLIR Team4718bc92018-07-17 16:56:54 -0700148 recordAffineMapReference(map);
149 }
150 }
151}
152
MLIR Teamb61885d2018-07-18 16:29:21 -0700153void ModuleState::visitAttribute(const Attribute *attr) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700154 if (auto *mapAttr = dyn_cast<AffineMapAttr>(attr)) {
155 recordAffineMapReference(mapAttr->getValue());
Uday Bondhugulabc535622018-08-07 14:24:38 -0700156 } else if (auto *arrayAttr = dyn_cast<ArrayAttr>(attr)) {
157 for (auto elt : arrayAttr->getValue()) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700158 visitAttribute(elt);
159 }
160 }
161}
162
163void ModuleState::visitOperation(const Operation *op) {
Chris Lattnerca2ee872018-07-31 18:32:59 -0700164 // Visit all the types used in the operation.
165 for (auto *operand : op->getOperands())
166 visitType(operand->getType());
167 for (auto *result : op->getResults())
168 visitType(result->getType());
169
170 // Visit each of the attributes.
171 for (auto elt : op->getAttrs())
MLIR Teamb61885d2018-07-18 16:29:21 -0700172 visitAttribute(elt.second);
MLIR Teamb61885d2018-07-18 16:29:21 -0700173}
174
MLIR Team4718bc92018-07-17 16:56:54 -0700175void ModuleState::visitExtFunction(const ExtFunction *fn) {
176 visitType(fn->getType());
177}
178
179void ModuleState::visitCFGFunction(const CFGFunction *fn) {
180 visitType(fn->getType());
MLIR Teamb61885d2018-07-18 16:29:21 -0700181 for (auto &block : *fn) {
182 for (auto &op : block.getOperations()) {
183 visitOperation(&op);
184 }
185 }
MLIR Team4718bc92018-07-17 16:56:54 -0700186}
187
Uday Bondhugulabc535622018-08-07 14:24:38 -0700188void ModuleState::visitIfStmt(const IfStmt *ifStmt) {
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -0700189 recordIntegerSetReference(ifStmt->getIntegerSet());
Chris Lattnere787b322018-08-08 11:14:57 -0700190 for (auto &childStmt : *ifStmt->getThen())
Uday Bondhugulabc535622018-08-07 14:24:38 -0700191 visitStatement(&childStmt);
Chris Lattnere787b322018-08-08 11:14:57 -0700192 if (ifStmt->hasElse())
193 for (auto &childStmt : *ifStmt->getElse())
Uday Bondhugulabc535622018-08-07 14:24:38 -0700194 visitStatement(&childStmt);
195}
196
197void ModuleState::visitForStmt(const ForStmt *forStmt) {
Tatiana Shpeismande8829f2018-08-24 23:38:14 -0700198 AffineMap *lbMap = forStmt->getLowerBoundMap();
199 if (!hasShorthandForm(lbMap))
200 recordAffineMapReference(lbMap);
201
202 AffineMap *ubMap = forStmt->getUpperBoundMap();
203 if (!hasShorthandForm(ubMap))
204 recordAffineMapReference(ubMap);
205
Uday Bondhugulabc535622018-08-07 14:24:38 -0700206 for (auto &childStmt : *forStmt)
207 visitStatement(&childStmt);
208}
209
210void ModuleState::visitOperationStmt(const OperationStmt *opStmt) {
Chris Lattner0497c4b2018-08-15 09:09:54 -0700211 for (auto attr : opStmt->getAttrs())
212 visitAttribute(attr.second);
Uday Bondhugulabc535622018-08-07 14:24:38 -0700213}
214
215void ModuleState::visitStatement(const Statement *stmt) {
216 switch (stmt->getKind()) {
217 case Statement::Kind::If:
218 return visitIfStmt(cast<IfStmt>(stmt));
219 case Statement::Kind::For:
220 return visitForStmt(cast<ForStmt>(stmt));
221 case Statement::Kind::Operation:
222 return visitOperationStmt(cast<OperationStmt>(stmt));
223 default:
224 return;
225 }
226}
227
MLIR Team4718bc92018-07-17 16:56:54 -0700228void ModuleState::visitMLFunction(const MLFunction *fn) {
229 visitType(fn->getType());
Uday Bondhugulabc535622018-08-07 14:24:38 -0700230 for (auto &stmt : *fn) {
231 ModuleState::visitStatement(&stmt);
232 }
MLIR Team4718bc92018-07-17 16:56:54 -0700233}
234
235void ModuleState::visitFunction(const Function *fn) {
236 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700237 case Function::Kind::ExtFunc:
238 return visitExtFunction(cast<ExtFunction>(fn));
239 case Function::Kind::CFGFunc:
240 return visitCFGFunction(cast<CFGFunction>(fn));
241 case Function::Kind::MLFunc:
242 return visitMLFunction(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700243 }
244}
245
Uday Bondhugulabc535622018-08-07 14:24:38 -0700246// Initializes module state, populating affine map and integer set state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700247void ModuleState::initialize(const Module *module) {
Chris Lattnera8e47672018-07-25 14:08:16 -0700248 for (auto &fn : *module) {
249 visitFunction(&fn);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700250 }
251}
252
253//===----------------------------------------------------------------------===//
254// ModulePrinter
255//===----------------------------------------------------------------------===//
256
257namespace {
258class ModulePrinter {
259public:
260 ModulePrinter(raw_ostream &os, ModuleState &state) : os(os), state(state) {}
261 explicit ModulePrinter(const ModulePrinter &printer)
262 : os(printer.os), state(printer.state) {}
263
264 template <typename Container, typename UnaryFunctor>
265 inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
266 interleave(c.begin(), c.end(), each_fn, [&]() { os << ", "; });
267 }
268
269 void print(const Module *module);
Chris Lattner1aa46322018-08-21 17:55:22 -0700270 void printFunctionReference(const Function *func);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700271 void printAttribute(const Attribute *attr);
272 void printType(const Type *type);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700273 void print(const Function *fn);
274 void print(const ExtFunction *fn);
275 void print(const CFGFunction *fn);
276 void print(const MLFunction *fn);
277
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700278 void printAffineMap(const AffineMap *map);
279 void printAffineExpr(const AffineExpr *expr);
Uday Bondhugulabc535622018-08-07 14:24:38 -0700280 void printAffineConstraint(const AffineExpr *expr, bool isEq);
281 void printIntegerSet(const IntegerSet *set);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700282
283protected:
284 raw_ostream &os;
285 ModuleState &state;
286
287 void printFunctionSignature(const Function *fn);
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700288 void printFunctionResultType(const FunctionType *type);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700289 void printAffineMapId(int affineMapId) const;
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700290 void printAffineMapReference(const AffineMap *affineMap);
Uday Bondhugulabc535622018-08-07 14:24:38 -0700291 void printIntegerSetId(int integerSetId) const;
292 void printIntegerSetReference(const IntegerSet *integerSet);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700293
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700294 /// This enum is used to represent the binding stength of the enclosing
295 /// context that an AffineExpr is being printed in, so we can intelligently
296 /// produce parens.
297 enum class BindingStrength {
298 Weak, // + and -
299 Strong, // All other binary operators.
300 };
301 void printAffineExprInternal(const AffineExpr *expr,
302 BindingStrength enclosingTightness);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700303};
304} // end anonymous namespace
305
MLIR Team4718bc92018-07-17 16:56:54 -0700306// Prints function with initialized module state.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700307void ModulePrinter::print(const Function *fn) {
MLIR Team4718bc92018-07-17 16:56:54 -0700308 switch (fn->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700309 case Function::Kind::ExtFunc:
310 return print(cast<ExtFunction>(fn));
311 case Function::Kind::CFGFunc:
312 return print(cast<CFGFunction>(fn));
313 case Function::Kind::MLFunc:
314 return print(cast<MLFunction>(fn));
MLIR Team4718bc92018-07-17 16:56:54 -0700315 }
316}
317
318// Prints affine map identifier.
Chris Lattner4fd59b02018-07-20 09:35:47 -0700319void ModulePrinter::printAffineMapId(int affineMapId) const {
MLIR Team4718bc92018-07-17 16:56:54 -0700320 os << "#map" << affineMapId;
321}
322
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700323void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700324 int mapId = state.getAffineMapId(affineMap);
MLIR Teamb61885d2018-07-18 16:29:21 -0700325 if (mapId >= 0) {
326 // Map will be printed at top of module so print reference to its id.
327 printAffineMapId(mapId);
328 } else {
329 // Map not in module state so print inline.
330 affineMap->print(os);
331 }
332}
333
Uday Bondhugulabc535622018-08-07 14:24:38 -0700334// Prints integer set identifier.
335void ModulePrinter::printIntegerSetId(int integerSetId) const {
336 os << "@@set" << integerSetId;
337}
338
339void ModulePrinter::printIntegerSetReference(const IntegerSet *integerSet) {
340 int setId;
341 if ((setId = state.getIntegerSetId(integerSet)) >= 0) {
342 // The set will be printed at top of module; so print reference to its id.
343 printIntegerSetId(setId);
344 } else {
345 // Set not in module state so print inline.
346 integerSet->print(os);
347 }
348}
349
Chris Lattner4fd59b02018-07-20 09:35:47 -0700350void ModulePrinter::print(const Module *module) {
James Molloyc4666722018-07-24 09:48:31 -0700351 for (const auto &map : state.getAffineMapIds()) {
352 printAffineMapId(state.getAffineMapId(map));
MLIR Team4718bc92018-07-17 16:56:54 -0700353 os << " = ";
James Molloyc4666722018-07-24 09:48:31 -0700354 map->print(os);
MLIR Team4718bc92018-07-17 16:56:54 -0700355 os << '\n';
356 }
Uday Bondhugulabc535622018-08-07 14:24:38 -0700357 for (const auto &set : state.getIntegerSetIds()) {
358 printIntegerSetId(state.getIntegerSetId(set));
359 os << " = ";
360 set->print(os);
361 os << '\n';
362 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700363 for (auto const &fn : *module)
364 print(&fn);
MLIR Team4718bc92018-07-17 16:56:54 -0700365}
366
Chris Lattner0497c4b2018-08-15 09:09:54 -0700367/// Print a floating point value in a way that the parser will be able to
368/// round-trip losslessly.
369static void printFloatValue(double value, raw_ostream &os) {
370 APFloat apValue(value);
371
372 // We would like to output the FP constant value in exponential notation,
373 // but we cannot do this if doing so will lose precision. Check here to
374 // make sure that we only output it in exponential format if we can parse
375 // the value back and get the same value.
376 bool isInf = apValue.isInfinity();
377 bool isNaN = apValue.isNaN();
378 if (!isInf && !isNaN) {
379 SmallString<128> strValue;
380 apValue.toString(strValue, 6, 0, false);
381
382 // Check to make sure that the stringized number is not some string like
383 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
384 // that the string matches the "[-+]?[0-9]" regex.
385 assert(((strValue[0] >= '0' && strValue[0] <= '9') ||
386 ((strValue[0] == '-' || strValue[0] == '+') &&
387 (strValue[1] >= '0' && strValue[1] <= '9'))) &&
388 "[-+]?[0-9] regex does not match!");
389 // Reparse stringized version!
390 if (APFloat(APFloat::IEEEdouble(), strValue).convertToDouble() == value) {
391 os << strValue;
392 return;
393 }
394 }
395
396 // Otherwise, print it in a hexadecimal form. Convert it to an integer so we
397 // can print it out using integer math.
398 union {
399 double doubleValue;
400 uint64_t integerValue;
401 };
402 doubleValue = value;
403 os << "0x";
404 // Print out 16 nibbles worth of hex digit.
405 for (unsigned i = 0; i != 16; ++i) {
406 os << llvm::hexdigit(integerValue >> 60);
407 integerValue <<= 4;
408 }
409}
410
Chris Lattner1aa46322018-08-21 17:55:22 -0700411void ModulePrinter::printFunctionReference(const Function *func) {
412 os << '@' << func->getName();
413}
414
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700415void ModulePrinter::printAttribute(const Attribute *attr) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700416 switch (attr->getKind()) {
417 case Attribute::Kind::Bool:
418 os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
419 break;
420 case Attribute::Kind::Integer:
421 os << cast<IntegerAttr>(attr)->getValue();
422 break;
423 case Attribute::Kind::Float:
Chris Lattner0497c4b2018-08-15 09:09:54 -0700424 printFloatValue(cast<FloatAttr>(attr)->getValue(), os);
MLIR Teamb61885d2018-07-18 16:29:21 -0700425 break;
426 case Attribute::Kind::String:
Chris Lattner0497c4b2018-08-15 09:09:54 -0700427 os << '"';
428 printEscapedString(cast<StringAttr>(attr)->getValue(), os);
429 os << '"';
MLIR Teamb61885d2018-07-18 16:29:21 -0700430 break;
Chris Lattner0497c4b2018-08-15 09:09:54 -0700431 case Attribute::Kind::Array:
MLIR Teamb61885d2018-07-18 16:29:21 -0700432 os << '[';
Chris Lattner0497c4b2018-08-15 09:09:54 -0700433 interleaveComma(cast<ArrayAttr>(attr)->getValue(),
434 [&](Attribute *attr) { printAttribute(attr); });
MLIR Teamb61885d2018-07-18 16:29:21 -0700435 os << ']';
436 break;
MLIR Teamb61885d2018-07-18 16:29:21 -0700437 case Attribute::Kind::AffineMap:
438 printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
439 break;
James Molloyf0d2f442018-08-03 01:54:46 -0700440 case Attribute::Kind::Type:
441 printType(cast<TypeAttr>(attr)->getValue());
442 break;
Chris Lattner4613d9e2018-08-19 21:17:22 -0700443 case Attribute::Kind::Function: {
444 auto *function = cast<FunctionAttr>(attr)->getValue();
445 if (!function) {
446 os << "<<FUNCTION ATTR FOR DELETED FUNCTION>>";
447 } else {
Chris Lattner1aa46322018-08-21 17:55:22 -0700448 printFunctionReference(function);
449 os << " : ";
Chris Lattner4613d9e2018-08-19 21:17:22 -0700450 printType(function->getType());
451 }
452 break;
453 }
MLIR Teamb61885d2018-07-18 16:29:21 -0700454 }
455}
456
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700457void ModulePrinter::printType(const Type *type) {
MLIR Team4718bc92018-07-17 16:56:54 -0700458 switch (type->getKind()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700459 case Type::Kind::AffineInt:
460 os << "affineint";
461 return;
462 case Type::Kind::BF16:
463 os << "bf16";
464 return;
465 case Type::Kind::F16:
466 os << "f16";
467 return;
468 case Type::Kind::F32:
469 os << "f32";
470 return;
471 case Type::Kind::F64:
472 os << "f64";
473 return;
Jacques Pienaarc0d69302018-07-27 11:07:12 -0700474 case Type::Kind::TFControl:
475 os << "tf_control";
476 return;
James Molloy72b0cbe2018-08-01 12:55:27 -0700477 case Type::Kind::TFString:
478 os << "tf_string";
479 return;
MLIR Team4718bc92018-07-17 16:56:54 -0700480
481 case Type::Kind::Integer: {
482 auto *integer = cast<IntegerType>(type);
483 os << 'i' << integer->getWidth();
484 return;
485 }
486 case Type::Kind::Function: {
487 auto *func = cast<FunctionType>(type);
488 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700489 interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700490 os << ") -> ";
491 auto results = func->getResults();
492 if (results.size() == 1)
493 os << *results[0];
494 else {
495 os << '(';
Chris Lattner413db6a2018-07-25 12:55:50 -0700496 interleaveComma(results, [&](Type *type) { printType(type); });
MLIR Team4718bc92018-07-17 16:56:54 -0700497 os << ')';
498 }
499 return;
500 }
501 case Type::Kind::Vector: {
502 auto *v = cast<VectorType>(type);
503 os << "vector<";
James Molloy87d81022018-07-23 11:44:40 -0700504 for (auto dim : v->getShape())
505 os << dim << 'x';
MLIR Team4718bc92018-07-17 16:56:54 -0700506 os << *v->getElementType() << '>';
507 return;
508 }
509 case Type::Kind::RankedTensor: {
510 auto *v = cast<RankedTensorType>(type);
511 os << "tensor<";
512 for (auto dim : v->getShape()) {
513 if (dim < 0)
514 os << '?';
515 else
516 os << dim;
517 os << 'x';
518 }
519 os << *v->getElementType() << '>';
520 return;
521 }
522 case Type::Kind::UnrankedTensor: {
523 auto *v = cast<UnrankedTensorType>(type);
Chris Lattner413db6a2018-07-25 12:55:50 -0700524 os << "tensor<??";
525 printType(v->getElementType());
526 os << '>';
MLIR Team4718bc92018-07-17 16:56:54 -0700527 return;
528 }
529 case Type::Kind::MemRef: {
530 auto *v = cast<MemRefType>(type);
531 os << "memref<";
532 for (auto dim : v->getShape()) {
533 if (dim < 0)
534 os << '?';
535 else
536 os << dim;
537 os << 'x';
538 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700539 printType(v->getElementType());
MLIR Team4718bc92018-07-17 16:56:54 -0700540 for (auto map : v->getAffineMaps()) {
541 os << ", ";
MLIR Teamb61885d2018-07-18 16:29:21 -0700542 printAffineMapReference(map);
MLIR Team4718bc92018-07-17 16:56:54 -0700543 }
Chris Lattner413db6a2018-07-25 12:55:50 -0700544 // Only print the memory space if it is the non-default one.
545 if (v->getMemorySpace())
546 os << ", " << v->getMemorySpace();
MLIR Team4718bc92018-07-17 16:56:54 -0700547 os << '>';
548 return;
549 }
550 }
551}
552
553//===----------------------------------------------------------------------===//
Chris Lattner4fd59b02018-07-20 09:35:47 -0700554// Affine expressions and maps
555//===----------------------------------------------------------------------===//
556
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700557void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700558 printAffineExprInternal(expr, BindingStrength::Weak);
559}
560
561void ModulePrinter::printAffineExprInternal(
562 const AffineExpr *expr, BindingStrength enclosingTightness) {
563 const char *binopSpelling = nullptr;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700564 switch (expr->getKind()) {
565 case AffineExpr::Kind::SymbolId:
566 os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
567 return;
568 case AffineExpr::Kind::DimId:
569 os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
570 return;
571 case AffineExpr::Kind::Constant:
572 os << cast<AffineConstantExpr>(expr)->getValue();
573 return;
574 case AffineExpr::Kind::Add:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700575 binopSpelling = " + ";
576 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700577 case AffineExpr::Kind::Mul:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700578 binopSpelling = " * ";
579 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700580 case AffineExpr::Kind::FloorDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700581 binopSpelling = " floordiv ";
582 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700583 case AffineExpr::Kind::CeilDiv:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700584 binopSpelling = " ceildiv ";
585 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700586 case AffineExpr::Kind::Mod:
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700587 binopSpelling = " mod ";
588 break;
Chris Lattner4fd59b02018-07-20 09:35:47 -0700589 }
Chris Lattner4fd59b02018-07-20 09:35:47 -0700590
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700591 auto *binOp = cast<AffineBinaryOpExpr>(expr);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700592
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700593 // Handle tightly binding binary operators.
594 if (binOp->getKind() != AffineExpr::Kind::Add) {
595 if (enclosingTightness == BindingStrength::Strong)
596 os << '(';
597
598 printAffineExprInternal(binOp->getLHS(), BindingStrength::Strong);
599 os << binopSpelling;
600 printAffineExprInternal(binOp->getRHS(), BindingStrength::Strong);
601
602 if (enclosingTightness == BindingStrength::Strong)
603 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700604 return;
605 }
606
607 // Print out special "pretty" forms for add.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700608 if (enclosingTightness == BindingStrength::Strong)
609 os << '(';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700610
611 // Pretty print addition to a product that has a negative operand as a
612 // subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700613 if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700614 if (rhs->getKind() == AffineExpr::Kind::Mul) {
615 if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700616 if (rrhs->getValue() == -1) {
617 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
618 os << " - ";
619 printAffineExprInternal(rhs->getLHS(), BindingStrength::Weak);
620
621 if (enclosingTightness == BindingStrength::Strong)
622 os << ')';
623 return;
624 }
625
626 if (rrhs->getValue() < -1) {
627 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700628 os << " - ";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700629 printAffineExprInternal(rhs->getLHS(), BindingStrength::Strong);
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700630 os << " * " << -rrhs->getValue();
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700631 if (enclosingTightness == BindingStrength::Strong)
632 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700633 return;
634 }
635 }
636 }
637 }
638
639 // Pretty print addition to a negative number as a subtraction.
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700640 if (auto *rhs = dyn_cast<AffineConstantExpr>(binOp->getRHS())) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700641 if (rhs->getValue() < 0) {
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700642 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Uday Bondhugulabc535622018-08-07 14:24:38 -0700643 os << " - " << -rhs->getValue();
644 if (enclosingTightness == BindingStrength::Strong)
645 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700646 return;
647 }
648 }
649
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700650 printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
Chris Lattner4fd59b02018-07-20 09:35:47 -0700651 os << " + ";
Chris Lattner7d3b77c2018-07-31 16:21:36 -0700652 printAffineExprInternal(binOp->getRHS(), BindingStrength::Weak);
653
654 if (enclosingTightness == BindingStrength::Strong)
655 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700656}
657
Uday Bondhugulabc535622018-08-07 14:24:38 -0700658void ModulePrinter::printAffineConstraint(const AffineExpr *expr, bool isEq) {
659 printAffineExprInternal(expr, BindingStrength::Weak);
660 isEq ? os << " == 0" : os << " >= 0";
661}
662
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700663void ModulePrinter::printAffineMap(const AffineMap *map) {
Chris Lattner4fd59b02018-07-20 09:35:47 -0700664 // Dimension identifiers.
665 os << '(';
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700666 for (int i = 0; i < (int)map->getNumDims() - 1; ++i)
667 os << 'd' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700668 if (map->getNumDims() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700669 os << 'd' << map->getNumDims() - 1;
670 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700671
672 // Symbolic identifiers.
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700673 if (map->getNumSymbols() != 0) {
674 os << '[';
675 for (unsigned i = 0; i < map->getNumSymbols() - 1; ++i)
676 os << 's' << i << ", ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700677 if (map->getNumSymbols() >= 1)
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700678 os << 's' << map->getNumSymbols() - 1;
679 os << ']';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700680 }
681
682 // AffineMap should have at least one result.
683 assert(!map->getResults().empty());
684 // Result affine expressions.
685 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700686 interleaveComma(map->getResults(),
687 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700688 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700689
690 if (!map->isBounded()) {
691 return;
692 }
693
694 // Print range sizes for bounded affine maps.
695 os << " size (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700696 interleaveComma(map->getRangeSizes(),
697 [&](AffineExpr *expr) { printAffineExpr(expr); });
Chris Lattnerdc3ba382018-07-29 14:13:03 -0700698 os << ')';
Chris Lattner4fd59b02018-07-20 09:35:47 -0700699}
700
Uday Bondhugulabc535622018-08-07 14:24:38 -0700701void ModulePrinter::printIntegerSet(const IntegerSet *set) {
702 // Dimension identifiers.
703 os << '(';
704 for (unsigned i = 1; i < set->getNumDims(); ++i)
705 os << 'd' << i - 1 << ", ";
706 if (set->getNumDims() >= 1)
707 os << 'd' << set->getNumDims() - 1;
708 os << ')';
709
710 // Symbolic identifiers.
711 if (set->getNumSymbols() != 0) {
712 os << '[';
713 for (unsigned i = 0; i < set->getNumSymbols() - 1; ++i)
714 os << 's' << i << ", ";
715 if (set->getNumSymbols() >= 1)
716 os << 's' << set->getNumSymbols() - 1;
717 os << ']';
718 }
719
720 // Print constraints.
721 os << " : (";
722 auto numConstraints = set->getNumConstraints();
723 for (int i = 1; i < numConstraints; ++i) {
724 printAffineConstraint(set->getConstraint(i - 1), set->isEq(i - 1));
725 os << ", ";
726 }
727 if (numConstraints >= 1)
728 printAffineConstraint(set->getConstraint(numConstraints - 1),
729 set->isEq(numConstraints - 1));
730 os << ')';
731}
732
Chris Lattner4fd59b02018-07-20 09:35:47 -0700733//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700734// Function printing
735//===----------------------------------------------------------------------===//
736
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700737void ModulePrinter::printFunctionResultType(const FunctionType *type) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700738 switch (type->getResults().size()) {
MLIR Team54b55a22018-07-18 10:16:05 -0700739 case 0:
740 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700741 case 1:
MLIR Team4718bc92018-07-17 16:56:54 -0700742 os << " -> ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700743 printType(type->getResults()[0]);
Chris Lattner4c95a502018-06-23 16:03:42 -0700744 break;
745 default:
746 os << " -> (";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700747 interleaveComma(type->getResults(),
748 [&](Type *eltType) { printType(eltType); });
Chris Lattner4c95a502018-06-23 16:03:42 -0700749 os << ')';
750 break;
751 }
752}
753
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700754void ModulePrinter::printFunctionSignature(const Function *fn) {
755 auto type = fn->getType();
756
757 os << "@" << fn->getName() << '(';
758 interleaveComma(type->getInputs(),
759 [&](Type *eltType) { printType(eltType); });
760 os << ')';
761
762 printFunctionResultType(type);
763}
764
Chris Lattner4fd59b02018-07-20 09:35:47 -0700765void ModulePrinter::print(const ExtFunction *fn) {
Chris Lattner4c95a502018-06-23 16:03:42 -0700766 os << "extfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -0700767 printFunctionSignature(fn);
MLIR Team54b55a22018-07-18 10:16:05 -0700768 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -0700769}
770
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700771namespace {
772
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700773// FunctionPrinter contains common functionality for printing
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700774// CFG and ML functions.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700775class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700776public:
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700777 FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700778
779 void printOperation(const Operation *op);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700780 void printDefaultOp(const Operation *op);
781
782 // Implement OpAsmPrinter.
783 raw_ostream &getStream() const { return os; }
784 void printType(const Type *type) { ModulePrinter::printType(type); }
785 void printAttribute(const Attribute *attr) {
786 ModulePrinter::printAttribute(attr);
787 }
788 void printAffineMap(const AffineMap *map) {
Chris Lattner3164ae62018-07-28 09:36:25 -0700789 return ModulePrinter::printAffineMapReference(map);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700790 }
Uday Bondhugulabc535622018-08-07 14:24:38 -0700791 void printIntegerSet(const IntegerSet *set) {
792 return ModulePrinter::printIntegerSetReference(set);
793 }
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700794 void printAffineExpr(const AffineExpr *expr) {
795 return ModulePrinter::printAffineExpr(expr);
796 }
Chris Lattner1aa46322018-08-21 17:55:22 -0700797 void printFunctionReference(const Function *func) {
798 return ModulePrinter::printFunctionReference(func);
799 }
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700800
801 void printOperand(const SSAValue *value) { printValueID(value); }
Tatiana Shpeismanc335d182018-08-03 11:12:34 -0700802
Chris Lattner85cf26d2018-08-02 16:54:36 -0700803 void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
804 ArrayRef<const char *> elidedAttrs = {}) override;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700805
Chris Lattnerd4964212018-08-01 10:43:18 -0700806 enum { nameSentinel = ~0U };
807
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700808protected:
Chris Lattnerf8cce872018-07-20 09:28:54 -0700809 void numberValueID(const SSAValue *value) {
810 assert(!valueIDs.count(value) && "Value numbered multiple times");
Chris Lattnerd4964212018-08-01 10:43:18 -0700811
812 SmallString<32> specialNameBuffer;
813 llvm::raw_svector_ostream specialName(specialNameBuffer);
814
815 // Give constant integers special names.
816 if (auto *op = value->getDefiningOperation()) {
817 if (auto intOp = op->getAs<ConstantIntOp>()) {
Chris Lattner384da8c2018-08-02 17:16:58 -0700818 // i1 constants get special names.
819 if (intOp->getType()->isInteger(1)) {
820 specialName << (intOp->getValue() ? "true" : "false");
821 } else {
Chris Lattner992a1272018-08-07 12:02:37 -0700822 specialName << 'c' << intOp->getValue() << '_' << *intOp->getType();
Chris Lattner384da8c2018-08-02 17:16:58 -0700823 }
Chris Lattner992a1272018-08-07 12:02:37 -0700824 } else if (auto intOp = op->getAs<ConstantAffineIntOp>()) {
825 specialName << 'c' << intOp->getValue();
Chris Lattner4613d9e2018-08-19 21:17:22 -0700826 } else if (auto constant = op->getAs<ConstantOp>()) {
827 if (isa<FunctionAttr>(constant->getValue()))
828 specialName << 'f';
829 else
830 specialName << "cst";
Chris Lattnerd4964212018-08-01 10:43:18 -0700831 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700832 }
Chris Lattnerd4964212018-08-01 10:43:18 -0700833
834 if (specialNameBuffer.empty()) {
835 switch (value->getKind()) {
836 case SSAValueKind::BBArgument:
837 // If this is an argument to the function, give it an 'arg' name.
838 if (auto *bb = cast<BBArgument>(value)->getOwner())
839 if (auto *fn = bb->getFunction())
840 if (&fn->front() == bb) {
841 specialName << "arg" << nextArgumentID++;
842 break;
843 }
844 // Otherwise number it normally.
845 LLVM_FALLTHROUGH;
846 case SSAValueKind::InstResult:
847 case SSAValueKind::StmtResult:
848 // This is an uninteresting result, give it a boring number and be
849 // done with it.
850 valueIDs[value] = nextValueID++;
851 return;
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700852 case SSAValueKind::MLFuncArgument:
Chris Lattnerd4964212018-08-01 10:43:18 -0700853 specialName << "arg" << nextArgumentID++;
854 break;
855 case SSAValueKind::ForStmt:
856 specialName << 'i' << nextLoopID++;
857 break;
858 }
859 }
860
861 // Ok, this value had an interesting name. Remember it with a sentinel.
862 valueIDs[value] = nameSentinel;
863
864 // Remember that we've used this name, checking to see if we had a conflict.
865 auto insertRes = usedNames.insert(specialName.str());
866 if (insertRes.second) {
867 // If this is the first use of the name, then we're successful!
868 valueNames[value] = insertRes.first->first();
869 return;
870 }
871
872 // Otherwise, we had a conflict - probe until we find a unique name. This
873 // is guaranteed to terminate (and usually in a single iteration) because it
874 // generates new names by incrementing nextConflictID.
875 while (1) {
876 std::string probeName =
877 specialName.str().str() + "_" + llvm::utostr(nextConflictID++);
878 insertRes = usedNames.insert(probeName);
879 if (insertRes.second) {
880 // If this is the first use of the name, then we're successful!
881 valueNames[value] = insertRes.first->first();
882 return;
883 }
884 }
Chris Lattnerf8cce872018-07-20 09:28:54 -0700885 }
886
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700887 void printValueID(const SSAValue *value, bool printResultNo = true) const {
Chris Lattner6119d382018-07-20 18:41:34 -0700888 int resultNo = -1;
889 auto lookupValue = value;
890
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700891 // If this is a reference to the result of a multi-result instruction or
892 // statement, print out the # identifier and make sure to map our lookup
893 // to the first result of the instruction.
Chris Lattner6119d382018-07-20 18:41:34 -0700894 if (auto *result = dyn_cast<InstResult>(value)) {
895 if (result->getOwner()->getNumResults() != 1) {
896 resultNo = result->getResultNumber();
897 lookupValue = result->getOwner()->getResult(0);
898 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700899 } else if (auto *result = dyn_cast<StmtResult>(value)) {
900 if (result->getOwner()->getNumResults() != 1) {
901 resultNo = result->getResultNumber();
902 lookupValue = result->getOwner()->getResult(0);
903 }
Chris Lattner6119d382018-07-20 18:41:34 -0700904 }
905
906 auto it = valueIDs.find(lookupValue);
907 if (it == valueIDs.end()) {
Chris Lattnerf8cce872018-07-20 09:28:54 -0700908 os << "<<INVALID SSA VALUE>>";
Chris Lattner6119d382018-07-20 18:41:34 -0700909 return;
910 }
911
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700912 os << '%';
Chris Lattnerd4964212018-08-01 10:43:18 -0700913 if (it->second != nameSentinel) {
914 os << it->second;
915 } else {
916 auto nameIt = valueNames.find(lookupValue);
917 assert(nameIt != valueNames.end() && "Didn't have a name entry?");
918 os << nameIt->second;
919 }
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700920
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700921 if (resultNo != -1 && printResultNo)
Chris Lattner6119d382018-07-20 18:41:34 -0700922 os << '#' << resultNo;
Chris Lattnerf8cce872018-07-20 09:28:54 -0700923 }
924
925private:
Chris Lattnerd4964212018-08-01 10:43:18 -0700926 /// This is the value ID for each SSA value in the current function. If this
927 /// returns ~0, then the valueID has an entry in valueNames.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700928 DenseMap<const SSAValue *, unsigned> valueIDs;
Chris Lattnerd4964212018-08-01 10:43:18 -0700929 DenseMap<const SSAValue *, StringRef> valueNames;
930
931 /// This keeps track of all of the non-numeric names that are in flight,
932 /// allowing us to check for duplicates.
933 llvm::StringSet<> usedNames;
934
935 /// This is the next value ID to assign in numbering.
Chris Lattnerf8cce872018-07-20 09:28:54 -0700936 unsigned nextValueID = 0;
Chris Lattnerd4964212018-08-01 10:43:18 -0700937 /// This is the ID to assign to the next induction variable.
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -0700938 unsigned nextLoopID = 0;
Chris Lattnerd4964212018-08-01 10:43:18 -0700939 /// This is the next ID to assign to an MLFunction argument.
940 unsigned nextArgumentID = 0;
941
942 /// This is the next ID to assign when a name conflict is detected.
943 unsigned nextConflictID = 0;
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700944};
James Molloy87d81022018-07-23 11:44:40 -0700945} // end anonymous namespace
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700946
Chris Lattner85cf26d2018-08-02 16:54:36 -0700947void FunctionPrinter::printOptionalAttrDict(
948 ArrayRef<NamedAttribute> attrs, ArrayRef<const char *> elidedAttrs) {
949 // If there are no attributes, then there is nothing to be done.
950 if (attrs.empty())
951 return;
952
953 // Filter out any attributes that shouldn't be included.
954 SmallVector<NamedAttribute, 8> filteredAttrs;
955 for (auto attr : attrs) {
Chris Lattner4613d9e2018-08-19 21:17:22 -0700956 auto attrName = attr.first.strref();
Chris Lattner85cf26d2018-08-02 16:54:36 -0700957 // Never print attributes that start with a colon. These are internal
958 // attributes that represent location or other internal metadata.
959 if (attrName.startswith(":"))
960 continue;
961
962 // If the caller has requested that this attribute be ignored, then drop it.
963 bool ignore = false;
964 for (const char *elide : elidedAttrs)
965 ignore |= attrName == StringRef(elide);
966
967 // Otherwise add it to our filteredAttrs list.
968 if (!ignore)
969 filteredAttrs.push_back(attr);
970 }
971
972 // If there are no attributes left to print after filtering, then we're done.
973 if (filteredAttrs.empty())
974 return;
975
976 // Otherwise, print them all out in braces.
977 os << " {";
978 interleaveComma(filteredAttrs, [&](NamedAttribute attr) {
979 os << attr.first << ": ";
980 printAttribute(attr.second);
981 });
982 os << '}';
983}
984
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700985void FunctionPrinter::printOperation(const Operation *op) {
Chris Lattnerac591f12018-07-22 21:02:26 -0700986 if (op->getNumResults()) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -0700987 printValueID(op->getResult(0), /*printResultNo=*/false);
Chris Lattnerac591f12018-07-22 21:02:26 -0700988 os << " = ";
Chris Lattnerf8cce872018-07-20 09:28:54 -0700989 }
990
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700991 // Check to see if this is a known operation. If so, use the registered
992 // custom printer hook.
Chris Lattner4613d9e2018-08-19 21:17:22 -0700993 if (auto *opInfo = state.operationSet->lookup(op->getName())) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700994 opInfo->printAssembly(op, this);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -0700995 return;
996 }
997
Chris Lattnerf8cce872018-07-20 09:28:54 -0700998 // Otherwise use the standard verbose printing approach.
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -0700999 printDefaultOp(op);
1000}
Chris Lattnerf8cce872018-07-20 09:28:54 -07001001
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001002void FunctionPrinter::printDefaultOp(const Operation *op) {
Chris Lattner0497c4b2018-08-15 09:09:54 -07001003 os << '"';
Chris Lattner4613d9e2018-08-19 21:17:22 -07001004 printEscapedString(op->getName(), os);
Chris Lattner0497c4b2018-08-15 09:09:54 -07001005 os << "\"(";
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001006
Chris Lattnerac591f12018-07-22 21:02:26 -07001007 interleaveComma(op->getOperands(),
1008 [&](const SSAValue *value) { printValueID(value); });
Chris Lattner7f9cc272018-07-19 08:35:28 -07001009
Chris Lattnerf8cce872018-07-20 09:28:54 -07001010 os << ')';
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001011 auto attrs = op->getAttrs();
Chris Lattner85cf26d2018-08-02 16:54:36 -07001012 printOptionalAttrDict(attrs);
Chris Lattner3b2ef762018-07-18 15:31:25 -07001013
Chris Lattnerac591f12018-07-22 21:02:26 -07001014 // Print the type signature of the operation.
1015 os << " : (";
1016 interleaveComma(op->getOperands(),
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001017 [&](const SSAValue *value) { printType(value->getType()); });
Chris Lattnerac591f12018-07-22 21:02:26 -07001018 os << ") -> ";
Chris Lattnerf8cce872018-07-20 09:28:54 -07001019
Chris Lattnerac591f12018-07-22 21:02:26 -07001020 if (op->getNumResults() == 1) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001021 printType(op->getResult(0)->getType());
Chris Lattnerac591f12018-07-22 21:02:26 -07001022 } else {
1023 os << '(';
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001024 interleaveComma(op->getResults(), [&](const SSAValue *result) {
1025 printType(result->getType());
1026 });
Chris Lattnerac591f12018-07-22 21:02:26 -07001027 os << ')';
Chris Lattnerf8cce872018-07-20 09:28:54 -07001028 }
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001029}
1030
Chris Lattner4c95a502018-06-23 16:03:42 -07001031//===----------------------------------------------------------------------===//
1032// CFG Function printing
1033//===----------------------------------------------------------------------===//
1034
1035namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001036class CFGFunctionPrinter : public FunctionPrinter {
Chris Lattner4c95a502018-06-23 16:03:42 -07001037public:
Chris Lattner4fd59b02018-07-20 09:35:47 -07001038 CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
Chris Lattner4c95a502018-06-23 16:03:42 -07001039
1040 const CFGFunction *getFunction() const { return function; }
1041
1042 void print();
1043 void print(const BasicBlock *block);
Chris Lattnered65a732018-06-28 20:45:33 -07001044
1045 void print(const Instruction *inst);
1046 void print(const OperationInst *inst);
1047 void print(const ReturnInst *inst);
1048 void print(const BranchInst *inst);
James Molloy4f788372018-07-24 15:01:27 -07001049 void print(const CondBranchInst *inst);
Chris Lattner4c95a502018-06-23 16:03:42 -07001050
1051 unsigned getBBID(const BasicBlock *block) {
1052 auto it = basicBlockIDs.find(block);
1053 assert(it != basicBlockIDs.end() && "Block not in this function?");
1054 return it->second;
1055 }
1056
1057private:
1058 const CFGFunction *function;
MLIR Team54b55a22018-07-18 10:16:05 -07001059 DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
Chris Lattnerf8cce872018-07-20 09:28:54 -07001060
Chris Lattner4fd59b02018-07-20 09:35:47 -07001061 void numberValuesInBlock(const BasicBlock *block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001062};
James Molloy87d81022018-07-23 11:44:40 -07001063} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -07001064
Chris Lattner4fd59b02018-07-20 09:35:47 -07001065CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
1066 const ModulePrinter &other)
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001067 : FunctionPrinter(other), function(function) {
Chris Lattner4c95a502018-06-23 16:03:42 -07001068 // Each basic block gets a unique ID per function.
1069 unsigned blockID = 0;
Chris Lattnerf8cce872018-07-20 09:28:54 -07001070 for (auto &block : *function) {
1071 basicBlockIDs[&block] = blockID++;
Chris Lattner4fd59b02018-07-20 09:35:47 -07001072 numberValuesInBlock(&block);
Chris Lattnerf8cce872018-07-20 09:28:54 -07001073 }
1074}
1075
1076/// Number all of the SSA values in the specified basic block.
Chris Lattner4fd59b02018-07-20 09:35:47 -07001077void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -07001078 for (auto *arg : block->getArguments()) {
1079 numberValueID(arg);
1080 }
Chris Lattnerf8cce872018-07-20 09:28:54 -07001081 for (auto &op : *block) {
1082 // We number instruction that have results, and we only number the first
1083 // result.
1084 if (op.getNumResults() != 0)
1085 numberValueID(op.getResult(0));
1086 }
1087
1088 // Terminators do not define values.
Chris Lattner4c95a502018-06-23 16:03:42 -07001089}
1090
Chris Lattner4fd59b02018-07-20 09:35:47 -07001091void CFGFunctionPrinter::print() {
Chris Lattner4c95a502018-06-23 16:03:42 -07001092 os << "cfgfunc ";
Chris Lattner4fd59b02018-07-20 09:35:47 -07001093 printFunctionSignature(getFunction());
Chris Lattner4c95a502018-06-23 16:03:42 -07001094 os << " {\n";
1095
James Molloy87d81022018-07-23 11:44:40 -07001096 for (auto &block : *function)
1097 print(&block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001098 os << "}\n\n";
1099}
1100
Chris Lattner4fd59b02018-07-20 09:35:47 -07001101void CFGFunctionPrinter::print(const BasicBlock *block) {
James Molloy61a656c2018-07-22 15:45:24 -07001102 os << "bb" << getBBID(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001103
James Molloy61a656c2018-07-22 15:45:24 -07001104 if (!block->args_empty()) {
1105 os << '(';
1106 interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
1107 printValueID(arg);
1108 os << ": ";
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001109 printType(arg->getType());
James Molloy61a656c2018-07-22 15:45:24 -07001110 });
1111 os << ')';
1112 }
Chris Lattner25ce3062018-07-27 11:10:12 -07001113 os << ':';
1114
1115 // Print out some context information about the predecessors of this block.
1116 if (!block->getFunction()) {
1117 os << "\t// block is not in a function!";
1118 } else if (block->hasNoPredecessors()) {
1119 // Don't print "no predecessors" for the entry block.
1120 if (block != &block->getFunction()->front())
1121 os << "\t// no predecessors";
1122 } else if (auto *pred = block->getSinglePredecessor()) {
1123 os << "\t// pred: bb" << getBBID(pred);
1124 } else {
1125 // We want to print the predecessors in increasing numeric order, not in
1126 // whatever order the use-list is in, so gather and sort them.
1127 SmallVector<unsigned, 4> predIDs;
1128 for (auto *pred : block->getPredecessors())
1129 predIDs.push_back(getBBID(pred));
1130 llvm::array_pod_sort(predIDs.begin(), predIDs.end());
1131
1132 os << "\t// " << predIDs.size() << " preds: ";
1133
1134 interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
1135 }
1136 os << '\n';
James Molloy61a656c2018-07-22 15:45:24 -07001137
Jacques Pienaarb020c542018-07-15 00:06:54 -07001138 for (auto &inst : block->getOperations()) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001139 os << " ";
Chris Lattner3a467cc2018-07-01 20:28:00 -07001140 print(&inst);
James Molloy61a656c2018-07-22 15:45:24 -07001141 os << '\n';
Jacques Pienaarb020c542018-07-15 00:06:54 -07001142 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001143
James Molloy6e4519b2018-08-03 03:51:38 -07001144 os << " ";
Chris Lattner4c95a502018-06-23 16:03:42 -07001145 print(block->getTerminator());
James Molloy61a656c2018-07-22 15:45:24 -07001146 os << '\n';
Chris Lattner4c95a502018-06-23 16:03:42 -07001147}
1148
Chris Lattner4fd59b02018-07-20 09:35:47 -07001149void CFGFunctionPrinter::print(const Instruction *inst) {
Chris Lattnerffde6e92018-09-06 09:17:08 -07001150 if (!inst) {
1151 os << "<<null instruction>>\n";
1152 return;
1153 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001154 switch (inst->getKind()) {
Chris Lattnered65a732018-06-28 20:45:33 -07001155 case Instruction::Kind::Operation:
1156 return print(cast<OperationInst>(inst));
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001157 case TerminatorInst::Kind::Branch:
Chris Lattnered65a732018-06-28 20:45:33 -07001158 return print(cast<BranchInst>(inst));
James Molloy4f788372018-07-24 15:01:27 -07001159 case TerminatorInst::Kind::CondBranch:
1160 return print(cast<CondBranchInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -07001161 case TerminatorInst::Kind::Return:
Chris Lattnered65a732018-06-28 20:45:33 -07001162 return print(cast<ReturnInst>(inst));
Chris Lattner4c95a502018-06-23 16:03:42 -07001163 }
1164}
1165
Chris Lattner4fd59b02018-07-20 09:35:47 -07001166void CFGFunctionPrinter::print(const OperationInst *inst) {
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001167 printOperation(inst);
Chris Lattner3b2ef762018-07-18 15:31:25 -07001168}
Chris Lattner1604e472018-07-23 08:42:19 -07001169
Chris Lattner4fd59b02018-07-20 09:35:47 -07001170void CFGFunctionPrinter::print(const BranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001171 os << "br bb" << getBBID(inst->getDest());
Chris Lattner1604e472018-07-23 08:42:19 -07001172
1173 if (inst->getNumOperands() != 0) {
1174 os << '(';
Chris Lattner0497c4b2018-08-15 09:09:54 -07001175 interleaveComma(inst->getOperands(),
1176 [&](const CFGValue *operand) { printValueID(operand); });
Chris Lattner1604e472018-07-23 08:42:19 -07001177 os << ") : ";
Chris Lattner0497c4b2018-08-15 09:09:54 -07001178 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
1179 printType(operand->getType());
Chris Lattner1604e472018-07-23 08:42:19 -07001180 });
1181 }
Chris Lattnered65a732018-06-28 20:45:33 -07001182}
Chris Lattner1604e472018-07-23 08:42:19 -07001183
James Molloy4f788372018-07-24 15:01:27 -07001184void CFGFunctionPrinter::print(const CondBranchInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001185 os << "cond_br ";
James Molloy4f788372018-07-24 15:01:27 -07001186 printValueID(inst->getCondition());
1187
1188 os << ", bb" << getBBID(inst->getTrueDest());
1189 if (inst->getNumTrueOperands() != 0) {
1190 os << '(';
1191 interleaveComma(inst->getTrueOperands(),
1192 [&](const CFGValue *operand) { printValueID(operand); });
1193 os << " : ";
1194 interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001195 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -07001196 });
1197 os << ")";
1198 }
1199
1200 os << ", bb" << getBBID(inst->getFalseDest());
1201 if (inst->getNumFalseOperands() != 0) {
1202 os << '(';
1203 interleaveComma(inst->getFalseOperands(),
1204 [&](const CFGValue *operand) { printValueID(operand); });
1205 os << " : ";
1206 interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001207 printType(operand->getType());
James Molloy4f788372018-07-24 15:01:27 -07001208 });
1209 os << ")";
1210 }
1211}
1212
Chris Lattner40746442018-07-21 14:32:09 -07001213void CFGFunctionPrinter::print(const ReturnInst *inst) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001214 os << "return";
Chris Lattner40746442018-07-21 14:32:09 -07001215
James Molloy6bf60c22018-08-02 08:28:20 -07001216 if (inst->getNumOperands() == 0)
1217 return;
Chris Lattner40746442018-07-21 14:32:09 -07001218
James Molloy6bf60c22018-08-02 08:28:20 -07001219 os << ' ';
James Molloy4f788372018-07-24 15:01:27 -07001220 interleaveComma(inst->getOperands(),
1221 [&](const CFGValue *operand) { printValueID(operand); });
1222 os << " : ";
Chris Lattnerac591f12018-07-22 21:02:26 -07001223 interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001224 printType(operand->getType());
Chris Lattner40746442018-07-21 14:32:09 -07001225 });
1226}
MLIR Team54b55a22018-07-18 10:16:05 -07001227
Chris Lattner4fd59b02018-07-20 09:35:47 -07001228void ModulePrinter::print(const CFGFunction *fn) {
1229 CFGFunctionPrinter(fn, *this).print();
Chris Lattnered65a732018-06-28 20:45:33 -07001230}
1231
Chris Lattner4c95a502018-06-23 16:03:42 -07001232//===----------------------------------------------------------------------===//
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001233// ML Function printing
Chris Lattner4c95a502018-06-23 16:03:42 -07001234//===----------------------------------------------------------------------===//
1235
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001236namespace {
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001237class MLFunctionPrinter : public FunctionPrinter {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001238public:
Chris Lattner4fd59b02018-07-20 09:35:47 -07001239 MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001240
1241 const MLFunction *getFunction() const { return function; }
1242
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001243 // Prints ML function.
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001244 void print();
1245
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001246 // Prints ML function signature.
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001247 void printFunctionSignature();
1248
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001249 // Methods to print ML function statements.
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001250 void print(const Statement *stmt);
Tatiana Shpeismanfa412f72018-07-09 17:42:46 -07001251 void print(const OperationStmt *stmt);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001252 void print(const ForStmt *stmt);
1253 void print(const IfStmt *stmt);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001254 void print(const StmtBlock *block);
1255
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001256 // Print loop bounds.
1257 void printDimAndSymbolList(ArrayRef<StmtOperand> ops, unsigned numDims);
1258 void printBound(AffineBound bound, const char *prefix);
1259
1260 // Number of spaces used for indenting nested statements.
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001261 const static unsigned indentWidth = 2;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001262
1263private:
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001264 void numberValues();
1265
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001266 const MLFunction *function;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001267 int numSpaces;
1268};
James Molloy87d81022018-07-23 11:44:40 -07001269} // end anonymous namespace
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001270
Chris Lattner4fd59b02018-07-20 09:35:47 -07001271MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
1272 const ModulePrinter &other)
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001273 : FunctionPrinter(other), function(function), numSpaces(0) {
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001274 assert(function && "Cannot print nullptr function");
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001275 numberValues();
1276}
1277
1278/// Number all of the SSA values in this ML function.
1279void MLFunctionPrinter::numberValues() {
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001280 // Numbers ML function arguments.
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001281 for (auto *arg : function->getArguments())
1282 numberValueID(arg);
1283
1284 // Walks ML function statements and numbers for statements and
1285 // the first result of the operation statements.
Uday Bondhugula081d9e72018-07-27 10:58:14 -07001286 struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001287 NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
1288 void visitOperationStmt(OperationStmt *stmt) {
1289 if (stmt->getNumResults() != 0)
1290 printer->numberValueID(stmt->getResult(0));
1291 }
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -07001292 void visitForStmt(ForStmt *stmt) { printer->numberValueID(stmt); }
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001293 MLFunctionPrinter *printer;
1294 };
1295
1296 NumberValuesPass pass(this);
Chris Lattner0497c4b2018-08-15 09:09:54 -07001297 // TODO: it'd be cleaner to have constant visitor instead of using const_cast.
Uday Bondhugula081d9e72018-07-27 10:58:14 -07001298 pass.walk(const_cast<MLFunction *>(function));
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001299}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001300
Chris Lattner4fd59b02018-07-20 09:35:47 -07001301void MLFunctionPrinter::print() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001302 os << "mlfunc ";
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001303 printFunctionSignature();
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001304 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001305 print(function);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001306 os << "}\n\n";
1307}
1308
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001309void MLFunctionPrinter::printFunctionSignature() {
1310 auto type = function->getType();
1311
1312 os << "@" << function->getName() << '(';
1313
1314 for (unsigned i = 0, e = function->getNumArguments(); i != e; ++i) {
1315 if (i > 0)
1316 os << ", ";
1317 auto *arg = function->getArgument(i);
1318 printOperand(arg);
1319 os << " : ";
1320 printType(arg->getType());
1321 }
1322 os << ")";
1323 printFunctionResultType(type);
1324}
1325
Chris Lattner4fd59b02018-07-20 09:35:47 -07001326void MLFunctionPrinter::print(const StmtBlock *block) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001327 numSpaces += indentWidth;
Jacques Pienaarb020c542018-07-15 00:06:54 -07001328 for (auto &stmt : block->getStatements()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001329 print(&stmt);
Jacques Pienaarb020c542018-07-15 00:06:54 -07001330 os << "\n";
1331 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001332 numSpaces -= indentWidth;
1333}
1334
Chris Lattner4fd59b02018-07-20 09:35:47 -07001335void MLFunctionPrinter::print(const Statement *stmt) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001336 switch (stmt->getKind()) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001337 case Statement::Kind::Operation:
1338 return print(cast<OperationStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001339 case Statement::Kind::For:
1340 return print(cast<ForStmt>(stmt));
1341 case Statement::Kind::If:
1342 return print(cast<IfStmt>(stmt));
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001343 }
1344}
1345
Chris Lattner4fd59b02018-07-20 09:35:47 -07001346void MLFunctionPrinter::print(const OperationStmt *stmt) {
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -07001347 os.indent(numSpaces);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001348 printOperation(stmt);
1349}
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001350
Chris Lattner4fd59b02018-07-20 09:35:47 -07001351void MLFunctionPrinter::print(const ForStmt *stmt) {
Tatiana Shpeisman3838db72018-07-30 15:18:10 -07001352 os.indent(numSpaces) << "for ";
Tatiana Shpeismanc9c4b342018-07-31 07:40:14 -07001353 printOperand(stmt);
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001354 os << " = ";
1355 printBound(stmt->getLowerBound(), "max");
1356 os << " to ";
1357 printBound(stmt->getUpperBound(), "min");
1358
Uday Bondhugula67701712018-08-21 16:01:23 -07001359 if (stmt->getStep() != 1)
1360 os << " step " << stmt->getStep();
Tatiana Shpeisman1da50c42018-07-19 09:52:39 -07001361
1362 os << " {\n";
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001363 print(static_cast<const StmtBlock *>(stmt));
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001364 os.indent(numSpaces) << "}";
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001365}
1366
Tatiana Shpeismande8829f2018-08-24 23:38:14 -07001367void MLFunctionPrinter::printDimAndSymbolList(ArrayRef<StmtOperand> ops,
1368 unsigned numDims) {
1369 auto printComma = [&]() { os << ", "; };
1370 os << '(';
1371 interleave(ops.begin(), ops.begin() + numDims,
1372 [&](const StmtOperand &v) { printOperand(v.get()); }, printComma);
1373 os << ')';
1374
1375 if (numDims < ops.size()) {
1376 os << '[';
1377 interleave(ops.begin() + numDims, ops.end(),
1378 [&](const StmtOperand &v) { printOperand(v.get()); },
1379 printComma);
1380 os << ']';
1381 }
1382}
1383
1384void MLFunctionPrinter::printBound(AffineBound bound, const char *prefix) {
1385 AffineMap *map = bound.getMap();
1386
1387 // Check if this bound should be printed using short-hand notation.
1388 if (map->getNumResults() == 1) {
1389 AffineExpr *expr = map->getResult(0);
1390
1391 // Print constant bound.
1392 if (auto *constExpr = dyn_cast<AffineConstantExpr>(expr)) {
1393 os << constExpr->getValue();
1394 return;
1395 }
1396
1397 // Print bound that consists of a single SSA id.
1398 if (isa<AffineDimExpr>(expr) || isa<AffineSymbolExpr>(expr)) {
1399 printOperand(bound.getOperand(0));
1400 return;
1401 }
1402 } else {
1403 // Map has multiple results. Print 'min' or 'max' prefix.
1404 os << prefix << ' ';
1405 }
1406
1407 // Print the map and the operands.
1408 printAffineMapReference(map);
1409 printDimAndSymbolList(bound.getStmtOperands(), map->getNumDims());
1410}
1411
Chris Lattner4fd59b02018-07-20 09:35:47 -07001412void MLFunctionPrinter::print(const IfStmt *stmt) {
Tatiana Shpeismanc6aa35b2018-08-28 15:26:20 -07001413 os.indent(numSpaces) << "if ";
1414 IntegerSet *set = stmt->getIntegerSet();
1415 printIntegerSetReference(set);
1416 printDimAndSymbolList(stmt->getStmtOperands(), set->getNumDims());
1417 os << " {\n";
Chris Lattnere787b322018-08-08 11:14:57 -07001418 print(stmt->getThen());
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001419 os.indent(numSpaces) << "}";
Chris Lattnere787b322018-08-08 11:14:57 -07001420 if (stmt->hasElse()) {
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001421 os << " else {\n";
Chris Lattnere787b322018-08-08 11:14:57 -07001422 print(stmt->getElse());
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001423 os.indent(numSpaces) << "}";
1424 }
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001425}
1426
Chris Lattner4fd59b02018-07-20 09:35:47 -07001427void ModulePrinter::print(const MLFunction *fn) {
1428 MLFunctionPrinter(fn, *this).print();
MLIR Team4718bc92018-07-17 16:56:54 -07001429}
1430
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001431//===----------------------------------------------------------------------===//
1432// print and dump methods
1433//===----------------------------------------------------------------------===//
Chris Lattnered65a732018-06-28 20:45:33 -07001434
MLIR Teamb61885d2018-07-18 16:29:21 -07001435void Attribute::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001436 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001437 ModulePrinter(os, state).printAttribute(this);
MLIR Teamb61885d2018-07-18 16:29:21 -07001438}
1439
James Molloy87d81022018-07-23 11:44:40 -07001440void Attribute::dump() const { print(llvm::errs()); }
MLIR Teamb61885d2018-07-18 16:29:21 -07001441
MLIR Team4718bc92018-07-17 16:56:54 -07001442void Type::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001443 ModuleState state(getContext());
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001444 ModulePrinter(os, state).printType(this);
MLIR Team4718bc92018-07-17 16:56:54 -07001445}
1446
MLIR Team54b55a22018-07-18 10:16:05 -07001447void Type::dump() const { print(llvm::errs()); }
MLIR Team4718bc92018-07-17 16:56:54 -07001448
MLIR Team718c82f2018-07-16 09:45:22 -07001449void AffineMap::dump() const {
1450 print(llvm::errs());
1451 llvm::errs() << "\n";
1452}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001453
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001454void AffineExpr::dump() const {
1455 print(llvm::errs());
1456 llvm::errs() << "\n";
1457}
1458
Uday Bondhugulabc535622018-08-07 14:24:38 -07001459void IntegerSet::dump() const {
1460 print(llvm::errs());
1461 llvm::errs() << "\n";
1462}
1463
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001464void AffineExpr::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001465 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001466 ModulePrinter(os, state).printAffineExpr(this);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001467}
1468
1469void AffineMap::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001470 ModuleState state(/*no context is known*/ nullptr);
Chris Lattnerdd0c2ca2018-07-24 16:07:22 -07001471 ModulePrinter(os, state).printAffineMap(this);
Chris Lattner4fd59b02018-07-20 09:35:47 -07001472}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001473
Uday Bondhugulabc535622018-08-07 14:24:38 -07001474void IntegerSet::print(raw_ostream &os) const {
1475 ModuleState state(/*no context is known*/ nullptr);
1476 ModulePrinter(os, state).printIntegerSet(this);
1477}
1478
Chris Lattner384da8c2018-08-02 17:16:58 -07001479void SSAValue::print(raw_ostream &os) const {
1480 switch (getKind()) {
1481 case SSAValueKind::BBArgument:
1482 // TODO: Improve this.
1483 os << "<bb argument>\n";
1484 return;
1485 case SSAValueKind::InstResult:
1486 return getDefiningInst()->print(os);
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -07001487 case SSAValueKind::MLFuncArgument:
Chris Lattner384da8c2018-08-02 17:16:58 -07001488 // TODO: Improve this.
1489 os << "<function argument>\n";
1490 return;
1491 case SSAValueKind::StmtResult:
1492 return getDefiningStmt()->print(os);
1493 case SSAValueKind::ForStmt:
1494 return cast<ForStmt>(this)->print(os);
1495 }
1496}
1497
1498void SSAValue::dump() const { print(llvm::errs()); }
1499
Chris Lattner4fd59b02018-07-20 09:35:47 -07001500void Instruction::print(raw_ostream &os) const {
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001501 if (!getFunction()) {
1502 os << "<<UNLINKED INSTRUCTION>>\n";
1503 return;
1504 }
Chris Lattner4fd59b02018-07-20 09:35:47 -07001505 ModuleState state(getFunction()->getContext());
1506 ModulePrinter modulePrinter(os, state);
1507 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
1508}
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001509
Chris Lattner4fd59b02018-07-20 09:35:47 -07001510void Instruction::dump() const {
1511 print(llvm::errs());
1512 llvm::errs() << "\n";
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001513}
1514
Chris Lattner4c95a502018-06-23 16:03:42 -07001515void BasicBlock::print(raw_ostream &os) const {
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001516 if (!getFunction()) {
1517 os << "<<UNLINKED BLOCK>>\n";
1518 return;
1519 }
Chris Lattner4fd59b02018-07-20 09:35:47 -07001520 ModuleState state(getFunction()->getContext());
1521 ModulePrinter modulePrinter(os, state);
1522 CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001523}
1524
MLIR Team54b55a22018-07-18 10:16:05 -07001525void BasicBlock::dump() const { print(llvm::errs()); }
Chris Lattner4c95a502018-06-23 16:03:42 -07001526
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001527void Statement::print(raw_ostream &os) const {
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001528 MLFunction *function = findFunction();
Tatiana Shpeismanc335d182018-08-03 11:12:34 -07001529 if (!function) {
1530 os << "<<UNLINKED STATEMENT>>\n";
1531 return;
1532 }
1533
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001534 ModuleState state(function->getContext());
Chris Lattner4fd59b02018-07-20 09:35:47 -07001535 ModulePrinter modulePrinter(os, state);
Tatiana Shpeismand880b352018-07-31 23:14:16 -07001536 MLFunctionPrinter(function, modulePrinter).print(this);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001537}
1538
MLIR Team54b55a22018-07-18 10:16:05 -07001539void Statement::dump() const { print(llvm::errs()); }
Jacques Pienaarb020c542018-07-15 00:06:54 -07001540
Chris Lattnere787b322018-08-08 11:14:57 -07001541void StmtBlock::printBlock(raw_ostream &os) const {
Uday Bondhugula84b80952018-08-03 13:22:26 -07001542 MLFunction *function = findFunction();
1543 ModuleState state(function->getContext());
1544 ModulePrinter modulePrinter(os, state);
1545 MLFunctionPrinter(function, modulePrinter).print(this);
1546}
1547
Chris Lattnere787b322018-08-08 11:14:57 -07001548void StmtBlock::dumpBlock() const { printBlock(llvm::errs()); }
Uday Bondhugula84b80952018-08-03 13:22:26 -07001549
Chris Lattner4c95a502018-06-23 16:03:42 -07001550void Function::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001551 ModuleState state(getContext());
1552 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001553}
1554
MLIR Team54b55a22018-07-18 10:16:05 -07001555void Function::dump() const { print(llvm::errs()); }
1556
Chris Lattner4c95a502018-06-23 16:03:42 -07001557void Module::print(raw_ostream &os) const {
Chris Lattner4fd59b02018-07-20 09:35:47 -07001558 ModuleState state(getContext());
1559 state.initialize(this);
1560 ModulePrinter(os, state).print(this);
Chris Lattner4c95a502018-06-23 16:03:42 -07001561}
1562
MLIR Team54b55a22018-07-18 10:16:05 -07001563void Module::dump() const { print(llvm::errs()); }