Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions mlir/docs/Dialects/IRDL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# 'irdl' Dialect

[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 @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)
}
}
```

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:

- **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:

```mlir
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.

## Operations

[include "Dialects/IRDLOps.md"]
2 changes: 1 addition & 1 deletion mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_mlir_dialect(IRDL irdl)
add_mlir_doc(IRDLOps IRDL Dialects/ -gen-dialect-doc -dialect=irdl)
add_mlir_doc(IRDLOps IRDLOps Dialects/ -gen-op-doc -dialect=irdl)

# Add IRDL interfaces
set(LLVM_TARGET_DEFINITIONS IRDLInterfaces.td)
Expand Down