llvm/mlir/lib/IR/AsmPrinter.cpp

//===- AsmPrinter.cpp - MLIR Assembly Printer Implementation --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the MLIR AsmPrinter class, which is used to implement
// the various print() methods on the core IR objects.
//
//===----------------------------------------------------------------------===//

#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/BuiltinTypeInterfaces.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/DialectResourceBlobManager.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Verifier.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#include <type_traits>

#include <optional>
#include <tuple>

usingnamespacemlir;
usingnamespacemlir::detail;

#define DEBUG_TYPE

void OperationName::print(raw_ostream &os) const {}

void OperationName::dump() const {}

//===--------------------------------------------------------------------===//
// AsmParser
//===--------------------------------------------------------------------===//

AsmParser::~AsmParser() = default;
DialectAsmParser::~DialectAsmParser() = default;
OpAsmParser::~OpAsmParser() = default;

MLIRContext *AsmParser::getContext() const {}

/// Parse a type list.
/// This is out-of-line to work-around https://github.com/llvm/llvm-project/issues/62918
ParseResult AsmParser::parseTypeList(SmallVectorImpl<Type> &result) {}

//===----------------------------------------------------------------------===//
// DialectAsmPrinter
//===----------------------------------------------------------------------===//

DialectAsmPrinter::~DialectAsmPrinter() = default;

//===----------------------------------------------------------------------===//
// OpAsmPrinter
//===----------------------------------------------------------------------===//

OpAsmPrinter::~OpAsmPrinter() = default;

void OpAsmPrinter::printFunctionalType(Operation *op) {}

//===----------------------------------------------------------------------===//
// Operation OpAsm interface.
//===----------------------------------------------------------------------===//

/// The OpAsmOpInterface, see OpAsmInterface.td for more details.
#include "mlir/IR/OpAsmInterface.cpp.inc"

LogicalResult
OpAsmDialectInterface::parseResource(AsmParsedResourceEntry &entry) const {}

//===----------------------------------------------------------------------===//
// OpPrintingFlags
//===----------------------------------------------------------------------===//

namespace {
/// This struct contains command line options that can be used to initialize
/// various bits of the AsmPrinter. This uses a struct wrapper to avoid the need
/// for global command line options.
struct AsmPrinterOptions {};
} // namespace

static llvm::ManagedStatic<AsmPrinterOptions> clOptions;

/// Register a set of useful command-line options that can be used to configure
/// various flags within the AsmPrinter.
void mlir::registerAsmPrinterCLOptions() {}

/// Initialize the printing flags with default supplied by the cl::opts above.
OpPrintingFlags::OpPrintingFlags()
    :{}

/// Enable the elision of large elements attributes, by printing a '...'
/// instead of the element data, when the number of elements is greater than
/// `largeElementLimit`. Note: The IR generated with this option is not
/// parsable.
OpPrintingFlags &
OpPrintingFlags::elideLargeElementsAttrs(int64_t largeElementLimit) {}

OpPrintingFlags &
OpPrintingFlags::printLargeElementsAttrWithHex(int64_t largeElementLimit) {}

OpPrintingFlags &
OpPrintingFlags::elideLargeResourceString(int64_t largeResourceLimit) {}

/// Enable printing of debug information. If 'prettyForm' is set to true,
/// debug information is printed in a more readable 'pretty' form.
OpPrintingFlags &OpPrintingFlags::enableDebugInfo(bool enable,
                                                  bool prettyForm) {}

/// Always print operations in the generic form.
OpPrintingFlags &OpPrintingFlags::printGenericOpForm(bool enable) {}

/// Always skip Regions.
OpPrintingFlags &OpPrintingFlags::skipRegions(bool skip) {}

/// Do not verify the operation when using custom operation printers.
OpPrintingFlags &OpPrintingFlags::assumeVerified() {}

/// Use local scope when printing the operation. This allows for using the
/// printer in a more localized and thread-safe setting, but may not necessarily
/// be identical of what the IR will look like when dumping the full module.
OpPrintingFlags &OpPrintingFlags::useLocalScope() {}

/// Print users of values as comments.
OpPrintingFlags &OpPrintingFlags::printValueUsers() {}

/// Return if the given ElementsAttr should be elided.
bool OpPrintingFlags::shouldElideElementsAttr(ElementsAttr attr) const {}

/// Return if the given ElementsAttr should be printed as hex string.
bool OpPrintingFlags::shouldPrintElementsAttrWithHex(ElementsAttr attr) const {}

