[mlir][IR] Use tablegen for the BuiltinDialect and operations
authorRiver Riddle <riddleriver@gmail.com>
Tue, 17 Nov 2020 08:37:14 +0000 (00:37 -0800)
committerRiver Riddle <riddleriver@gmail.com>
Tue, 17 Nov 2020 08:53:40 +0000 (00:53 -0800)
This has been a long standing TODO, and cleans up a bit of IR/. This will also make it easier to move FuncOp out of IR/ at some point in the future. For now, Module.h and Function.h just forward BuiltinDialect.h. These files will be removed in a followup.

Differential Revision: https://reviews.llvm.org/D91571

12 files changed:
mlir/include/mlir/IR/BuiltinDialect.h [new file with mode: 0644]
mlir/include/mlir/IR/BuiltinOps.td [new file with mode: 0644]
mlir/include/mlir/IR/CMakeLists.txt
mlir/include/mlir/IR/Function.h
mlir/include/mlir/IR/Module.h
mlir/include/mlir/IR/OpDefinition.h
mlir/include/mlir/IR/Operation.h
mlir/lib/IR/BuiltinDialect.cpp [moved from mlir/lib/IR/Function.cpp with 54% similarity]
mlir/lib/IR/CMakeLists.txt
mlir/lib/IR/MLIRContext.cpp
mlir/lib/IR/Module.cpp [deleted file]
mlir/lib/TableGen/OpClass.cpp

