2018-06-24 07:03:42 +08:00
|
|
|
//===- AsmPrinter.cpp - MLIR Assembly Printer Implementation --------------===//
|
|
|
|
//
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
// =============================================================================
|
|
|
|
//
|
|
|
|
// This file implements the MLIR AsmPrinter class, which is used to implement
|
|
|
|
// the various print() methods on the core IR objects.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-06-30 09:09:29 +08:00
|
|
|
#include "mlir/IR/AffineExpr.h"
|
|
|
|
#include "mlir/IR/AffineMap.h"
|
2018-07-05 11:45:39 +08:00
|
|
|
#include "mlir/IR/Attributes.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
#include "mlir/IR/CFGFunction.h"
|
2018-06-29 08:02:32 +08:00
|
|
|
#include "mlir/IR/MLFunction.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
#include "mlir/IR/Module.h"
|
2018-07-25 07:07:22 +08:00
|
|
|
#include "mlir/IR/OpImplementation.h"
|
2018-07-06 00:12:11 +08:00
|
|
|
#include "mlir/IR/OperationSet.h"
|
2018-08-02 01:43:18 +08:00
|
|
|
#include "mlir/IR/StandardOps.h"
|
2018-07-14 04:03:13 +08:00
|
|
|
#include "mlir/IR/Statements.h"
|
2018-07-27 09:09:20 +08:00
|
|
|
#include "mlir/IR/StmtVisitor.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
#include "mlir/IR/Types.h"
|
|
|
|
#include "mlir/Support/STLExtras.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2018-08-02 01:43:18 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/ADT/StringSet.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
using namespace mlir;
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Identifier::print(raw_ostream &os) const { os << str(); }
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Identifier::dump() const { print(llvm::errs()); }
|
2018-07-05 11:45:39 +08:00
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
OpAsmPrinter::~OpAsmPrinter() {}
|
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2018-07-21 00:35:47 +08:00
|
|
|
// ModuleState
|
2018-07-18 07:56:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
2018-07-19 01:16:05 +08:00
|
|
|
class ModuleState {
|
|
|
|
public:
|
2018-07-21 00:35:47 +08:00
|
|
|
/// This is the operation set for the current context if it is knowable (a
|
|
|
|
/// context could be determined), otherwise this is null.
|
|
|
|
OperationSet *const operationSet;
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
explicit ModuleState(MLIRContext *context)
|
|
|
|
: operationSet(context ? &OperationSet::get(context) : nullptr) {}
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
// Initializes module state, populating affine map state.
|
|
|
|
void initialize(const Module *module);
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
int getAffineMapId(const AffineMap *affineMap) const {
|
2018-07-18 07:56:54 +08:00
|
|
|
auto it = affineMapIds.find(affineMap);
|
|
|
|
if (it == affineMapIds.end()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
2018-07-25 00:48:31 +08:00
|
|
|
ArrayRef<const AffineMap *> getAffineMapIds() const { return affineMapsById; }
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
private:
|
2018-07-21 00:35:47 +08:00
|
|
|
void recordAffineMapReference(const AffineMap *affineMap) {
|
|
|
|
if (affineMapIds.count(affineMap) == 0) {
|
2018-07-25 00:48:31 +08:00
|
|
|
affineMapIds[affineMap] = affineMapsById.size();
|
|
|
|
affineMapsById.push_back(affineMap);
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit functions.
|
|
|
|
void visitFunction(const Function *fn);
|
|
|
|
void visitExtFunction(const ExtFunction *fn);
|
|
|
|
void visitCFGFunction(const CFGFunction *fn);
|
|
|
|
void visitMLFunction(const MLFunction *fn);
|
|
|
|
void visitType(const Type *type);
|
2018-07-19 07:29:21 +08:00
|
|
|
void visitAttribute(const Attribute *attr);
|
|
|
|
void visitOperation(const Operation *op);
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
DenseMap<const AffineMap *, int> affineMapIds;
|
2018-07-25 00:48:31 +08:00
|
|
|
std::vector<const AffineMap *> affineMapsById;
|
2018-07-18 07:56:54 +08:00
|
|
|
};
|
2018-07-24 02:44:40 +08:00
|
|
|
} // end anonymous namespace
|
2018-07-18 07:56:54 +08:00
|
|
|
|
|
|
|
// TODO Support visiting other types/instructions when implemented.
|
|
|
|
void ModuleState::visitType(const Type *type) {
|
2018-07-29 00:36:25 +08:00
|
|
|
if (auto *funcType = dyn_cast<FunctionType>(type)) {
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit input and result types for functions.
|
2018-07-29 00:36:25 +08:00
|
|
|
for (auto *input : funcType->getInputs())
|
2018-07-18 07:56:54 +08:00
|
|
|
visitType(input);
|
2018-07-29 00:36:25 +08:00
|
|
|
for (auto *result : funcType->getResults())
|
2018-07-18 07:56:54 +08:00
|
|
|
visitType(result);
|
2018-07-29 00:36:25 +08:00
|
|
|
} else if (auto *memref = dyn_cast<MemRefType>(type)) {
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit affine maps in memref type.
|
2018-07-29 00:36:25 +08:00
|
|
|
for (auto *map : memref->getAffineMaps()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
recordAffineMapReference(map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 07:29:21 +08:00
|
|
|
void ModuleState::visitAttribute(const Attribute *attr) {
|
2018-07-29 00:36:25 +08:00
|
|
|
if (auto *mapAttr = dyn_cast<AffineMapAttr>(attr)) {
|
|
|
|
recordAffineMapReference(mapAttr->getValue());
|
|
|
|
} else if (auto *array = dyn_cast<ArrayAttr>(attr)) {
|
|
|
|
for (auto elt : array->getValue()) {
|
2018-07-19 07:29:21 +08:00
|
|
|
visitAttribute(elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleState::visitOperation(const Operation *op) {
|
2018-08-01 09:32:59 +08:00
|
|
|
// Visit all the types used in the operation.
|
|
|
|
for (auto *operand : op->getOperands())
|
|
|
|
visitType(operand->getType());
|
|
|
|
for (auto *result : op->getResults())
|
|
|
|
visitType(result->getType());
|
|
|
|
|
|
|
|
// Visit each of the attributes.
|
|
|
|
for (auto elt : op->getAttrs())
|
2018-07-19 07:29:21 +08:00
|
|
|
visitAttribute(elt.second);
|
|
|
|
}
|
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
void ModuleState::visitExtFunction(const ExtFunction *fn) {
|
|
|
|
visitType(fn->getType());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleState::visitCFGFunction(const CFGFunction *fn) {
|
|
|
|
visitType(fn->getType());
|
2018-07-19 07:29:21 +08:00
|
|
|
for (auto &block : *fn) {
|
|
|
|
for (auto &op : block.getOperations()) {
|
|
|
|
visitOperation(&op);
|
|
|
|
}
|
|
|
|
}
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleState::visitMLFunction(const MLFunction *fn) {
|
|
|
|
visitType(fn->getType());
|
2018-07-19 07:29:21 +08:00
|
|
|
// TODO Visit function body statements (and attributes if required).
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleState::visitFunction(const Function *fn) {
|
|
|
|
switch (fn->getKind()) {
|
2018-07-19 01:16:05 +08:00
|
|
|
case Function::Kind::ExtFunc:
|
|
|
|
return visitExtFunction(cast<ExtFunction>(fn));
|
|
|
|
case Function::Kind::CFGFunc:
|
|
|
|
return visitCFGFunction(cast<CFGFunction>(fn));
|
|
|
|
case Function::Kind::MLFunc:
|
|
|
|
return visitMLFunction(cast<MLFunction>(fn));
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
// Initializes module state, populating affine map state.
|
|
|
|
void ModuleState::initialize(const Module *module) {
|
2018-07-26 05:08:16 +08:00
|
|
|
for (auto &fn : *module) {
|
|
|
|
visitFunction(&fn);
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ModulePrinter
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class ModulePrinter {
|
|
|
|
public:
|
|
|
|
ModulePrinter(raw_ostream &os, ModuleState &state) : os(os), state(state) {}
|
|
|
|
explicit ModulePrinter(const ModulePrinter &printer)
|
|
|
|
: os(printer.os), state(printer.state) {}
|
|
|
|
|
|
|
|
template <typename Container, typename UnaryFunctor>
|
|
|
|
inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
|
|
|
|
interleave(c.begin(), c.end(), each_fn, [&]() { os << ", "; });
|
|
|
|
}
|
|
|
|
|
|
|
|
void print(const Module *module);
|
2018-07-25 07:07:22 +08:00
|
|
|
void printAttribute(const Attribute *attr);
|
|
|
|
void printType(const Type *type);
|
2018-07-21 00:35:47 +08:00
|
|
|
void print(const Function *fn);
|
|
|
|
void print(const ExtFunction *fn);
|
|
|
|
void print(const CFGFunction *fn);
|
|
|
|
void print(const MLFunction *fn);
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void printAffineMap(const AffineMap *map);
|
|
|
|
void printAffineExpr(const AffineExpr *expr);
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
raw_ostream &os;
|
|
|
|
ModuleState &state;
|
|
|
|
|
|
|
|
void printFunctionSignature(const Function *fn);
|
|
|
|
void printAffineMapId(int affineMapId) const;
|
2018-07-25 07:07:22 +08:00
|
|
|
void printAffineMapReference(const AffineMap *affineMap);
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2018-08-01 07:21:36 +08:00
|
|
|
/// This enum is used to represent the binding stength of the enclosing
|
|
|
|
/// context that an AffineExpr is being printed in, so we can intelligently
|
|
|
|
/// produce parens.
|
|
|
|
enum class BindingStrength {
|
|
|
|
Weak, // + and -
|
|
|
|
Strong, // All other binary operators.
|
|
|
|
};
|
|
|
|
void printAffineExprInternal(const AffineExpr *expr,
|
|
|
|
BindingStrength enclosingTightness);
|
2018-07-21 00:35:47 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
// Prints function with initialized module state.
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::print(const Function *fn) {
|
2018-07-18 07:56:54 +08:00
|
|
|
switch (fn->getKind()) {
|
2018-07-19 01:16:05 +08:00
|
|
|
case Function::Kind::ExtFunc:
|
|
|
|
return print(cast<ExtFunction>(fn));
|
|
|
|
case Function::Kind::CFGFunc:
|
|
|
|
return print(cast<CFGFunction>(fn));
|
|
|
|
case Function::Kind::MLFunc:
|
|
|
|
return print(cast<MLFunction>(fn));
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prints affine map identifier.
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::printAffineMapId(int affineMapId) const {
|
2018-07-18 07:56:54 +08:00
|
|
|
os << "#map" << affineMapId;
|
|
|
|
}
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
|
2018-07-21 00:35:47 +08:00
|
|
|
int mapId = state.getAffineMapId(affineMap);
|
2018-07-19 07:29:21 +08:00
|
|
|
if (mapId >= 0) {
|
|
|
|
// Map will be printed at top of module so print reference to its id.
|
|
|
|
printAffineMapId(mapId);
|
|
|
|
} else {
|
|
|
|
// Map not in module state so print inline.
|
|
|
|
affineMap->print(os);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::print(const Module *module) {
|
2018-07-25 00:48:31 +08:00
|
|
|
for (const auto &map : state.getAffineMapIds()) {
|
|
|
|
printAffineMapId(state.getAffineMapId(map));
|
2018-07-18 07:56:54 +08:00
|
|
|
os << " = ";
|
2018-07-25 00:48:31 +08:00
|
|
|
map->print(os);
|
2018-07-18 07:56:54 +08:00
|
|
|
os << '\n';
|
|
|
|
}
|
2018-07-26 05:08:16 +08:00
|
|
|
for (auto const &fn : *module)
|
|
|
|
print(&fn);
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void ModulePrinter::printAttribute(const Attribute *attr) {
|
2018-07-19 07:29:21 +08:00
|
|
|
switch (attr->getKind()) {
|
|
|
|
case Attribute::Kind::Bool:
|
|
|
|
os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case Attribute::Kind::Integer:
|
|
|
|
os << cast<IntegerAttr>(attr)->getValue();
|
|
|
|
break;
|
|
|
|
case Attribute::Kind::Float:
|
|
|
|
// FIXME: this isn't precise, we should print with a hex format.
|
|
|
|
os << cast<FloatAttr>(attr)->getValue();
|
|
|
|
break;
|
|
|
|
case Attribute::Kind::String:
|
|
|
|
// FIXME: should escape the string.
|
|
|
|
os << '"' << cast<StringAttr>(attr)->getValue() << '"';
|
|
|
|
break;
|
|
|
|
case Attribute::Kind::Array: {
|
|
|
|
auto elts = cast<ArrayAttr>(attr)->getValue();
|
|
|
|
os << '[';
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
|
2018-07-19 07:29:21 +08:00
|
|
|
os << ']';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Attribute::Kind::AffineMap:
|
|
|
|
printAffineMapReference(cast<AffineMapAttr>(attr)->getValue());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void ModulePrinter::printType(const Type *type) {
|
2018-07-18 07:56:54 +08:00
|
|
|
switch (type->getKind()) {
|
2018-07-19 01:16:05 +08:00
|
|
|
case Type::Kind::AffineInt:
|
|
|
|
os << "affineint";
|
|
|
|
return;
|
|
|
|
case Type::Kind::BF16:
|
|
|
|
os << "bf16";
|
|
|
|
return;
|
|
|
|
case Type::Kind::F16:
|
|
|
|
os << "f16";
|
|
|
|
return;
|
|
|
|
case Type::Kind::F32:
|
|
|
|
os << "f32";
|
|
|
|
return;
|
|
|
|
case Type::Kind::F64:
|
|
|
|
os << "f64";
|
|
|
|
return;
|
2018-07-28 02:07:12 +08:00
|
|
|
case Type::Kind::TFControl:
|
|
|
|
os << "tf_control";
|
|
|
|
return;
|
2018-08-02 03:55:27 +08:00
|
|
|
case Type::Kind::TFString:
|
|
|
|
os << "tf_string";
|
|
|
|
return;
|
2018-07-18 07:56:54 +08:00
|
|
|
|
|
|
|
case Type::Kind::Integer: {
|
|
|
|
auto *integer = cast<IntegerType>(type);
|
|
|
|
os << 'i' << integer->getWidth();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::Function: {
|
|
|
|
auto *func = cast<FunctionType>(type);
|
|
|
|
os << '(';
|
2018-07-26 03:55:50 +08:00
|
|
|
interleaveComma(func->getInputs(), [&](Type *type) { printType(type); });
|
2018-07-18 07:56:54 +08:00
|
|
|
os << ") -> ";
|
|
|
|
auto results = func->getResults();
|
|
|
|
if (results.size() == 1)
|
|
|
|
os << *results[0];
|
|
|
|
else {
|
|
|
|
os << '(';
|
2018-07-26 03:55:50 +08:00
|
|
|
interleaveComma(results, [&](Type *type) { printType(type); });
|
2018-07-18 07:56:54 +08:00
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::Vector: {
|
|
|
|
auto *v = cast<VectorType>(type);
|
|
|
|
os << "vector<";
|
2018-07-24 02:44:40 +08:00
|
|
|
for (auto dim : v->getShape())
|
|
|
|
os << dim << 'x';
|
2018-07-18 07:56:54 +08:00
|
|
|
os << *v->getElementType() << '>';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::RankedTensor: {
|
|
|
|
auto *v = cast<RankedTensorType>(type);
|
|
|
|
os << "tensor<";
|
|
|
|
for (auto dim : v->getShape()) {
|
|
|
|
if (dim < 0)
|
|
|
|
os << '?';
|
|
|
|
else
|
|
|
|
os << dim;
|
|
|
|
os << 'x';
|
|
|
|
}
|
|
|
|
os << *v->getElementType() << '>';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::UnrankedTensor: {
|
|
|
|
auto *v = cast<UnrankedTensorType>(type);
|
2018-07-26 03:55:50 +08:00
|
|
|
os << "tensor<??";
|
|
|
|
printType(v->getElementType());
|
|
|
|
os << '>';
|
2018-07-18 07:56:54 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::MemRef: {
|
|
|
|
auto *v = cast<MemRefType>(type);
|
|
|
|
os << "memref<";
|
|
|
|
for (auto dim : v->getShape()) {
|
|
|
|
if (dim < 0)
|
|
|
|
os << '?';
|
|
|
|
else
|
|
|
|
os << dim;
|
|
|
|
os << 'x';
|
|
|
|
}
|
2018-07-26 03:55:50 +08:00
|
|
|
printType(v->getElementType());
|
2018-07-18 07:56:54 +08:00
|
|
|
for (auto map : v->getAffineMaps()) {
|
|
|
|
os << ", ";
|
2018-07-19 07:29:21 +08:00
|
|
|
printAffineMapReference(map);
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
2018-07-26 03:55:50 +08:00
|
|
|
// Only print the memory space if it is the non-default one.
|
|
|
|
if (v->getMemorySpace())
|
|
|
|
os << ", " << v->getMemorySpace();
|
2018-07-18 07:56:54 +08:00
|
|
|
os << '>';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Affine expressions and maps
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(expr, BindingStrength::Weak);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModulePrinter::printAffineExprInternal(
|
|
|
|
const AffineExpr *expr, BindingStrength enclosingTightness) {
|
|
|
|
const char *binopSpelling = nullptr;
|
2018-07-21 00:35:47 +08:00
|
|
|
switch (expr->getKind()) {
|
|
|
|
case AffineExpr::Kind::SymbolId:
|
|
|
|
os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
|
|
|
|
return;
|
|
|
|
case AffineExpr::Kind::DimId:
|
|
|
|
os << 'd' << cast<AffineDimExpr>(expr)->getPosition();
|
|
|
|
return;
|
|
|
|
case AffineExpr::Kind::Constant:
|
|
|
|
os << cast<AffineConstantExpr>(expr)->getValue();
|
|
|
|
return;
|
|
|
|
case AffineExpr::Kind::Add:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " + ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
case AffineExpr::Kind::Mul:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " * ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
case AffineExpr::Kind::FloorDiv:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " floordiv ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
case AffineExpr::Kind::CeilDiv:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " ceildiv ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
case AffineExpr::Kind::Mod:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " mod ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-08-01 07:21:36 +08:00
|
|
|
auto *binOp = cast<AffineBinaryOpExpr>(expr);
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2018-08-01 07:21:36 +08:00
|
|
|
// Handle tightly binding binary operators.
|
|
|
|
if (binOp->getKind() != AffineExpr::Kind::Add) {
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << '(';
|
|
|
|
|
|
|
|
printAffineExprInternal(binOp->getLHS(), BindingStrength::Strong);
|
|
|
|
os << binopSpelling;
|
|
|
|
printAffineExprInternal(binOp->getRHS(), BindingStrength::Strong);
|
|
|
|
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print out special "pretty" forms for add.
|
2018-08-01 07:21:36 +08:00
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << '(';
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
// Pretty print addition to a product that has a negative operand as a
|
|
|
|
// subtraction.
|
2018-08-01 07:21:36 +08:00
|
|
|
if (auto *rhs = dyn_cast<AffineBinaryOpExpr>(binOp->getRHS())) {
|
2018-07-21 00:35:47 +08:00
|
|
|
if (rhs->getKind() == AffineExpr::Kind::Mul) {
|
|
|
|
if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
|
2018-08-01 07:21:36 +08:00
|
|
|
if (rrhs->getValue() == -1) {
|
|
|
|
printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
|
|
|
|
os << " - ";
|
|
|
|
printAffineExprInternal(rhs->getLHS(), BindingStrength::Weak);
|
|
|
|
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rrhs->getValue() < -1) {
|
|
|
|
printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
|
2018-08-02 13:02:00 +08:00
|
|
|
os << " - ";
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(rhs->getLHS(), BindingStrength::Strong);
|
2018-08-02 13:02:00 +08:00
|
|
|
os << " * " << -rrhs->getValue();
|
2018-08-01 07:21:36 +08:00
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pretty print addition to a negative number as a subtraction.
|
2018-08-01 07:21:36 +08:00
|
|
|
if (auto *rhs = dyn_cast<AffineConstantExpr>(binOp->getRHS())) {
|
2018-07-21 00:35:47 +08:00
|
|
|
if (rhs->getValue() < 0) {
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
|
|
|
|
os << " - " << -rhs->getValue() << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(binOp->getLHS(), BindingStrength::Weak);
|
2018-07-21 00:35:47 +08:00
|
|
|
os << " + ";
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(binOp->getRHS(), BindingStrength::Weak);
|
|
|
|
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void ModulePrinter::printAffineMap(const AffineMap *map) {
|
2018-07-21 00:35:47 +08:00
|
|
|
// Dimension identifiers.
|
|
|
|
os << '(';
|
2018-07-30 05:13:03 +08:00
|
|
|
for (int i = 0; i < (int)map->getNumDims() - 1; ++i)
|
|
|
|
os << 'd' << i << ", ";
|
2018-07-21 00:35:47 +08:00
|
|
|
if (map->getNumDims() >= 1)
|
2018-07-30 05:13:03 +08:00
|
|
|
os << 'd' << map->getNumDims() - 1;
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
// Symbolic identifiers.
|
2018-07-30 05:13:03 +08:00
|
|
|
if (map->getNumSymbols() != 0) {
|
|
|
|
os << '[';
|
|
|
|
for (unsigned i = 0; i < map->getNumSymbols() - 1; ++i)
|
|
|
|
os << 's' << i << ", ";
|
2018-07-21 00:35:47 +08:00
|
|
|
if (map->getNumSymbols() >= 1)
|
2018-07-30 05:13:03 +08:00
|
|
|
os << 's' << map->getNumSymbols() - 1;
|
|
|
|
os << ']';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// AffineMap should have at least one result.
|
|
|
|
assert(!map->getResults().empty());
|
|
|
|
// Result affine expressions.
|
|
|
|
os << " -> (";
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(map->getResults(),
|
|
|
|
[&](AffineExpr *expr) { printAffineExpr(expr); });
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
if (!map->isBounded()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print range sizes for bounded affine maps.
|
|
|
|
os << " size (";
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(map->getRangeSizes(),
|
|
|
|
[&](AffineExpr *expr) { printAffineExpr(expr); });
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Function printing
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::printFunctionSignature(const Function *fn) {
|
2018-06-24 07:03:42 +08:00
|
|
|
auto type = fn->getType();
|
|
|
|
|
|
|
|
os << "@" << fn->getName() << '(';
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(type->getInputs(),
|
|
|
|
[&](Type *eltType) { printType(eltType); });
|
2018-06-24 07:03:42 +08:00
|
|
|
os << ')';
|
|
|
|
|
|
|
|
switch (type->getResults().size()) {
|
2018-07-19 01:16:05 +08:00
|
|
|
case 0:
|
|
|
|
break;
|
2018-06-24 07:03:42 +08:00
|
|
|
case 1:
|
2018-07-18 07:56:54 +08:00
|
|
|
os << " -> ";
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(type->getResults()[0]);
|
2018-06-24 07:03:42 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
os << " -> (";
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(type->getResults(),
|
|
|
|
[&](Type *eltType) { printType(eltType); });
|
2018-06-24 07:03:42 +08:00
|
|
|
os << ')';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::print(const ExtFunction *fn) {
|
2018-06-24 07:03:42 +08:00
|
|
|
os << "extfunc ";
|
2018-07-21 00:35:47 +08:00
|
|
|
printFunctionSignature(fn);
|
2018-07-19 01:16:05 +08:00
|
|
|
os << '\n';
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 08:42:46 +08:00
|
|
|
namespace {
|
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
// FunctionPrinter contains common functionality for printing
|
2018-07-10 08:42:46 +08:00
|
|
|
// CFG and ML functions.
|
2018-07-25 07:07:22 +08:00
|
|
|
class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
|
2018-07-10 08:42:46 +08:00
|
|
|
public:
|
2018-07-25 07:07:22 +08:00
|
|
|
FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
|
2018-07-10 08:42:46 +08:00
|
|
|
|
|
|
|
void printOperation(const Operation *op);
|
2018-07-25 07:07:22 +08:00
|
|
|
void printDefaultOp(const Operation *op);
|
|
|
|
|
|
|
|
// Implement OpAsmPrinter.
|
|
|
|
raw_ostream &getStream() const { return os; }
|
|
|
|
void printType(const Type *type) { ModulePrinter::printType(type); }
|
|
|
|
void printAttribute(const Attribute *attr) {
|
|
|
|
ModulePrinter::printAttribute(attr);
|
|
|
|
}
|
|
|
|
void printAffineMap(const AffineMap *map) {
|
2018-07-29 00:36:25 +08:00
|
|
|
return ModulePrinter::printAffineMapReference(map);
|
2018-07-25 07:07:22 +08:00
|
|
|
}
|
|
|
|
void printAffineExpr(const AffineExpr *expr) {
|
|
|
|
return ModulePrinter::printAffineExpr(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printOperand(const SSAValue *value) { printValueID(value); }
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-08-02 01:43:18 +08:00
|
|
|
enum { nameSentinel = ~0U };
|
|
|
|
|
2018-07-10 08:42:46 +08:00
|
|
|
protected:
|
2018-07-21 00:28:54 +08:00
|
|
|
void numberValueID(const SSAValue *value) {
|
|
|
|
assert(!valueIDs.count(value) && "Value numbered multiple times");
|
2018-08-02 01:43:18 +08:00
|
|
|
|
|
|
|
SmallString<32> specialNameBuffer;
|
|
|
|
llvm::raw_svector_ostream specialName(specialNameBuffer);
|
|
|
|
|
|
|
|
// Give constant integers special names.
|
|
|
|
if (auto *op = value->getDefiningOperation()) {
|
|
|
|
if (auto intOp = op->getAs<ConstantIntOp>()) {
|
|
|
|
specialName << 'c' << intOp->getValue();
|
|
|
|
if (!intOp->getType()->isAffineInt())
|
|
|
|
specialName << '_' << *intOp->getType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (specialNameBuffer.empty()) {
|
|
|
|
switch (value->getKind()) {
|
|
|
|
case SSAValueKind::BBArgument:
|
|
|
|
// If this is an argument to the function, give it an 'arg' name.
|
|
|
|
if (auto *bb = cast<BBArgument>(value)->getOwner())
|
|
|
|
if (auto *fn = bb->getFunction())
|
|
|
|
if (&fn->front() == bb) {
|
|
|
|
specialName << "arg" << nextArgumentID++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Otherwise number it normally.
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case SSAValueKind::InstResult:
|
|
|
|
case SSAValueKind::StmtResult:
|
|
|
|
// This is an uninteresting result, give it a boring number and be
|
|
|
|
// done with it.
|
|
|
|
valueIDs[value] = nextValueID++;
|
|
|
|
return;
|
|
|
|
case SSAValueKind::FnArgument:
|
|
|
|
specialName << "arg" << nextArgumentID++;
|
|
|
|
break;
|
|
|
|
case SSAValueKind::ForStmt:
|
|
|
|
specialName << 'i' << nextLoopID++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ok, this value had an interesting name. Remember it with a sentinel.
|
|
|
|
valueIDs[value] = nameSentinel;
|
|
|
|
|
|
|
|
// Remember that we've used this name, checking to see if we had a conflict.
|
|
|
|
auto insertRes = usedNames.insert(specialName.str());
|
|
|
|
if (insertRes.second) {
|
|
|
|
// If this is the first use of the name, then we're successful!
|
|
|
|
valueNames[value] = insertRes.first->first();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we had a conflict - probe until we find a unique name. This
|
|
|
|
// is guaranteed to terminate (and usually in a single iteration) because it
|
|
|
|
// generates new names by incrementing nextConflictID.
|
|
|
|
while (1) {
|
|
|
|
std::string probeName =
|
|
|
|
specialName.str().str() + "_" + llvm::utostr(nextConflictID++);
|
|
|
|
insertRes = usedNames.insert(probeName);
|
|
|
|
if (insertRes.second) {
|
|
|
|
// If this is the first use of the name, then we're successful!
|
|
|
|
valueNames[value] = insertRes.first->first();
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 06:18:10 +08:00
|
|
|
}
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 06:18:10 +08:00
|
|
|
void printValueID(const SSAValue *value, bool printResultNo = true) const {
|
2018-07-21 09:41:34 +08:00
|
|
|
int resultNo = -1;
|
|
|
|
auto lookupValue = value;
|
|
|
|
|
2018-07-31 06:18:10 +08:00
|
|
|
// If this is a reference to the result of a multi-result instruction or
|
|
|
|
// statement, print out the # identifier and make sure to map our lookup
|
|
|
|
// to the first result of the instruction.
|
2018-07-21 09:41:34 +08:00
|
|
|
if (auto *result = dyn_cast<InstResult>(value)) {
|
|
|
|
if (result->getOwner()->getNumResults() != 1) {
|
|
|
|
resultNo = result->getResultNumber();
|
|
|
|
lookupValue = result->getOwner()->getResult(0);
|
|
|
|
}
|
2018-07-31 06:18:10 +08:00
|
|
|
} else if (auto *result = dyn_cast<StmtResult>(value)) {
|
|
|
|
if (result->getOwner()->getNumResults() != 1) {
|
|
|
|
resultNo = result->getResultNumber();
|
|
|
|
lookupValue = result->getOwner()->getResult(0);
|
|
|
|
}
|
2018-07-21 09:41:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
auto it = valueIDs.find(lookupValue);
|
|
|
|
if (it == valueIDs.end()) {
|
2018-07-21 00:28:54 +08:00
|
|
|
os << "<<INVALID SSA VALUE>>";
|
2018-07-21 09:41:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-31 06:18:10 +08:00
|
|
|
os << '%';
|
2018-08-02 01:43:18 +08:00
|
|
|
if (it->second != nameSentinel) {
|
|
|
|
os << it->second;
|
|
|
|
} else {
|
|
|
|
auto nameIt = valueNames.find(lookupValue);
|
|
|
|
assert(nameIt != valueNames.end() && "Didn't have a name entry?");
|
|
|
|
os << nameIt->second;
|
|
|
|
}
|
2018-07-31 06:18:10 +08:00
|
|
|
|
|
|
|
if (resultNo != -1 && printResultNo)
|
2018-07-21 09:41:34 +08:00
|
|
|
os << '#' << resultNo;
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-08-02 01:43:18 +08:00
|
|
|
/// This is the value ID for each SSA value in the current function. If this
|
|
|
|
/// returns ~0, then the valueID has an entry in valueNames.
|
2018-07-21 00:28:54 +08:00
|
|
|
DenseMap<const SSAValue *, unsigned> valueIDs;
|
2018-08-02 01:43:18 +08:00
|
|
|
DenseMap<const SSAValue *, StringRef> valueNames;
|
|
|
|
|
|
|
|
/// This keeps track of all of the non-numeric names that are in flight,
|
|
|
|
/// allowing us to check for duplicates.
|
|
|
|
llvm::StringSet<> usedNames;
|
|
|
|
|
|
|
|
/// This is the next value ID to assign in numbering.
|
2018-07-21 00:28:54 +08:00
|
|
|
unsigned nextValueID = 0;
|
2018-08-02 01:43:18 +08:00
|
|
|
/// This is the ID to assign to the next induction variable.
|
2018-07-31 22:40:14 +08:00
|
|
|
unsigned nextLoopID = 0;
|
2018-08-02 01:43:18 +08:00
|
|
|
/// This is the next ID to assign to an MLFunction argument.
|
|
|
|
unsigned nextArgumentID = 0;
|
|
|
|
|
|
|
|
/// This is the next ID to assign when a name conflict is detected.
|
|
|
|
unsigned nextConflictID = 0;
|
2018-07-10 08:42:46 +08:00
|
|
|
};
|
2018-07-24 02:44:40 +08:00
|
|
|
} // end anonymous namespace
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void FunctionPrinter::printOperation(const Operation *op) {
|
2018-07-23 12:02:26 +08:00
|
|
|
if (op->getNumResults()) {
|
2018-07-31 06:18:10 +08:00
|
|
|
printValueID(op->getResult(0), /*printResultNo=*/false);
|
2018-07-23 12:02:26 +08:00
|
|
|
os << " = ";
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 08:42:46 +08:00
|
|
|
// Check to see if this is a known operation. If so, use the registered
|
|
|
|
// custom printer hook.
|
2018-07-21 00:35:47 +08:00
|
|
|
if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
|
2018-07-25 07:07:22 +08:00
|
|
|
opInfo->printAssembly(op, this);
|
2018-07-10 08:42:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:28:54 +08:00
|
|
|
// Otherwise use the standard verbose printing approach.
|
2018-07-25 07:07:22 +08:00
|
|
|
printDefaultOp(op);
|
|
|
|
}
|
2018-07-21 00:28:54 +08:00
|
|
|
|
2018-07-25 07:07:22 +08:00
|
|
|
void FunctionPrinter::printDefaultOp(const Operation *op) {
|
2018-07-10 08:42:46 +08:00
|
|
|
// TODO: escape name if necessary.
|
2018-07-21 00:28:54 +08:00
|
|
|
os << "\"" << op->getName().str() << "\"(";
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-07-23 12:02:26 +08:00
|
|
|
interleaveComma(op->getOperands(),
|
|
|
|
[&](const SSAValue *value) { printValueID(value); });
|
2018-07-19 23:35:28 +08:00
|
|
|
|
2018-07-21 00:28:54 +08:00
|
|
|
os << ')';
|
2018-07-10 08:42:46 +08:00
|
|
|
auto attrs = op->getAttrs();
|
|
|
|
if (!attrs.empty()) {
|
|
|
|
os << '{';
|
2018-07-21 00:35:47 +08:00
|
|
|
interleaveComma(attrs, [&](NamedAttribute attr) {
|
2018-07-21 00:28:54 +08:00
|
|
|
os << attr.first << ": ";
|
2018-07-25 07:07:22 +08:00
|
|
|
printAttribute(attr.second);
|
2018-07-21 00:28:54 +08:00
|
|
|
});
|
2018-07-10 08:42:46 +08:00
|
|
|
os << '}';
|
|
|
|
}
|
2018-07-19 06:31:25 +08:00
|
|
|
|
2018-07-23 12:02:26 +08:00
|
|
|
// Print the type signature of the operation.
|
|
|
|
os << " : (";
|
|
|
|
interleaveComma(op->getOperands(),
|
2018-07-25 07:07:22 +08:00
|
|
|
[&](const SSAValue *value) { printType(value->getType()); });
|
2018-07-23 12:02:26 +08:00
|
|
|
os << ") -> ";
|
2018-07-21 00:28:54 +08:00
|
|
|
|
2018-07-23 12:02:26 +08:00
|
|
|
if (op->getNumResults() == 1) {
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(op->getResult(0)->getType());
|
2018-07-23 12:02:26 +08:00
|
|
|
} else {
|
|
|
|
os << '(';
|
2018-07-25 07:07:22 +08:00
|
|
|
interleaveComma(op->getResults(), [&](const SSAValue *result) {
|
|
|
|
printType(result->getType());
|
|
|
|
});
|
2018-07-23 12:02:26 +08:00
|
|
|
os << ')';
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
2018-07-10 08:42:46 +08:00
|
|
|
}
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CFG Function printing
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
2018-07-25 07:07:22 +08:00
|
|
|
class CFGFunctionPrinter : public FunctionPrinter {
|
2018-06-24 07:03:42 +08:00
|
|
|
public:
|
2018-07-21 00:35:47 +08:00
|
|
|
CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
|
2018-06-24 07:03:42 +08:00
|
|
|
|
|
|
|
const CFGFunction *getFunction() const { return function; }
|
|
|
|
|
|
|
|
void print();
|
|
|
|
void print(const BasicBlock *block);
|
2018-06-29 11:45:33 +08:00
|
|
|
|
|
|
|
void print(const Instruction *inst);
|
|
|
|
void print(const OperationInst *inst);
|
|
|
|
void print(const ReturnInst *inst);
|
|
|
|
void print(const BranchInst *inst);
|
2018-07-25 06:01:27 +08:00
|
|
|
void print(const CondBranchInst *inst);
|
2018-06-24 07:03:42 +08:00
|
|
|
|
|
|
|
unsigned getBBID(const BasicBlock *block) {
|
|
|
|
auto it = basicBlockIDs.find(block);
|
|
|
|
assert(it != basicBlockIDs.end() && "Block not in this function?");
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const CFGFunction *function;
|
2018-07-19 01:16:05 +08:00
|
|
|
DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
|
2018-07-21 00:28:54 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void numberValuesInBlock(const BasicBlock *block);
|
2018-06-24 07:03:42 +08:00
|
|
|
};
|
2018-07-24 02:44:40 +08:00
|
|
|
} // end anonymous namespace
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
|
|
|
|
const ModulePrinter &other)
|
2018-07-25 07:07:22 +08:00
|
|
|
: FunctionPrinter(other), function(function) {
|
2018-06-24 07:03:42 +08:00
|
|
|
// Each basic block gets a unique ID per function.
|
|
|
|
unsigned blockID = 0;
|
2018-07-21 00:28:54 +08:00
|
|
|
for (auto &block : *function) {
|
|
|
|
basicBlockIDs[&block] = blockID++;
|
2018-07-21 00:35:47 +08:00
|
|
|
numberValuesInBlock(&block);
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Number all of the SSA values in the specified basic block.
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::numberValuesInBlock(const BasicBlock *block) {
|
2018-07-23 06:45:24 +08:00
|
|
|
for (auto *arg : block->getArguments()) {
|
|
|
|
numberValueID(arg);
|
|
|
|
}
|
2018-07-21 00:28:54 +08:00
|
|
|
for (auto &op : *block) {
|
|
|
|
// We number instruction that have results, and we only number the first
|
|
|
|
// result.
|
|
|
|
if (op.getNumResults() != 0)
|
|
|
|
numberValueID(op.getResult(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Terminators do not define values.
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::print() {
|
2018-06-24 07:03:42 +08:00
|
|
|
os << "cfgfunc ";
|
2018-07-21 00:35:47 +08:00
|
|
|
printFunctionSignature(getFunction());
|
2018-06-24 07:03:42 +08:00
|
|
|
os << " {\n";
|
|
|
|
|
2018-07-24 02:44:40 +08:00
|
|
|
for (auto &block : *function)
|
|
|
|
print(&block);
|
2018-06-24 07:03:42 +08:00
|
|
|
os << "}\n\n";
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::print(const BasicBlock *block) {
|
2018-07-23 06:45:24 +08:00
|
|
|
os << "bb" << getBBID(block);
|
|
|
|
|
|
|
|
if (!block->args_empty()) {
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
|
|
|
|
printValueID(arg);
|
|
|
|
os << ": ";
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(arg->getType());
|
2018-07-23 06:45:24 +08:00
|
|
|
});
|
|
|
|
os << ')';
|
|
|
|
}
|
2018-07-28 02:10:12 +08:00
|
|
|
os << ':';
|
|
|
|
|
|
|
|
// Print out some context information about the predecessors of this block.
|
|
|
|
if (!block->getFunction()) {
|
|
|
|
os << "\t// block is not in a function!";
|
|
|
|
} else if (block->hasNoPredecessors()) {
|
|
|
|
// Don't print "no predecessors" for the entry block.
|
|
|
|
if (block != &block->getFunction()->front())
|
|
|
|
os << "\t// no predecessors";
|
|
|
|
} else if (auto *pred = block->getSinglePredecessor()) {
|
|
|
|
os << "\t// pred: bb" << getBBID(pred);
|
|
|
|
} else {
|
|
|
|
// We want to print the predecessors in increasing numeric order, not in
|
|
|
|
// whatever order the use-list is in, so gather and sort them.
|
|
|
|
SmallVector<unsigned, 4> predIDs;
|
|
|
|
for (auto *pred : block->getPredecessors())
|
|
|
|
predIDs.push_back(getBBID(pred));
|
|
|
|
llvm::array_pod_sort(predIDs.begin(), predIDs.end());
|
|
|
|
|
|
|
|
os << "\t// " << predIDs.size() << " preds: ";
|
|
|
|
|
|
|
|
interleaveComma(predIDs, [&](unsigned predID) { os << "bb" << predID; });
|
|
|
|
}
|
|
|
|
os << '\n';
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-07-15 15:06:54 +08:00
|
|
|
for (auto &inst : block->getOperations()) {
|
2018-07-27 09:09:20 +08:00
|
|
|
os << " ";
|
2018-07-02 11:28:00 +08:00
|
|
|
print(&inst);
|
2018-07-23 06:45:24 +08:00
|
|
|
os << '\n';
|
2018-07-15 15:06:54 +08:00
|
|
|
}
|
2018-06-24 07:03:42 +08:00
|
|
|
|
|
|
|
print(block->getTerminator());
|
2018-07-23 06:45:24 +08:00
|
|
|
os << '\n';
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::print(const Instruction *inst) {
|
2018-06-24 07:03:42 +08:00
|
|
|
switch (inst->getKind()) {
|
2018-06-29 11:45:33 +08:00
|
|
|
case Instruction::Kind::Operation:
|
|
|
|
return print(cast<OperationInst>(inst));
|
2018-06-25 02:18:29 +08:00
|
|
|
case TerminatorInst::Kind::Branch:
|
2018-06-29 11:45:33 +08:00
|
|
|
return print(cast<BranchInst>(inst));
|
2018-07-25 06:01:27 +08:00
|
|
|
case TerminatorInst::Kind::CondBranch:
|
|
|
|
return print(cast<CondBranchInst>(inst));
|
2018-06-24 07:03:42 +08:00
|
|
|
case TerminatorInst::Kind::Return:
|
2018-06-29 11:45:33 +08:00
|
|
|
return print(cast<ReturnInst>(inst));
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::print(const OperationInst *inst) {
|
2018-07-10 08:42:46 +08:00
|
|
|
printOperation(inst);
|
2018-07-19 06:31:25 +08:00
|
|
|
}
|
2018-07-23 23:42:19 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void CFGFunctionPrinter::print(const BranchInst *inst) {
|
2018-07-27 09:09:20 +08:00
|
|
|
os << "br bb" << getBBID(inst->getDest());
|
2018-07-23 23:42:19 +08:00
|
|
|
|
|
|
|
if (inst->getNumOperands() != 0) {
|
|
|
|
os << '(';
|
|
|
|
// TODO: Use getOperands() when we have it.
|
|
|
|
interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
|
|
|
|
printValueID(operand.get());
|
|
|
|
});
|
|
|
|
os << ") : ";
|
|
|
|
interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(operand.get()->getType());
|
2018-07-23 23:42:19 +08:00
|
|
|
});
|
|
|
|
}
|
2018-06-29 11:45:33 +08:00
|
|
|
}
|
2018-07-23 23:42:19 +08:00
|
|
|
|
2018-07-25 06:01:27 +08:00
|
|
|
void CFGFunctionPrinter::print(const CondBranchInst *inst) {
|
2018-07-27 09:09:20 +08:00
|
|
|
os << "cond_br ";
|
2018-07-25 06:01:27 +08:00
|
|
|
printValueID(inst->getCondition());
|
|
|
|
|
|
|
|
os << ", bb" << getBBID(inst->getTrueDest());
|
|
|
|
if (inst->getNumTrueOperands() != 0) {
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(inst->getTrueOperands(),
|
|
|
|
[&](const CFGValue *operand) { printValueID(operand); });
|
|
|
|
os << " : ";
|
|
|
|
interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(operand->getType());
|
2018-07-25 06:01:27 +08:00
|
|
|
});
|
|
|
|
os << ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
os << ", bb" << getBBID(inst->getFalseDest());
|
|
|
|
if (inst->getNumFalseOperands() != 0) {
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(inst->getFalseOperands(),
|
|
|
|
[&](const CFGValue *operand) { printValueID(operand); });
|
|
|
|
os << " : ";
|
|
|
|
interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(operand->getType());
|
2018-07-25 06:01:27 +08:00
|
|
|
});
|
|
|
|
os << ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-22 05:32:09 +08:00
|
|
|
void CFGFunctionPrinter::print(const ReturnInst *inst) {
|
2018-07-27 09:09:20 +08:00
|
|
|
os << "return";
|
2018-07-22 05:32:09 +08:00
|
|
|
|
2018-08-02 23:28:20 +08:00
|
|
|
if (inst->getNumOperands() == 0)
|
|
|
|
return;
|
2018-07-22 05:32:09 +08:00
|
|
|
|
2018-08-02 23:28:20 +08:00
|
|
|
os << ' ';
|
2018-07-25 06:01:27 +08:00
|
|
|
interleaveComma(inst->getOperands(),
|
|
|
|
[&](const CFGValue *operand) { printValueID(operand); });
|
|
|
|
os << " : ";
|
2018-07-23 12:02:26 +08:00
|
|
|
interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
|
2018-07-25 07:07:22 +08:00
|
|
|
printType(operand->getType());
|
2018-07-22 05:32:09 +08:00
|
|
|
});
|
|
|
|
}
|
2018-07-19 01:16:05 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::print(const CFGFunction *fn) {
|
|
|
|
CFGFunctionPrinter(fn, *this).print();
|
2018-06-29 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2018-07-04 08:51:28 +08:00
|
|
|
// ML Function printing
|
2018-06-24 07:03:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-07-04 08:51:28 +08:00
|
|
|
namespace {
|
2018-07-25 07:07:22 +08:00
|
|
|
class MLFunctionPrinter : public FunctionPrinter {
|
2018-07-04 08:51:28 +08:00
|
|
|
public:
|
2018-07-21 00:35:47 +08:00
|
|
|
MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
|
2018-07-04 08:51:28 +08:00
|
|
|
|
|
|
|
const MLFunction *getFunction() const { return function; }
|
|
|
|
|
2018-07-14 04:03:13 +08:00
|
|
|
// Prints ML function
|
2018-07-04 08:51:28 +08:00
|
|
|
void print();
|
|
|
|
|
2018-07-14 04:03:13 +08:00
|
|
|
// Methods to print ML function statements
|
2018-07-04 08:51:28 +08:00
|
|
|
void print(const Statement *stmt);
|
2018-07-10 08:42:46 +08:00
|
|
|
void print(const OperationStmt *stmt);
|
2018-07-04 08:51:28 +08:00
|
|
|
void print(const ForStmt *stmt);
|
|
|
|
void print(const IfStmt *stmt);
|
2018-07-14 04:03:13 +08:00
|
|
|
void print(const StmtBlock *block);
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-07-14 04:03:13 +08:00
|
|
|
// Number of spaces used for indenting nested statements
|
|
|
|
const static unsigned indentWidth = 2;
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-07-14 04:03:13 +08:00
|
|
|
private:
|
2018-07-27 09:09:20 +08:00
|
|
|
void numberValues();
|
|
|
|
|
2018-07-04 08:51:28 +08:00
|
|
|
const MLFunction *function;
|
|
|
|
int numSpaces;
|
|
|
|
};
|
2018-07-24 02:44:40 +08:00
|
|
|
} // end anonymous namespace
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
|
|
|
|
const ModulePrinter &other)
|
2018-07-27 09:09:20 +08:00
|
|
|
: FunctionPrinter(other), function(function), numSpaces(0) {
|
|
|
|
numberValues();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Number all of the SSA values in this ML function.
|
|
|
|
void MLFunctionPrinter::numberValues() {
|
|
|
|
// Visits all operation statements and numbers the first result.
|
2018-07-28 01:58:14 +08:00
|
|
|
struct NumberValuesPass : public StmtWalker<NumberValuesPass> {
|
2018-07-27 09:09:20 +08:00
|
|
|
NumberValuesPass(MLFunctionPrinter *printer) : printer(printer) {}
|
|
|
|
void visitOperationStmt(OperationStmt *stmt) {
|
|
|
|
if (stmt->getNumResults() != 0)
|
|
|
|
printer->numberValueID(stmt->getResult(0));
|
|
|
|
}
|
2018-07-31 22:40:14 +08:00
|
|
|
void visitForStmt(ForStmt *stmt) { printer->numberValueID(stmt); }
|
2018-07-27 09:09:20 +08:00
|
|
|
MLFunctionPrinter *printer;
|
|
|
|
};
|
|
|
|
|
|
|
|
NumberValuesPass pass(this);
|
|
|
|
// TODO: it'd be cleaner to have constant visitor istead of using const_cast.
|
2018-07-28 01:58:14 +08:00
|
|
|
pass.walk(const_cast<MLFunction *>(function));
|
2018-07-27 09:09:20 +08:00
|
|
|
}
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print() {
|
2018-07-04 08:51:28 +08:00
|
|
|
os << "mlfunc ";
|
|
|
|
// FIXME: should print argument names rather than just signature
|
2018-07-21 00:35:47 +08:00
|
|
|
printFunctionSignature(function);
|
2018-07-04 08:51:28 +08:00
|
|
|
os << " {\n";
|
2018-07-14 04:03:13 +08:00
|
|
|
print(function);
|
2018-07-04 08:51:28 +08:00
|
|
|
os << " return\n";
|
|
|
|
os << "}\n\n";
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print(const StmtBlock *block) {
|
2018-07-14 04:03:13 +08:00
|
|
|
numSpaces += indentWidth;
|
2018-07-15 15:06:54 +08:00
|
|
|
for (auto &stmt : block->getStatements()) {
|
2018-07-14 04:03:13 +08:00
|
|
|
print(&stmt);
|
2018-07-15 15:06:54 +08:00
|
|
|
os << "\n";
|
|
|
|
}
|
2018-07-14 04:03:13 +08:00
|
|
|
numSpaces -= indentWidth;
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print(const Statement *stmt) {
|
2018-07-04 08:51:28 +08:00
|
|
|
switch (stmt->getKind()) {
|
2018-07-17 02:47:09 +08:00
|
|
|
case Statement::Kind::Operation:
|
|
|
|
return print(cast<OperationStmt>(stmt));
|
2018-07-04 08:51:28 +08:00
|
|
|
case Statement::Kind::For:
|
|
|
|
return print(cast<ForStmt>(stmt));
|
|
|
|
case Statement::Kind::If:
|
|
|
|
return print(cast<IfStmt>(stmt));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print(const OperationStmt *stmt) {
|
2018-07-27 09:09:20 +08:00
|
|
|
os.indent(numSpaces);
|
2018-07-21 00:35:47 +08:00
|
|
|
printOperation(stmt);
|
|
|
|
}
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print(const ForStmt *stmt) {
|
2018-07-31 06:18:10 +08:00
|
|
|
os.indent(numSpaces) << "for ";
|
2018-07-31 22:40:14 +08:00
|
|
|
printOperand(stmt);
|
2018-07-31 06:18:10 +08:00
|
|
|
os << " = " << *stmt->getLowerBound();
|
2018-07-20 00:52:39 +08:00
|
|
|
os << " to " << *stmt->getUpperBound();
|
|
|
|
if (stmt->getStep()->getValue() != 1)
|
|
|
|
os << " step " << *stmt->getStep();
|
|
|
|
|
|
|
|
os << " {\n";
|
2018-07-14 04:03:13 +08:00
|
|
|
print(static_cast<const StmtBlock *>(stmt));
|
2018-07-17 02:47:09 +08:00
|
|
|
os.indent(numSpaces) << "}";
|
2018-07-04 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void MLFunctionPrinter::print(const IfStmt *stmt) {
|
2018-07-14 04:03:13 +08:00
|
|
|
os.indent(numSpaces) << "if () {\n";
|
|
|
|
print(stmt->getThenClause());
|
|
|
|
os.indent(numSpaces) << "}";
|
|
|
|
if (stmt->hasElseClause()) {
|
|
|
|
os << " else {\n";
|
|
|
|
print(stmt->getElseClause());
|
|
|
|
os.indent(numSpaces) << "}";
|
|
|
|
}
|
2018-07-04 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModulePrinter::print(const MLFunction *fn) {
|
|
|
|
MLFunctionPrinter(fn, *this).print();
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
|
2018-07-04 08:51:28 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// print and dump methods
|
|
|
|
//===----------------------------------------------------------------------===//
|
2018-06-29 11:45:33 +08:00
|
|
|
|
2018-07-19 07:29:21 +08:00
|
|
|
void Attribute::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(/*no context is known*/ nullptr);
|
2018-07-25 07:07:22 +08:00
|
|
|
ModulePrinter(os, state).printAttribute(this);
|
2018-07-19 07:29:21 +08:00
|
|
|
}
|
|
|
|
|
2018-07-24 02:44:40 +08:00
|
|
|
void Attribute::dump() const { print(llvm::errs()); }
|
2018-07-19 07:29:21 +08:00
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
void Type::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(getContext());
|
2018-07-25 07:07:22 +08:00
|
|
|
ModulePrinter(os, state).printType(this);
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Type::dump() const { print(llvm::errs()); }
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2018-07-17 00:45:22 +08:00
|
|
|
void AffineMap::dump() const {
|
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
|
|
|
}
|
2018-07-10 00:00:25 +08:00
|
|
|
|
2018-07-04 11:16:08 +08:00
|
|
|
void AffineExpr::dump() const {
|
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
|
|
|
}
|
|
|
|
|
2018-06-30 09:09:29 +08:00
|
|
|
void AffineExpr::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(/*no context is known*/ nullptr);
|
2018-07-25 07:07:22 +08:00
|
|
|
ModulePrinter(os, state).printAffineExpr(this);
|
2018-06-30 09:09:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AffineMap::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(/*no context is known*/ nullptr);
|
2018-07-25 07:07:22 +08:00
|
|
|
ModulePrinter(os, state).printAffineMap(this);
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
2018-07-12 12:31:07 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void Instruction::print(raw_ostream &os) const {
|
|
|
|
ModuleState state(getFunction()->getContext());
|
|
|
|
ModulePrinter modulePrinter(os, state);
|
|
|
|
CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
|
|
|
|
}
|
2018-07-12 12:31:07 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void Instruction::dump() const {
|
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
2018-06-30 09:09:29 +08:00
|
|
|
}
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
void BasicBlock::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(getFunction()->getContext());
|
|
|
|
ModulePrinter modulePrinter(os, state);
|
|
|
|
CFGFunctionPrinter(getFunction(), modulePrinter).print(this);
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void BasicBlock::dump() const { print(llvm::errs()); }
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-07-04 08:51:28 +08:00
|
|
|
void Statement::print(raw_ostream &os) const {
|
2018-08-01 14:14:16 +08:00
|
|
|
MLFunction *function = findFunction();
|
|
|
|
ModuleState state(function->getContext());
|
2018-07-21 00:35:47 +08:00
|
|
|
ModulePrinter modulePrinter(os, state);
|
2018-08-01 14:14:16 +08:00
|
|
|
MLFunctionPrinter(function, modulePrinter).print(this);
|
2018-06-29 08:02:32 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Statement::dump() const { print(llvm::errs()); }
|
2018-07-15 15:06:54 +08:00
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
void Function::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(getContext());
|
|
|
|
ModulePrinter(os, state).print(this);
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Function::dump() const { print(llvm::errs()); }
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
void Module::print(raw_ostream &os) const {
|
2018-07-21 00:35:47 +08:00
|
|
|
ModuleState state(getContext());
|
|
|
|
state.initialize(this);
|
|
|
|
ModulePrinter(os, state).print(this);
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
void Module::dump() const { print(llvm::errs()); }
|