/// Return the size limit for printing large ElementsAttr.
std::optional<int64_t> OpPrintingFlags::getLargeElementsAttrLimit() const {}

/// Return the size limit for printing large ElementsAttr as hex string.
int64_t OpPrintingFlags::getLargeElementsAttrHexLimit() const {}

/// Return the size limit for printing large ElementsAttr.
std::optional<uint64_t> OpPrintingFlags::getLargeResourceStringLimit() const {}

/// Return if debug information should be printed.
bool OpPrintingFlags::shouldPrintDebugInfo() const {}

/// Return if debug information should be printed in the pretty form.
bool OpPrintingFlags::shouldPrintDebugInfoPrettyForm() const {}

/// Return if operations should be printed in the generic form.
bool OpPrintingFlags::shouldPrintGenericOpForm() const {}

/// Return if Region should be skipped.
bool OpPrintingFlags::shouldSkipRegions() const {}

/// Return if operation verification should be skipped.
bool OpPrintingFlags::shouldAssumeVerified() const {}

/// Return if the printer should use local scope when dumping the IR.
bool OpPrintingFlags::shouldUseLocalScope() const {}

/// Return if the printer should print users of values.
bool OpPrintingFlags::shouldPrintValueUsers() const {}

/// Return if the printer should use unique IDs.
bool OpPrintingFlags::shouldPrintUniqueSSAIDs() const {}

//===----------------------------------------------------------------------===//
// NewLineCounter
//===----------------------------------------------------------------------===//

namespace {
/// This class is a simple formatter that emits a new line when inputted into a
/// stream, that enables counting the number of newlines emitted. This class
/// should be used whenever emitting newlines in the printer.
struct NewLineCounter {};

static raw_ostream &operator<<(raw_ostream &os, NewLineCounter &newLine) {}
} // namespace

//===----------------------------------------------------------------------===//
// AsmPrinter::Impl
//===----------------------------------------------------------------------===//

namespace mlir {
class AsmPrinter::Impl {};
} // namespace mlir

//===----------------------------------------------------------------------===//
// AliasInitializer
//===----------------------------------------------------------------------===//

namespace {
/// This class represents a specific instance of a symbol Alias.
class SymbolAlias {};

/// This class represents a utility that initializes the set of attribute and
/// type aliases, without the need to store the extra information within the
/// main AliasState class or pass it around via function arguments.
class AliasInitializer {};

/// This class implements a dummy OpAsmPrinter that doesn't print any output,
/// and merely collects the attributes and types that *would* be printed in a
/// normal print invocation so that we can generate proper aliases. This allows
/// for us to generate aliases only for the attributes and types that would be
/// in the output, and trims down unnecessary output.
class DummyAliasOperationPrinter : private OpAsmPrinter {};

class DummyAliasDialectAsmPrinter : public DialectAsmPrinter {};
} // namespace

/// Sanitize the given name such that it can be used as a valid identifier. If
/// the string needs to be modified in any way, the provided buffer is used to
/// store the new copy,
static StringRef sanitizeIdentifier(StringRef name, SmallString<16> &buffer,
                                    StringRef allowedPunctChars = "$._-",
                                    bool allowTrailingDigit = true) {}

/// Given a collection of aliases and symbols, initialize a mapping from a
/// symbol to a given alias.
void AliasInitializer::initializeAliases(
    llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
    llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {}

void AliasInitializer::initialize(
    Operation *op, const OpPrintingFlags &printerFlags,
    llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {}

template <typename T, typename... PrintArgs>
std::pair<size_t, size_t> AliasInitializer::visitImpl(
    T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
    bool canBeDeferred, PrintArgs &&...printArgs) {}

void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {}

template <typename T>
void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
                                     bool canBeDeferred) {}

//===----------------------------------------------------------------------===//
// AliasState
//===----------------------------------------------------------------------===//

namespace {
/// This class manages the state for type and attribute aliases.
class AliasState {};
} // namespace

void AliasState::initialize(
    Operation *op, const OpPrintingFlags &printerFlags,
    DialectInterfaceCollection<OpAsmDialectInterface> &interfaces) {}

LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {}

LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {}

void AliasState::printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
                              bool isDeferred) {}

//===----------------------------------------------------------------------===//
// SSANameState
//===----------------------------------------------------------------------===//