diff --git a/mlir/include/mlir/IR/BuiltinDialect.h b/mlir/include/mlir/IR/BuiltinDialect.h
new file mode 100644 (file)
index 0000000..06d20cb
--- /dev/null
@@ -0,0 +1,93 @@
+//===- BuiltinDialect.h - MLIR Builtin Dialect ------------------*- 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 file contains the Builtin dialect and its operations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_IR_BUILTINDIALECT_H_
+#define MLIR_IR_BUILTINDIALECT_H_
+
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/FunctionSupport.h"
+#include "mlir/IR/OwningOpRefBase.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Interfaces/CallInterfaces.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+
+//===----------------------------------------------------------------------===//
+// Dialect
+//===----------------------------------------------------------------------===//
+
+#include "mlir/IR/BuiltinDialect.h.inc"
+
+//===----------------------------------------------------------------------===//
+// Dialect Operations
+//===----------------------------------------------------------------------===//
+
+#define GET_OP_CLASSES
+#include "mlir/IR/BuiltinOps.h.inc"
+
+//===----------------------------------------------------------------------===//
+// Dialect Utilities
+//===----------------------------------------------------------------------===//
+
+namespace mlir {
+/// This class acts as an owning reference to a module, and will automatically
+/// destroy the held module on destruction if the held module is valid.
+class OwningModuleRef : public OwningOpRefBase<ModuleOp> {
+public:
+  using OwningOpRefBase<ModuleOp>::OwningOpRefBase;
+};
+} // end namespace mlir
+
+namespace llvm {
+// Functions hash just like pointers.
+template <>
+struct DenseMapInfo<mlir::FuncOp> {
+  static mlir::FuncOp getEmptyKey() {
+    auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
+    return mlir::FuncOp::getFromOpaquePointer(pointer);
+  }
+  static mlir::FuncOp getTombstoneKey() {
+    auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
+    return mlir::FuncOp::getFromOpaquePointer(pointer);
+  }
+  static unsigned getHashValue(mlir::FuncOp val) {
+    return hash_value(val.getAsOpaquePointer());
+  }
+  static bool isEqual(mlir::FuncOp lhs, mlir::FuncOp rhs) { return lhs == rhs; }
+};
+
+/// Allow stealing the low bits of FuncOp.
+template <>
+struct PointerLikeTypeTraits<mlir::FuncOp> {
+  static inline void *getAsVoidPointer(mlir::FuncOp val) {
+    return const_cast<void *>(val.getAsOpaquePointer());
+  }
+  static inline mlir::FuncOp getFromVoidPointer(void *p) {
+    return mlir::FuncOp::getFromOpaquePointer(p);
+  }
+  static constexpr int NumLowBitsAvailable = 3;
+};
+
+/// Allow stealing the low bits of ModuleOp.
+template <>
+struct PointerLikeTypeTraits<mlir::ModuleOp> {
+public:
+  static inline void *getAsVoidPointer(mlir::ModuleOp val) {
+    return const_cast<void *>(val.getAsOpaquePointer());
+  }
+  static inline mlir::ModuleOp getFromVoidPointer(void *p) {
+    return mlir::ModuleOp::getFromOpaquePointer(p);
+  }
+  static constexpr int NumLowBitsAvailable = 3;
+};
+} // end namespace llvm
+
+#endif // MLIR_IR_BUILTINDIALECT_H_
diff --git a/mlir/include/mlir/IR/BuiltinOps.td b/mlir/include/mlir/IR/BuiltinOps.td
new file mode 100644 (file)
index 0000000..bc573e0
--- /dev/null
@@ -0,0 +1,235 @@
+//===- BuiltinOps.td - Builtin operation definitions -------*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the set of builtin MLIR operations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BUILTIN_OPS
+#define BUILTIN_OPS
+
+include "mlir/IR/SymbolInterfaces.td"
+include "mlir/Interfaces/CallInterfaces.td"
+
+def Builtin_Dialect : Dialect {
+  let summary =
+    "A dialect containing the builtin Attributes, Operations, and Types";
+
+  let name = "";
+  let cppNamespace = "::mlir";
+}
+
+// Base class for Builtin dialect ops.
+class Builtin_Op<string mnemonic, list<OpTrait> traits = []> :
+    Op<Builtin_Dialect, mnemonic, traits>;
+
+//===----------------------------------------------------------------------===//
+// FuncOp
+//===----------------------------------------------------------------------===//
+
+def FuncOp : Builtin_Op<"func", [
+  AffineScope, AutomaticAllocationScope, CallableOpInterface, FunctionLike,
+  IsolatedFromAbove, Symbol
+]> {
+  let summary = "An operation with a name containing a single `SSACFG` region";
+  let description = [{
+    Operations within the function cannot implicitly capture values defined
+    outside of the function, i.e. Functions are `IsolatedFromAbove`. All
+    external references must use function arguments or attributes that establish
+    a symbolic connection (e.g. symbols referenced by name via a string
+    attribute like SymbolRefAttr). An external function declaration (used when
+    referring to a function declared in some other module) has no body. While
+    the MLIR textual form provides a nice inline syntax for function arguments,
+    they are internally represented as “block arguments” to the first block in
+    the region.
+
+    Only dialect attribute names may be specified in the attribute dictionaries
+    for function arguments, results, or the function itself.
+
+    Example:
+
+    ```mlir
+    // External function definitions.
+    func @abort()
+    func @scribble(i32, i64, memref<? x 128 x f32, #layout_map0>) -> f64
+
+    // A function that returns its argument twice:
+    func @count(%x: i64) -> (i64, i64)
+      attributes {fruit: "banana"} {
+      return %x, %x: i64, i64
+    }
+
+    // A function with an argument attribute
+    func @example_fn_arg(%x: i32 {swift.self = unit})
+
+    // A function with a result attribute
+    func @example_fn_result() -> (f64 {dialectName.attrName = 0 : i64})
+
+    // A function with an attribute
+    func @example_fn_attr() attributes {dialectName.attrName = false}
+    ```
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name,
+                       TypeAttr:$type,
+                       OptionalAttr<StrAttr>:$sym_visibility);
+  let regions = (region AnyRegion:$body);
+
+  let builders = [OpBuilderDAG<(ins
+    "StringRef":$name, "FunctionType":$type,
+    CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
+    CArg<"ArrayRef<MutableDictionaryAttr>", "{}">:$argAttrs)
+  >];
+  let extraClassDeclaration = [{
+    static FuncOp create(Location location, StringRef name, FunctionType type,
+                         ArrayRef<NamedAttribute> attrs = {});
+    static FuncOp create(Location location, StringRef name, FunctionType type,
+                         iterator_range<dialect_attr_iterator> attrs);
+    static FuncOp create(Location location, StringRef name, FunctionType type,
+                         ArrayRef<NamedAttribute> attrs,
+                         ArrayRef<MutableDictionaryAttr> argAttrs);
+
+    /// Create a deep copy of this function and all of its blocks, remapping any
+    /// operands that use values outside of the function using the map that is
+    /// provided (leaving them alone if no entry is present). If the mapper
+    /// contains entries for function arguments, these arguments are not
+    /// included in the new function. Replaces references to cloned sub-values
+    /// with the corresponding value that is copied, and adds those mappings to
+    /// the mapper.
+    FuncOp clone(BlockAndValueMapping &mapper);
+    FuncOp clone();
+
+    /// Clone the internal blocks and attributes from this function into dest.
+    /// Any cloned blocks are appended to the back of dest. This function
+    /// asserts that the attributes of the current function and dest are
+    /// compatible.
+    void cloneInto(FuncOp dest, BlockAndValueMapping &mapper);
+
+    //===------------------------------------------------------------------===//
+    // CallableOpInterface
+    //===------------------------------------------------------------------===//
+
+    /// Returns the region on the current operation that is callable. This may
+    /// return null in the case of an external callable object, e.g. an external
+    /// function.
+    Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
+
+    /// Returns the results types that the callable region produces when
+    /// executed.
+    ArrayRef<Type> getCallableResults() { return getType().getResults(); }
+
+    //===------------------------------------------------------------------===//
+    // SymbolOpInterface Methods
+    //===------------------------------------------------------------------===//
+
+    bool isDeclaration() { return isExternal(); }
+
+  private:
+    // This trait needs access to the hooks defined below.
+    friend class OpTrait::FunctionLike<FuncOp>;
+
+    /// Returns the number of arguments. This is a hook for
+    /// OpTrait::FunctionLike.
+    unsigned getNumFuncArguments() { return getType().getInputs().size(); }
+
+    /// Returns the number of results. This is a hook for OpTrait::FunctionLike.
+    unsigned getNumFuncResults() { return getType().getResults().size(); }
+
+    /// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
+    /// attribute is present and checks if it holds a function type. Ensures
+    /// getType, getNumFuncArguments, and getNumFuncResults can be called
+    /// safely.
+    LogicalResult verifyType() {
+      auto type = getTypeAttr().getValue();
+      if (!type.isa<FunctionType>())
+        return emitOpError("requires '" + getTypeAttrName() +
+                           "' attribute of function type");
+      return success();
+    }
+  }];
+  let parser = [{ return ::parseFuncOp(parser, result); }];
+  let printer = [{ return ::print(*this, p); }];
+  let verifier = [{ return ::verify(*this); }];
+}
+
+//===----------------------------------------------------------------------===//
+// ModuleOp
+//===----------------------------------------------------------------------===//
+
+def ModuleOp : Builtin_Op<"module", [
+  AffineScope, IsolatedFromAbove, NoRegionArguments, SymbolTable, Symbol,
+  SingleBlockImplicitTerminator<"ModuleTerminatorOp">
+]> {
+  let summary = "A top level container operation";
+  let description = [{
+    A `module` represents a top-level container operation. It contains a single
+    SSACFG region containing a single block which can contain any
+    operations. Operations within this region cannot implicitly capture values
+    defined outside the module, i.e. Modules are `IsolatedFromAbove`. Modules
+    have an optional symbol name which can be used to refer to them in
+    operations.
+
+    Example:
+
+    ```mlir
+    module {
+      func @foo()
+    }
+    ```
+  }];
+
+  let arguments = (ins OptionalAttr<SymbolNameAttr>:$sym_name,
+                       OptionalAttr<StrAttr>:$sym_visibility);
+  let regions = (region SizedRegion<1>:$body);
+
+  let assemblyFormat = "($sym_name^)? attr-dict-with-keyword $body";
+  let builders = [OpBuilderDAG<(ins CArg<"Optional<StringRef>", "{}">:$name)>];
+  let extraClassDeclaration = [{
+    /// Construct a module from the given location with an optional name.
+    static ModuleOp create(Location loc, Optional<StringRef> name = llvm::None);
+
+    /// Return the name of this module if present.
+    Optional<StringRef> getName() { return sym_name(); }
+
+    /// Print the this module in the custom top-level form.
+    void print(raw_ostream &os, OpPrintingFlags flags = llvm::None);
+    void print(raw_ostream &os, AsmState &state,
+               OpPrintingFlags flags = llvm::None);
+    void dump();
+
+    //===------------------------------------------------------------------===//
+    // SymbolOpInterface Methods
+    //===------------------------------------------------------------------===//
+
+    /// A ModuleOp may optionally define a symbol.
+    bool isOptionalSymbol() { return true; }
+  }];
+  let verifier = [{ return ::verify(*this); }];
+
+  // We need to ensure the block inside the region is properly terminated;
+  // the auto-generated builders do not guarantee that.
+  let skipDefaultBuilders = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// ModuleTerminatorOp
+//===----------------------------------------------------------------------===//
+
+def ModuleTerminatorOp : Builtin_Op<"module_terminator", [
+  Terminator, HasParent<"ModuleOp">
+]> {
+  let summary = "A pseudo op that marks the end of a module";
+  let description = [{
+    `module_terminator` is a special terminator operation for the body of a
+    `module`, it has no semantic meaning beyond keeping the body of a `module`
+    well-formed.
+  }];
+  let assemblyFormat = "attr-dict";
+}
+
+#endif // BUILTIN_OPS
index c65616f..45649b3 100644 (file)
@@ -1,3 +1,11 @@
 add_mlir_interface(OpAsmInterface)
 add_mlir_interface(SymbolInterfaces)
 add_mlir_interface(RegionKindInterface)
+
+set(LLVM_TARGET_DEFINITIONS BuiltinOps.td)
+mlir_tablegen(BuiltinOps.h.inc -gen-op-decls)
+mlir_tablegen(BuiltinOps.cpp.inc -gen-op-defs)
+mlir_tablegen(BuiltinDialect.h.inc -gen-dialect-decls)
+add_public_tablegen_target(MLIRBuiltinOpsIncGen)
+
+add_mlir_doc(BuiltinOps -gen-op-doc Builtin Dialects/)
index 3ff2700..e8d19de 100644 (file)
 #ifndef MLIR_IR_FUNCTION_H
 #define MLIR_IR_FUNCTION_H
 
-#include "mlir/IR/Block.h"
-#include "mlir/IR/FunctionSupport.h"
-#include "mlir/IR/OpDefinition.h"
-#include "mlir/IR/SymbolTable.h"
-#include "mlir/Interfaces/CallInterfaces.h"
-#include "llvm/Support/PointerLikeTypeTraits.h"
-
-namespace mlir {
-//===--------------------------------------------------------------------===//
-// Function Operation.
-//===--------------------------------------------------------------------===//
-
-/// FuncOp represents a function, or an operation containing one region that
-/// forms a CFG(Control Flow Graph). The region of a function is not allowed to
-/// implicitly capture global values, and all external references must use
-/// Function arguments or attributes that establish a symbolic connection(e.g.
-/// symbols referenced by name via a string attribute).
-class FuncOp
-    : public Op<FuncOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
-                OpTrait::OneRegion, OpTrait::IsIsolatedFromAbove,
-                OpTrait::FunctionLike, OpTrait::AutomaticAllocationScope,
-                OpTrait::AffineScope, CallableOpInterface::Trait,
-                SymbolOpInterface::Trait> {
-public:
-  using Op::Op;
-  using Op::print;
-
-  static StringRef getOperationName() { return "func"; }
-
-  static FuncOp create(Location location, StringRef name, FunctionType type,
-                       ArrayRef<NamedAttribute> attrs = {});
-  static FuncOp create(Location location, StringRef name, FunctionType type,
-                       iterator_range<dialect_attr_iterator> attrs);
-  static FuncOp create(Location location, StringRef name, FunctionType type,
-                       ArrayRef<NamedAttribute> attrs,
-                       ArrayRef<MutableDictionaryAttr> argAttrs);
-
-  static void build(OpBuilder &builder, OperationState &result, StringRef name,
-                    FunctionType type, ArrayRef<NamedAttribute> attrs = {},
-                    ArrayRef<MutableDictionaryAttr> argAttrs = {});
-
-  /// Operation hooks.
-  static ParseResult parse(OpAsmParser &parser, OperationState &result);
-  void print(OpAsmPrinter &p);
-  LogicalResult verify();
-
-  /// Create a deep copy of this function and all of its blocks, remapping
-  /// any operands that use values outside of the function using the map that is
-  /// provided (leaving them alone if no entry is present). If the mapper
-  /// contains entries for function arguments, these arguments are not included
-  /// in the new function. Replaces references to cloned sub-values with the
-  /// corresponding value that is copied, and adds those mappings to the mapper.
-  FuncOp clone(BlockAndValueMapping &mapper);
-  FuncOp clone();
-
-  /// Clone the internal blocks and attributes from this function into dest. Any
-  /// cloned blocks are appended to the back of dest. This function asserts that
-  /// the attributes of the current function and dest are compatible.
-  void cloneInto(FuncOp dest, BlockAndValueMapping &mapper);
-
-  //===--------------------------------------------------------------------===//
-  // CallableOpInterface
-  //===--------------------------------------------------------------------===//
-
-  /// Returns the region on the current operation that is callable. This may
-  /// return null in the case of an external callable object, e.g. an external
-  /// function.
-  Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
-
-  /// Returns the results types that the callable region produces when executed.
-  ArrayRef<Type> getCallableResults() { return getType().getResults(); }
-
-  //===--------------------------------------------------------------------===//
-  // SymbolOpInterface Methods
-  //===--------------------------------------------------------------------===//
-
-  bool isDeclaration() { return isExternal(); }
-
-private:
-  // This trait needs access to the hooks defined below.
-  friend class OpTrait::FunctionLike<FuncOp>;
-
-  /// Returns the number of arguments. This is a hook for OpTrait::FunctionLike.
-  unsigned getNumFuncArguments() { return getType().getInputs().size(); }
-
-  /// Returns the number of results. This is a hook for OpTrait::FunctionLike.
-  unsigned getNumFuncResults() { return getType().getResults().size(); }
-
-  /// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
-  /// attribute is present and checks if it holds a function type.  Ensures
-  /// getType, getNumFuncArguments, and getNumFuncResults can be called safely.
-  LogicalResult verifyType() {
-    auto type = getTypeAttr().getValue();
-    if (!type.isa<FunctionType>())
-      return emitOpError("requires '" + getTypeAttrName() +
-                         "' attribute of function type");
-    return success();
-  }
-};
-} // end namespace mlir
-
-namespace llvm {
-
-// Functions hash just like pointers.
-template <> struct DenseMapInfo<mlir::FuncOp> {
-  static mlir::FuncOp getEmptyKey() {
-    auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
-    return mlir::FuncOp::getFromOpaquePointer(pointer);
-  }
-  static mlir::FuncOp getTombstoneKey() {
-    auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
-    return mlir::FuncOp::getFromOpaquePointer(pointer);
-  }
-  static unsigned getHashValue(mlir::FuncOp val) {
-    return hash_value(val.getAsOpaquePointer());
-  }
-  static bool isEqual(mlir::FuncOp LHS, mlir::FuncOp RHS) { return LHS == RHS; }
-};
-
-/// Allow stealing the low bits of FuncOp.
-template <> struct PointerLikeTypeTraits<mlir::FuncOp> {
-public:
-  static inline void *getAsVoidPointer(mlir::FuncOp I) {
-    return const_cast<void *>(I.getAsOpaquePointer());
-  }
-  static inline mlir::FuncOp getFromVoidPointer(void *P) {
-    return mlir::FuncOp::getFromOpaquePointer(P);
-  }
-  static constexpr int NumLowBitsAvailable = 3;
-};
-
-} // namespace llvm
+// TODO: This is a temporary forward until Function.h is removed.
+#include "mlir/IR/BuiltinDialect.h"
 
 #endif // MLIR_IR_FUNCTION_H
index 8a51013..facbaff 100644 (file)
 #ifndef MLIR_IR_MODULE_H
 #define MLIR_IR_MODULE_H
 
-#include "mlir/IR/OwningOpRefBase.h"
-#include "mlir/IR/SymbolTable.h"
-#include "llvm/Support/PointerLikeTypeTraits.h"
-
-namespace mlir {
-class ModuleTerminatorOp;
-
-//===----------------------------------------------------------------------===//
-// Module Operation.
-//===----------------------------------------------------------------------===//
-
-/// ModuleOp represents a module, or an operation containing one region with a
-/// single block containing opaque operations. The region of a module is not
-/// allowed to implicitly capture global values, and all external references
-/// must use symbolic references via attributes(e.g. via a string name).
-class ModuleOp
-    : public Op<
-          ModuleOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
-          OpTrait::IsIsolatedFromAbove, OpTrait::AffineScope,
-          OpTrait::SymbolTable,
-          OpTrait::SingleBlockImplicitTerminator<ModuleTerminatorOp>::Impl,
-          SymbolOpInterface::Trait, OpTrait::NoRegionArguments> {
-public:
-  using Op::Op;
-  using Op::print;
-
-  static StringRef getOperationName() { return "module"; }
-
-  static void build(OpBuilder &builder, OperationState &result,
-                    Optional<StringRef> name = llvm::None);
-
-  /// Construct a module from the given location with an optional name.
-  static ModuleOp create(Location loc, Optional<StringRef> name = llvm::None);
-
-  /// Operation hooks.
-  static ParseResult parse(OpAsmParser &parser, OperationState &result);
-  void print(OpAsmPrinter &p);
-  LogicalResult verify();
-
-  /// Return body of this module.
-  Region &getBodyRegion();
-  Block *getBody();
-
-  /// Return the name of this module if present.
-  Optional<StringRef> getName();
-
-  /// Print the this module in the custom top-level form.
-  void print(raw_ostream &os, OpPrintingFlags flags = llvm::None);
-  void print(raw_ostream &os, AsmState &state,
-             OpPrintingFlags flags = llvm::None);
-  void dump();
-
-  //===--------------------------------------------------------------------===//
-  // Body Management.
-  //===--------------------------------------------------------------------===//
-
-  /// Iteration over the operations in the module.
-  using iterator = Block::iterator;
-
-  iterator begin() { return getBody()->begin(); }
-  iterator end() { return getBody()->end(); }
-  Operation &front() { return *begin(); }
-
-  /// This returns a range of operations of the given type 'T' held within the
-  /// module.
-  template <typename T> iterator_range<Block::op_iterator<T>> getOps() {
-    return getBody()->getOps<T>();
-  }
-
-  /// Insert the operation into the back of the body, before the terminator.
-  void push_back(Operation *op) {
-    insert(Block::iterator(getBody()->getTerminator()), op);
-  }
-
-  /// Insert the operation at the given insertion point. Note: The operation is
-  /// never inserted after the terminator, even if the insertion point is end().
-  void insert(Operation *insertPt, Operation *op) {
-    insert(Block::iterator(insertPt), op);
-  }
-  void insert(Block::iterator insertPt, Operation *op) {
-    auto *body = getBody();
-    if (insertPt == body->end())
-      insertPt = Block::iterator(body->getTerminator());
-    body->getOperations().insert(insertPt, op);
-  }
-
-  //===--------------------------------------------------------------------===//
-  // SymbolOpInterface Methods
-  //===--------------------------------------------------------------------===//
-
-  /// A ModuleOp may optionally define a symbol.
-  bool isOptionalSymbol() { return true; }
-};
-
-/// The ModuleTerminatorOp is a special terminator operation for the body of a
-/// ModuleOp, it has no semantic meaning beyond keeping the body of a ModuleOp
-/// well-formed.
-///
-/// This operation does _not_ have a custom syntax. However, ModuleOp will omit
-/// the terminator in their custom syntax for brevity.
-class ModuleTerminatorOp
-    : public Op<ModuleTerminatorOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
-                OpTrait::HasParent<ModuleOp>::Impl, OpTrait::IsTerminator> {
-public:
-  using Op::Op;
-  static StringRef getOperationName() { return "module_terminator"; }
-  static void build(OpBuilder &, OperationState &) {}
-};
-
-/// This class acts as an owning reference to a module, and will automatically
-/// destroy the held module on destruction if the held module is valid.
-class OwningModuleRef : public OwningOpRefBase<ModuleOp> {
-public:
-  using OwningOpRefBase<ModuleOp>::OwningOpRefBase;
-};
-
-} // end namespace mlir
-
-namespace llvm {
-
-/// Allow stealing the low bits of ModuleOp.
-template <> struct PointerLikeTypeTraits<mlir::ModuleOp> {
-public:
-  static inline void *getAsVoidPointer(mlir::ModuleOp I) {
-    return const_cast<void *>(I.getAsOpaquePointer());
-  }
-  static inline mlir::ModuleOp getFromVoidPointer(void *P) {
-    return mlir::ModuleOp::getFromOpaquePointer(P);
-  }
-  static constexpr int NumLowBitsAvailable = 3;
-};
-
-} // end namespace llvm
+// TODO: This is a temporary forward until Module.h is removed.
+#include "mlir/IR/BuiltinDialect.h"
 
 #endif // MLIR_IR_MODULE_H
index d673b2b..e594c7f 100644 (file)
@@ -787,6 +787,132 @@ class VariadicSuccessors
 };
 
 //===----------------------------------------------------------------------===//
+// SingleBlockImplicitTerminator
+
+/// This class provides APIs and verifiers for ops with regions having a single
+/// block that must terminate with `TerminatorOpType`.
+template <typename TerminatorOpType>
+struct SingleBlockImplicitTerminator {
+  template <typename ConcreteType>
+  class Impl : public TraitBase<ConcreteType, Impl> {
+  private:
+    /// Builds a terminator operation without relying on OpBuilder APIs to avoid
+    /// cyclic header inclusion.
+    static Operation *buildTerminator(OpBuilder &builder, Location loc) {
+      OperationState state(loc, TerminatorOpType::getOperationName());
+      TerminatorOpType::build(builder, state);
+      return Operation::create(state);
+    }
+
+  public:
+    static LogicalResult verifyTrait(Operation *op) {
+      for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
+        Region &region = op->getRegion(i);
+
+        // Empty regions are fine.
+        if (region.empty())
+          continue;
+
+        // Non-empty regions must contain a single basic block.
+        if (std::next(region.begin()) != region.end())
+          return op->emitOpError("expects region #")
+                 << i << " to have 0 or 1 blocks";
+
+        Block &block = region.front();
+        if (block.empty())
+          return op->emitOpError() << "expects a non-empty block";
+        Operation &terminator = block.back();
+        if (isa<TerminatorOpType>(terminator))
+          continue;
+
+        return op->emitOpError("expects regions to end with '" +
+                               TerminatorOpType::getOperationName() +
+                               "', found '" +
+                               terminator.getName().getStringRef() + "'")
+                   .attachNote()
+               << "in custom textual format, the absence of terminator implies "
+                  "'"
+               << TerminatorOpType::getOperationName() << '\'';
+      }
+
+      return success();
+    }
+
+    /// Ensure that the given region has the terminator required by this trait.
+    /// If OpBuilder is provided, use it to build the terminator and notify the
+    /// OpBuilder litsteners accordingly. If only a Builder is provided, locally
+    /// construct an OpBuilder with no listeners; this should only be used if no
+    /// OpBuilder is available at the call site, e.g., in the parser.
+    static void ensureTerminator(Region &region, Builder &builder,
+                                 Location loc) {
+      ::mlir::impl::ensureRegionTerminator(region, builder, loc,
+                                           buildTerminator);
+    }
+    static void ensureTerminator(Region &region, OpBuilder &builder,
+                                 Location loc) {
+      ::mlir::impl::ensureRegionTerminator(region, builder, loc,
+                                           buildTerminator);
+    }
+
+    Block *getBody(unsigned idx = 0) {
+      Region &region = this->getOperation()->getRegion(idx);
+      assert(!region.empty() && "unexpected empty region");
+      return &region.front();
+    }
+    Region &getBodyRegion(unsigned idx = 0) {
+      return this->getOperation()->getRegion(idx);
+    }
+
+    //===------------------------------------------------------------------===//
+    // Single Region Utilities
+    //===------------------------------------------------------------------===//
+
+    /// The following are a set of methods only enabled when the parent
+    /// operation has a single region. Each of these methods take an additional
+    /// template parameter that represents the concrete operation so that we
+    /// can use SFINAE to disable the methods for non-single region operations.
+    template <typename OpT, typename T = void>
+    using enable_if_single_region =
+        typename std::enable_if_t<OpT::template hasTrait<OneRegion>(), T>;
+
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT, Block::iterator> begin() {
+      return getBody()->begin();
+    }
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT, Block::iterator> end() {
+      return getBody()->end();
+    }
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT, Operation &> front() {
+      return *begin();
+    }
+
+    /// Insert the operation into the back of the body, before the terminator.
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT> push_back(Operation *op) {
+      insert(Block::iterator(getBody()->getTerminator()), op);
+    }
+
+    /// Insert the operation at the given insertion point. Note: The operation
+    /// is never inserted after the terminator, even if the insertion point is
+    /// end().
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT> insert(Operation *insertPt, Operation *op) {
+      insert(Block::iterator(insertPt), op);
+    }
+    template <typename OpT = ConcreteType>
+    enable_if_single_region<OpT> insert(Block::iterator insertPt,
+                                        Operation *op) {
+      auto *body = getBody();
+      if (insertPt == body->end())
+        insertPt = Block::iterator(body->getTerminator());
+      body->getOperations().insert(insertPt, op);
+    }
+  };
+};
+
+//===----------------------------------------------------------------------===//
 // Misc Traits
 
 /// This class provides verification for ops that are known to have the same
