[Mlir-commits] [mlir] 31229d4 - [mlir] Introduce IRDL dialect

Mehdi Amini llvmlistbot at llvm.org
Mon Apr 3 10:08:30 PDT 2023


Author: Mathieu Fehr
Date: 2023-04-03T10:08:21-07:00
New Revision: 31229d48bbfd394b64179d9be94f74ab70c84630

URL: https://github.com/llvm/llvm-project/commit/31229d48bbfd394b64179d9be94f74ab70c84630
DIFF: https://github.com/llvm/llvm-project/commit/31229d48bbfd394b64179d9be94f74ab70c84630.diff

LOG: [mlir] Introduce IRDL dialect

This patch introduces the IRDL dialect, which allow users to represent
dynamic dialect definitions as an MLIR program.

The IRDL dialect defines operations, attributes, and types, using
attribute constraints. For example:

```
module {
  irdl.dialect @cmath {
    irdl.type @complex {
      %0 = irdl.is f32
      %1 = irdl.is f64
      %2 = irdl.any_of(%0, %1)
      irdl.parameters(%2)
    }

    irdl.operation @norm {
      %0 = irdl.any
      %1 = irdl.parametric @complex<%0>
      irdl.operands(%1)
      irdl.results(%0)
    }
}
```

This program will define a new `cmath.complex` type, which expects a single
parameter, which is either an `f32` or an `f64`. It also defines an
`cmath.norm` operation, which expects a single `cmath.complex` type as operand,
and returns a value of the underlying type. Note that like PDL (which IRDL is
heavily inspired from), both uses of `%0` are expected to be of the same attribute.

IRDL handles attributes and types with the same operations, and does this by always
wrapping types in a `TypeAttr`. This is to simplify the language.

Depends on D144690

Reviewed By: rriddle, mehdi_amini

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

Added: 
    mlir/include/mlir/Dialect/IRDL/CMakeLists.txt
    mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
    mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
    mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
    mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
    mlir/include/mlir/Dialect/IRDL/IR/IRDLTraits.h
    mlir/include/mlir/Dialect/IRDL/IR/IRDLTypes.td
    mlir/lib/Dialect/IRDL/CMakeLists.txt
    mlir/lib/Dialect/IRDL/IR/IRDL.cpp
    mlir/test/Dialect/IRDL/cmath.irdl.mlir
    mlir/test/Dialect/IRDL/testd.irdl.mlir

Modified: 
    mlir/include/mlir/Dialect/CMakeLists.txt
    mlir/include/mlir/InitAllDialects.h
    mlir/lib/Dialect/CMakeLists.txt
    mlir/test/mlir-opt/commandline.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/CMakeLists.txt b/mlir/include/mlir/Dialect/CMakeLists.txt
index a9843d1a1249..58cc690d9a78 100644
--- a/mlir/include/mlir/Dialect/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(EmitC)
 add_subdirectory(Func)
 add_subdirectory(GPU)
 add_subdirectory(Index)
+add_subdirectory(IRDL)
 add_subdirectory(LLVMIR)
 add_subdirectory(Linalg)
 add_subdirectory(MLProgram)