namespace {
/// Info about block printing: a number which is its position in the visitation
/// order, and a name that is used to print reference to it, e.g. ^bb42.
struct BlockInfo {};

/// This class manages the state of SSA value names.
class SSANameState {};
} // namespace

SSANameState::SSANameState(Operation *op, const OpPrintingFlags &printerFlags)
    :{}

void SSANameState::printValueID(Value value, bool printResultNo,
                                raw_ostream &stream) const {}

void SSANameState::printOperationID(Operation *op, raw_ostream &stream) const {}

ArrayRef<int> SSANameState::getOpResultGroups(Operation *op) {}

BlockInfo SSANameState::getBlockInfo(Block *block) {}

void SSANameState::shadowRegionArgs(Region &region, ValueRange namesToUse) {}

void SSANameState::numberValuesInRegion(Region &region) {}

void SSANameState::numberValuesInBlock(Block &block) {}

void SSANameState::numberValuesInOp(Operation &op) {}

void SSANameState::getResultIDAndNumber(
    OpResult result, Value &lookupValue,
    std::optional<int> &lookupResultNo) const {}

void SSANameState::setValueName(Value value, StringRef name) {}

StringRef SSANameState::uniqueValueName(StringRef name) {}

//===----------------------------------------------------------------------===//
// DistinctState
//===----------------------------------------------------------------------===//

namespace {
/// This class manages the state for distinct attributes.
class DistinctState {};
} // namespace

uint64_t DistinctState::getId(DistinctAttr distinctAttr) {}

//===----------------------------------------------------------------------===//
// Resources
//===----------------------------------------------------------------------===//

AsmParsedResourceEntry::~AsmParsedResourceEntry() = default;
AsmResourceBuilder::~AsmResourceBuilder() = default;
AsmResourceParser::~AsmResourceParser() = default;
AsmResourcePrinter::~AsmResourcePrinter() = default;

StringRef mlir::toString(AsmResourceEntryKind kind) {}

AsmResourceParser &FallbackAsmResourceMap::getParserFor(StringRef key) {}

std::vector<std::unique_ptr<AsmResourcePrinter>>
FallbackAsmResourceMap::getPrinters() {}

LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
    AsmParsedResourceEntry &entry) {}

void FallbackAsmResourceMap::ResourceCollection::buildResources(
    Operation *op, AsmResourceBuilder &builder) const {}

//===----------------------------------------------------------------------===//
// AsmState
//===----------------------------------------------------------------------===//

namespace mlir {
namespace detail {
class AsmStateImpl {};

template <typename Range>
void printDimensionList(raw_ostream &stream, Range &&shape) {}

} // namespace detail
} // namespace mlir

/// Verifies the operation and switches to generic op printing if verification
/// fails. We need to do this because custom print functions may fail for
/// invalid ops.
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op,
                                              OpPrintingFlags printerFlags) {}

AsmState::AsmState(Operation *op, const OpPrintingFlags &printerFlags,
                   LocationMap *locationMap, FallbackAsmResourceMap *map)
    :{}
AsmState::AsmState(MLIRContext *ctx, const OpPrintingFlags &printerFlags,
                   LocationMap *locationMap, FallbackAsmResourceMap *map)
    :{}
AsmState::~AsmState() = default;

const OpPrintingFlags &AsmState::getPrinterFlags() const {}

void AsmState::attachResourcePrinter(
    std::unique_ptr<AsmResourcePrinter> printer) {}

DenseMap<Dialect *, SetVector<AsmDialectResourceHandle>> &
AsmState::getDialectResources() const {}

//===----------------------------------------------------------------------===//
// AsmPrinter::Impl
//===----------------------------------------------------------------------===//

AsmPrinter::Impl::Impl(raw_ostream &os, AsmStateImpl &state)
    :{}

void AsmPrinter::Impl::printTrailingLocation(Location loc, bool allowAlias) {}

void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty,
                                             bool isTopLevel) {}

/// Print a floating point value in a way that the parser will be able to
/// round-trip losslessly.
static void printFloatValue(const APFloat &apValue, raw_ostream &os,
                            bool *printedHex = nullptr) {}

void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {}

void AsmPrinter::Impl::printResourceHandle(
    const AsmDialectResourceHandle &resource) {}

/// Returns true if the given dialect symbol data is simple enough to print in
/// the pretty form. This is essentially when the symbol takes the form:
///   identifier (`<` body `>`)?
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName) {}

