MLIR

Multi-Level IR Compiler Framework

'irdl' Dialect

IR Definition Language Dialect 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:

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.

Operations 

source

irdl.all_of (irdl::AllOfOp) 

Constraints to the intersection of the provided constraints

Syntax:

operation ::= `irdl.all_of` `(` $args `)` ` ` attr-dict

irdl.all_of defines a constraint that accepts any type or attribute that satisfies all of its provided constraints.

Example:

irdl.dialect cmath {
  irdl.type complex_f32 {
    %0 = irdl.is i32
    %1 = irdl.is f32
    %2 = irdl.any_of(%0, %1) // is 32-bit

    %3 = irdl.is f32
    %4 = irdl.is f64
    %5 = irdl.any_of(%3, %4) // is a float

    %6 = irdl.all_of(%2, %5) // is a 32-bit float
    irdl.parameters(%6)
  }
}

The above program defines a type complex inside the dialect cmath that can has one parameter that must be 32-bit long and a float (in other words, that must be f32).

Traits: HasParent<TypeOp, AttributeOp, OperationOp>, SameOperandsAndResultType

Interfaces: VerifyConstraintInterface

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.any (irdl::AnyOp) 

Accept any type or attribute

Syntax:

operation ::= `irdl.any` attr-dict

irdl.any defines a constraint that accepts any type or attribute.

Example:

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.

Traits: HasParent<TypeOp, AttributeOp, OperationOp>

Interfaces: InferTypeOpInterface, VerifyConstraintInterface

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.any_of (irdl::AnyOfOp) 

Constraints to the union of the provided constraints

Syntax:

operation ::= `irdl.any_of` `(` $args `)` ` ` attr-dict

irdl.any_of defines a constraint that accepts any type or attribute that satisfies at least one of its provided type constraints.

Example:

irdl.dialect cmath {
  irdl.type complex {
    %0 = irdl.is i32
    %1 = irdl.is i64
    %2 = irdl.is f32
    %3 = irdl.is f64
    %4 = irdl.any_of(%0, %1, %2, %3)
    irdl.parameters(%4)
  }
}

The above program defines a type complex inside the dialect cmath that can have a single type parameter that can be either i32, i64, f32 or f32.

Traits: HasParent<TypeOp, AttributeOp, OperationOp>, SameOperandsAndResultType

Interfaces: VerifyConstraintInterface

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.attribute (irdl::AttributeOp) 

Define a new attribute

Syntax:

operation ::= `irdl.attribute` $sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)

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:

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".

Traits: AtMostOneChildOf<ParametersOp>, HasParent<DialectOp>, NoRegionArguments, NoTerminator

Interfaces: Symbol

Attributes: 

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute

irdl.attributes (irdl::AttributesOp) 

Define the attributes of an operation

Syntax:

operation ::= `irdl.attributes` custom<AttributesOp>($attributeValues, $attributeValueNames) attr-dict

irdl.attributes defines the attributes of the irdl.operation parent operation definition.

In the following example, irdl.attributes defines the attributes of the attr_op operation:

irdl.dialect @example {

  irdl.operation @attr_op {
    %0 = irdl.any
    %1 = irdl.is i64
    irdl.attibutes {
      "attr1" = %0,
      "attr2" = %1
    }
  }
}

The operation will expect an arbitrary attribute “attr1” and an attribute “attr2” with value i64.

Traits: HasParent<OperationOp>

Attributes: 

AttributeMLIR TypeDescription
attributeValueNames::mlir::ArrayAttrstring array attribute

Operands: 

OperandDescription
attributeValuesvariadic of IRDL handle to an mlir::Attribute

irdl.base (irdl::BaseOp) 

Constraints an attribute/type base

Syntax:

operation ::= `irdl.base` ($base_ref^)? ($base_name^)? ` ` attr-dict

irdl.base defines a constraint that only accepts a single type or attribute base, e.g. an IntegerType. The attribute base is defined either by a symbolic reference to the corresponding IRDL definition, or by the name of the base. Named bases are prefixed with ! or # respectively for types and attributes.

Example:

irdl.dialect @cmath {
  irdl.type @complex {
    %0 = irdl.base "!builtin.integer"
    irdl.parameters(%0)
  }

  irdl.type @complex_wrapper {
    %0 = irdl.base @complex
    irdl.parameters(%0)
  }
}

The above program defines a cmath.complex type that expects a single parameter, which is a type with base name builtin.integer, which is the name of an IntegerType type. It also defines a cmath.complex_wrapper type that expects a single parameter, which is a type of base type cmath.complex.

Traits: HasParent<TypeOp, AttributeOp, OperationOp>

Interfaces: InferTypeOpInterface, SymbolUserOpInterface, VerifyConstraintInterface