@@ -1036,78 +1162,6 @@ public:
   }
 };
 
-/// This class provides APIs and verifiers for ops with regions having a single
-/// block that must terminate with `TerminatorOpType`.
-template <typename TerminatorOpType> struct SingleBlockImplicitTerminator {
-  template <typename ConcreteType>
-  class Impl : public TraitBase<ConcreteType, Impl> {
-  private:
-    /// Builds a terminator operation without relying on OpBuilder APIs to avoid
-    /// cyclic header inclusion.
-    static Operation *buildTerminator(OpBuilder &builder, Location loc) {
-      OperationState state(loc, TerminatorOpType::getOperationName());
-      TerminatorOpType::build(builder, state);
-      return Operation::create(state);
-    }
-
-  public:
-    static LogicalResult verifyTrait(Operation *op) {
-      for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
-        Region &region = op->getRegion(i);
-
-        // Empty regions are fine.
-        if (region.empty())
-          continue;
-
-        // Non-empty regions must contain a single basic block.
-        if (std::next(region.begin()) != region.end())
-          return op->emitOpError("expects region #")
-                 << i << " to have 0 or 1 blocks";
-
-        Block &block = region.front();
-        if (block.empty())
-          return op->emitOpError() << "expects a non-empty block";
-        Operation &terminator = block.back();
-        if (isa<TerminatorOpType>(terminator))
-          continue;
-
-        return op->emitOpError("expects regions to end with '" +
-                               TerminatorOpType::getOperationName() +
-                               "', found '" +
-                               terminator.getName().getStringRef() + "'")
-                   .attachNote()
-               << "in custom textual format, the absence of terminator implies "
-                  "'"
-               << TerminatorOpType::getOperationName() << '\'';
-      }
-
-      return success();
-    }
-
-    /// Ensure that the given region has the terminator required by this trait.
-    /// If OpBuilder is provided, use it to build the terminator and notify the
-    /// OpBuilder litsteners accordingly. If only a Builder is provided, locally
-    /// construct an OpBuilder with no listeners; this should only be used if no
-    /// OpBuilder is available at the call site, e.g., in the parser.
-    static void ensureTerminator(Region &region, Builder &builder,
-                                 Location loc) {
-      ::mlir::impl::ensureRegionTerminator(region, builder, loc,
-                                           buildTerminator);
-    }
-    static void ensureTerminator(Region &region, OpBuilder &builder,
-                                 Location loc) {
-      ::mlir::impl::ensureRegionTerminator(region, builder, loc,
-                                           buildTerminator);
-    }
-
-    Block *getBody(unsigned idx = 0) {
-      Region &region = this->getOperation()->getRegion(idx);
-      assert(!region.empty() && "unexpected empty region");
-      return &region.front();
-    }
-  };
-};
-
 /// This class provides a verifier for ops that are expecting their parent
 /// to be one of the given parent ops
 template <typename... ParentOpTypes>