/// Print the given dialect symbol to the stream.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix,
                               StringRef dialectName, StringRef symString) {}

/// Returns true if the given string can be represented as a bare identifier.
static bool isBareIdentifier(StringRef name) {}

/// Print the given string as a keyword, or a quoted and escaped string if it
/// has any special or non-printable characters in it.
static void printKeywordOrString(StringRef keyword, raw_ostream &os) {}

/// Print the given string as a symbol reference. A symbol reference is
/// represented as a string prefixed with '@'. The reference is surrounded with
/// ""'s and escaped if it has any special or non-printable characters in it.
static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {}

// Print out a valid ElementsAttr that is succinct and can represent any
// potential shape/type, for use when eliding a large ElementsAttr.
//
// We choose to use a dense resource ElementsAttr literal with conspicuous
// content to hopefully alert readers to the fact that this has been elided.
static void printElidedElementsAttr(raw_ostream &os) {}

LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {}

LogicalResult AsmPrinter::Impl::printAlias(Type type) {}

void AsmPrinter::Impl::printAttribute(Attribute attr,
                                      AttrTypeElision typeElision) {}

void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
                                          AttrTypeElision typeElision) {}

/// Print the integer element of a DenseElementsAttr.
static void printDenseIntElement(const APInt &value, raw_ostream &os,
                                 Type type) {}

static void
printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
                           function_ref<void(unsigned)> printEltFn) {}

void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
                                              bool allowHex) {}

void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
    DenseIntOrFPElementsAttr attr, bool allowHex) {}

void AsmPrinter::Impl::printDenseStringElementsAttr(
    DenseStringElementsAttr attr) {}

void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {}

void AsmPrinter::Impl::printType(Type type) {}

void AsmPrinter::Impl::printTypeImpl(Type type) {}

void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
                                             ArrayRef<StringRef> elidedAttrs,
                                             bool withKeyword) {}
void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {}

void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {}

void AsmPrinter::Impl::printDialectType(Type type) {}

void AsmPrinter::Impl::printEscapedString(StringRef str) {}

void AsmPrinter::Impl::printHexString(StringRef str) {}
void AsmPrinter::Impl::printHexString(ArrayRef<char> data) {}

LogicalResult AsmPrinter::Impl::pushCyclicPrinting(const void *opaquePointer) {}

void AsmPrinter::Impl::popCyclicPrinting() {}

void AsmPrinter::Impl::printDimensionList(ArrayRef<int64_t> shape) {}

//===--------------------------------------------------------------------===//
// AsmPrinter
//===--------------------------------------------------------------------===//

AsmPrinter::~AsmPrinter() = default;

raw_ostream &AsmPrinter::getStream() const {}

/// Print the given floating point value in a stablized form.
void AsmPrinter::printFloat(const APFloat &value) {}

void AsmPrinter::printType(Type type) {}

void AsmPrinter::printAttribute(Attribute attr) {}

LogicalResult AsmPrinter::printAlias(Attribute attr) {}

LogicalResult AsmPrinter::printAlias(Type type) {}

void AsmPrinter::printAttributeWithoutType(Attribute attr) {}

void AsmPrinter::printKeywordOrString(StringRef keyword) {}

void AsmPrinter::printString(StringRef keyword) {}

void AsmPrinter::printSymbolName(StringRef symbolRef) {}

void AsmPrinter::printResourceHandle(const AsmDialectResourceHandle &resource) {}

void AsmPrinter::printDimensionList(ArrayRef<int64_t> shape) {}

LogicalResult AsmPrinter::pushCyclicPrinting(const void *opaquePointer) {}

void AsmPrinter::popCyclicPrinting() {}

//===----------------------------------------------------------------------===//
// Affine expressions and maps
//===----------------------------------------------------------------------===//

void AsmPrinter::Impl::printAffineExpr(
    AffineExpr expr, function_ref<void(unsigned, bool)> printValueName) {}

void AsmPrinter::Impl::printAffineExprInternal(
    AffineExpr expr, BindingStrength enclosingTightness,
    function_ref<void(unsigned, bool)> printValueName) {}

void AsmPrinter::Impl::printAffineConstraint(AffineExpr expr, bool isEq) {}

void AsmPrinter::Impl::printAffineMap(AffineMap map) {}

void AsmPrinter::Impl::printIntegerSet(IntegerSet set) {}

