[Mlir-commits] [mlir] [IRDL] [NFC] Add the IRDL dialect rationale document (PR #157858)
Théo Degioanni
llvmlistbot at llvm.org
Thu Sep 11 03:11:04 PDT 2025
https://github.com/Moxinilian updated https://github.com/llvm/llvm-project/pull/157858
>From 367d9f6e4d7e35e3f27e44cb85de57b03ec49dfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20Degioanni?=
<theo.degioanni.llvm.deluge062 at simplelogin.fr>
Date: Wed, 10 Sep 2025 14:39:01 +0100
Subject: [PATCH 1/4] add IRDL rationale
---
mlir/docs/Rationale/IRDLRationale.md | 58 ++++++++++++++++++++++++++++
mlir/docs/Rationale/_index.md | 4 ++
2 files changed, 62 insertions(+)
create mode 100644 mlir/docs/Rationale/IRDLRationale.md
diff --git a/mlir/docs/Rationale/IRDLRationale.md b/mlir/docs/Rationale/IRDLRationale.md
new file mode 100644
index 0000000000000..0fddb1d34760b
--- /dev/null
+++ b/mlir/docs/Rationale/IRDLRationale.md
@@ -0,0 +1,58 @@
+# IRDL Rationale
+
+The IRDL (*Intermediate Representation Definition Language*) dialect allows defining MLIR dialects as MLIR programs. Nested operations are used to represent dialect structure: dialects contain operations, types and attributes, themselves containing type parameters, operands, results, etc. Each of those concepts are mapped to MLIR operations in the IRDL dialect, as shown in the example below:
+
+```mlir
+irdl.dialect @my_dialect {
+ irdl.type @my_type {
+ // This type has a single parameter that must be i32.
+ %constraint = irdl.is : i32
+ irdl.parameters(param1: %constraint)
+ }
+
+ irdl.operation @my_scale_op {
+ // This operation represents the scaling of a vector.
+ %vec_constraint = irdl.is : vector<i64>
+ %scalar_constraint = irdl.is : i64
+ irdl.operands(vector: %vec_constraint, scalar: %scalar_constraint)
+ irdl.results(result: %vec_constraint)
+ }
+}
+```
+
+IRDL provides a declarative way to define verifiers using constraint operations (`irdl.is` in the example above). See [constraints and combinators](#constraints-and-combinators) for more details.
+
+The core principles of IRDL are the following, in no particular order:
+
+- **Portability.** IRDL dialects should be self-contained, such that dialects can be easily distributed with minimal assumptions on which compiler infrastructure (or which commit of MLIR) is used.
+- **Introspection.** The IRDL dialect definition mechanism should strive towards offering as much introspection abilities as possible. Dialects should be as easy to manipulate, generate, and analyze as possible.
+- **Runtime declaration support**. The specification of IRDL dialects should offer the ability to have them be loaded at runtime, via dynamic registration or JIT compilation. Compatibility with dynamic workflows should not hinder the ability to compile IRDL dialects into ahead-of-time declarations.
+- **Reliability.** Concepts in IRDL should be consistent and predictable, with as much focus on high-level simplicity as possible. Consequently, IRDL definitions that verify should work out of the box, and those that do not verify should provide clear and understandable errors in all circumstances.
+
+While IRDL simplifies IR definition, it remains an IR itself and thus does not require to be comfortably user-writeable.
+
+## Constraints and combinators
+
+Attribute, type and operation verifiers are expressed in terms of constraint variables. Constraint variables are defined as the results of constraint operations (like `irdl.is` or constraint combinators).
+
+Constraint variables act as variables: as such, matching against the same constraint variable multiple times can only succeed if the matching type or attribute is the same as the one that previously matched. In the following example:
+
+```
+irdl.type foo {
+ %ty = irdl.any_type
+ irdl.parameters(param1: %ty, param2: %ty)
+}
+```
+
+only types with two equal parameters will successfully match (`foo<i32, i32>` would match while `foo<i32, i64>` would fail, even though both i32 and i64 individually satisfy the `irdl.any_type` constraint). This constraint variable mechanism allows to easily express a requirement on type or attribute equality.
+
+To declare more complex verifiers, IRDL provides constraint-combinator operations such as `irdl.any_of`, `irdl.all_of` or `irdl.parametric`. These combinators can be used to combine constraint variables into new constraint variables. Like all uses of constraint variables, their constraint variable operands enforce equality of matched types of attributes as explained in the previous paragraph.
+
+## Motivating use cases
+
+To illustrate the rationale behind IRDL, the following list describes examples of intended use cases for IRDL, in no particular order:
+
+- **Fuzzer generation.** With declarative verifier definitions, it is possible to compile IRDL dialects into compiler fuzzers that generate only programs passing verifiers.
+- **Portable dialects between compiler infrastructures.** Some compiler infrastructures are independent from MLIR but are otherwise IR-compatible. Portable IRDL dialects allow to share the dialect definitions between MLIR and other compiler infrastructures without needing to maintain multiple potentially out-of-sync definitions.
+- **Dialect simplification.** Because IRDL definitions can easily be mechanically modified, it is possible to simplify the definition of dialects based on which operations are actually used, leading to smaller compilers.
+- **SMT analysis.** Because IRDL dialect definitions are declarative, their definition can be lowered to alternative representations like SMT, allowing analysis of the behavior of transforms taking verifiers into account.
diff --git a/mlir/docs/Rationale/_index.md b/mlir/docs/Rationale/_index.md
index 4fd0362ff55f5..6ad70a542058a 100644
--- a/mlir/docs/Rationale/_index.md
+++ b/mlir/docs/Rationale/_index.md
@@ -29,3 +29,7 @@ rationale for some of the design decisions behind MLIR.
[Usage of 'const' in MLIR, for core IR types](UsageOfConst.md)
: Explains the rationale for eschewing the use of `const` entirely for the
core IR types in MLIR.
+
+[IRDL Rationale](IRDLRationale.md)
+: Describes the purpose of the IRDL dialect and the guiding principles behind
+ it.
>From 538bc18faaec4192b69d4b20706057e9e06877b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20Degioanni?=
<theo.degioanni.llvm.deluge062 at simplelogin.fr>
Date: Thu, 11 Sep 2025 10:58:41 +0100
Subject: [PATCH 2/4] move rationale to dialect docs
---
.../IRDLRationale.md => Dialects/IRDL.md} | 67 +++++++++++++------
.../mlir/Dialect/IRDL/IR/CMakeLists.txt | 2 +-
2 files changed, 47 insertions(+), 22 deletions(-)
rename mlir/docs/{Rationale/IRDLRationale.md => Dialects/IRDL.md} (72%)
diff --git a/mlir/docs/Rationale/IRDLRationale.md b/mlir/docs/Dialects/IRDL.md
similarity index 72%
rename from mlir/docs/Rationale/IRDLRationale.md
rename to mlir/docs/Dialects/IRDL.md
index 0fddb1d34760b..8a841b83ca620 100644
--- a/mlir/docs/Rationale/IRDLRationale.md
+++ b/mlir/docs/Dialects/IRDL.md
@@ -1,26 +1,47 @@
-# IRDL Rationale
+# 'irdl' Dialect
-The IRDL (*Intermediate Representation Definition Language*) dialect allows defining MLIR dialects as MLIR programs. Nested operations are used to represent dialect structure: dialects contain operations, types and attributes, themselves containing type parameters, operands, results, etc. Each of those concepts are mapped to MLIR operations in the IRDL dialect, as shown in the example below:
+[TOC]
+
+## Basics
+
+The IRDL (*Intermediate Representation Definition Language*) dialect allows defining MLIR dialects as MLIR programs. Nested operations are used to represent dialect structure: dialects contain operations, types and attributes, themselves containing type parameters, operands, results, etc. Each of those concepts are mapped to MLIR operations in the IRDL dialect, as shown in the example dialect below:
```mlir
-irdl.dialect @my_dialect {
- irdl.type @my_type {
- // This type has a single parameter that must be i32.
- %constraint = irdl.is : i32
- irdl.parameters(param1: %constraint)
- }
-
- irdl.operation @my_scale_op {
- // This operation represents the scaling of a vector.
- %vec_constraint = irdl.is : vector<i64>
- %scalar_constraint = irdl.is : i64
- irdl.operands(vector: %vec_constraint, scalar: %scalar_constraint)
- irdl.results(result: %vec_constraint)
- }
+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 @mul {
+ %0 = irdl.is f32
+ %1 = irdl.is f64
+ %2 = irdl.any_of(%0, %1)
+ %3 = irdl.parametric @cmath::@complex<%2>
+ irdl.operands(%3, %3)
+ irdl.results(%3)
+ }
}
```
-IRDL provides a declarative way to define verifiers using constraint operations (`irdl.is` in the example above). See [constraints and combinators](#constraints-and-combinators) for more details.
+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). For more information, see
+[constraints and combinators](#constraints-and-combinators).
+
+In order to simplify the dialect, IRDL variables are handles over
+`mlir::Attribute`. In order to support manipulating `mlir::Type`,
+IRDL wraps all types in an `mlir::TypeAttr` attribute.
+
+## Principles
The core principles of IRDL are the following, in no particular order:
@@ -37,10 +58,10 @@ Attribute, type and operation verifiers are expressed in terms of constraint var
Constraint variables act as variables: as such, matching against the same constraint variable multiple times can only succeed if the matching type or attribute is the same as the one that previously matched. In the following example:
-```
-irdl.type foo {
- %ty = irdl.any_type
- irdl.parameters(param1: %ty, param2: %ty)
+```mlir
+irdl.type @foo {
+ %ty = irdl.any_type
+ irdl.parameters(param1: %ty, param2: %ty)
}
```
@@ -56,3 +77,7 @@ To illustrate the rationale behind IRDL, the following list describes examples o
- **Portable dialects between compiler infrastructures.** Some compiler infrastructures are independent from MLIR but are otherwise IR-compatible. Portable IRDL dialects allow to share the dialect definitions between MLIR and other compiler infrastructures without needing to maintain multiple potentially out-of-sync definitions.
- **Dialect simplification.** Because IRDL definitions can easily be mechanically modified, it is possible to simplify the definition of dialects based on which operations are actually used, leading to smaller compilers.
- **SMT analysis.** Because IRDL dialect definitions are declarative, their definition can be lowered to alternative representations like SMT, allowing analysis of the behavior of transforms taking verifiers into account.
+
+## Operations
+
+[include "Dialects/IRDLOps.md"]
diff --git a/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
index ec3e06bedae03..beadd51d84301 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
@@ -1,5 +1,5 @@
add_mlir_dialect(IRDL irdl)
-add_mlir_doc(IRDLOps IRDL Dialects/ -gen-dialect-doc)
+add_mlir_doc(IRDLOps IRDLOps Dialects/ -gen-op-doc)
# Add IRDL interfaces
set(LLVM_TARGET_DEFINITIONS IRDLInterfaces.td)
>From 54b5a986a5aa2b6d8d1e8e2f629df080672c9d24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20Degioanni?=
<theo.degioanni.llvm.deluge062 at simplelogin.fr>
Date: Thu, 11 Sep 2025 11:03:41 +0100
Subject: [PATCH 3/4] fix line lengths
---
mlir/docs/Dialects/IRDL.md | 74 +++++++++++++++++++++++++++++---------
1 file changed, 57 insertions(+), 17 deletions(-)
diff --git a/mlir/docs/Dialects/IRDL.md b/mlir/docs/Dialects/IRDL.md
index 8a841b83ca620..c09457ac38634 100644
--- a/mlir/docs/Dialects/IRDL.md
+++ b/mlir/docs/Dialects/IRDL.md
@@ -4,7 +4,12 @@
## Basics
-The IRDL (*Intermediate Representation Definition Language*) dialect allows defining MLIR dialects as MLIR programs. Nested operations are used to represent dialect structure: dialects contain operations, types and attributes, themselves containing type parameters, operands, results, etc. Each of those concepts are mapped to MLIR operations in the IRDL dialect, as shown in the example dialect below:
+The IRDL (*Intermediate Representation Definition Language*) dialect allows
+defining MLIR dialects as MLIR programs. Nested operations are used to
+represent dialect structure: dialects contain operations, types and
+attributes, themselves containing type parameters, operands, results, etc.
+Each of those concepts are mapped to MLIR operations in the IRDL dialect, as
+shown in the example dialect below:
```mlir
irdl.dialect @cmath {
@@ -45,18 +50,34 @@ IRDL wraps all types in an `mlir::TypeAttr` attribute.
The core principles of IRDL are the following, in no particular order:
-- **Portability.** IRDL dialects should be self-contained, such that dialects can be easily distributed with minimal assumptions on which compiler infrastructure (or which commit of MLIR) is used.
-- **Introspection.** The IRDL dialect definition mechanism should strive towards offering as much introspection abilities as possible. Dialects should be as easy to manipulate, generate, and analyze as possible.
-- **Runtime declaration support**. The specification of IRDL dialects should offer the ability to have them be loaded at runtime, via dynamic registration or JIT compilation. Compatibility with dynamic workflows should not hinder the ability to compile IRDL dialects into ahead-of-time declarations.
-- **Reliability.** Concepts in IRDL should be consistent and predictable, with as much focus on high-level simplicity as possible. Consequently, IRDL definitions that verify should work out of the box, and those that do not verify should provide clear and understandable errors in all circumstances.
-
-While IRDL simplifies IR definition, it remains an IR itself and thus does not require to be comfortably user-writeable.
+- **Portability.** IRDL dialects should be self-contained, such that dialects
+ can be easily distributed with minimal assumptions on which compiler
+ infrastructure (or which commit of MLIR) is used.
+- **Introspection.** The IRDL dialect definition mechanism should strive
+ towards offering as much introspection abilities as possible. Dialects
+ should be as easy to manipulate, generate, and analyze as possible.
+- **Runtime declaration support**. The specification of IRDL dialects should
+ offer the ability to have them be loaded at runtime, via dynamic registration
+ or JIT compilation. Compatibility with dynamic workflows should not hinder
+ the ability to compile IRDL dialects into ahead-of-time declarations.
+- **Reliability.** Concepts in IRDL should be consistent and predictable, with
+ as much focus on high-level simplicity as possible. Consequently, IRDL
+ definitions that verify should work out of the box, and those that do not
+ verify should provide clear and understandable errors in all circumstances.
+
+While IRDL simplifies IR definition, it remains an IR itself and thus does not
+require to be comfortably user-writeable.
## Constraints and combinators
-Attribute, type and operation verifiers are expressed in terms of constraint variables. Constraint variables are defined as the results of constraint operations (like `irdl.is` or constraint combinators).
+Attribute, type and operation verifiers are expressed in terms of constraint
+variables. Constraint variables are defined as the results of constraint
+operations (like `irdl.is` or constraint combinators).
-Constraint variables act as variables: as such, matching against the same constraint variable multiple times can only succeed if the matching type or attribute is the same as the one that previously matched. In the following example:
+Constraint variables act as variables: as such, matching against the same
+constraint variable multiple times can only succeed if the matching type or
+attribute is the same as the one that previously matched. In the following
+example:
```mlir
irdl.type @foo {
@@ -65,18 +86,37 @@ irdl.type @foo {
}
```
-only types with two equal parameters will successfully match (`foo<i32, i32>` would match while `foo<i32, i64>` would fail, even though both i32 and i64 individually satisfy the `irdl.any_type` constraint). This constraint variable mechanism allows to easily express a requirement on type or attribute equality.
+only types with two equal parameters will successfully match (`foo<i32, i32>`
+would match while `foo<i32, i64>` would fail, even though both i32 and i64
+individually satisfy the `irdl.any_type` constraint). This constraint variable
+mechanism allows to easily express a requirement on type or attribute equality.
-To declare more complex verifiers, IRDL provides constraint-combinator operations such as `irdl.any_of`, `irdl.all_of` or `irdl.parametric`. These combinators can be used to combine constraint variables into new constraint variables. Like all uses of constraint variables, their constraint variable operands enforce equality of matched types of attributes as explained in the previous paragraph.
+To declare more complex verifiers, IRDL provides constraint-combinator
+operations such as `irdl.any_of`, `irdl.all_of` or `irdl.parametric`. These
+combinators can be used to combine constraint variables into new constraint
+variables. Like all uses of constraint variables, their constraint variable
+operands enforce equality of matched types of attributes as explained in the
+previous paragraph.
## Motivating use cases
-To illustrate the rationale behind IRDL, the following list describes examples of intended use cases for IRDL, in no particular order:
-
-- **Fuzzer generation.** With declarative verifier definitions, it is possible to compile IRDL dialects into compiler fuzzers that generate only programs passing verifiers.
-- **Portable dialects between compiler infrastructures.** Some compiler infrastructures are independent from MLIR but are otherwise IR-compatible. Portable IRDL dialects allow to share the dialect definitions between MLIR and other compiler infrastructures without needing to maintain multiple potentially out-of-sync definitions.
-- **Dialect simplification.** Because IRDL definitions can easily be mechanically modified, it is possible to simplify the definition of dialects based on which operations are actually used, leading to smaller compilers.
-- **SMT analysis.** Because IRDL dialect definitions are declarative, their definition can be lowered to alternative representations like SMT, allowing analysis of the behavior of transforms taking verifiers into account.
+To illustrate the rationale behind IRDL, the following list describes examples
+of intended use cases for IRDL, in no particular order:
+
+- **Fuzzer generation.** With declarative verifier definitions, it is possible
+ to compile IRDL dialects into compiler fuzzers that generate only programs
+ passing verifiers.
+- **Portable dialects between compiler infrastructures.** Some compiler
+ infrastructures are independent from MLIR but are otherwise IR-compatible.
+ Portable IRDL dialects allow to share the dialect definitions between MLIR
+ and other compiler infrastructures without needing to maintain multiple
+ potentially out-of-sync definitions.
+- **Dialect simplification.** Because IRDL definitions can easily be
+ mechanically modified, it is possible to simplify the definition of dialects
+ based on which operations are actually used, leading to smaller compilers.
+- **SMT analysis.** Because IRDL dialect definitions are declarative, their
+ definition can be lowered to alternative representations like SMT, allowing
+ analysis of the behavior of transforms taking verifiers into account.
## Operations
>From cd192011dbf6b4eb0d2258b60d68118c2b8b104a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20Degioanni?=
<theo.degioanni.llvm.deluge062 at simplelogin.fr>
Date: Thu, 11 Sep 2025 11:10:51 +0100
Subject: [PATCH 4/4] remove rationale from index
---
mlir/docs/Rationale/_index.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/mlir/docs/Rationale/_index.md b/mlir/docs/Rationale/_index.md
index 6ad70a542058a..4fd0362ff55f5 100644
--- a/mlir/docs/Rationale/_index.md
+++ b/mlir/docs/Rationale/_index.md
@@ -29,7 +29,3 @@ rationale for some of the design decisions behind MLIR.
[Usage of 'const' in MLIR, for core IR types](UsageOfConst.md)
: Explains the rationale for eschewing the use of `const` entirely for the
core IR types in MLIR.
-
-[IRDL Rationale](IRDLRationale.md)
-: Describes the purpose of the IRDL dialect and the guiding principles behind
- it.
More information about the Mlir-commits
mailing list