index fa54cb6..5b3c448 100644 (file)
@@ -147,9 +147,9 @@ public:
   void replaceUsesOfWith(Value from, Value to);
 
   /// Replace all uses of results of this operation with the provided 'values'.
-  template <typename ValuesT,
-            typename = decltype(std::declval<ValuesT>().begin())>
-  void replaceAllUsesWith(ValuesT &&values) {
+  template <typename ValuesT>
+  std::enable_if_t<!std::is_convertible<ValuesT, Operation *>::value>
+  replaceAllUsesWith(ValuesT &&values) {
     assert(std::distance(values.begin(), values.end()) == getNumResults() &&
            "expected 'values' to correspond 1-1 with the number of results");
 
similarity index 54%
rename from mlir/lib/IR/Function.cpp
rename to mlir/lib/IR/BuiltinDialect.cpp
index 03378f2..ca080eb 100644 (file)
@@ -1,4 +1,4 @@
-//===- Function.cpp - MLIR Function Classes -------------------------------===//
+//===- BuiltinDialect.cpp - MLIR Builtin Dialect --------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,19 +6,65 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "mlir/IR/Function.h"
+#include "mlir/IR/BuiltinDialect.h"
 #include "mlir/IR/BlockAndValueMapping.h"
 #include "mlir/IR/Builders.h"
 #include "mlir/IR/FunctionImplementation.h"
-#include "llvm/ADT/BitVector.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/StandardTypes.h"
 #include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
 
 using namespace mlir;
 
 //===----------------------------------------------------------------------===//
-// Function Operation.
+// Builtin Dialect
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
+  using OpAsmDialectInterface::OpAsmDialectInterface;
+
+  LogicalResult getAlias(Attribute attr, raw_ostream &os) const override {
+    if (attr.isa<AffineMapAttr>()) {
+      os << "map";
+      return success();
+    }
+    if (attr.isa<IntegerSetAttr>()) {
+      os << "set";
+      return success();
+    }
+    if (attr.isa<LocationAttr>()) {
+      os << "loc";
+      return success();
+    }
+    return failure();
+  }
+};
+} // end anonymous namespace.
+
+/// A builtin dialect to define types/etc that are necessary for the validity of
+/// the IR.
+void BuiltinDialect::initialize() {
+  addTypes<ComplexType, BFloat16Type, Float16Type, Float32Type, Float64Type,
+           FunctionType, IndexType, IntegerType, MemRefType, UnrankedMemRefType,
+           NoneType, OpaqueType, RankedTensorType, TupleType,
+           UnrankedTensorType, VectorType>();
+  addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
+                DenseStringElementsAttr, DictionaryAttr, FloatAttr,
+                SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
+                OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
+                UnitAttr>();
+  addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
+                UnknownLoc>();
+  addOperations<
+#define GET_OP_LIST
+#include "mlir/IR/BuiltinOps.cpp.inc"
+      >();
+  addInterfaces<BuiltinOpAsmDialectInterface>();
+}
+
+//===----------------------------------------------------------------------===//
+// FuncOp
 //===----------------------------------------------------------------------===//
 
 FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