//===----------------------------------------------------------------------===//
// OperationPrinter
//===----------------------------------------------------------------------===//

namespace {
/// This class contains the logic for printing operations, regions, and blocks.
class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {};
} // namespace

void OperationPrinter::printTopLevelOperation(Operation *op) {}

void OperationPrinter::printFileMetadataDictionary(Operation *op) {}

void OperationPrinter::printResourceFileMetadata(
    function_ref<void()> checkAddMetadataDict, Operation *op) {}

/// Print a block argument in the usual format of:
///   %ssaName : type {attr1=42} loc("here")
/// where location printing is controlled by the standard internal option.
/// You may pass omitType=true to not print a type, and pass an empty
/// attribute list if you don't care for attributes.
void OperationPrinter::printRegionArgument(BlockArgument arg,
                                           ArrayRef<NamedAttribute> argAttrs,
                                           bool omitType) {}

void OperationPrinter::printFullOpWithIndentAndLoc(Operation *op) {}

void OperationPrinter::printFullOp(Operation *op) {}

void OperationPrinter::printUsersComment(Operation *op) {}

void OperationPrinter::printUsersComment(BlockArgument arg) {}

void OperationPrinter::printValueUsers(Value value) {}

void OperationPrinter::printUserIDs(Operation *user, bool prefixComma) {}

void OperationPrinter::printCustomOrGenericOp(Operation *op) {}

void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {}

void OperationPrinter::printBlockName(Block *block) {}

void OperationPrinter::print(Block *block, bool printBlockArgs,
                             bool printBlockTerminator) {}

void OperationPrinter::printValueID(Value value, bool printResultNo,
                                    raw_ostream *streamOverride) const {}

void OperationPrinter::printOperationID(Operation *op,
                                        raw_ostream *streamOverride) const {}

void OperationPrinter::printSuccessor(Block *successor) {}

void OperationPrinter::printSuccessorAndUseList(Block *successor,
                                                ValueRange succOperands) {}

void OperationPrinter::printRegion(Region &region, bool printEntryBlockArgs,
                                   bool printBlockTerminators,
                                   bool printEmptyBlock) {}

void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
                                              ValueRange operands) {}

void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
                                               ValueRange dimOperands,
                                               ValueRange symOperands) {}

//===----------------------------------------------------------------------===//
// print and dump methods
//===----------------------------------------------------------------------===//

void Attribute::print(raw_ostream &os, bool elideType) const {}
void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {}

void Attribute::dump() const {}

void Attribute::printStripped(raw_ostream &os, AsmState &state) const {}
void Attribute::printStripped(raw_ostream &os) const {}

void Type::print(raw_ostream &os) const {}
void Type::print(raw_ostream &os, AsmState &state) const {}

void Type::dump() const {}

void AffineMap::dump() const {}

void IntegerSet::dump() const {}

void AffineExpr::print(raw_ostream &os) const {}

void AffineExpr::dump() const {}

void AffineMap::print(raw_ostream &os) const {}

void IntegerSet::print(raw_ostream &os) const {}

void Value::print(raw_ostream &os) const {}
void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {}
void Value::print(raw_ostream &os, AsmState &state) const {}

void Value::dump() const {}

void Value::printAsOperand(raw_ostream &os, AsmState &state) const {}

static Operation *findParent(Operation *op, bool shouldUseLocalScope) {}

void Value::printAsOperand(raw_ostream &os,
                           const OpPrintingFlags &flags) const {}

void Operation::print(raw_ostream &os, const OpPrintingFlags &printerFlags) {}
void Operation::print(raw_ostream &os, AsmState &state) {}

void Operation::dump() {}

void Block::print(raw_ostream &os) {}
void Block::print(raw_ostream &os, AsmState &state) {}

void Block::dump() {}

/// Print out the name of the block without printing its body.
void Block::printAsOperand(raw_ostream &os, bool printType) {}
void Block::printAsOperand(raw_ostream &os, AsmState &state) {}

raw_ostream &mlir::operator<<(raw_ostream &os, Block &block) {}

//===--------------------------------------------------------------------===//
// Custom printers
//===--------------------------------------------------------------------===//
namespace mlir {

void printDimensionList(OpAsmPrinter &printer, Operation *op,
                        ArrayRef<int64_t> dimensions) {}

ParseResult parseDimensionList(OpAsmParser &parser,
                               DenseI64ArrayAttr &dimensions) {}

} // namespace mlir