//===- OpImplementation.h - Classes for implementing Op types ---*- C++ -*-===// // // 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 classes used by the implementation details of Op types. // //===----------------------------------------------------------------------===// #ifndef MLIR_IR_OPIMPLEMENTATION_H #define MLIR_IR_OPIMPLEMENTATION_H #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/DialectInterface.h" #include "mlir/IR/OpDefinition.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/SMLoc.h" #include <optional> namespace mlir { class AsmParsedResourceEntry; class AsmResourceBuilder; class Builder; //===----------------------------------------------------------------------===// // AsmDialectResourceHandle //===----------------------------------------------------------------------===// /// This class represents an opaque handle to a dialect resource entry. class AsmDialectResourceHandle { … }; /// This class represents a CRTP base class for dialect resource handles. It /// abstracts away various utilities necessary for defined derived resource /// handles. template <typename DerivedT, typename ResourceT, typename DialectT> class AsmDialectResourceHandleBase : public AsmDialectResourceHandle { … }; inline llvm::hash_code hash_value(const AsmDialectResourceHandle ¶m) { … } //===----------------------------------------------------------------------===// // AsmPrinter //===----------------------------------------------------------------------===// /// This base class exposes generic asm printer hooks, usable across the various /// derived printers. class AsmPrinter { … }; template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, Type type) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, Attribute attr) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, const APFloat &value) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, float value) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, double value) { … } // Support printing anything that isn't convertible to one of the other // streamable types, even if it isn't exactly one of them. For example, we want // to print FunctionType with the Type version above, not have it match this. template <typename AsmPrinterT, typename T, std::enable_if_t<!std::is_convertible<T &, Value &>::value && !std::is_convertible<T &, Type &>::value && !std::is_convertible<T &, Attribute &>::value && !std::is_convertible<T &, ValueRange>::value && !std::is_convertible<T &, APFloat &>::value && !llvm::is_one_of<T, bool, float, double>::value, T> * = nullptr> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, const T &other) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, bool value) { … } template <typename AsmPrinterT, typename ValueRangeT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, const ValueTypeRange<ValueRangeT> &types) { … } template <typename AsmPrinterT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, const TypeRange &types) { … } // Prevent matching the TypeRange version above for ValueRange // printing through base AsmPrinter. This is needed so that the // ValueRange printing behaviour does not change from printing // the SSA values to printing the types for the operands when // using AsmPrinter instead of OpAsmPrinter. template <typename AsmPrinterT, typename T> inline std::enable_if_t<std::is_same<AsmPrinter, AsmPrinterT>::value && std::is_convertible<T &, ValueRange>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, const T &other) = delete; template <typename AsmPrinterT, typename ElementT> inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, AsmPrinterT &> operator<<(AsmPrinterT &p, ArrayRef<ElementT> types) { … } //===----------------------------------------------------------------------===// // OpAsmPrinter //===----------------------------------------------------------------------===// /// This is a pure-virtual base class that exposes the asmprinter hooks /// necessary to implement a custom print() method. class OpAsmPrinter : public AsmPrinter { … }; // Make the implementations convenient to use. inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Value value) { … } template <typename T, std::enable_if_t<std::is_convertible<T &, ValueRange>::value && !std::is_convertible<T &, Value &>::value, T> * = nullptr> inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) { … } inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Block *value) { … } //===----------------------------------------------------------------------===// // AsmParser //===----------------------------------------------------------------------===// /// This base class exposes generic asm parser hooks, usable across the various /// derived parsers. class AsmParser { … }; //===----------------------------------------------------------------------===// // OpAsmParser //===----------------------------------------------------------------------===// /// The OpAsmParser has methods for interacting with the asm parser: parsing /// things from it, emitting errors etc. It has an intentionally high-level API /// that is designed to reduce/constrain syntax innovation in individual /// operations. /// /// For example, consider an op like this: /// /// %x = load %p[%1, %2] : memref<...> /// /// The "%x = load" tokens are already parsed and therefore invisible to the /// custom op parser. This can be supported by calling `parseOperandList` to /// parse the %p, then calling `parseOperandList` with a `SquareDelimiter` to /// parse the indices, then calling `parseColonTypeList` to parse the result /// type. /// class OpAsmParser : public AsmParser { … }; //===--------------------------------------------------------------------===// // Dialect OpAsm interface. //===--------------------------------------------------------------------===// /// A functor used to set the name of the start of a result group of an /// operation. See 'getAsmResultNames' below for more details. OpAsmSetValueNameFn; /// A functor used to set the name of blocks in regions directly nested under /// an operation. OpAsmSetBlockNameFn; class OpAsmDialectInterface : public DialectInterface::Base<OpAsmDialectInterface> { … }; //===--------------------------------------------------------------------===// // Custom printers and parsers. //===--------------------------------------------------------------------===// // Handles custom<DimensionList>(...) in TableGen. void printDimensionList(OpAsmPrinter &printer, Operation *op, ArrayRef<int64_t> dimensions); ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions); } // namespace mlir //===--------------------------------------------------------------------===// // Operation OpAsm interface. //===--------------------------------------------------------------------===// /// The OpAsmOpInterface, see OpAsmInterface.td for more details. #include "mlir/IR/OpAsmInterface.h.inc" namespace llvm { template <> struct DenseMapInfo<mlir::AsmDialectResourceHandle> { … }; } // namespace llvm #endif