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-10-11 05:23:30 +08:00
|
|
|
#include "mlir/IR/BuiltinOps.h"
|
2018-12-28 03:07:34 +08:00
|
|
|
#include "mlir/IR/Function.h"
|
2018-12-29 08:05:35 +08:00
|
|
|
#include "mlir/IR/InstVisitor.h"
|
|
|
|
#include "mlir/IR/Instructions.h"
|
2018-08-08 05:24:38 +08:00
|
|
|
#include "mlir/IR/IntegerSet.h"
|
2019-01-11 14:08:39 +08:00
|
|
|
#include "mlir/IR/MLIRContext.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"
|
2019-01-04 06:29:52 +08:00
|
|
|
#include "mlir/IR/StandardTypes.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
#include "mlir/Support/STLExtras.h"
|
2018-08-16 00:09:54 +08:00
|
|
|
#include "llvm/ADT/APFloat.h"
|
2018-06-24 07:03:42 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2018-11-13 06:58:53 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2019-01-11 14:08:39 +08:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2018-08-02 01:43:18 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/ADT/StringSet.h"
|
2019-01-11 14:08:39 +08:00
|
|
|
#include "llvm/Support/Regex.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-10-10 13:08:52 +08:00
|
|
|
void OperationName::print(raw_ostream &os) const { os << getStringRef(); }
|
|
|
|
|
|
|
|
void OperationName::dump() const { print(llvm::errs()); }
|
|
|
|
|
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-10-22 10:49:31 +08:00
|
|
|
/// This is the current context if it is knowable, otherwise this is null.
|
|
|
|
MLIRContext *const context;
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2018-10-22 10:49:31 +08:00
|
|
|
explicit ModuleState(MLIRContext *context) : context(context) {}
|
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
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
StringRef getAffineMapAlias(AffineMap affineMap) const {
|
|
|
|
return affineMapToAlias.lookup(affineMap);
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
int getAffineMapId(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-10-10 07:39:24 +08:00
|
|
|
ArrayRef<AffineMap> getAffineMapIds() const { return affineMapsById; }
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
StringRef getIntegerSetAlias(IntegerSet integerSet) const {
|
|
|
|
return integerSetToAlias.lookup(integerSet);
|
|
|
|
}
|
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
int getIntegerSetId(IntegerSet integerSet) const {
|
2018-08-08 05:24:38 +08:00
|
|
|
auto it = integerSetIds.find(integerSet);
|
|
|
|
if (it == integerSetIds.end()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
ArrayRef<IntegerSet> getIntegerSetIds() const { return integerSetsById; }
|
2018-08-08 05:24:38 +08:00
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
StringRef getTypeAlias(Type ty) const { return typeToAlias.lookup(ty); }
|
|
|
|
|
|
|
|
ArrayRef<Type> getTypeIds() const { return usedTypes.getArrayRef(); }
|
|
|
|
|
2018-07-19 01:16:05 +08:00
|
|
|
private:
|
2018-10-10 07:39:24 +08:00
|
|
|
void recordAffineMapReference(AffineMap affineMap) {
|
2018-07-21 00:35:47 +08:00
|
|
|
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-10-11 00:45:59 +08:00
|
|
|
void recordIntegerSetReference(IntegerSet integerSet) {
|
2018-08-08 05:24:38 +08:00
|
|
|
if (integerSetIds.count(integerSet) == 0) {
|
|
|
|
integerSetIds[integerSet] = integerSetsById.size();
|
|
|
|
integerSetsById.push_back(integerSet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
void recordTypeReference(Type ty) { usedTypes.insert(ty); }
|
|
|
|
|
2018-08-25 14:38:14 +08:00
|
|
|
// Return true if this map could be printed using the shorthand form.
|
2018-10-10 07:39:24 +08:00
|
|
|
static bool hasShorthandForm(AffineMap boundMap) {
|
|
|
|
if (boundMap.isSingleConstant())
|
2018-08-25 14:38:14 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check if the affine map is single dim id or single symbol identity -
|
|
|
|
// (i)->(i) or ()[s]->(i)
|
2018-10-10 07:39:24 +08:00
|
|
|
return boundMap.getNumInputs() == 1 && boundMap.getNumResults() == 1 &&
|
|
|
|
(boundMap.getResult(0).isa<AffineDimExpr>() ||
|
|
|
|
boundMap.getResult(0).isa<AffineSymbolExpr>());
|
2018-08-25 14:38:14 +08:00
|
|
|
}
|
|
|
|
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit functions.
|
2018-12-29 08:05:35 +08:00
|
|
|
void visitInstruction(const Instruction *inst);
|
|
|
|
void visitForInst(const ForInst *forInst);
|
|
|
|
void visitIfInst(const IfInst *ifInst);
|
|
|
|
void visitOperationInst(const OperationInst *opInst);
|
2018-10-31 05:59:22 +08:00
|
|
|
void visitType(Type type);
|
2018-10-26 06:46:10 +08:00
|
|
|
void visitAttribute(Attribute attr);
|
2018-07-19 07:29:21 +08:00
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
// Initialize symbol aliases.
|
|
|
|
void initializeSymbolAliases();
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
DenseMap<AffineMap, int> affineMapIds;
|
|
|
|
std::vector<AffineMap> affineMapsById;
|
2019-01-11 14:08:39 +08:00
|
|
|
DenseMap<AffineMap, StringRef> affineMapToAlias;
|
2018-08-08 05:24:38 +08:00
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
DenseMap<IntegerSet, int> integerSetIds;
|
|
|
|
std::vector<IntegerSet> integerSetsById;
|
2019-01-11 14:08:39 +08:00
|
|
|
DenseMap<IntegerSet, StringRef> integerSetToAlias;
|
|
|
|
|
|
|
|
llvm::SetVector<Type> usedTypes;
|
|
|
|
DenseMap<Type, StringRef> typeToAlias;
|
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.
|
2018-10-31 05:59:22 +08:00
|
|
|
void ModuleState::visitType(Type type) {
|
2019-01-11 14:08:39 +08:00
|
|
|
recordTypeReference(type);
|
2018-10-31 05:59:22 +08:00
|
|
|
if (auto funcType = type.dyn_cast<FunctionType>()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit input and result types for functions.
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto input : funcType.getInputs())
|
2018-07-18 07:56:54 +08:00
|
|
|
visitType(input);
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto result : funcType.getResults())
|
2018-07-18 07:56:54 +08:00
|
|
|
visitType(result);
|
2018-10-31 05:59:22 +08:00
|
|
|
} else if (auto memref = type.dyn_cast<MemRefType>()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
// Visit affine maps in memref type.
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto map : memref.getAffineMaps()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
recordAffineMapReference(map);
|
|
|
|
}
|
2019-01-11 14:08:39 +08:00
|
|
|
} else if (auto vecOrTensor = type.dyn_cast<VectorOrTensorType>()) {
|
|
|
|
visitType(vecOrTensor.getElementType());
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
void ModuleState::visitAttribute(Attribute attr) {
|
|
|
|
if (auto mapAttr = attr.dyn_cast<AffineMapAttr>()) {
|
|
|
|
recordAffineMapReference(mapAttr.getValue());
|
2018-10-26 13:13:03 +08:00
|
|
|
} else if (auto setAttr = attr.dyn_cast<IntegerSetAttr>()) {
|
|
|
|
recordIntegerSetReference(setAttr.getValue());
|
2018-10-26 06:46:10 +08:00
|
|
|
} else if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
|
|
|
|
for (auto elt : arrayAttr.getValue()) {
|
2018-07-19 07:29:21 +08:00
|
|
|
visitAttribute(elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void ModuleState::visitIfInst(const IfInst *ifInst) {
|
|
|
|
recordIntegerSetReference(ifInst->getIntegerSet());
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void ModuleState::visitForInst(const ForInst *forInst) {
|
|
|
|
AffineMap lbMap = forInst->getLowerBoundMap();
|
2018-08-25 14:38:14 +08:00
|
|
|
if (!hasShorthandForm(lbMap))
|
|
|
|
recordAffineMapReference(lbMap);
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
AffineMap ubMap = forInst->getUpperBoundMap();
|
2018-08-25 14:38:14 +08:00
|
|
|
if (!hasShorthandForm(ubMap))
|
|
|
|
recordAffineMapReference(ubMap);
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 07:33:43 +08:00
|
|
|
void ModuleState::visitOperationInst(const OperationInst *op) {
|
|
|
|
// 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())
|
|
|
|
visitAttribute(elt.second);
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void ModuleState::visitInstruction(const Instruction *inst) {
|
|
|
|
switch (inst->getKind()) {
|
|
|
|
case Instruction::Kind::If:
|
|
|
|
return visitIfInst(cast<IfInst>(inst));
|
|
|
|
case Instruction::Kind::For:
|
|
|
|
return visitForInst(cast<ForInst>(inst));
|
|
|
|
case Instruction::Kind::OperationInst:
|
|
|
|
return visitOperationInst(cast<OperationInst>(inst));
|
2018-07-18 07:56:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
// Utility to generate a function to register a symbol alias.
|
|
|
|
template <typename SymbolsInModuleSetTy, typename SymbolTy>
|
|
|
|
static void registerSymbolAlias(StringRef name, SymbolTy sym,
|
|
|
|
SymbolsInModuleSetTy &symbolsInModuleSet,
|
|
|
|
llvm::StringSet<> &usedAliases,
|
|
|
|
DenseMap<SymbolTy, StringRef> &symToAlias) {
|
|
|
|
assert(!name.empty() && "expected alias name to be non-empty");
|
|
|
|
assert(sym && "expected alias symbol to be non-null");
|
|
|
|
// TODO(riverriddle) Assert that the provided alias name can be lexed as
|
|
|
|
// an identifier.
|
|
|
|
|
|
|
|
// Check if the symbol is not referenced by the module or the name is
|
|
|
|
// already used by another alias.
|
|
|
|
if (!symbolsInModuleSet.count(sym) || !usedAliases.insert(name).second)
|
|
|
|
return;
|
|
|
|
symToAlias.try_emplace(sym, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleState::initializeSymbolAliases() {
|
|
|
|
// Track the identifiers in use for each symbol so that the same identifier
|
|
|
|
// isn't used twice.
|
|
|
|
llvm::StringSet<> usedAliases;
|
|
|
|
|
|
|
|
// Get the currently registered dialects.
|
|
|
|
auto dialects = context->getRegisteredDialects();
|
|
|
|
|
|
|
|
// Collect the set of aliases from each dialect.
|
|
|
|
SmallVector<std::pair<StringRef, AffineMap>, 8> affineMapAliases;
|
|
|
|
SmallVector<std::pair<StringRef, IntegerSet>, 8> integerSetAliases;
|
|
|
|
SmallVector<std::pair<StringRef, Type>, 16> typeAliases;
|
|
|
|
for (auto *dialect : dialects) {
|
|
|
|
dialect->getAffineMapAliases(affineMapAliases);
|
|
|
|
dialect->getIntegerSetAliases(integerSetAliases);
|
|
|
|
dialect->getTypeAliases(typeAliases);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register the affine aliases.
|
|
|
|
// Create a regex for the non-alias names of sets and maps, so that an alias
|
|
|
|
// is not registered with a conflicting name.
|
|
|
|
llvm::Regex reservedAffineNames("(set|map)[0-9]+");
|
|
|
|
|
|
|
|
// AffineMap aliases
|
|
|
|
for (auto &affineAliasPair : affineMapAliases) {
|
|
|
|
if (!reservedAffineNames.match(affineAliasPair.first))
|
|
|
|
registerSymbolAlias(affineAliasPair.first, affineAliasPair.second,
|
|
|
|
affineMapIds, usedAliases, affineMapToAlias);
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntegerSet aliases
|
|
|
|
for (auto &integerSetAliasPair : integerSetAliases) {
|
|
|
|
if (!reservedAffineNames.match(integerSetAliasPair.first))
|
|
|
|
registerSymbolAlias(integerSetAliasPair.first, integerSetAliasPair.second,
|
|
|
|
integerSetIds, usedAliases, integerSetToAlias);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the set of used identifiers as types can have the same identifiers as
|
|
|
|
// affine structures.
|
|
|
|
usedAliases.clear();
|
|
|
|
|
|
|
|
for (auto &typeAliasPair : typeAliases)
|
|
|
|
registerSymbolAlias(typeAliasPair.first, typeAliasPair.second, usedTypes,
|
|
|
|
usedAliases, typeToAlias);
|
|
|
|
}
|
|
|
|
|
2018-08-08 05:24:38 +08:00
|
|
|
// Initializes module state, populating affine map and integer set state.
|
2018-07-21 00:35:47 +08:00
|
|
|
void ModuleState::initialize(const Module *module) {
|
2018-07-26 05:08:16 +08:00
|
|
|
for (auto &fn : *module) {
|
2018-12-30 07:33:43 +08:00
|
|
|
visitType(fn.getType());
|
|
|
|
|
|
|
|
const_cast<Function &>(fn).walkInsts(
|
|
|
|
[&](Instruction *op) { ModuleState::visitInstruction(op); });
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
2019-01-11 14:08:39 +08:00
|
|
|
|
|
|
|
// Initialize the symbol aliases.
|
|
|
|
initializeSymbolAliases();
|
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-08-22 08:55:22 +08:00
|
|
|
void printFunctionReference(const Function *func);
|
2018-10-26 06:46:10 +08:00
|
|
|
void printAttribute(Attribute attr);
|
2018-10-31 05:59:22 +08:00
|
|
|
void printType(Type type);
|
2018-07-21 00:35:47 +08:00
|
|
|
void print(const Function *fn);
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
void printAffineMap(AffineMap map);
|
2018-10-09 04:47:18 +08:00
|
|
|
void printAffineExpr(AffineExpr expr);
|
|
|
|
void printAffineConstraint(AffineExpr expr, bool isEq);
|
2018-10-11 00:45:59 +08:00
|
|
|
void printIntegerSet(IntegerSet set);
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
raw_ostream &os;
|
|
|
|
ModuleState &state;
|
|
|
|
|
2018-09-19 07:36:26 +08:00
|
|
|
void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
|
|
|
|
ArrayRef<const char *> elidedAttrs = {});
|
2018-07-21 00:35:47 +08:00
|
|
|
void printAffineMapId(int affineMapId) const;
|
2018-10-10 07:39:24 +08:00
|
|
|
void printAffineMapReference(AffineMap affineMap);
|
2019-01-11 14:08:39 +08:00
|
|
|
void printAffineMapAlias(StringRef alias) const;
|
2018-08-08 05:24:38 +08:00
|
|
|
void printIntegerSetId(int integerSetId) const;
|
2018-10-11 00:45:59 +08:00
|
|
|
void printIntegerSetReference(IntegerSet integerSet);
|
2019-01-11 14:08:39 +08:00
|
|
|
void printIntegerSetAlias(StringRef alias) const;
|
2018-10-26 06:46:10 +08:00
|
|
|
void printDenseElementsAttr(DenseElementsAttr attr);
|
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
|
2018-10-10 01:59:27 +08:00
|
|
|
/// context that an AffineExprStorage is being printed in, so we can
|
2018-10-09 04:47:18 +08:00
|
|
|
/// intelligently produce parens.
|
2018-08-01 07:21:36 +08:00
|
|
|
enum class BindingStrength {
|
|
|
|
Weak, // + and -
|
|
|
|
Strong, // All other binary operators.
|
|
|
|
};
|
2018-10-09 04:47:18 +08:00
|
|
|
void printAffineExprInternal(AffineExpr expr,
|
2018-08-01 07:21:36 +08:00
|
|
|
BindingStrength enclosingTightness);
|
2018-07-21 00:35:47 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
void ModulePrinter::printAffineMapAlias(StringRef alias) const {
|
|
|
|
os << '#' << alias;
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
void ModulePrinter::printAffineMapReference(AffineMap affineMap) {
|
2019-01-11 14:08:39 +08:00
|
|
|
// Check for an affine map alias.
|
|
|
|
auto alias = state.getAffineMapAlias(affineMap);
|
|
|
|
if (!alias.empty())
|
|
|
|
return printAffineMapAlias(alias);
|
|
|
|
|
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.
|
2018-10-10 07:39:24 +08:00
|
|
|
affineMap.print(os);
|
2018-07-19 07:29:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-08 05:24:38 +08:00
|
|
|
// Prints integer set identifier.
|
|
|
|
void ModulePrinter::printIntegerSetId(int integerSetId) const {
|
2018-10-26 09:33:42 +08:00
|
|
|
os << "#set" << integerSetId;
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
|
2019-01-11 14:08:39 +08:00
|
|
|
void ModulePrinter::printIntegerSetAlias(StringRef alias) const {
|
|
|
|
os << '#' << alias;
|
|
|
|
}
|
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
void ModulePrinter::printIntegerSetReference(IntegerSet integerSet) {
|
2019-01-11 14:08:39 +08:00
|
|
|
// Check for an integer set alias.
|
|
|
|
auto alias = state.getIntegerSetAlias(integerSet);
|
|
|
|
if (!alias.empty()) {
|
|
|
|
printIntegerSetAlias(alias);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-08 05:24:38 +08:00
|
|
|
int setId;
|
|
|
|
if ((setId = state.getIntegerSetId(integerSet)) >= 0) {
|
|
|
|
// The set will be printed at top of module; so print reference to its id.
|
|
|
|
printIntegerSetId(setId);
|
|
|
|
} else {
|
|
|
|
// Set not in module state so print inline.
|
2018-10-11 00:45:59 +08:00
|
|
|
integerSet.print(os);
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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()) {
|
2019-01-11 14:08:39 +08:00
|
|
|
StringRef alias = state.getAffineMapAlias(map);
|
|
|
|
if (!alias.empty())
|
|
|
|
printAffineMapAlias(alias);
|
|
|
|
else
|
|
|
|
printAffineMapId(state.getAffineMapId(map));
|
2018-07-18 07:56:54 +08:00
|
|
|
os << " = ";
|
2018-10-10 07:39:24 +08:00
|
|
|
map.print(os);
|
2018-07-18 07:56:54 +08:00
|
|
|
os << '\n';
|
|
|
|
}
|
2018-08-08 05:24:38 +08:00
|
|
|
for (const auto &set : state.getIntegerSetIds()) {
|
2019-01-11 14:08:39 +08:00
|
|
|
StringRef alias = state.getIntegerSetAlias(set);
|
|
|
|
if (!alias.empty())
|
|
|
|
printIntegerSetAlias(alias);
|
|
|
|
else
|
|
|
|
printIntegerSetId(state.getIntegerSetId(set));
|
2018-08-08 05:24:38 +08:00
|
|
|
os << " = ";
|
2018-10-11 00:45:59 +08:00
|
|
|
set.print(os);
|
2018-08-08 05:24:38 +08:00
|
|
|
os << '\n';
|
|
|
|
}
|
2019-01-11 14:08:39 +08:00
|
|
|
for (const auto &type : state.getTypeIds()) {
|
|
|
|
StringRef alias = state.getTypeAlias(type);
|
|
|
|
if (!alias.empty())
|
|
|
|
os << '!' << alias << " = type " << type << '\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-08-16 00:09:54 +08:00
|
|
|
/// Print a floating point value in a way that the parser will be able to
|
|
|
|
/// round-trip losslessly.
|
2018-10-21 09:31:49 +08:00
|
|
|
static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
|
2018-08-16 00:09:54 +08:00
|
|
|
// We would like to output the FP constant value in exponential notation,
|
|
|
|
// but we cannot do this if doing so will lose precision. Check here to
|
|
|
|
// make sure that we only output it in exponential format if we can parse
|
|
|
|
// the value back and get the same value.
|
|
|
|
bool isInf = apValue.isInfinity();
|
|
|
|
bool isNaN = apValue.isNaN();
|
|
|
|
if (!isInf && !isNaN) {
|
|
|
|
SmallString<128> strValue;
|
|
|
|
apValue.toString(strValue, 6, 0, false);
|
|
|
|
|
|
|
|
// Check to make sure that the stringized number is not some string like
|
|
|
|
// "Inf" or NaN, that atof will accept, but the lexer will not. Check
|
|
|
|
// that the string matches the "[-+]?[0-9]" regex.
|
|
|
|
assert(((strValue[0] >= '0' && strValue[0] <= '9') ||
|
|
|
|
((strValue[0] == '-' || strValue[0] == '+') &&
|
|
|
|
(strValue[1] >= '0' && strValue[1] <= '9'))) &&
|
|
|
|
"[-+]?[0-9] regex does not match!");
|
|
|
|
// Reparse stringized version!
|
2018-12-17 23:19:53 +08:00
|
|
|
if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
|
2018-08-16 00:09:54 +08:00
|
|
|
os << strValue;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-21 09:31:49 +08:00
|
|
|
SmallVector<char, 16> str;
|
|
|
|
apValue.toString(str);
|
|
|
|
os << str;
|
2018-08-16 00:09:54 +08:00
|
|
|
}
|
|
|
|
|
2018-08-22 08:55:22 +08:00
|
|
|
void ModulePrinter::printFunctionReference(const Function *func) {
|
|
|
|
os << '@' << func->getName();
|
|
|
|
}
|
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
void ModulePrinter::printAttribute(Attribute attr) {
|
2018-11-30 10:47:39 +08:00
|
|
|
if (!attr) {
|
|
|
|
os << "<<NULL ATTRIBUTE>>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
switch (attr.getKind()) {
|
2018-07-19 07:29:21 +08:00
|
|
|
case Attribute::Kind::Bool:
|
2018-10-26 06:46:10 +08:00
|
|
|
os << (attr.cast<BoolAttr>().getValue() ? "true" : "false");
|
2018-07-19 07:29:21 +08:00
|
|
|
break;
|
2018-11-16 09:53:51 +08:00
|
|
|
case Attribute::Kind::Integer: {
|
|
|
|
auto intAttr = attr.cast<IntegerAttr>();
|
|
|
|
// Print all integer attributes as signed unless i1.
|
2018-12-18 02:05:56 +08:00
|
|
|
bool isSigned = intAttr.getType().isIndex() ||
|
|
|
|
intAttr.getType().getIntOrFloatBitWidth() != 1;
|
2018-11-16 09:53:51 +08:00
|
|
|
intAttr.getValue().print(os, isSigned);
|
2018-07-19 07:29:21 +08:00
|
|
|
break;
|
2018-11-16 09:53:51 +08:00
|
|
|
}
|
2018-07-19 07:29:21 +08:00
|
|
|
case Attribute::Kind::Float:
|
2018-10-26 06:46:10 +08:00
|
|
|
printFloatValue(attr.cast<FloatAttr>().getValue(), os);
|
2018-07-19 07:29:21 +08:00
|
|
|
break;
|
|
|
|
case Attribute::Kind::String:
|
2018-08-16 00:09:54 +08:00
|
|
|
os << '"';
|
2018-10-26 06:46:10 +08:00
|
|
|
printEscapedString(attr.cast<StringAttr>().getValue(), os);
|
2018-08-16 00:09:54 +08:00
|
|
|
os << '"';
|
2018-07-19 07:29:21 +08:00
|
|
|
break;
|
2018-08-16 00:09:54 +08:00
|
|
|
case Attribute::Kind::Array:
|
2018-07-19 07:29:21 +08:00
|
|
|
os << '[';
|
2018-10-26 06:46:10 +08:00
|
|
|
interleaveComma(attr.cast<ArrayAttr>().getValue(),
|
|
|
|
[&](Attribute attr) { printAttribute(attr); });
|
2018-07-19 07:29:21 +08:00
|
|
|
os << ']';
|
|
|
|
break;
|
|
|
|
case Attribute::Kind::AffineMap:
|
2018-10-26 06:46:10 +08:00
|
|
|
printAffineMapReference(attr.cast<AffineMapAttr>().getValue());
|
2018-08-03 16:54:46 +08:00
|
|
|
break;
|
2018-10-26 13:13:03 +08:00
|
|
|
case Attribute::Kind::IntegerSet:
|
|
|
|
printIntegerSetReference(attr.cast<IntegerSetAttr>().getValue());
|
|
|
|
break;
|
2018-08-03 16:54:46 +08:00
|
|
|
case Attribute::Kind::Type:
|
2018-10-26 06:46:10 +08:00
|
|
|
printType(attr.cast<TypeAttr>().getValue());
|
2018-07-19 07:29:21 +08:00
|
|
|
break;
|
2018-08-20 12:17:22 +08:00
|
|
|
case Attribute::Kind::Function: {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto *function = attr.cast<FunctionAttr>().getValue();
|
2018-08-20 12:17:22 +08:00
|
|
|
if (!function) {
|
|
|
|
os << "<<FUNCTION ATTR FOR DELETED FUNCTION>>";
|
|
|
|
} else {
|
2018-08-22 08:55:22 +08:00
|
|
|
printFunctionReference(function);
|
|
|
|
os << " : ";
|
2018-08-20 12:17:22 +08:00
|
|
|
printType(function->getType());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-10-24 04:44:04 +08:00
|
|
|
case Attribute::Kind::OpaqueElements: {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto eltsAttr = attr.cast<OpaqueElementsAttr>();
|
2018-10-24 04:44:04 +08:00
|
|
|
os << "opaque<";
|
2018-10-26 06:46:10 +08:00
|
|
|
printType(eltsAttr.getType());
|
|
|
|
os << ", " << '"' << "0x" << llvm::toHex(eltsAttr.getValue()) << '"' << '>';
|
2018-10-24 04:44:04 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-10-19 04:54:44 +08:00
|
|
|
case Attribute::Kind::DenseIntElements:
|
|
|
|
case Attribute::Kind::DenseFPElements: {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto eltsAttr = attr.cast<DenseElementsAttr>();
|
2018-10-19 04:54:44 +08:00
|
|
|
os << "dense<";
|
2018-10-26 06:46:10 +08:00
|
|
|
printType(eltsAttr.getType());
|
2018-10-19 04:54:44 +08:00
|
|
|
os << ", ";
|
|
|
|
printDenseElementsAttr(eltsAttr);
|
|
|
|
os << '>';
|
|
|
|
break;
|
|
|
|
}
|
2018-10-10 23:57:51 +08:00
|
|
|
case Attribute::Kind::SplatElements: {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto elementsAttr = attr.cast<SplatElementsAttr>();
|
2018-10-10 23:57:51 +08:00
|
|
|
os << "splat<";
|
2018-10-26 06:46:10 +08:00
|
|
|
printType(elementsAttr.getType());
|
2018-10-10 23:57:51 +08:00
|
|
|
os << ", ";
|
2018-10-26 06:46:10 +08:00
|
|
|
printAttribute(elementsAttr.getValue());
|
2018-10-10 23:57:51 +08:00
|
|
|
os << '>';
|
|
|
|
break;
|
|
|
|
}
|
Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.
The syntax is:
`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`
Example: a sparse tensor
sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor
[[1, 0, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 0]]
PiperOrigin-RevId: 217764319
2018-10-19 05:02:20 +08:00
|
|
|
case Attribute::Kind::SparseElements: {
|
2018-10-26 06:46:10 +08:00
|
|
|
auto elementsAttr = attr.cast<SparseElementsAttr>();
|
Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.
The syntax is:
`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`
Example: a sparse tensor
sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor
[[1, 0, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 0]]
PiperOrigin-RevId: 217764319
2018-10-19 05:02:20 +08:00
|
|
|
os << "sparse<";
|
2018-10-26 06:46:10 +08:00
|
|
|
printType(elementsAttr.getType());
|
Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.
The syntax is:
`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`
Example: a sparse tensor
sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor
[[1, 0, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 0]]
PiperOrigin-RevId: 217764319
2018-10-19 05:02:20 +08:00
|
|
|
os << ", ";
|
2018-10-26 06:46:10 +08:00
|
|
|
printDenseElementsAttr(elementsAttr.getIndices());
|
Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.
The syntax is:
`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`
Example: a sparse tensor
sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor
[[1, 0, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 0]]
PiperOrigin-RevId: 217764319
2018-10-19 05:02:20 +08:00
|
|
|
os << ", ";
|
2018-10-26 06:46:10 +08:00
|
|
|
printDenseElementsAttr(elementsAttr.getValues());
|
Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.
The syntax is:
`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`
Example: a sparse tensor
sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor
[[1, 0, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 0]]
PiperOrigin-RevId: 217764319
2018-10-19 05:02:20 +08:00
|
|
|
os << '>';
|
|
|
|
break;
|
|
|
|
}
|
2018-07-19 07:29:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
void ModulePrinter::printDenseElementsAttr(DenseElementsAttr attr) {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto type = attr.getType();
|
|
|
|
auto shape = type.getShape();
|
|
|
|
auto rank = type.getRank();
|
2018-10-19 04:54:44 +08:00
|
|
|
|
2018-10-26 06:46:10 +08:00
|
|
|
SmallVector<Attribute, 16> elements;
|
|
|
|
attr.getValues(elements);
|
2018-10-19 04:54:44 +08:00
|
|
|
|
|
|
|
// Special case for degenerate tensors.
|
|
|
|
if (elements.empty()) {
|
|
|
|
for (int i = 0; i < rank; ++i)
|
|
|
|
os << '[';
|
|
|
|
for (int i = 0; i < rank; ++i)
|
|
|
|
os << ']';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We use a mixed-radix counter to iterate through the shape. When we bump a
|
|
|
|
// non-least-significant digit, we emit a close bracket. When we next emit an
|
|
|
|
// element we re-open all closed brackets.
|
|
|
|
|
|
|
|
// The mixed-radix counter, with radices in 'shape'.
|
|
|
|
SmallVector<unsigned, 4> counter(rank, 0);
|
|
|
|
// The number of brackets that have been opened and not closed.
|
|
|
|
unsigned openBrackets = 0;
|
|
|
|
|
|
|
|
auto bumpCounter = [&]() {
|
|
|
|
// Bump the least significant digit.
|
|
|
|
++counter[rank - 1];
|
|
|
|
// Iterate backwards bubbling back the increment.
|
|
|
|
for (unsigned i = rank - 1; i > 0; --i)
|
|
|
|
if (counter[i] >= shape[i]) {
|
|
|
|
// Index 'i' is rolled over. Bump (i-1) and close a bracket.
|
|
|
|
counter[i] = 0;
|
|
|
|
++counter[i - 1];
|
|
|
|
--openBrackets;
|
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for (unsigned idx = 0, e = elements.size(); idx != e; ++idx) {
|
|
|
|
if (idx != 0)
|
|
|
|
os << ", ";
|
|
|
|
while (openBrackets++ < rank)
|
|
|
|
os << '[';
|
|
|
|
openBrackets = rank;
|
|
|
|
printAttribute(elements[idx]);
|
|
|
|
bumpCounter();
|
|
|
|
}
|
|
|
|
while (openBrackets-- > 0)
|
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
void ModulePrinter::printType(Type type) {
|
2019-01-11 14:08:39 +08:00
|
|
|
// Check for an alias for this type.
|
|
|
|
StringRef alias = state.getTypeAlias(type);
|
|
|
|
if (!alias.empty()) {
|
|
|
|
os << '!' << alias;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-31 05:59:22 +08:00
|
|
|
switch (type.getKind()) {
|
2019-01-03 06:16:40 +08:00
|
|
|
default: {
|
|
|
|
auto &dialect = type.getDialect();
|
2019-01-08 01:58:34 +08:00
|
|
|
os << '!' << dialect.getNamespace() << "<\"";
|
2019-01-03 06:16:40 +08:00
|
|
|
assert(dialect.typePrintHook && "Expected dialect type printing hook.");
|
|
|
|
dialect.typePrintHook(type, os);
|
|
|
|
os << "\">";
|
|
|
|
return;
|
|
|
|
}
|
2019-01-08 01:58:34 +08:00
|
|
|
case Type::Kind::Unknown: {
|
|
|
|
auto unknownTy = type.cast<UnknownType>();
|
|
|
|
os << '!' << unknownTy.getDialectNamespace() << "<\""
|
|
|
|
<< unknownTy.getTypeData() << "\">";
|
|
|
|
return;
|
|
|
|
}
|
2018-10-07 08:21:53 +08:00
|
|
|
case Type::Kind::Index:
|
|
|
|
os << "index";
|
2018-07-19 01:16:05 +08:00
|
|
|
return;
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::BF16:
|
2018-07-19 01:16:05 +08:00
|
|
|
os << "bf16";
|
|
|
|
return;
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::F16:
|
2018-07-19 01:16:05 +08:00
|
|
|
os << "f16";
|
|
|
|
return;
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::F32:
|
2018-07-19 01:16:05 +08:00
|
|
|
os << "f32";
|
|
|
|
return;
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::F64:
|
2018-07-19 01:16:05 +08:00
|
|
|
os << "f64";
|
|
|
|
return;
|
2018-07-18 07:56:54 +08:00
|
|
|
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::Integer: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto integer = type.cast<IntegerType>();
|
|
|
|
os << 'i' << integer.getWidth();
|
2018-07-18 07:56:54 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
case Type::Kind::Function: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto func = type.cast<FunctionType>();
|
2018-07-18 07:56:54 +08:00
|
|
|
os << '(';
|
2018-10-31 05:59:22 +08:00
|
|
|
interleaveComma(func.getInputs(), [&](Type type) { printType(type); });
|
2018-07-18 07:56:54 +08:00
|
|
|
os << ") -> ";
|
2018-10-31 05:59:22 +08:00
|
|
|
auto results = func.getResults();
|
2018-07-18 07:56:54 +08:00
|
|
|
if (results.size() == 1)
|
2018-10-31 05:59:22 +08:00
|
|
|
os << results[0];
|
2018-07-18 07:56:54 +08:00
|
|
|
else {
|
|
|
|
os << '(';
|
2018-10-31 05:59:22 +08:00
|
|
|
interleaveComma(results, [&](Type type) { printType(type); });
|
2018-07-18 07:56:54 +08:00
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::Vector: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto v = type.cast<VectorType>();
|
2018-07-18 07:56:54 +08:00
|
|
|
os << "vector<";
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto dim : v.getShape())
|
2018-07-24 02:44:40 +08:00
|
|
|
os << dim << 'x';
|
2018-10-31 05:59:22 +08:00
|
|
|
os << v.getElementType() << '>';
|
2018-07-18 07:56:54 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::RankedTensor: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto v = type.cast<RankedTensorType>();
|
2018-07-18 07:56:54 +08:00
|
|
|
os << "tensor<";
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto dim : v.getShape()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
if (dim < 0)
|
|
|
|
os << '?';
|
|
|
|
else
|
|
|
|
os << dim;
|
|
|
|
os << 'x';
|
|
|
|
}
|
2018-10-31 05:59:22 +08:00
|
|
|
os << v.getElementType() << '>';
|
2018-07-18 07:56:54 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::UnrankedTensor: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto v = type.cast<UnrankedTensorType>();
|
2018-09-14 01:43:35 +08:00
|
|
|
os << "tensor<*x";
|
2018-10-31 05:59:22 +08:00
|
|
|
printType(v.getElementType());
|
2018-07-26 03:55:50 +08:00
|
|
|
os << '>';
|
2018-07-18 07:56:54 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-01-04 06:29:52 +08:00
|
|
|
case StandardTypes::MemRef: {
|
2018-10-31 05:59:22 +08:00
|
|
|
auto v = type.cast<MemRefType>();
|
2018-07-18 07:56:54 +08:00
|
|
|
os << "memref<";
|
2018-10-31 05:59:22 +08:00
|
|
|
for (auto dim : v.getShape()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
if (dim < 0)
|
|
|
|
os << '?';
|
|
|
|
else
|
|
|
|
os << dim;
|
|
|
|
os << 'x';
|
|
|
|
}
|
2018-10-31 05:59:22 +08:00
|
|
|
printType(v.getElementType());
|
|
|
|
for (auto map : v.getAffineMaps()) {
|
2018-07-18 07:56:54 +08:00
|
|
|
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.
|
2018-10-31 05:59:22 +08:00
|
|
|
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-10-09 04:47:18 +08:00
|
|
|
void ModulePrinter::printAffineExpr(AffineExpr expr) {
|
2018-08-01 07:21:36 +08:00
|
|
|
printAffineExprInternal(expr, BindingStrength::Weak);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModulePrinter::printAffineExprInternal(
|
2018-10-09 04:47:18 +08:00
|
|
|
AffineExpr expr, BindingStrength enclosingTightness) {
|
2018-08-01 07:21:36 +08:00
|
|
|
const char *binopSpelling = nullptr;
|
2018-10-10 01:59:27 +08:00
|
|
|
switch (expr.getKind()) {
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::SymbolId:
|
2018-10-10 01:59:27 +08:00
|
|
|
os << 's' << expr.cast<AffineSymbolExpr>().getPosition();
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::DimId:
|
2018-10-10 01:59:27 +08:00
|
|
|
os << 'd' << expr.cast<AffineDimExpr>().getPosition();
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::Constant:
|
2018-10-10 01:59:27 +08:00
|
|
|
os << expr.cast<AffineConstantExpr>().getValue();
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::Add:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " + ";
|
|
|
|
break;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::Mul:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " * ";
|
|
|
|
break;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::FloorDiv:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " floordiv ";
|
|
|
|
break;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::CeilDiv:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " ceildiv ";
|
|
|
|
break;
|
2018-10-09 01:20:25 +08:00
|
|
|
case AffineExprKind::Mod:
|
2018-08-01 07:21:36 +08:00
|
|
|
binopSpelling = " mod ";
|
|
|
|
break;
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-10-09 04:47:18 +08:00
|
|
|
auto binOp = expr.cast<AffineBinaryOpExpr>();
|
2019-01-21 22:59:58 +08:00
|
|
|
AffineExpr lhsExpr = binOp.getLHS();
|
|
|
|
AffineExpr rhsExpr = binOp.getRHS();
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2018-08-01 07:21:36 +08:00
|
|
|
// Handle tightly binding binary operators.
|
2018-10-10 01:59:27 +08:00
|
|
|
if (binOp.getKind() != AffineExprKind::Add) {
|
2018-08-01 07:21:36 +08:00
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << '(';
|
|
|
|
|
2019-01-21 22:59:58 +08:00
|
|
|
// Pretty print multiplication with -1.
|
|
|
|
auto rhsConst = rhsExpr.dyn_cast<AffineConstantExpr>();
|
|
|
|
if (rhsConst && rhsConst.getValue() == -1) {
|
|
|
|
os << "-";
|
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Strong);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Strong);
|
2018-08-01 07:21:36 +08:00
|
|
|
os << binopSpelling;
|
2019-01-21 22:59:58 +08:00
|
|
|
printAffineExprInternal(rhsExpr, BindingStrength::Strong);
|
2018-08-01 07:21:36 +08:00
|
|
|
|
|
|
|
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-10-09 04:47:18 +08:00
|
|
|
if (auto rhs = rhsExpr.dyn_cast<AffineBinaryOpExpr>()) {
|
2018-10-10 01:59:27 +08:00
|
|
|
if (rhs.getKind() == AffineExprKind::Mul) {
|
|
|
|
AffineExpr rrhsExpr = rhs.getRHS();
|
2018-10-09 04:47:18 +08:00
|
|
|
if (auto rrhs = rrhsExpr.dyn_cast<AffineConstantExpr>()) {
|
2018-10-10 01:59:27 +08:00
|
|
|
if (rrhs.getValue() == -1) {
|
2019-01-21 22:59:58 +08:00
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Weak);
|
2018-08-01 07:21:36 +08:00
|
|
|
os << " - ";
|
2018-10-19 09:18:04 +08:00
|
|
|
if (rhs.getLHS().getKind() == AffineExprKind::Add) {
|
|
|
|
printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong);
|
|
|
|
} else {
|
|
|
|
printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak);
|
|
|
|
}
|
2018-08-01 07:21:36 +08:00
|
|
|
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-10 01:59:27 +08:00
|
|
|
if (rrhs.getValue() < -1) {
|
2019-01-21 22:59:58 +08:00
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Weak);
|
2018-08-02 13:02:00 +08:00
|
|
|
os << " - ";
|
2018-10-10 01:59:27 +08:00
|
|
|
printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong);
|
|
|
|
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.
|
2019-01-21 22:59:58 +08:00
|
|
|
if (auto rhsConst = rhsExpr.dyn_cast<AffineConstantExpr>()) {
|
|
|
|
if (rhsConst.getValue() < 0) {
|
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Weak);
|
|
|
|
os << " - " << -rhsConst.getValue();
|
2018-08-08 05:24:38 +08:00
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-21 22:59:58 +08:00
|
|
|
printAffineExprInternal(lhsExpr, BindingStrength::Weak);
|
2018-07-21 00:35:47 +08:00
|
|
|
os << " + ";
|
2019-01-21 22:59:58 +08:00
|
|
|
printAffineExprInternal(rhsExpr, BindingStrength::Weak);
|
2018-08-01 07:21:36 +08:00
|
|
|
|
|
|
|
if (enclosingTightness == BindingStrength::Strong)
|
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-10-09 04:47:18 +08:00
|
|
|
void ModulePrinter::printAffineConstraint(AffineExpr expr, bool isEq) {
|
2018-08-08 05:24:38 +08:00
|
|
|
printAffineExprInternal(expr, BindingStrength::Weak);
|
|
|
|
isEq ? os << " == 0" : os << " >= 0";
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
void ModulePrinter::printAffineMap(AffineMap map) {
|
2018-07-21 00:35:47 +08:00
|
|
|
// Dimension identifiers.
|
|
|
|
os << '(';
|
2018-10-10 07:39:24 +08:00
|
|
|
for (int i = 0; i < (int)map.getNumDims() - 1; ++i)
|
2018-07-30 05:13:03 +08:00
|
|
|
os << 'd' << i << ", ";
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumDims() >= 1)
|
|
|
|
os << 'd' << map.getNumDims() - 1;
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
|
|
|
|
// Symbolic identifiers.
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumSymbols() != 0) {
|
2018-07-30 05:13:03 +08:00
|
|
|
os << '[';
|
2018-10-10 07:39:24 +08:00
|
|
|
for (unsigned i = 0; i < map.getNumSymbols() - 1; ++i)
|
2018-07-30 05:13:03 +08:00
|
|
|
os << 's' << i << ", ";
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumSymbols() >= 1)
|
|
|
|
os << 's' << map.getNumSymbols() - 1;
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ']';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// AffineMap should have at least one result.
|
2018-10-10 07:39:24 +08:00
|
|
|
assert(!map.getResults().empty());
|
2018-07-21 00:35:47 +08:00
|
|
|
// Result affine expressions.
|
|
|
|
os << " -> (";
|
2018-10-10 07:39:24 +08:00
|
|
|
interleaveComma(map.getResults(),
|
2018-10-09 04:47:18 +08:00
|
|
|
[&](AffineExpr expr) { printAffineExpr(expr); });
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
if (!map.isBounded()) {
|
2018-07-21 00:35:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print range sizes for bounded affine maps.
|
|
|
|
os << " size (";
|
2018-10-10 07:39:24 +08:00
|
|
|
interleaveComma(map.getRangeSizes(),
|
2018-10-09 04:47:18 +08:00
|
|
|
[&](AffineExpr expr) { printAffineExpr(expr); });
|
2018-07-30 05:13:03 +08:00
|
|
|
os << ')';
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
void ModulePrinter::printIntegerSet(IntegerSet set) {
|
2018-08-08 05:24:38 +08:00
|
|
|
// Dimension identifiers.
|
|
|
|
os << '(';
|
2018-10-11 00:45:59 +08:00
|
|
|
for (unsigned i = 1; i < set.getNumDims(); ++i)
|
2018-08-08 05:24:38 +08:00
|
|
|
os << 'd' << i - 1 << ", ";
|
2018-10-11 00:45:59 +08:00
|
|
|
if (set.getNumDims() >= 1)
|
|
|
|
os << 'd' << set.getNumDims() - 1;
|
2018-08-08 05:24:38 +08:00
|
|
|
os << ')';
|
|
|
|
|
|
|
|
// Symbolic identifiers.
|
2018-10-11 00:45:59 +08:00
|
|
|
if (set.getNumSymbols() != 0) {
|
2018-08-08 05:24:38 +08:00
|
|
|
os << '[';
|
2018-10-11 00:45:59 +08:00
|
|
|
for (unsigned i = 0; i < set.getNumSymbols() - 1; ++i)
|
2018-08-08 05:24:38 +08:00
|
|
|
os << 's' << i << ", ";
|
2018-10-11 00:45:59 +08:00
|
|
|
if (set.getNumSymbols() >= 1)
|
|
|
|
os << 's' << set.getNumSymbols() - 1;
|
2018-08-08 05:24:38 +08:00
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print constraints.
|
|
|
|
os << " : (";
|
2018-10-11 00:45:59 +08:00
|
|
|
auto numConstraints = set.getNumConstraints();
|
2018-08-08 05:24:38 +08:00
|
|
|
for (int i = 1; i < numConstraints; ++i) {
|
2018-10-11 00:45:59 +08:00
|
|
|
printAffineConstraint(set.getConstraint(i - 1), set.isEq(i - 1));
|
2018-08-08 05:24:38 +08:00
|
|
|
os << ", ";
|
|
|
|
}
|
|
|
|
if (numConstraints >= 1)
|
2018-10-11 00:45:59 +08:00
|
|
|
printAffineConstraint(set.getConstraint(numConstraints - 1),
|
|
|
|
set.isEq(numConstraints - 1));
|
2018-08-08 05:24:38 +08:00
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
|
2018-06-24 07:03:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Function printing
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-09-19 07:36:26 +08:00
|
|
|
void ModulePrinter::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
|
|
|
|
ArrayRef<const char *> elidedAttrs) {
|
|
|
|
// If there are no attributes, then there is nothing to be done.
|
|
|
|
if (attrs.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Filter out any attributes that shouldn't be included.
|
|
|
|
SmallVector<NamedAttribute, 8> filteredAttrs;
|
|
|
|
for (auto attr : attrs) {
|
|
|
|
auto attrName = attr.first.strref();
|
|
|
|
// Never print attributes that start with a colon. These are internal
|
|
|
|
// attributes that represent location or other internal metadata.
|
|
|
|
if (attrName.startswith(":"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If the caller has requested that this attribute be ignored, then drop it.
|
|
|
|
bool ignore = false;
|
|
|
|
for (const char *elide : elidedAttrs)
|
|
|
|
ignore |= attrName == StringRef(elide);
|
|
|
|
|
|
|
|
// Otherwise add it to our filteredAttrs list.
|
|
|
|
if (!ignore) {
|
|
|
|
filteredAttrs.push_back(attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are no attributes left to print after filtering, then we're done.
|
|
|
|
if (filteredAttrs.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Otherwise, print them all out in braces.
|
|
|
|
os << " {";
|
|
|
|
interleaveComma(filteredAttrs, [&](NamedAttribute attr) {
|
|
|
|
os << attr.first << ": ";
|
|
|
|
printAttribute(attr.second);
|
|
|
|
});
|
|
|
|
os << '}';
|
|
|
|
}
|
|
|
|
|
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-12-29 03:41:56 +08:00
|
|
|
FunctionPrinter(const Function *function, const ModulePrinter &other);
|
|
|
|
|
|
|
|
// Prints the function as a whole.
|
|
|
|
void print();
|
|
|
|
|
|
|
|
// Print the function signature.
|
2018-12-30 05:56:57 +08:00
|
|
|
void printFunctionSignature();
|
2018-12-29 03:41:56 +08:00
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
// Methods to print instructions.
|
|
|
|
void print(const Instruction *inst);
|
2018-12-29 03:41:56 +08:00
|
|
|
void print(const OperationInst *inst);
|
2018-12-29 08:05:35 +08:00
|
|
|
void print(const ForInst *inst);
|
|
|
|
void print(const IfInst *inst);
|
2018-12-29 05:07:39 +08:00
|
|
|
void print(const Block *block);
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-12-28 13:21:41 +08:00
|
|
|
void printOperation(const OperationInst *op);
|
|
|
|
void printDefaultOp(const OperationInst *op);
|
2018-07-25 07:07:22 +08:00
|
|
|
|
|
|
|
// Implement OpAsmPrinter.
|
|
|
|
raw_ostream &getStream() const { return os; }
|
2018-10-31 05:59:22 +08:00
|
|
|
void printType(Type type) { ModulePrinter::printType(type); }
|
2018-10-26 06:46:10 +08:00
|
|
|
void printAttribute(Attribute attr) { ModulePrinter::printAttribute(attr); }
|
2018-10-10 07:39:24 +08:00
|
|
|
void printAffineMap(AffineMap map) {
|
2018-07-29 00:36:25 +08:00
|
|
|
return ModulePrinter::printAffineMapReference(map);
|
2018-07-25 07:07:22 +08:00
|
|
|
}
|
2018-10-11 00:45:59 +08:00
|
|
|
void printIntegerSet(IntegerSet set) {
|
2018-08-08 05:24:38 +08:00
|
|
|
return ModulePrinter::printIntegerSetReference(set);
|
|
|
|
}
|
2018-10-09 04:47:18 +08:00
|
|
|
void printAffineExpr(AffineExpr expr) {
|
2018-07-25 07:07:22 +08:00
|
|
|
return ModulePrinter::printAffineExpr(expr);
|
|
|
|
}
|
2018-08-22 08:55:22 +08:00
|
|
|
void printFunctionReference(const Function *func) {
|
|
|
|
return ModulePrinter::printFunctionReference(func);
|
|
|
|
}
|
2018-12-28 06:35:10 +08:00
|
|
|
void printOperand(const Value *value) { printValueID(value); }
|
2018-08-04 02:12:34 +08:00
|
|
|
|
2018-08-03 07:54:36 +08:00
|
|
|
void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
|
2018-09-19 07:36:26 +08:00
|
|
|
ArrayRef<const char *> elidedAttrs = {}) {
|
|
|
|
return ModulePrinter::printOptionalAttrDict(attrs, elidedAttrs);
|
|
|
|
};
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-08-02 01:43:18 +08:00
|
|
|
enum { nameSentinel = ~0U };
|
|
|
|
|
2018-12-31 08:22:50 +08:00
|
|
|
void printBlockName(const Block *block) {
|
|
|
|
auto id = getBlockID(block);
|
|
|
|
if (id != ~0U)
|
|
|
|
os << "^bb" << id;
|
|
|
|
else
|
|
|
|
os << "^INVALIDBLOCK";
|
|
|
|
}
|
2018-08-02 01:43:18 +08:00
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
unsigned getBlockID(const Block *block) {
|
|
|
|
auto it = blockIDs.find(block);
|
2018-12-31 08:22:50 +08:00
|
|
|
return it != blockIDs.end() ? it->second : ~0U;
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void printSuccessorAndUseList(const OperationInst *term,
|
|
|
|
unsigned index) override;
|
2018-07-21 09:41:34 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// Print if and loop bounds.
|
|
|
|
void printDimAndSymbolList(ArrayRef<InstOperand> ops, unsigned numDims);
|
|
|
|
void printBound(AffineBound bound, const char *prefix);
|
2018-07-21 09:41:34 +08:00
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
// Number of spaces used for indenting nested instructions.
|
2018-12-29 03:41:56 +08:00
|
|
|
const static unsigned indentWidth = 2;
|
2018-07-31 06:18:10 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
protected:
|
|
|
|
void numberValueID(const Value *value);
|
2018-12-29 05:07:39 +08:00
|
|
|
void numberValuesInBlock(const Block &block);
|
2018-12-29 03:41:56 +08:00
|
|
|
void printValueID(const Value *value, bool printResultNo = true) const;
|
2018-07-21 00:28:54 +08:00
|
|
|
|
|
|
|
private:
|
2018-12-29 03:41:56 +08:00
|
|
|
const Function *function;
|
|
|
|
|
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-12-28 06:35:10 +08:00
|
|
|
DenseMap<const Value *, unsigned> valueIDs;
|
|
|
|
DenseMap<const Value *, StringRef> valueNames;
|
2018-08-02 01:43:18 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
/// This is the block ID for each block in the current function.
|
2018-12-29 05:07:39 +08:00
|
|
|
DenseMap<const Block *, unsigned> blockIDs;
|
2018-12-29 03:41:56 +08:00
|
|
|
|
2018-08-02 01:43:18 +08:00
|
|
|
/// This keeps track of all of the non-numeric names that are in flight,
|
|
|
|
/// allowing us to check for duplicates.
|
|
|
|
llvm::StringSet<> usedNames;
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// This is the current indentation level for nested structures.
|
|
|
|
unsigned currentIndent = 0;
|
|
|
|
|
2018-08-02 01:43:18 +08:00
|
|
|
/// 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-12-29 00:48:09 +08:00
|
|
|
/// This is the next ID to assign to a Function argument.
|
2018-08-02 01:43:18 +08:00
|
|
|
unsigned nextArgumentID = 0;
|
|
|
|
/// This is the next ID to assign when a name conflict is detected.
|
|
|
|
unsigned nextConflictID = 0;
|
2018-12-29 03:41:56 +08:00
|
|
|
/// This is the next block ID to assign in numbering.
|
|
|
|
unsigned nextBlockID = 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-12-29 03:41:56 +08:00
|
|
|
FunctionPrinter::FunctionPrinter(const Function *function,
|
|
|
|
const ModulePrinter &other)
|
|
|
|
: ModulePrinter(other), function(function) {
|
2018-07-10 08:42:46 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
for (auto &block : *function)
|
|
|
|
numberValuesInBlock(block);
|
2018-07-10 08:42:46 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
/// Number all of the SSA values in the specified block list.
|
2018-12-29 05:07:39 +08:00
|
|
|
void FunctionPrinter::numberValuesInBlock(const Block &block) {
|
2018-12-29 03:41:56 +08:00
|
|
|
// Each block gets a unique ID, and all of the instructions within it get
|
|
|
|
// numbered as well.
|
2018-12-29 05:07:39 +08:00
|
|
|
blockIDs[&block] = nextBlockID++;
|
2018-07-21 00:28:54 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
for (auto *arg : block.getArguments())
|
2018-07-23 06:45:24 +08:00
|
|
|
numberValueID(arg);
|
2018-12-29 03:41:56 +08:00
|
|
|
|
|
|
|
for (auto &inst : block) {
|
2018-07-21 00:28:54 +08:00
|
|
|
// We number instruction that have results, and we only number the first
|
|
|
|
// result.
|
2018-12-29 03:41:56 +08:00
|
|
|
switch (inst.getKind()) {
|
2018-12-29 08:05:35 +08:00
|
|
|
case Instruction::Kind::OperationInst: {
|
2018-12-29 03:41:56 +08:00
|
|
|
auto *opInst = cast<OperationInst>(&inst);
|
2018-12-28 03:07:34 +08:00
|
|
|
if (opInst->getNumResults() != 0)
|
|
|
|
numberValueID(opInst->getResult(0));
|
2018-12-29 03:41:56 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-12-29 08:05:35 +08:00
|
|
|
case Instruction::Kind::For: {
|
|
|
|
auto *forInst = cast<ForInst>(&inst);
|
2018-12-29 03:41:56 +08:00
|
|
|
// Number the induction variable.
|
|
|
|
numberValueID(forInst);
|
|
|
|
// Recursively number the stuff in the body.
|
|
|
|
numberValuesInBlock(*forInst->getBody());
|
|
|
|
break;
|
|
|
|
}
|
2018-12-29 08:05:35 +08:00
|
|
|
case Instruction::Kind::If: {
|
|
|
|
auto *ifInst = cast<IfInst>(&inst);
|
2018-12-29 03:41:56 +08:00
|
|
|
numberValuesInBlock(*ifInst->getThen());
|
|
|
|
if (auto *elseBlock = ifInst->getElse())
|
|
|
|
numberValuesInBlock(*elseBlock);
|
|
|
|
}
|
|
|
|
}
|
2018-07-21 00:28:54 +08:00
|
|
|
}
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void FunctionPrinter::numberValueID(const Value *value) {
|
|
|
|
assert(!valueIDs.count(value) && "Value numbered multiple times");
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
SmallString<32> specialNameBuffer;
|
|
|
|
llvm::raw_svector_ostream specialName(specialNameBuffer);
|
2018-07-23 06:45:24 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// Give constant integers special names.
|
|
|
|
if (auto *op = value->getDefiningInst()) {
|
|
|
|
if (auto intOp = op->dyn_cast<ConstantIntOp>()) {
|
|
|
|
// i1 constants get special names.
|
|
|
|
if (intOp->getType().isInteger(1)) {
|
|
|
|
specialName << (intOp->getValue() ? "true" : "false");
|
|
|
|
} else {
|
|
|
|
specialName << 'c' << intOp->getValue() << '_' << intOp->getType();
|
|
|
|
}
|
|
|
|
} else if (auto intOp = op->dyn_cast<ConstantIndexOp>()) {
|
|
|
|
specialName << 'c' << intOp->getValue();
|
|
|
|
} else if (auto constant = op->dyn_cast<ConstantOp>()) {
|
|
|
|
if (constant->getValue().isa<FunctionAttr>())
|
|
|
|
specialName << 'f';
|
|
|
|
else
|
|
|
|
specialName << "cst";
|
|
|
|
}
|
2018-07-23 06:45:24 +08:00
|
|
|
}
|
2018-07-28 02:10:12 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
if (specialNameBuffer.empty()) {
|
|
|
|
switch (value->getKind()) {
|
|
|
|
case Value::Kind::BlockArgument:
|
|
|
|
// If this is an argument to the function, give it an 'arg' name.
|
|
|
|
if (auto *block = cast<BlockArgument>(value)->getOwner())
|
|
|
|
if (auto *fn = block->getFunction())
|
|
|
|
if (&fn->getBlockList().front() == block) {
|
|
|
|
specialName << "arg" << nextArgumentID++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Otherwise number it normally.
|
|
|
|
valueIDs[value] = nextValueID++;
|
|
|
|
return;
|
|
|
|
case Value::Kind::InstResult:
|
|
|
|
// This is an uninteresting result, give it a boring number and be
|
|
|
|
// done with it.
|
|
|
|
valueIDs[value] = nextValueID++;
|
|
|
|
return;
|
2018-12-29 08:05:35 +08:00
|
|
|
case Value::Kind::ForInst:
|
2018-12-29 03:41:56 +08:00
|
|
|
specialName << 'i' << nextLoopID++;
|
|
|
|
break;
|
|
|
|
}
|
2018-07-28 02:10:12 +08:00
|
|
|
}
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// Ok, this value had an interesting name. Remember it with a sentinel.
|
|
|
|
valueIDs[value] = nameSentinel;
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// 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();
|
2018-09-07 00:17:08 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-07-23 23:42:19 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// 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-11-16 01:56:06 +08:00
|
|
|
}
|
2018-07-27 09:09:20 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void FunctionPrinter::print() {
|
2018-12-30 05:56:57 +08:00
|
|
|
printFunctionSignature();
|
2018-07-27 09:09:20 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// Print out function attributes, if present.
|
|
|
|
auto attrs = function->getAttrs();
|
|
|
|
if (!attrs.empty()) {
|
|
|
|
os << "\n attributes ";
|
|
|
|
printOptionalAttrDict(attrs);
|
|
|
|
}
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
if (!function->empty()) {
|
|
|
|
os << " {\n";
|
|
|
|
for (const auto &block : *function)
|
|
|
|
print(&block);
|
|
|
|
os << "}\n";
|
|
|
|
}
|
|
|
|
os << '\n';
|
2018-07-04 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 05:56:57 +08:00
|
|
|
void FunctionPrinter::printFunctionSignature() {
|
2019-01-03 02:20:00 +08:00
|
|
|
os << "func @" << function->getName() << '(';
|
2018-12-30 05:56:57 +08:00
|
|
|
|
|
|
|
auto fnType = function->getType();
|
|
|
|
|
|
|
|
// If this is an external function, don't print argument labels.
|
|
|
|
if (function->empty()) {
|
|
|
|
interleaveComma(fnType.getInputs(),
|
|
|
|
[&](Type eltType) { printType(eltType); });
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 0, e = function->getNumArguments(); i != e; ++i) {
|
|
|
|
if (i > 0)
|
|
|
|
os << ", ";
|
|
|
|
auto *arg = function->getArgument(i);
|
|
|
|
printOperand(arg);
|
|
|
|
os << ": ";
|
|
|
|
printType(arg->getType());
|
|
|
|
}
|
|
|
|
}
|
2018-12-29 03:41:56 +08:00
|
|
|
os << ')';
|
|
|
|
|
2018-12-30 05:56:57 +08:00
|
|
|
switch (fnType.getResults().size()) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
os << " -> ";
|
|
|
|
printType(fnType.getResults()[0]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
os << " -> (";
|
|
|
|
interleaveComma(fnType.getResults(),
|
|
|
|
[&](Type eltType) { printType(eltType); });
|
|
|
|
os << ')';
|
|
|
|
break;
|
|
|
|
}
|
2018-08-07 02:54:39 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 07:33:43 +08:00
|
|
|
/// Return true if the introducer for the specified block should be printed.
|
|
|
|
static bool shouldPrintBlockArguments(const Block *block) {
|
|
|
|
// Never print the entry block of the function - it is included in the
|
|
|
|
// argument list.
|
|
|
|
if (block == &block->getFunction()->front())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If this is the first block in a nested region, and if there are no
|
|
|
|
// arguments, then we can omit it.
|
|
|
|
if (block == &block->getParent()->front() && block->getNumArguments() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Otherwise print it.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
void FunctionPrinter::print(const Block *block) {
|
2018-12-30 05:56:57 +08:00
|
|
|
// Print the block label and argument list, unless this is the first block of
|
|
|
|
// the function, or the first block of an IfInst/ForInst with no arguments.
|
2018-12-30 07:33:43 +08:00
|
|
|
if (shouldPrintBlockArguments(block)) {
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent);
|
2018-12-29 05:07:39 +08:00
|
|
|
printBlockName(block);
|
2018-12-29 03:41:56 +08:00
|
|
|
|
|
|
|
// Print the argument list if non-empty.
|
|
|
|
if (!block->args_empty()) {
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(block->getArguments(), [&](const BlockArgument *arg) {
|
|
|
|
printValueID(arg);
|
|
|
|
os << ": ";
|
|
|
|
printType(arg->getType());
|
|
|
|
});
|
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
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()) {
|
2018-12-30 05:56:57 +08:00
|
|
|
os << "\t// no predecessors";
|
2018-12-29 03:41:56 +08:00
|
|
|
} else if (auto *pred = block->getSinglePredecessor()) {
|
|
|
|
os << "\t// pred: ";
|
2018-12-29 05:07:39 +08:00
|
|
|
printBlockName(pred);
|
2018-12-29 03:41:56 +08:00
|
|
|
} 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.
|
2018-12-31 08:22:50 +08:00
|
|
|
SmallVector<std::pair<unsigned, const Block *>, 4> predIDs;
|
2018-12-29 03:41:56 +08:00
|
|
|
for (auto *pred : block->getPredecessors())
|
2018-12-31 08:22:50 +08:00
|
|
|
predIDs.push_back({getBlockID(pred), pred});
|
2018-12-29 03:41:56 +08:00
|
|
|
llvm::array_pod_sort(predIDs.begin(), predIDs.end());
|
|
|
|
|
|
|
|
os << "\t// " << predIDs.size() << " preds: ";
|
|
|
|
|
2018-12-31 08:22:50 +08:00
|
|
|
interleaveComma(predIDs, [&](std::pair<unsigned, const Block *> pred) {
|
|
|
|
printBlockName(pred.second);
|
|
|
|
});
|
2018-12-29 03:41:56 +08:00
|
|
|
}
|
|
|
|
os << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
currentIndent += indentWidth;
|
2018-12-29 05:07:39 +08:00
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
for (auto &inst : block->getInstructions()) {
|
|
|
|
print(&inst);
|
2018-12-29 03:41:56 +08:00
|
|
|
os << '\n';
|
2018-07-15 15:06:54 +08:00
|
|
|
}
|
2018-12-29 03:41:56 +08:00
|
|
|
currentIndent -= indentWidth;
|
2018-07-14 04:03:13 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void FunctionPrinter::print(const Instruction *inst) {
|
|
|
|
switch (inst->getKind()) {
|
|
|
|
case Instruction::Kind::OperationInst:
|
|
|
|
return print(cast<OperationInst>(inst));
|
|
|
|
case Instruction::Kind::For:
|
|
|
|
return print(cast<ForInst>(inst));
|
|
|
|
case Instruction::Kind::If:
|
|
|
|
return print(cast<IfInst>(inst));
|
2018-07-04 08:51:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void FunctionPrinter::print(const OperationInst *inst) {
|
|
|
|
os.indent(currentIndent);
|
|
|
|
printOperation(inst);
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
2018-07-04 08:51:28 +08:00
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void FunctionPrinter::print(const ForInst *inst) {
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent) << "for ";
|
2018-12-29 08:05:35 +08:00
|
|
|
printOperand(inst);
|
2018-08-25 14:38:14 +08:00
|
|
|
os << " = ";
|
2018-12-29 08:05:35 +08:00
|
|
|
printBound(inst->getLowerBound(), "max");
|
2018-08-25 14:38:14 +08:00
|
|
|
os << " to ";
|
2018-12-29 08:05:35 +08:00
|
|
|
printBound(inst->getUpperBound(), "min");
|
2018-08-25 14:38:14 +08:00
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
if (inst->getStep() != 1)
|
|
|
|
os << " step " << inst->getStep();
|
2018-07-20 00:52:39 +08:00
|
|
|
|
|
|
|
os << " {\n";
|
2018-12-29 08:05:35 +08:00
|
|
|
print(inst->getBody());
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent) << "}";
|
|
|
|
}
|
|
|
|
|
2018-12-29 08:05:35 +08:00
|
|
|
void FunctionPrinter::print(const IfInst *inst) {
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent) << "if ";
|
2018-12-29 08:05:35 +08:00
|
|
|
IntegerSet set = inst->getIntegerSet();
|
2018-12-29 03:41:56 +08:00
|
|
|
printIntegerSetReference(set);
|
2018-12-29 08:05:35 +08:00
|
|
|
printDimAndSymbolList(inst->getInstOperands(), set.getNumDims());
|
2018-12-29 03:41:56 +08:00
|
|
|
os << " {\n";
|
2018-12-29 08:05:35 +08:00
|
|
|
print(inst->getThen());
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent) << "}";
|
2018-12-29 08:05:35 +08:00
|
|
|
if (inst->hasElse()) {
|
2018-12-29 03:41:56 +08:00
|
|
|
os << " else {\n";
|
2018-12-29 08:05:35 +08:00
|
|
|
print(inst->getElse());
|
2018-12-29 03:41:56 +08:00
|
|
|
os.indent(currentIndent) << "}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionPrinter::printValueID(const Value *value,
|
|
|
|
bool printResultNo) const {
|
|
|
|
int resultNo = -1;
|
|
|
|
auto lookupValue = value;
|
|
|
|
|
|
|
|
// If this is a reference to the result of a multi-result instruction or
|
2018-12-29 08:05:35 +08:00
|
|
|
// instruction, print out the # identifier and make sure to map our lookup
|
2018-12-29 03:41:56 +08:00
|
|
|
// to the first result of the instruction.
|
|
|
|
if (auto *result = dyn_cast<InstResult>(value)) {
|
|
|
|
if (result->getOwner()->getNumResults() != 1) {
|
|
|
|
resultNo = result->getResultNumber();
|
|
|
|
lookupValue = result->getOwner()->getResult(0);
|
|
|
|
}
|
|
|
|
} else if (auto *result = dyn_cast<InstResult>(value)) {
|
|
|
|
if (result->getOwner()->getNumResults() != 1) {
|
|
|
|
resultNo = result->getResultNumber();
|
|
|
|
lookupValue = result->getOwner()->getResult(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = valueIDs.find(lookupValue);
|
|
|
|
if (it == valueIDs.end()) {
|
|
|
|
os << "<<INVALID SSA VALUE>>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
os << '%';
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resultNo != -1 && printResultNo)
|
|
|
|
os << '#' << resultNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionPrinter::printOperation(const OperationInst *op) {
|
|
|
|
if (op->getNumResults()) {
|
|
|
|
printValueID(op->getResult(0), /*printResultNo=*/false);
|
|
|
|
os << " = ";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if this is a known operation. If so, use the registered
|
|
|
|
// custom printer hook.
|
|
|
|
if (auto *opInfo = op->getAbstractOperation()) {
|
|
|
|
opInfo->printAssembly(op, this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise use the standard verbose printing approach.
|
|
|
|
printDefaultOp(op);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionPrinter::printDefaultOp(const OperationInst *op) {
|
|
|
|
os << '"';
|
|
|
|
printEscapedString(op->getName().getStringRef(), os);
|
|
|
|
os << "\"(";
|
|
|
|
|
2019-01-10 04:28:30 +08:00
|
|
|
// Get the list of operands that are not successor operands.
|
|
|
|
unsigned totalNumSuccessorOperands = 0;
|
|
|
|
unsigned numSuccessors = op->getNumSuccessors();
|
|
|
|
for (unsigned i = 0; i < numSuccessors; ++i)
|
|
|
|
totalNumSuccessorOperands += op->getNumSuccessorOperands(i);
|
|
|
|
unsigned numProperOperands = op->getNumOperands() - totalNumSuccessorOperands;
|
|
|
|
SmallVector<const Value *, 8> properOperands(
|
|
|
|
op->operand_begin(), std::next(op->operand_begin(), numProperOperands));
|
|
|
|
|
|
|
|
interleaveComma(properOperands,
|
2018-12-29 03:41:56 +08:00
|
|
|
[&](const Value *value) { printValueID(value); });
|
|
|
|
|
|
|
|
os << ')';
|
2019-01-10 04:28:30 +08:00
|
|
|
|
|
|
|
// For terminators, print the list of successors and their operands.
|
|
|
|
if (op->isTerminator() && numSuccessors > 0) {
|
|
|
|
os << '[';
|
|
|
|
for (unsigned i = 0; i < numSuccessors; ++i) {
|
|
|
|
if (i != 0)
|
|
|
|
os << ", ";
|
|
|
|
printSuccessorAndUseList(op, i);
|
|
|
|
}
|
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
auto attrs = op->getAttrs();
|
|
|
|
printOptionalAttrDict(attrs);
|
|
|
|
|
|
|
|
// Print the type signature of the operation.
|
|
|
|
os << " : (";
|
2019-01-10 04:28:30 +08:00
|
|
|
interleaveComma(properOperands,
|
2018-12-29 03:41:56 +08:00
|
|
|
[&](const Value *value) { printType(value->getType()); });
|
|
|
|
os << ") -> ";
|
|
|
|
|
|
|
|
if (op->getNumResults() == 1) {
|
|
|
|
printType(op->getResult(0)->getType());
|
|
|
|
} else {
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(op->getResults(),
|
|
|
|
[&](const Value *result) { printType(result->getType()); });
|
|
|
|
os << ')';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionPrinter::printSuccessorAndUseList(const OperationInst *term,
|
|
|
|
unsigned index) {
|
2018-12-29 05:07:39 +08:00
|
|
|
printBlockName(term->getSuccessor(index));
|
2018-12-29 03:41:56 +08:00
|
|
|
|
|
|
|
auto succOperands = term->getSuccessorOperands(index);
|
|
|
|
if (succOperands.begin() == succOperands.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
os << '(';
|
|
|
|
interleaveComma(succOperands,
|
|
|
|
[this](const Value *operand) { printValueID(operand); });
|
|
|
|
os << " : ";
|
|
|
|
interleaveComma(succOperands, [this](const Value *operand) {
|
|
|
|
printType(operand->getType());
|
|
|
|
});
|
|
|
|
os << ')';
|
2018-07-04 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void FunctionPrinter::printDimAndSymbolList(ArrayRef<InstOperand> ops,
|
|
|
|
unsigned numDims) {
|
2018-08-25 14:38:14 +08:00
|
|
|
auto printComma = [&]() { os << ", "; };
|
|
|
|
os << '(';
|
2018-12-28 20:14:52 +08:00
|
|
|
interleave(
|
|
|
|
ops.begin(), ops.begin() + numDims,
|
|
|
|
[&](const InstOperand &v) { printOperand(v.get()); }, printComma);
|
2018-08-25 14:38:14 +08:00
|
|
|
os << ')';
|
|
|
|
|
|
|
|
if (numDims < ops.size()) {
|
|
|
|
os << '[';
|
2018-12-28 20:14:52 +08:00
|
|
|
interleave(
|
|
|
|
ops.begin() + numDims, ops.end(),
|
|
|
|
[&](const InstOperand &v) { printOperand(v.get()); }, printComma);
|
2018-08-25 14:38:14 +08:00
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
void FunctionPrinter::printBound(AffineBound bound, const char *prefix) {
|
2018-10-10 07:39:24 +08:00
|
|
|
AffineMap map = bound.getMap();
|
2018-08-25 14:38:14 +08:00
|
|
|
|
|
|
|
// Check if this bound should be printed using short-hand notation.
|
2018-09-26 08:15:54 +08:00
|
|
|
// The decision to restrict printing short-hand notation to trivial cases
|
|
|
|
// comes from the will to roundtrip MLIR binary -> text -> binary in a
|
|
|
|
// lossless way.
|
|
|
|
// Therefore, short-hand parsing and printing is only supported for
|
|
|
|
// zero-operand constant maps and single symbol operand identity maps.
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumResults() == 1) {
|
|
|
|
AffineExpr expr = map.getResult(0);
|
2018-08-25 14:38:14 +08:00
|
|
|
|
|
|
|
// Print constant bound.
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumDims() == 0 && map.getNumSymbols() == 0) {
|
2018-10-09 04:47:18 +08:00
|
|
|
if (auto constExpr = expr.dyn_cast<AffineConstantExpr>()) {
|
2018-10-10 01:59:27 +08:00
|
|
|
os << constExpr.getValue();
|
2018-09-26 08:15:54 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-08-25 14:38:14 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 08:15:54 +08:00
|
|
|
// Print bound that consists of a single SSA symbol if the map is over a
|
|
|
|
// single symbol.
|
2018-10-10 07:39:24 +08:00
|
|
|
if (map.getNumDims() == 0 && map.getNumSymbols() == 1) {
|
2018-10-09 04:47:18 +08:00
|
|
|
if (auto symExpr = expr.dyn_cast<AffineSymbolExpr>()) {
|
2018-09-26 08:15:54 +08:00
|
|
|
printOperand(bound.getOperand(0));
|
|
|
|
return;
|
|
|
|
}
|
2018-08-25 14:38:14 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Map has multiple results. Print 'min' or 'max' prefix.
|
|
|
|
os << prefix << ' ';
|
|
|
|
}
|
|
|
|
|
2018-09-26 08:15:54 +08:00
|
|
|
// Print the map and its operands.
|
2018-08-25 14:38:14 +08:00
|
|
|
printAffineMapReference(map);
|
2018-12-28 20:14:52 +08:00
|
|
|
printDimAndSymbolList(bound.getInstOperands(), map.getNumDims());
|
2018-08-25 14:38:14 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
// Prints function with initialized module state.
|
|
|
|
void ModulePrinter::print(const Function *fn) {
|
|
|
|
FunctionPrinter(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-10-26 06:46:10 +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-10-31 05:59: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-10-10 07:39:24 +08:00
|
|
|
void AffineMap::dump() const {
|
2018-07-17 00:45:22 +08:00
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
|
|
|
}
|
2018-07-10 00:00:25 +08:00
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
void IntegerSet::dump() const {
|
2018-08-08 05:24:38 +08:00
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
|
|
|
}
|
|
|
|
|
2018-10-10 01:59:27 +08:00
|
|
|
void AffineExpr::print(raw_ostream &os) const {
|
2019-01-08 09:34:26 +08:00
|
|
|
if (expr == nullptr) {
|
|
|
|
os << "null affine expr";
|
|
|
|
return;
|
|
|
|
}
|
2018-10-22 10:49:31 +08:00
|
|
|
ModuleState state(getContext());
|
2018-10-10 01:59:27 +08:00
|
|
|
ModulePrinter(os, state).printAffineExpr(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffineExpr::dump() const {
|
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
2018-06-30 09:09:29 +08:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:39:24 +08:00
|
|
|
void AffineMap::print(raw_ostream &os) const {
|
2019-01-08 09:34:26 +08:00
|
|
|
if (map == nullptr) {
|
|
|
|
os << "null affine map";
|
|
|
|
return;
|
|
|
|
}
|
2018-10-23 02:47:10 +08:00
|
|
|
ModuleState state(getContext());
|
2018-10-10 07:39:24 +08:00
|
|
|
ModulePrinter(os, state).printAffineMap(*this);
|
2018-07-21 00:35:47 +08:00
|
|
|
}
|
2018-07-12 12:31:07 +08:00
|
|
|
|
2018-10-11 00:45:59 +08:00
|
|
|
void IntegerSet::print(raw_ostream &os) const {
|
2018-08-08 05:24:38 +08:00
|
|
|
ModuleState state(/*no context is known*/ nullptr);
|
2018-10-11 00:45:59 +08:00
|
|
|
ModulePrinter(os, state).printIntegerSet(*this);
|
2018-08-08 05:24:38 +08:00
|
|
|
}
|
|
|
|
|
2018-12-28 06:35:10 +08:00
|
|
|
void Value::print(raw_ostream &os) const {
|
2018-08-03 08:16:58 +08:00
|
|
|
switch (getKind()) {
|
2018-12-28 06:35:10 +08:00
|
|
|
case Value::Kind::BlockArgument:
|
2018-08-03 08:16:58 +08:00
|
|
|
// TODO: Improve this.
|
2018-12-25 10:01:01 +08:00
|
|
|
os << "<block argument>\n";
|
2018-08-03 08:16:58 +08:00
|
|
|
return;
|
2018-12-28 20:14:52 +08:00
|
|
|
case Value::Kind::InstResult:
|
2018-12-28 13:21:41 +08:00
|
|
|
return getDefiningInst()->print(os);
|
2018-12-29 08:05:35 +08:00
|
|
|
case Value::Kind::ForInst:
|
|
|
|
return cast<ForInst>(this)->print(os);
|
2018-08-03 08:16:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-28 06:35:10 +08:00
|
|
|
void Value::dump() const { print(llvm::errs()); }
|
2018-08-03 08:16:58 +08:00
|
|
|
|
2018-07-21 00:35:47 +08:00
|
|
|
void Instruction::print(raw_ostream &os) const {
|
2018-12-28 03:07:34 +08:00
|
|
|
auto *function = getFunction();
|
|
|
|
if (!function) {
|
2018-08-04 02:12:34 +08:00
|
|
|
os << "<<UNLINKED INSTRUCTION>>\n";
|
|
|
|
return;
|
|
|
|
}
|
2018-12-29 03:41:56 +08:00
|
|
|
|
|
|
|
ModuleState state(function->getContext());
|
|
|
|
ModulePrinter modulePrinter(os, state);
|
|
|
|
FunctionPrinter(function, modulePrinter).print(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::dump() const {
|
|
|
|
print(llvm::errs());
|
|
|
|
llvm::errs() << "\n";
|
2018-06-30 09:09:29 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
void Block::print(raw_ostream &os) const {
|
2018-12-28 03:07:34 +08:00
|
|
|
auto *function = getFunction();
|
|
|
|
if (!function) {
|
2018-08-04 02:12:34 +08:00
|
|
|
os << "<<UNLINKED BLOCK>>\n";
|
|
|
|
return;
|
|
|
|
}
|
2018-12-28 03:07:34 +08:00
|
|
|
|
2018-12-29 03:41:56 +08:00
|
|
|
ModuleState state(function->getContext());
|
|
|
|
ModulePrinter modulePrinter(os, state);
|
|
|
|
FunctionPrinter(function, modulePrinter).print(this);
|
2018-06-24 07:03:42 +08:00
|
|
|
}
|
|
|
|
|
2018-12-29 05:07:39 +08:00
|
|
|
void Block::dump() const { print(llvm::errs()); }
|
2018-06-24 07:03:42 +08:00
|
|
|
|
2018-12-29 13:24:30 +08:00
|
|
|
/// Print out the name of the block without printing its body.
|
2018-12-29 05:07:39 +08:00
|
|
|
void Block::printAsOperand(raw_ostream &os, bool printType) {
|
2018-09-22 05:40:36 +08:00
|
|
|
if (!getFunction()) {
|
|
|
|
os << "<<UNLINKED BLOCK>>\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ModuleState state(getFunction()->getContext());
|
|
|
|
ModulePrinter modulePrinter(os, state);
|
2018-12-29 05:07:39 +08:00
|
|
|
FunctionPrinter(getFunction(), modulePrinter).printBlockName(this);
|
2018-09-22 05:40:36 +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()); }
|
2018-11-10 03:27:28 +08:00
|
|
|
|
|
|
|
void Location::print(raw_ostream &os) const {
|
|
|
|
switch (getKind()) {
|
|
|
|
case Kind::Unknown:
|
|
|
|
os << "[unknown-location]";
|
|
|
|
break;
|
|
|
|
case Kind::FileLineCol: {
|
|
|
|
auto fileLoc = cast<FileLineColLoc>();
|
|
|
|
os << fileLoc.getFilename() << ':' << fileLoc.getLine() << ':'
|
|
|
|
<< fileLoc.getColumn();
|
|
|
|
break;
|
|
|
|
}
|
2018-12-27 04:12:28 +08:00
|
|
|
case Kind::Name: {
|
|
|
|
auto nameLoc = cast<NameLoc>();
|
|
|
|
os << nameLoc.getName();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Kind::CallSite: {
|
|
|
|
auto callLocation = cast<CallSiteLoc>();
|
|
|
|
auto callee = callLocation.getCallee();
|
|
|
|
auto caller = callLocation.getCaller();
|
|
|
|
callee.print(os);
|
|
|
|
if (caller.isa<CallSiteLoc>()) {
|
|
|
|
os << "\n at ";
|
|
|
|
}
|
|
|
|
caller.print(os);
|
|
|
|
break;
|
|
|
|
}
|
2018-11-10 03:27:28 +08:00
|
|
|
case Kind::FusedLocation: {
|
|
|
|
auto fusedLoc = cast<FusedLoc>();
|
|
|
|
if (auto metadata = fusedLoc.getMetadata())
|
|
|
|
os << '<' << metadata << '>';
|
|
|
|
os << '[';
|
|
|
|
interleave(
|
|
|
|
fusedLoc.getLocations(), [&](Location loc) { loc.print(os); },
|
|
|
|
[&]() { os << ", "; });
|
|
|
|
os << ']';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Location::dump() const { print(llvm::errs()); }
|