From: Mathieu Fehr Date: Mon, 3 Apr 2023 16:42:53 +0000 (-0700) Subject: [mlir] Introduce IRDL dialect X-Git-Tag: upstream/17.0.6~12832 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=31229d48bbfd394b64179d9be94f74ab70c84630;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/mlir/include/mlir/Dialect/CMakeLists.txt b/mlir/include/mlir/Dialect/CMakeLists.txt index a9843d1..58cc690 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 0000000..f33061b --- /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 0000000..e165bd7 --- /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 0000000..c22f5e2 --- /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 + +// 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 0000000..c8303a2 --- /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 0000000..59d1524 --- /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 traits = []> + : Op; + +class AtMostOneChildOf : 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($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($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($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:$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($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:$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:$args); + let assemblyFormat = " `(` $args `)` attr-dict "; +} + +//===----------------------------------------------------------------------===// +// IRDL Constraint operations +//===----------------------------------------------------------------------===// + +class IRDL_ConstraintOp traits = []> + : IRDL_Op { +} + +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:$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 0000000..1755341 --- /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 +class AtMostOneChildOf { +public: + template + class Impl + : public TraitBase::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(op).getOps()) { + int childOpIndex = 0; + if (((isa(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 + std::enable_if_t...>::value, + std::optional> + getOp() { + auto ops = + cast(this->getOperation()).template getOps(); + 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 0000000..7073eb81 --- /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 traits = []> + : TypeDef { + 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 aa7abb0..9090189 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 ®istry) { 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 5cf5c12..6f01ea7 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 0000000..4987a98 --- /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 0000000..e2649f2 --- /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 ®ion) { + 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 ®ion) { + 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 0000000..aaa5150 --- /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 0000000..d4a33ca --- /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 7076649..1b2ab3f 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