Attributes: 

AttributeMLIR TypeDescription
base_ref::mlir::SymbolRefAttrsymbol reference attribute
base_name::mlir::StringAttrstring attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.c_pred (irdl::CPredOp) 

Constraints an attribute using a C++ predicate

Syntax:

operation ::= `irdl.c_pred` $pred ` ` attr-dict

irdl.c_pred defines a constraint that is written in C++.

Dialects using this operation cannot be registered at runtime, as it relies on C++ code.

Special placeholders can be used to refer to entities in the context where this predicate is used. They serve as “hooks” to the enclosing environment. The following special placeholders are supported in constraints for an op:

  • $_builder will be replaced by a mlir::Builder instance.
  • $_op will be replaced by the current operation.
  • $_self will be replaced with the entity this predicate is attached to. Compared to ODS, $_self is always of type mlir::Attribute, and types are manipulated as TypeAttr attributes.

Example:

irdl.type @op_with_attr {
  %0 = irdl.c_pred "::llvm::isa<::mlir::IntegerAttr>($_self)"
  irdl.parameters(%0)
}

In this example, @op_with_attr is defined as a type with a single parameter, which is an IntegerAttr, as constrained by the C++ predicate.

Interfaces: InferTypeOpInterface

Attributes: 

AttributeMLIR TypeDescription
pred::mlir::StringAttrstring attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.dialect (irdl::DialectOp) 

Define a new dialect

Syntax:

operation ::= `irdl.dialect` $sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)

The irdl.dialect operation defines a dialect. All operations, attributes, and types defined inside its region will be part of the dialect.

Example:

irdl.dialect @cmath {
  ...
}

The above program defines a cmath dialect.

Traits: IsolatedFromAbove, NoTerminator, SymbolTable

Interfaces: Symbol

Attributes: 

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute

irdl.is (irdl::IsOp) 

Constraints an attribute/type to be a specific attribute instance

Syntax:

operation ::= `irdl.is` $expected ` ` attr-dict

irdl.is defines a constraint that only accepts a specific instance of a type or attribute.

Example:

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.

Traits: AlwaysSpeculatableImplTrait, HasParent<TypeOp, AttributeOp, OperationOp>

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), VerifyConstraintInterface

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
expected::mlir::Attributeany attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.operands (irdl::OperandsOp) 

Define the operands of an operation

Syntax:

operation ::= `irdl.operands` `` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict

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:

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.

The operands can also be marked as variadic or optional:

irdl.operands(%0, single %1, optional %2, variadic %3)

Here, %0 and %1 are required single operands, %2 is an optional operand, and %3 is a variadic operand.

When more than one operand is marked as optional or variadic, the operation will expect a ‘operandSegmentSizes’ attribute that defines the number of operands in each segment.

Traits: HasParent<OperationOp>

Attributes: 

AttributeMLIR TypeDescription
variadicity::mlir::irdl::VariadicityArrayAttr

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

irdl.operation (irdl::OperationOp) 

Define a new operation

Syntax:

operation ::= `irdl.operation` $sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)

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:

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.

Traits: AtMostOneChildOf<OperandsOp, ResultsOp, AttributesOp, RegionsOp>, HasParent<DialectOp>, NoRegionArguments, NoTerminator

Interfaces: Symbol

Attributes: 

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute

irdl.parameters (irdl::ParametersOp) 

Define the constraints on parameters of a type/attribute definition

Syntax:

operation ::= `irdl.parameters` `(` $args `)` attr-dict

irdl.parameters defines the constraints on parameters of a type or attribute definition.

Example:

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.

Traits: HasParent<AttributeOp, TypeOp>

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

irdl.parametric (irdl::ParametricOp) 

Constraints an attribute/type base and its parameters

Syntax:

operation ::= `irdl.parametric` $base_type `<` $args `>` ` ` attr-dict

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:

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.

Traits: AlwaysSpeculatableImplTrait, HasParent<TypeOp, AttributeOp, OperationOp>

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), SymbolUserOpInterface, VerifyConstraintInterface

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
base_type::mlir::SymbolRefAttrsymbol reference attribute

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

Results: 

ResultDescription
outputIRDL handle to an mlir::Attribute

irdl.region (irdl::RegionOp) 

Define a region of an operation

Syntax:

operation ::= `irdl.region` ``(`(` $entryBlockArgs $constrainedArguments^ `)`)?
              ``(` ` `with` `size` $numberOfBlocks^)? attr-dict

The irdl.region construct defines a set of characteristics that a region of an operation should satify.

These characteristics include constraints for the entry block arguments of the region and the total number of blocks it contains. The number of blocks must be a non-zero and non-negative integer, and it is optional by default. The set of constraints for the entry block arguments may be optional or empty. If no parentheses are provided, the set is assumed to be optional, and the arguments are not constrained in any way. If parentheses are provided with no arguments, it means that the region must have no entry block arguments