@@ -41,14 +87,14 @@ FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
   return func;
 }
 
-void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
+void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
                    FunctionType type, ArrayRef<NamedAttribute> attrs,
                    ArrayRef<MutableDictionaryAttr> argAttrs) {
-  result.addAttribute(SymbolTable::getSymbolAttrName(),
-                      builder.getStringAttr(name));
-  result.addAttribute(getTypeAttrName(), TypeAttr::get(type));
-  result.attributes.append(attrs.begin(), attrs.end());
-  result.addRegion();
+  state.addAttribute(SymbolTable::getSymbolAttrName(),
+                     builder.getStringAttr(name));
+  state.addAttribute(getTypeAttrName(), TypeAttr::get(type));
+  state.attributes.append(attrs.begin(), attrs.end());
+  state.addRegion();
 
   if (argAttrs.empty())
     return;
@@ -56,12 +102,10 @@ void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
   SmallString<8> argAttrName;
   for (unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
     if (auto argDict = argAttrs[i].getDictionary(builder.getContext()))
-      result.addAttribute(getArgAttrName(i, argAttrName), argDict);
+      state.addAttribute(getArgAttrName(i, argAttrName), argDict);
 }
 
-/// Parsing/Printing methods.
-
-ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
+static ParseResult parseFuncOp(OpAsmParser &parser, OperationState &result) {
   auto buildFuncType = [](Builder &builder, ArrayRef<Type> argTypes,
                           ArrayRef<Type> results, impl::VariadicFlag,
                           std::string &) {
@@ -72,25 +116,25 @@ ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
                                    buildFuncType);
 }
 
-void FuncOp::print(OpAsmPrinter &p) {
-  FunctionType fnType = getType();
-  impl::printFunctionLikeOp(p, *this, fnType.getInputs(), /*isVariadic=*/false,
+static void print(FuncOp op, OpAsmPrinter &p) {
+  FunctionType fnType = op.getType();
+  impl::printFunctionLikeOp(p, op, fnType.getInputs(), /*isVariadic=*/false,
                             fnType.getResults());
 }
 
-LogicalResult FuncOp::verify() {
+static LogicalResult verify(FuncOp op) {
   // If this function is external there is nothing to do.
-  if (isExternal())
+  if (op.isExternal())
     return success();
 
   // Verify that the argument list of the function and the arg list of the entry
   // block line up.  The trait already verified that the number of arguments is
   // the same between the signature and the block.
-  auto fnInputTypes = getType().getInputs();
-  Block &entryBlock = front();
+  auto fnInputTypes = op.getType().getInputs();
+  Block &entryBlock = op.front();
   for (unsigned i = 0, e = entryBlock.getNumArguments(); i != e; ++i)
     if (fnInputTypes[i] != entryBlock.getArgument(i).getType())
-      return emitOpError("type of entry block argument #")
+      return op.emitOpError("type of entry block argument #")
              << i << '(' << entryBlock.getArgument(i).getType()
              << ") must match the type of the corresponding argument in "
              << "function signature(" << fnInputTypes[i] << ')';
@@ -152,3 +196,46 @@ FuncOp FuncOp::clone() {
   BlockAndValueMapping mapper;
   return clone(mapper);
 }
+
+//===----------------------------------------------------------------------===//
+// ModuleOp
+//===----------------------------------------------------------------------===//
+
+void ModuleOp::build(OpBuilder &builder, OperationState &state,
+                     Optional<StringRef> name) {
+  ensureTerminator(*state.addRegion(), builder, state.location);
+  if (name) {
+    state.attributes.push_back(builder.getNamedAttr(
+        mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
+  }
+}
+
+/// Construct a module from the given context.
+ModuleOp ModuleOp::create(Location loc, Optional<StringRef> name) {
+  OpBuilder builder(loc->getContext());
+  return builder.create<ModuleOp>(loc, name);
+}
+
+static LogicalResult verify(ModuleOp op) {
+  // Check that none of the attributes are non-dialect attributes, except for
+  // the symbol related attributes.
+  for (auto attr : op.getAttrs()) {
+    if (!attr.first.strref().contains('.') &&
+        !llvm::is_contained(
+            ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
+                                mlir::SymbolTable::getVisibilityAttrName()},
+            attr.first.strref()))
+      return op.emitOpError()
+             << "can only contain dialect-specific attributes, found: '"
+             << attr.first << "'";
+  }
+
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// TableGen'd op method definitions
+//===----------------------------------------------------------------------===//
+
+#define GET_OP_CLASSES
+#include "mlir/IR/BuiltinOps.cpp.inc"
index 1305e11..5a8d3e2 100644 (file)
@@ -5,16 +5,15 @@ add_mlir_library(MLIRIR
   Attributes.cpp
   Block.cpp
   Builders.cpp
+  BuiltinDialect.cpp
   Diagnostics.cpp
   Dialect.cpp
   Dominance.cpp
-  Function.cpp
   FunctionImplementation.cpp
   FunctionSupport.cpp
   IntegerSet.cpp
   Location.cpp
   MLIRContext.cpp
-  Module.cpp
   Operation.cpp
   OperationSupport.cpp
   PatternMatch.cpp
@@ -33,10 +32,11 @@ add_mlir_library(MLIRIR
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/IR
 
   DEPENDS
+  MLIRBuiltinOpsIncGen
   MLIRCallInterfacesIncGen
   MLIROpAsmInterfaceIncGen
-  MLIRSymbolInterfacesIncGen
   MLIRRegionKindInterfaceIncGen
+  MLIRSymbolInterfacesIncGen
 
   LINK_LIBS PUBLIC
   MLIRSupport
index cdebb2a..a803914 100644 (file)
@@ -83,57 +83,6 @@ void mlir::registerMLIRContextCLOptions() {
 }
 
 //===----------------------------------------------------------------------===//
-// Builtin Dialect
-//===----------------------------------------------------------------------===//
-
-namespace {
-struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
-  using OpAsmDialectInterface::OpAsmDialectInterface;
-
-  LogicalResult getAlias(Attribute attr, raw_ostream &os) const override {
-    if (attr.isa<AffineMapAttr>()) {
-      os << "map";
-      return success();
-    }
-    if (attr.isa<IntegerSetAttr>()) {
-      os << "set";
-      return success();
-    }
-    if (attr.isa<LocationAttr>()) {
-      os << "loc";
-      return success();
-    }
-    return failure();
-  }
-};
-
-/// A builtin dialect to define types/etc that are necessary for the validity of
-/// the IR.
-struct BuiltinDialect : public Dialect {
-  BuiltinDialect(MLIRContext *context)
-      : Dialect(/*name=*/"", context, TypeID::get<BuiltinDialect>()) {
-    addTypes<ComplexType, BFloat16Type, Float16Type, Float32Type, Float64Type,
-             FunctionType, IndexType, IntegerType, MemRefType,
-             UnrankedMemRefType, NoneType, OpaqueType, RankedTensorType,
-             TupleType, UnrankedTensorType, VectorType>();
-    addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
-                  DenseStringElementsAttr, DictionaryAttr, FloatAttr,
-                  SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
-                  OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
-                  UnitAttr>();
-    addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
-                  UnknownLoc>();
-    addInterfaces<BuiltinOpAsmDialectInterface>();
-
-    // TODO: These operations should be moved to a different dialect when they
-    // have been fully decoupled from the core.
-    addOperations<FuncOp, ModuleOp, ModuleTerminatorOp>();
-  }
-  static StringRef getDialectNamespace() { return ""; }
-};
-} // end anonymous namespace.
-
-//===----------------------------------------------------------------------===//
 // Locking Utilities
 //===----------------------------------------------------------------------===//
 
diff --git a/mlir/lib/IR/Module.cpp b/mlir/lib/IR/Module.cpp
deleted file mode 100644 (file)
index 1f1e3aa..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-//===- Module.cpp - MLIR Module Operation ---------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "mlir/IR/Module.h"
-#include "mlir/IR/Builders.h"
-#include "mlir/IR/OpImplementation.h"
-
-using namespace mlir;
-
-//===----------------------------------------------------------------------===//
-// Module Operation.
-//===----------------------------------------------------------------------===//
-
-void ModuleOp::build(OpBuilder &builder, OperationState &result,
-                     Optional<StringRef> name) {
-  ensureTerminator(*result.addRegion(), builder, result.location);
-  if (name)
-    result.attributes.push_back(builder.getNamedAttr(
-        mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
-}
-
-/// Construct a module from the given context.
-ModuleOp ModuleOp::create(Location loc, Optional<StringRef> name) {
-  OperationState state(loc, "module");
-  OpBuilder builder(loc->getContext());
-  ModuleOp::build(builder, state, name);
-  return cast<ModuleOp>(Operation::create(state));
-}
-
-ParseResult ModuleOp::parse(OpAsmParser &parser, OperationState &result) {
-  // If the name is present, parse it.
-  StringAttr nameAttr;
-  (void)parser.parseOptionalSymbolName(
-      nameAttr, mlir::SymbolTable::getSymbolAttrName(), result.attributes);
-
-  // If module attributes are present, parse them.
-  if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
-    return failure();
-
-  // Parse the module body.
-  auto *body = result.addRegion();
-  if (parser.parseRegion(*body, llvm::None, llvm::None))
-    return failure();
-
-  // Ensure that this module has a valid terminator.
-  ensureTerminator(*body, parser.getBuilder(), result.location);
-  return success();
-}
-
-void ModuleOp::print(OpAsmPrinter &p) {
-  p << "module";
-
-  if (Optional<StringRef> name = getName()) {
-    p << ' ';
-    p.printSymbolName(*name);
-  }
-
-  // Print the module attributes.
-  p.printOptionalAttrDictWithKeyword(getAttrs(),
-                                     {mlir::SymbolTable::getSymbolAttrName()});
-
-  // Print the region.
-  p.printRegion(getOperation()->getRegion(0), /*printEntryBlockArgs=*/false,
-                /*printBlockTerminators=*/false);
-}
-
-LogicalResult ModuleOp::verify() {
-  auto &bodyRegion = getOperation()->getRegion(0);
-
-  // The body must contain a single basic block.
-  if (!llvm::hasSingleElement(bodyRegion))
-    return emitOpError("expected body region to have a single block");
-
-  // Check that none of the attributes are non-dialect attributes, except for
-  // the symbol related attributes.
-  for (auto attr : getOperation()->getMutableAttrDict().getAttrs()) {
-    if (!attr.first.strref().contains('.') &&
-        !llvm::is_contained(
-            ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
-                                mlir::SymbolTable::getVisibilityAttrName()},
-            attr.first.strref()))
-      return emitOpError(
-                 "can only contain dialect-specific attributes, found: '")
-             << attr.first << "'";
-  }
-
-  return success();
-}
-
-/// Return body of this module.
-Region &ModuleOp::getBodyRegion() { return getOperation()->getRegion(0); }
-Block *ModuleOp::getBody() { return &getBodyRegion().front(); }
-
-Optional<StringRef> ModuleOp::getName() {
-  if (auto nameAttr =
-          getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()))
-    return nameAttr.getValue();
-  return llvm::None;
-}
index ceb4f5a..2fad62e 100644 (file)
@@ -303,9 +303,10 @@ void OpClass::writeDeclTo(raw_ostream &os) const {
   os << "class " << className << " : public ::mlir::Op<" << className;
   for (const auto &trait : traitsVec)
     os << ", " << trait;
-  os << "> {\npublic:\n";
-  os << "  using Op::Op;\n";
-  os << "  using Adaptor = " << className << "Adaptor;\n";
+  os << "> {\npublic:\n"
+     << "  using Op::Op;\n"
+     << "  using Op::print;\n"
+     << "  using Adaptor = " << className << "Adaptor;\n";
 
   bool hasPrivateMethod = false;
   forAllMethods([&](const OpMethod &method) {