diff  --git a/mlir/include/mlir/Dialect/IRDL/CMakeLists.txt b/mlir/include/mlir/Dialect/IRDL/CMakeLists.txt
new file mode 100644
index 000000000000..f33061b2d87c
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(IR)

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
new file mode 100644
index 000000000000..e165bd72d3b9
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_mlir_dialect(IRDL irdl)
+
+# Add IRDL operations
+set(LLVM_TARGET_DEFINITIONS IRDLOps.td)
+mlir_tablegen(IRDLOps.h.inc -gen-op-decls)
+mlir_tablegen(IRDLOps.cpp.inc -gen-op-defs)
+add_public_tablegen_target(MLIRIRDLOpsIncGen)
+add_dependencies(mlir-generic-headers MLIRIRDLOpsIncGen)
+
+# Add IRDL types
+set(LLVM_TARGET_DEFINITIONS IRDLTypes.td)
+mlir_tablegen(IRDLTypesGen.h.inc -gen-typedef-decls)
+mlir_tablegen(IRDLTypesGen.cpp.inc -gen-typedef-defs)
+add_public_tablegen_target(MLIRIRDLTypesIncGen)
+add_dependencies(mlir-generic-headers MLIRIRDLTypesIncGen)

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
new file mode 100644
index 000000000000..c22f5e28d91c
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
@@ -0,0 +1,42 @@
+//===- IRDL.h - IR Definition Language 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 declares the dialect for the IR Definition Language.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDL_H_
+#define MLIR_DIALECT_IRDL_IR_IRDL_H_
+
+#include "mlir/Dialect/IRDL/IR/IRDLTraits.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Interfaces/InferTypeOpInterface.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+#include <memory>
+
+// Forward declaration.
+namespace mlir {
+namespace irdl {
+class OpDef;
+class OpDefAttr;
+} // namespace irdl
+} // namespace mlir
+
+//===----------------------------------------------------------------------===//
+// IRDL Dialect
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/IRDL/IR/IRDLDialect.h.inc"
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.h.inc"
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLOps.h.inc"
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDL_H_

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
new file mode 100644
index 000000000000..c8303a2cc0ec
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
@@ -0,0 +1,78 @@
+//===- IRDL.td - IR Definition Language Dialect ------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the IR Definition Language dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDL
+#define MLIR_DIALECT_IRDL_IR_IRDL
+
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// IRDL Dialect
+//===----------------------------------------------------------------------===//
+
+def IRDL_Dialect : Dialect {
+  let summary = "IR Definition Language Dialect";
+  let description = [{
+    IRDL is an SSA-based declarative representation of dynamic dialects.
+    It allows the definition of dialects, operations, attributes, and types,
+    with a declarative description of their verifiers. IRDL code is meant to
+    be generated and not written by hand. As such, the design focuses on ease
+    of generation/analysis instead of ease of writing/reading.
+
+    Users can define a new dialect with `irdl.dialect`, operations with
+    `irdl.operation`, types with `irdl.type`, and attributes with
+    `irdl.attribute`.
+
+    An example dialect is shown below:
+
+    ```mlir
+    irdl.dialect @cmath {
+      irdl.type @complex {
+        %0 = irdl.is_type : f32
+        %1 = irdl.is_type : f64
+        %2 = irdl.any_of(%0, %1)
+        irdl.parameters(%2)
+      }
+
+      irdl.operation @mul {
+        %0 = irdl.is_type : f32
+        %1 = irdl.is_type : f64
+        %2 = irdl.any_of(%0, %1)
+        %3 = irdl.parametric_type : "cmath.complex"<%2>
+        irdl.operands(%3, %3)
+        irdl.results(%3)
+      }
+    }
+    ```
+
+    This program defines a `cmath` dialect that defines a `complex` type, and
+    a `mul` operation. Both express constraints over their parameters using
+    SSA constraint operations. Informally, one can see those SSA values as
+    constraint variables that evaluate to a single type at constraint
+    evaluation. For example, the result of the `irdl.any_of` stored in `%2`
+    in the `mul` operation will collapse into either `f32` or `f64` for the
+    entirety of this instance of `mul` constraint evaluation. As such,
+    both operands and the result of `mul` must be of equal type (and not just
+    satisfy the same constraint).
+
+    IRDL variables are handle over `mlir::Attribute`. In order to support
+    manipulating `mlir::Type`, IRDL wraps all types in an `mlir::TypeAttr`
+    attribute. The rationale of this is to simplify the dialect.
+  }];
+
+  let useDefaultTypePrinterParser = 1;
+
+  let name = "irdl";
+  let cppNamespace = "::mlir::irdl";
+}
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDL

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
new file mode 100644
index 000000000000..59d152440b26
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
@@ -0,0 +1,358 @@
+//===- IRDLOps.td - IR Definition Language Dialect ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the IRDL dialect ops.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDLOPS
+#define MLIR_DIALECT_IRDL_IR_IRDLOPS
+
+include "IRDL.td"
+include "IRDLTypes.td"
+include "mlir/Interfaces/SideEffectInterfaces.td"
+include "mlir/Interfaces/InferTypeOpInterface.td"
+include "mlir/IR/SymbolInterfaces.td"
+
+class IRDL_Op<string mnemonic, list<Trait> traits = []>
+    : Op<IRDL_Dialect, mnemonic, traits>;
+
+class AtMostOneChildOf<string op> : ParamNativeOpTrait<"AtMostOneChildOf", op>;
+
+//===----------------------------------------------------------------------===//
+// Dialect definition
+//===----------------------------------------------------------------------===//
+
+def IRDL_DialectOp : IRDL_Op<"dialect",
+    [IsolatedFromAbove, NoTerminator, Symbol, SymbolTable]> {
+  let summary = "Define a new dialect";
+  let description = [{
+    The `irdl.dialect` operation defines a dialect. All operations, attributes,
+    and types defined inside its region will be part of the dialect.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+      ...
+    }
+    ```
+
+    The above program defines a `cmath` dialect.
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name);
+  let regions = (region SizedRegion<1>:$body);
+  let assemblyFormat =
+    "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)";
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Type and Attribute definition
+//===----------------------------------------------------------------------===//
+
+def IRDL_TypeOp : IRDL_Op<"type",
+    [HasParent<"DialectOp">, NoTerminator, NoRegionArguments,
+     AtMostOneChildOf<"ParametersOp">, Symbol]> {
+  let summary = "Define a new type";
+  let description = [{
+    `irdl.type` defines a new type belonging to the `irdl.dialect` parent.
+
+    The type parameters can be defined with an `irdl.parameters` operation in
+    the optional region.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+      irdl.type @complex {
+        %0 = irdl.is i32
+        %1 = irdl.is i64
+        %2 = irdl.any_of(%0, %1)
+        irdl.parameters(%2)
+      }
+    }
+    ```
+
+    The above program defines a type `complex` inside the dialect `cmath`. The
+    type has a single parameter that should be either `i32` or `i64`.
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name);
+  let regions = (region SizedRegion<1>:$body);
+  let assemblyFormat =
+    "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)";
+}
+
+def IRDL_AttributeOp : IRDL_Op<"attribute",
+    [HasParent<"DialectOp">, NoTerminator, NoRegionArguments,
+     AtMostOneChildOf<"ParametersOp">, Symbol]> {
+  let summary = "Define a new attribute";
+  let description = [{
+    `irdl.attribute` defines a new attribute belonging to the `irdl.dialect`
+    parent.
+
+    The attribute parameters can be defined with an `irdl.parameters` operation
+    in the optional region.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @testd {
+      irdl.attribute @enum_attr {
+        %0 = irdl.is "foo"
+        %1 = irdl.is "bar"
+        %2 = irdl.any_of(%0, %1)
+        irdl.parameters(%2)
+      }
+    }
+    ```
+
+    The above program defines an `enum_attr` attribute inside the `testd`
+    dialect. The attribute has one `StringAttr` parameter that should be
+    either a `"foo"` or a `"bar"`.
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name);
+  let regions = (region SizedRegion<1>:$body);
+  let assemblyFormat =
+    "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)";
+}
+
+def IRDL_ParametersOp : IRDL_Op<"parameters",
+    [ParentOneOf<["AttributeOp", "TypeOp"]>]> {
+  let summary =
+    "Define the constraints on parameters of a type/attribute definition";
+  let description = [{
+    `irdl.parameters` defines the constraints on parameters of a type or
+    attribute definition.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+      irdl.type @complex {
+        %0 = irdl.is i32
+        %1 = irdl.is i64
+        %2 = irdl.any_of(%0, %1)
+        irdl.parameters(%2)
+      }
+    }
+    ```
+
+    The above program defines a type `complex` inside the dialect `cmath`. The
+    type has a single parameter that should be either `i32` or `i64`.
+  }];
+
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
+  let assemblyFormat = " `(` $args `)` attr-dict ";
+}
+
+//===----------------------------------------------------------------------===//
+// IRDL Operation definition
+//===----------------------------------------------------------------------===//
+
+def IRDL_OperationOp : IRDL_Op<"operation",
+    [HasParent<"DialectOp">, NoTerminator, NoRegionArguments,
+    AtMostOneChildOf<"OperandsOp, ResultsOp">, Symbol]> {
+  let summary = "Define a new operation";
+  let description = [{
+    `irdl.operation` defines a new operation belonging to the `irdl.dialect`
+    parent.
+
+    Operations can define constraints on their operands and results with the
+    `irdl.results` and `irdl.operands` operations. If these operations are not
+    present in the region, the results or operands are expected to be empty.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+
+      irdl.type @complex { /* ... */ }
+
+      irdl.operation @norm {
+        %0 = irdl.any
+        %1 = irdl.parametric @complex<%0>
+        irdl.results(%0)
+        irdl.operands(%1)
+      }
+    }
+    ```
+
+    The above program defines an operation `norm` inside the dialect `cmath`.
+    The operation expects a single operand of base type `cmath.complex`, and
+    returns a single result of the element type of the operand.
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name);
+  let regions = (region SizedRegion<1>:$body);
+  let assemblyFormat =
+    "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)";
+}
+
+def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
+  let summary = "Define the operands of an operation";
+  let description = [{
+    `irdl.operands` define the operands of the `irdl.operation` parent operation
+    definition.
+
+    In the following example, `irdl.operands` defines the operands of the
+    `norm` operation:
+
+    ```mlir
+    irdl.dialect @cmath {
+
+      irdl.type @complex { /* ... */ }
+
+      irdl.operation @mul {
+        %0 = irdl.any
+        %1 = irdl.parametric @complex<%0>
+        irdl.results(%1)
+        irdl.operands(%1, %1)
+      }
+    }
+    ```
+
+    The `mul` operation will expect two operands of type `cmath.complex`, that
+    have the same type, and return a result of the same type.
+  }];
+
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
+  let assemblyFormat = " `(` $args `)` attr-dict ";
+}
+
+def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
+  let summary = "Define the results of an operation";
+  let description = [{
+    `irdl.results` define the results of the `irdl.operation` parent operation
+    definition.
+
+    In the following example, `irdl.results` defines the results of the
+    `norm` operation:
+
+    ```mlir
+    irdl.dialect @cmath {
+
+      irdl.type @complex { /* ... */ }
+
+      irdl.operation @get_values {
+        %0 = irdl.any
+        %1 = irdl.parametric @complex<%0>
+        irdl.results(%0, %0)
+        irdl.operands(%1)
+      }
+    }
+    ```
+
+    The operation will expect one operand of the `cmath.complex` type, and two
+    results that have the underlying type of the `cmath.complex`.
+  }];
+
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
+  let assemblyFormat = " `(` $args `)` attr-dict ";
+}
+
+//===----------------------------------------------------------------------===//
+// IRDL Constraint operations
+//===----------------------------------------------------------------------===//
+
+class IRDL_ConstraintOp<string mnemonic, list<Trait> traits = []>
+    : IRDL_Op<mnemonic, traits> {
+}
+
+def IRDL_Is : IRDL_ConstraintOp<"is",
+    [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, Pure]> {
+  let summary = "Constraints an attribute/type to be a specific attribute instance";
+  let description = [{
+    `irdl.is` defines a constraint that only accepts a specific instance of a
+    type or attribute.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+      irdl.type @complex_i32 {
+        %0 = irdl.is i32
+        irdl.parameters(%0)
+      }
+    }
+    ```
+
+    The above program defines a `complex_i32` type inside the dialect `cmath`
+    that can only have a `i32` as its parameter.
+  }];
+
+  let arguments = (ins AnyAttr:$expected);
+  let results = (outs IRDL_AttributeType:$output);
+  let assemblyFormat = " $expected ` ` attr-dict ";
+}
+
+def IRDL_Parametric : IRDL_ConstraintOp<"parametric",
+    [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, Pure]> {
+  let summary = "Constraints an attribute/type base and its parameters";
+  let description = [{
+    `irdl.parametric` defines a constraint that accepts only a single type
+    or attribute base. The attribute base is defined by a symbolic reference
+    to the corresponding definition. It will additionally constraint the
+    parameters of the type/attribute.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+
+      irdl.type @complex { /* ... */ }
+
+      irdl.operation @norm {
+        %0 = irdl.any
+        %1 = irdl.parametric @complex<%0>
+        irdl.operands(%1)
+        irdl.results(%0)
+      }
+    }
+    ```
+
+    The above program defines an operation `norm` inside the dialect `cmath` that
+    for any `T` takes a `cmath.complex` with parameter `T` and returns a `T`.
+  }];
+
+  let arguments = (ins SymbolRefAttr:$base_type,
+                       Variadic<IRDL_AttributeType>:$args);
+  let results = (outs IRDL_AttributeType:$output);
+  let assemblyFormat = " $base_type `<` $args `>` ` ` attr-dict ";
+}
+
+def IRDL_Any : IRDL_ConstraintOp<"any",
+    [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>]> {
+  let summary = "Accept any type or attribute";
+  let description = [{
+    `irdl.any` defines a constraint that accepts any type or attribute.
+
+    Example:
+
+    ```mlir
+    irdl.dialect @cmath {
+      irdl.type @complex_flexible {
+        %0 = irdl.any
+        irdl.parameters(%0)
+      }
+    }
+    ```
+
+    The above program defines a type `complex_flexible` inside the dialect
+    `cmath` that has a single parameter that can be any attribute.
+  }];
+
+  let results = (outs IRDL_AttributeType:$output);
+  let assemblyFormat = " attr-dict ";
+}
+
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDLOPS

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLTraits.h b/mlir/include/mlir/Dialect/IRDL/IR/IRDLTraits.h
new file mode 100644
index 000000000000..1755341160bb
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLTraits.h
@@ -0,0 +1,81 @@
+//===- IRDLTraits.h - IRDL traits definition ---------------------*- 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 declares the traits used by the IR Definition Language dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDLTRAITS_H_
+#define MLIR_DIALECT_IRDL_IR_IRDLTRAITS_H_
+
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/Support/LogicalResult.h"
+#include "llvm/Support/Casting.h"
+
+namespace mlir {
+namespace OpTrait {
+
+/// Characterize operations that have at most a single operation of certain
+/// types in their region.
+/// This check is only done on the children that are immediate children of the
+/// operation, and does not recurse into the children's regions.
+/// This trait expects the Op to satisfy the `OneRegion` trait.
+template <typename... ChildOps>
+class AtMostOneChildOf {
+public:
+  template <typename ConcreteType>
+  class Impl
+      : public TraitBase<ConcreteType, AtMostOneChildOf<ChildOps...>::Impl> {
+  public:
+    static LogicalResult verifyTrait(Operation *op) {
+      static_assert(
+          ConcreteType::template hasTrait<::mlir::OpTrait::OneRegion>(),
+          "expected operation to have a single region");
+      static_assert(sizeof...(ChildOps) > 0,
+                    "expected at least one child operation type");
+
+      // Contains `true` if the corresponding child op has been seen.
+      bool satisfiedOps[sizeof...(ChildOps)] = {};
+
+      for (Operation &child : cast<ConcreteType>(op).getOps()) {
+        int childOpIndex = 0;
+        if (((isa<ChildOps>(child) ? false : (++childOpIndex, true)) && ...))
+          continue;
+
+        // Check that the operation has not been seen before.
+        if (satisfiedOps[childOpIndex])
+          return op->emitError()
+                 << "failed to verify AtMostOneChildOf trait: the operation "
+                    "contains at least two operations of type "
+                 << child.getName();
+
+        // Mark the operation as seen.
+        satisfiedOps[childOpIndex] = true;
+      }
+      return success();
+    }
+
+    /// Get the unique operation of a specific op that is in the operation
+    /// region.
+    template <typename OpT>
+    std::enable_if_t<std::disjunction<std::is_same<OpT, ChildOps>...>::value,
+                     std::optional<OpT>>
+    getOp() {
+      auto ops =
+          cast<ConcreteType>(this->getOperation()).template getOps<OpT>();
+      if (ops.empty())
+        return {};
+      return {*ops.begin()};
+    }
+  };
+};
+} // namespace OpTrait
+} // namespace mlir
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDLTRAITS_H_

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLTypes.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDLTypes.td
new file mode 100644
index 000000000000..7073eb81664a
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLTypes.td
@@ -0,0 +1,54 @@
+//===- IRDLTypes.td - IRDL Types ---------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the types IRDL uses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDLTYPES
+#define MLIR_DIALECT_IRDL_IR_IRDLTYPES
+
+include "mlir/IR/AttrTypeBase.td"
+include "IRDL.td"
+
+class IRDL_Type<string name, string typeMnemonic, list<Trait> traits = []>
+    : TypeDef<IRDL_Dialect, name, traits> {
+  let mnemonic = typeMnemonic;
+}
+
+def IRDL_AttributeType : IRDL_Type<"Attribute", "attribute"> {
+  let summary = "IRDL handle to an `mlir::Attribute`";
+  let description = [{
+    This type represents a handle to an instance of an `mlir::Attribute`,
+    so it can be used in an IRDL operation, type, or attribute definition.
+    This type can also represent a handle to an instance of an `mlir::Type`,
+    by wrapping it in a `mlir::TypeAttr`. 
+
+    Example:
+
+    ```mlir
+    irdl.dialect cmath {
+
+      irdl.type @complex { /* ... */ }
+
+      irdl.operation @norm {
+        %0 = irdl.any
+        %1 = irdl.parametric @complex<%0>
+        irdl.operands(%1)
+        irdl.results(%0)
+      }
+    }
+    ```
+
+    Here, `%0` and `%1` are both of type `!irdl.attribute`. Note that in
+    particular, `%1` will be a handle to a `mlir::TypeAttr` wrapping an
+    instance of a `cmath.complex` type.
+  }];
+}
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDLTYPES

diff  --git a/mlir/include/mlir/InitAllDialects.h b/mlir/include/mlir/InitAllDialects.h
index aa7abb0e19b5..9090189a1bd1 100644
--- a/mlir/include/mlir/InitAllDialects.h
+++ b/mlir/include/mlir/InitAllDialects.h
@@ -33,6 +33,7 @@
 #include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/Dialect/GPU/IR/GPUDialect.h"
 #include "mlir/Dialect/GPU/TransformOps/GPUTransformOps.h"
+#include "mlir/Dialect/IRDL/IR/IRDL.h"
 #include "mlir/Dialect/Index/IR/IndexDialect.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Dialect/LLVMIR/NVVMDialect.h"
@@ -93,6 +94,7 @@ inline void registerAllDialects(DialectRegistry &registry) {
                   func::FuncDialect,
                   gpu::GPUDialect,
                   index::IndexDialect,
+                  irdl::IRDLDialect,
                   LLVM::LLVMDialect,
                   linalg::LinalgDialect,
                   math::MathDialect,

diff  --git a/mlir/lib/Dialect/CMakeLists.txt b/mlir/lib/Dialect/CMakeLists.txt
index 5cf5c125a7cb..6f01ea7a1da1 100644
--- a/mlir/lib/Dialect/CMakeLists.txt
+++ b/mlir/lib/Dialect/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(EmitC)
 add_subdirectory(Func)
 add_subdirectory(GPU)
 add_subdirectory(Index)
+add_subdirectory(IRDL)
 add_subdirectory(Linalg)
 add_subdirectory(LLVMIR)
 add_subdirectory(Math)

diff  --git a/mlir/lib/Dialect/IRDL/CMakeLists.txt b/mlir/lib/Dialect/IRDL/CMakeLists.txt
new file mode 100644
index 000000000000..4987a98e5355
--- /dev/null
+++ b/mlir/lib/Dialect/IRDL/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_mlir_dialect_library(MLIRIRDL
+  IR/IRDL.cpp
+
+  DEPENDS
+  MLIRIRDLIncGen
+  MLIRIRDLOpsIncGen
+  MLIRIRDLTypesIncGen
+
+  LINK_LIBS PUBLIC
+  MLIRIR
+  )

diff  --git a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
new file mode 100644
index 000000000000..e2649f22094c
--- /dev/null
+++ b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
@@ -0,0 +1,78 @@
+//===- IRDL.cpp - IRDL dialect ----------------------------------*- C++ -*-===//
+//
+// This file is licensed 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/Dialect/IRDL/IR/IRDL.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/DialectImplementation.h"
+#include "mlir/IR/ExtensibleDialect.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/Support/LogicalResult.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/Casting.h"
+
+using namespace mlir;
+using namespace mlir::irdl;
+
+//===----------------------------------------------------------------------===//
+// IRDL dialect.
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/IRDL/IR/IRDL.cpp.inc"
+
+#include "mlir/Dialect/IRDL/IR/IRDLDialect.cpp.inc"
+
+void IRDLDialect::initialize() {
+  addOperations<
+#define GET_OP_LIST
+#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"
+      >();
+  addTypes<
+#define GET_TYPEDEF_LIST
+#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
+      >();
+}
+
+//===----------------------------------------------------------------------===//
+// Parsing/Printing
+//===----------------------------------------------------------------------===//
+
+/// Parse a region, and add a single block if the region is empty.
+/// If no region is parsed, create a new region with a single empty block.
+static ParseResult parseSingleBlockRegion(OpAsmParser &p, Region &region) {
+  auto regionParseRes = p.parseOptionalRegion(region);
+  if (regionParseRes.has_value() && failed(regionParseRes.value()))
+    return failure();
+
+  // If the region is empty, add a single empty block.
+  if (region.empty())
+    region.push_back(new Block());
+
+  return success();
+}
+
+static void printSingleBlockRegion(OpAsmPrinter &p, Operation *op,
+                                   Region &region) {
+  if (!region.getBlocks().front().empty())
+    p.printRegion(region);
+}
+
+LogicalResult DialectOp::verify() {
+  if (!Dialect::isValidNamespace(getName()))
+    return emitOpError("invalid dialect name");
+  return success();
+}
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"

diff  --git a/mlir/test/Dialect/IRDL/cmath.irdl.mlir b/mlir/test/Dialect/IRDL/cmath.irdl.mlir
new file mode 100644
index 000000000000..aaa51501791c
--- /dev/null
+++ b/mlir/test/Dialect/IRDL/cmath.irdl.mlir
@@ -0,0 +1,43 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+module {
+  // CHECK-LABEL: irdl.dialect @cmath {
+  irdl.dialect @cmath {
+
+    // CHECK: irdl.type @complex {
+    // CHECK:   %[[v0:[^ ]*]] = irdl.is f32
+    // CHECK:   irdl.parameters(%[[v0]])
+    // CHECK: }
+    irdl.type @complex {
+      %0 = irdl.is f32
+      irdl.parameters(%0)
+    }
+
+    // CHECK: irdl.operation @norm {
+    // CHECK:   %[[v0:[^ ]*]] = irdl.any
+    // CHECK:   %[[v1:[^ ]*]] = irdl.parametric @complex<%[[v0]]>
+    // CHECK:   irdl.operands(%[[v1]])
+    // CHECK:   irdl.results(%[[v0]])
+    // CHECK: }
+    irdl.operation @norm {
+      %0 = irdl.any
+      %1 = irdl.parametric @complex<%0>
+      irdl.operands(%1)
+      irdl.results(%0)
+    }
+
+    // CHECK: irdl.operation @mul {
+    // CHECK:   %[[v0:[^ ]*]] = irdl.is f32
+    // CHECK:   %[[v3:[^ ]*]] = irdl.parametric @complex<%[[v0]]>
+    // CHECK:   irdl.operands(%[[v3]], %[[v3]])
+    // CHECK:   irdl.results(%[[v3]])
+    // CHECK: }
+    irdl.operation @mul {
+      %0 = irdl.is f32
+      %3 = irdl.parametric @complex<%0>
+      irdl.operands(%3, %3)
+      irdl.results(%3)
+    }
+
+  }
+}

diff  --git a/mlir/test/Dialect/IRDL/testd.irdl.mlir b/mlir/test/Dialect/IRDL/testd.irdl.mlir
new file mode 100644
index 000000000000..d4a33ca38a19
--- /dev/null
+++ b/mlir/test/Dialect/IRDL/testd.irdl.mlir
@@ -0,0 +1,71 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// CHECK: irdl.dialect @testd {
+irdl.dialect @testd {
+  // CHECK: irdl.type @parametric {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.any
+  // CHECK:   irdl.parameters(%[[v0]])
+  // CHECK: }
+  irdl.type @parametric {
+    %0 = irdl.any
+    irdl.parameters(%0)
+  }
+
+  // CHECK: irdl.type @attr_in_type_out {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.any
+  // CHECK:   irdl.parameters(%[[v0]])
+  // CHECK: }
+  irdl.type @attr_in_type_out {
+    %0 = irdl.any
+    irdl.parameters(%0)
+  }
+
+  // CHECK: irdl.operation @eq {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.is i32
+  // CHECK:   irdl.results(%[[v0]])
+  // CHECK: }
+  irdl.operation @eq {
+    %0 = irdl.is i32
+    irdl.results(%0)
+  }
+
+  // CHECK: irdl.operation @any {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.any
+  // CHECK:   irdl.results(%[[v0]])
+  // CHECK: }
+  irdl.operation @any {
+    %0 = irdl.any
+    irdl.results(%0)
+  }
+
+  // CHECK: irdl.operation @dynbase {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.any
+  // CHECK:   %[[v1:[^ ]*]] = irdl.parametric @parametric<%[[v0]]>
+  // CHECK:   irdl.results(%[[v1]])
+  // CHECK: }
+  irdl.operation @dynbase {
+    %0 = irdl.any
+    %1 = irdl.parametric @parametric<%0>
+    irdl.results(%1)
+  }
+
+  // CHECK: irdl.operation @dynparams {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.is i32
+  // CHECK:   %[[v3:[^ ]*]] = irdl.parametric @parametric<%[[v0]]>
+  // CHECK:   irdl.results(%[[v3]])
+  // CHECK: }
+  irdl.operation @dynparams {
+    %0 = irdl.is i32
+    %3 = irdl.parametric @parametric<%0>
+    irdl.results(%3)
+  }
+
+  // CHECK: irdl.operation @constraint_vars {
+  // CHECK:   %[[v0:[^ ]*]] = irdl.any
+  // CHECK:   irdl.results(%[[v0]], %[[v0]])
+  // CHECK: }
+  irdl.operation @constraint_vars {
+    %0 = irdl.any
+    irdl.results(%0, %0)
+  }
+}

diff  --git a/mlir/test/mlir-opt/commandline.mlir b/mlir/test/mlir-opt/commandline.mlir
index 70766498b5d8..1b2ab3f47b81 100644
--- a/mlir/test/mlir-opt/commandline.mlir
+++ b/mlir/test/mlir-opt/commandline.mlir
@@ -17,6 +17,7 @@
 // CHECK-SAME: func
 // CHECK-SAME: gpu
 // CHECK-SAME: index
+// CHECK-SAME: irdl
 // CHECK-SAME: linalg
 // CHECK-SAME: llvm
 // CHECK-SAME: math


        


More information about the Mlir-commits mailing list