Example:

irdl.dialect @example {
  irdl.operation @op_with_regions {
      %r0 = irdl.region
      %r1 = irdl.region()
      %v0 = irdl.is i32
      %v1 = irdl.is i64
      %r2 = irdl.region(%v0, %v1)
      %r3 = irdl.region with size 3

      irdl.regions(%r0, %r1, %r2, %r3)
  }
}

The above snippet demonstrates an operation named @op_with_regions, which is constrained to have four regions.

  • Region %r0 doesn’t have any constraints on the arguments or the number of blocks.
  • Region %r1 should have an empty set of arguments.
  • Region %r2 should have two arguments of types i32 and i64.
  • Region %r3 should contain exactly three blocks.

Traits: HasParent<OperationOp>

Interfaces: InferTypeOpInterface, VerifyRegionInterface

Attributes: 

AttributeMLIR TypeDescription
numberOfBlocks::mlir::IntegerAttr32-bit signless integer attribute
constrainedArguments::mlir::UnitAttrunit attribute

Operands: 

OperandDescription
entryBlockArgsvariadic of IRDL handle to an mlir::Attribute

Results: 

ResultDescription
outputIRDL handle to a region definition

irdl.regions (irdl::RegionsOp) 

Define the regions of an operation

Syntax:

operation ::= `irdl.regions` `(` $args `)` attr-dict

irdl.regions defines the regions of an operation by accepting values produced by irdl.region operation as arguments.

Example:

irdl.dialect @example {
  irdl.operation @op_with_regions {
    %r1 = irdl.region with size 3
    %0 = irdl.any
    %r2 = irdl.region(%0)
    irdl.regions(%r1, %r2)
  }
}

In the snippet above the operation is constrained to have two regions. The first region should contain three blocks. The second region should have one region with one argument.

Traits: HasParent<OperationOp>

Operands: 

OperandDescription
argsvariadic of IRDL handle to a region definition

irdl.results (irdl::ResultsOp) 

Define the results of an operation

Syntax:

operation ::= `irdl.results` `` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict

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:

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.

The results can also be marked as variadic or optional:

irdl.results(%0, single %1, optional %2, variadic %3)

Here, %0 and %1 are required single results, %2 is an optional result, and %3 is a variadic result.

When more than one result is marked as optional or variadic, the operation will expect a ‘resultSegmentSizes’ attribute that defines the number of results in each segment.

Traits: HasParent<OperationOp>

Attributes: 

AttributeMLIR TypeDescription
variadicity::mlir::irdl::VariadicityArrayAttr

Operands: 

OperandDescription
argsvariadic of IRDL handle to an mlir::Attribute

irdl.type (irdl::TypeOp) 

Define a new type

Syntax:

operation ::= `irdl.type` $sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)

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:

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.

Traits: AtMostOneChildOf<ParametersOp>, HasParent<DialectOp>, NoRegionArguments, NoTerminator

Interfaces: Symbol

Attributes: 

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute

Attributes 

VariadicityArrayAttr 

Syntax:

#irdl.variadicity_array<
  ::llvm::ArrayRef<VariadicityAttr>   # value
>

Parameters: 

ParameterC++ typeDescription
value::llvm::ArrayRef<VariadicityAttr>

VariadicityAttr 

A variadicity kind. Can be either ‘single’, ‘optional’, or ‘variadic’

Syntax:

#irdl.variadicity<
  ::mlir::irdl::Variadicity   # value
>

A irdl.variadicity attribute specifies that the associated operand or result definition is either a single definition (the default), an optional definition, or a variadic definition.

For instance:

irdl.operands (%arg1, single %arg2, optional %arg3, variadic %arg4)

In this example, both %arg1 and %arg2 are single operands, %arg3 is an optional operand, and %arg4 is a variadic operand.

Parameters: 

ParameterC++ typeDescription
value::mlir::irdl::Variadicityan enum of type Variadicity

Types 

AttributeType 

IRDL handle to an mlir::Attribute

Syntax: !irdl.attribute

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:

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.

RegionType 

IRDL handle to a region definition

Syntax: !irdl.region

This type represents a region constraint. It is produced by the irdl.region operation and consumed by the irdl.regions operation. The region can be constrained on the number of arguments and the number of blocks.

Example:

irdl.dialect @example {
  irdl.operation @op_with_regions {
    %r1 = irdl.region with size 3
    %0 = irdl.any
    %r2 = irdl.region(%0)
    irdl.regions(%r1, %r2)
  }
}

Here we have %r1 and %r2, both of which have the type !irdl.region.