[Mlir-commits] [mlir] d1e0545 - [mlir][Interfaces] Tidy up the documentation for interfaces
River Riddle
llvmlistbot at llvm.org
Wed Dec 9 15:34:31 PST 2020
Author: River Riddle
Date: 2020-12-09T15:34:07-08:00
New Revision: d1e0545445ced928ae4f0437997278e09cefde1d
URL: https://github.com/llvm/llvm-project/commit/d1e0545445ced928ae4f0437997278e09cefde1d
DIFF: https://github.com/llvm/llvm-project/commit/d1e0545445ced928ae4f0437997278e09cefde1d.diff
LOG: [mlir][Interfaces] Tidy up the documentation for interfaces
The documentation has become a bit stale with age, and doesn't include great documentation for some newer concepts. This revision tidies up a majority of it, with some more cleanup to come in the future. The documentation for the declarative specification is also moved from OpDefinitions.md to Interfaces.md, which is a much more logical place for it to live.
Differential Revision: https://reviews.llvm.org/D92895
Added:
Modified:
mlir/docs/Interfaces.md
mlir/docs/OpDefinitions.md
Removed:
################################################################################
diff --git a/mlir/docs/Interfaces.md b/mlir/docs/Interfaces.md
index 9e32a70888aa..4fe8421295ec 100644
--- a/mlir/docs/Interfaces.md
+++ b/mlir/docs/Interfaces.md
@@ -1,46 +1,47 @@
# Interfaces
-MLIR is a generic and extensible framework, representing
diff erent
-dialects with their own operations, attributes, types, and so on.
-MLIR Dialects can express operations with a wide variety of semantics
-and
diff erent levels of abstraction. The downside to this is that MLIR
-transformations and analyses need to account for the semantics of
-every operation, or handle operations conservatively. Without care,
-this can result in code with special-cases for each supported
-operation type. To combat this, MLIR provides the concept of
-`interfaces`.
+MLIR is a generic and extensible framework, representing
diff erent dialects with
+their own attributes, operations, types, and so on. MLIR Dialects can express
+operations with a wide variety of semantics and
diff erent levels of abstraction.
+The downside to this is that MLIR transformations and analyses need to be able
+to account for the semantics of every operation, or be overly conservative.
+Without care, this can result in code with special-cases for each supported
+operation type. To combat this, MLIR provides a concept of `interfaces`.
## Motivation
Interfaces provide a generic way of interacting with the IR. The goal is to be
able to express transformations/analyses in terms of these interfaces without
encoding specific knowledge about the exact operation or dialect involved. This
-makes the compiler more extensible by allowing the addition of new dialects and
-operations in a decoupled way with respect to the implementation of
+makes the compiler more easily extensible by allowing the addition of new
+dialects and operations in a decoupled way with respect to the implementation of
transformations/analyses.
### Dialect Interfaces
Dialect interfaces are generally useful for transformation passes or analyses
that want to operate generically on a set of attributes/operations/types, which
-might even be defined in
diff erent dialects. These interfaces generally involve
-wide coverage over the entire dialect and are only used for a handful of
-transformations/analyses. In these cases, registering the interface directly on
-each operation is overly complex and cumbersome. The interface is not core to
-the operation, just to the specific transformation. An example of where this
-type of interface would be used is inlining. Inlining generally queries
-high-level information about the operations within a dialect, like legality and
-cost modeling, that often is not specific to one operation.
-
-A dialect interface can be defined by inheriting from the CRTP base class
-`DialectInterfaceBase::Base`. This class provides the necessary utilities for
-registering an interface with the dialect so that it can be looked up later.
-Once the interface has been defined, dialects can override it using
-dialect-specific information. The interfaces defined by a dialect are registered
-in a similar mechanism to Attributes, Operations, Types, etc.
+may be defined in
diff erent dialects. These interfaces generally involve wide
+coverage over an entire dialect and are only used for a handful of analyses or
+transformations. In these cases, registering the interface directly on each
+operation is overly complex and cumbersome. The interface is not core to the
+operation, just to the specific transformation. An example of where this type of
+interface would be used is inlining. Inlining generally queries high-level
+information about the operations within a dialect, like cost modeling and
+legality, that often is not specific to one operation.
+
+A dialect interface can be defined by inheriting from the
+[CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) base
+class `DialectInterfaceBase::Base<>`. This class provides the necessary
+utilities for registering an interface with a dialect so that it can be
+referenced later. Once the interface has been defined, dialects can override it
+using dialect-specific information. The interfaces defined by a dialect are
+registered via `addInterfaces<>`, a similar mechanism to Attributes, Operations,
+Types, etc
```c++
-/// Define an Inlining interface to allow for dialects to opt-in.
+/// Define a base inlining interface class to allow for dialects to opt-in to
+/// the inliner.
class DialectInlinerInterface :
public DialectInterface::Base<DialectInlinerInterface> {
public:
@@ -55,8 +56,8 @@ public:
}
};
-/// Override the inliner interface to add support for inlining affine
-/// operations.
+/// Override the inliner interface to add support for the AffineDialect to
+/// enable inlining affine operations.
struct AffineInlinerInterface : public DialectInlinerInterface {
/// Affine structures have specific inlining constraints.
bool isLegalToInline(Region *dest, Region *src,
@@ -71,21 +72,24 @@ AffineDialect::AffineDialect(MLIRContext *context) ... {
}
```
-Once registered, these interfaces can be queried from the dialect by
-the transformation/analysis that wants to use them, without
-determining the particular dialect subclass:
+Once registered, these interfaces can be queried from the dialect by an analysis
+or transformation without the need to determine the specific dialect subclass:
```c++
Dialect *dialect = ...;
-if (auto *interface = dialect->getInterface<DialectInlinerInterface>())
- ... // The dialect provides this interface.
+if (DialectInlinerInterface *interface
+ = dialect->getRegisteredInterface<DialectInlinerInterface>()) {
+ // The dialect has provided an implementation of this interface.
+ ...
+}
```
-#### DialectInterfaceCollections
+#### DialectInterfaceCollection
-An additional utility is provided via DialectInterfaceCollection. This CRTP
-class allows for collecting all of the dialects that have registered a given
-interface within the context.
+An additional utility is provided via `DialectInterfaceCollection`. This class
+allows for collecting all of the dialects that have registered a given interface
+within an instance of the `MLIRContext`. This can be useful to hide and optimize
+the lookup of a registered dialect interface.
```c++
class InlinerInterface : public
@@ -111,57 +115,80 @@ if(!interface.isLegalToInline(...))
Attribute/Operation/Type interfaces, as the names suggest, are those registered
at the level of a specific attribute/operation/type. These interfaces provide
access to derived objects by providing a virtual interface that must be
-implemented. As an example, the `Linalg` dialect may implement an interface that
-provides general queries about some of the dialects library operations. These
-queries may provide things like: the number of parallel loops; the number of
-inputs and outputs; etc.
-
-These interfaces are defined by overriding the CRTP base class `AttrInterface`,
-`OpInterface`, or `TypeInterface` respectively. These classes take, as a
-template parameter, a `Traits` class that defines a `Concept` and a `Model`
-class. These classes provide an implementation of concept-based polymorphism,
-where the Concept defines a set of virtual methods that are overridden by the
-Model that is templated on the concrete object type. It is important to note
-that these classes should be pure in that they contain no non-static data
-members. Objects that wish to override this interface should add the provided
-trait `*Interface<..>::Trait` to the trait list upon registration.
+implemented. As an example, many analyses and transformations want to reason
+about the side effects of an operation to improve performance and correctness.
+The side effects of an operation are generally tied to the semantics of a
+specific operation, for example an `affine.load` operation has a `write` effect
+(as the name may suggest).
+
+These interfaces are defined by overriding the
+[CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) class
+for the specific IR entity; `AttrInterface`, `OpInterface`, or `TypeInterface`
+respectively. These classes take, as a template parameter, a `Traits` class that
+defines a `Concept` and a `Model` class. These classes provide an implementation
+of concept-based polymorphism, where the `Concept` defines a set of virtual
+methods that are overridden by the `Model` that is templated on the concrete
+entity type. It is important to note that these classes should be pure, and
+should not contain non-static data members or other mutable data. To attach an
+interface to an object, the base interface classes provide a
+[`Trait`](Traits.md) class that can be appended to the trait list of that
+object.
```c++
struct ExampleOpInterfaceTraits {
- /// Define a base concept class that defines the virtual interface that needs
- /// to be overridden.
+ /// Define a base concept class that specifies the virtual interface to be
+ /// implemented.
struct Concept {
virtual ~Concept();
- virtual unsigned getNumInputs(Operation *op) const = 0;
+
+ /// This is an example of a non-static hook to an operation.
+ virtual unsigned exampleInterfaceHook(Operation *op) const = 0;
+
+ /// This is an example of a static hook to an operation. A static hook does
+ /// not require a concrete instance of the operation. The implementation is
+ /// a virtual hook, the same as the non-static case, because the
+ /// implementation of the hook itself still requires indirection.
+ virtual unsigned exampleStaticInterfaceHook() const = 0;
};
/// Define a model class that specializes a concept on a given operation type.
- template <typename OpT>
+ template <typename ConcreteOp>
struct Model : public Concept {
/// Override the method to dispatch on the concrete operation.
- unsigned getNumInputs(Operation *op) const final {
- return llvm::cast<OpT>(op).getNumInputs();
+ unsigned exampleInterfaceHook(Operation *op) const final {
+ return llvm::cast<ConcreteOp>(op).exampleInterfaceHook();
+ }
+
+ /// Override the static method to dispatch to the concrete operation type.
+ unsigned exampleStaticInterfaceHook() const final {
+ return ConcreteOp::exampleStaticInterfaceHook();
}
};
};
+/// Define the main interface class that analyses and transformations will
+/// interface with.
class ExampleOpInterface : public OpInterface<ExampleOpInterface,
ExampleOpInterfaceTraits> {
public:
- /// Use base class constructor to support LLVM-style casts.
+ /// Inherit the base class constructor to support LLVM-style casting.
using OpInterface<ExampleOpInterface, ExampleOpInterfaceTraits>::OpInterface;
- /// The interface dispatches to 'getImpl()', an instance of the concept.
- unsigned getNumInputs() const {
- return getImpl()->getNumInputs(getOperation());
+ /// The interface dispatches to 'getImpl()', a method provided by the base
+ /// `OpInterface` class that returns an instance of the concept.
+ unsigned exampleInterfaceHook() const {
+ return getImpl()->exampleInterfaceHook(getOperation());
+ }
+ unsigned exampleStaticInterfaceHook() const {
+ return getImpl()->exampleStaticInterfaceHook(getOperation()->getName());
}
};
```
Once the interface has been defined, it is registered to an operation by adding
-the provided trait `ExampleOpInterface::Trait`. Using this interface is just
-like using any other derived operation type, i.e. casting:
+the provided trait `ExampleOpInterface::Trait` as described earlier. Using this
+interface is just like using any other derived operation type, i.e. casting:
```c++
/// When defining the operation, the interface is registered via the nested
@@ -169,21 +196,29 @@ like using any other derived operation type, i.e. casting:
class MyOp : public Op<MyOp, ExampleOpInterface::Trait> {
public:
/// The definition of the interface method on the derived operation.
- unsigned getNumInputs() { return ...; }
+ unsigned exampleInterfaceHook() { return ...; }
+ static unsigned exampleStaticInterfaceHook() { return ...; }
};
/// Later, we can query if a specific operation(like 'MyOp') overrides the given
/// interface.
Operation *op = ...;
if (ExampleOpInterface example = dyn_cast<ExampleOpInterface>(op))
- llvm::errs() << "num inputs = " << example.getNumInputs() << "\n";
+ llvm::errs() << "hook returned = " << example.exampleInterfaceHook() << "\n";
```
#### Utilizing the ODS Framework
-Operation interfaces require a bit of boiler plate to connect all of the pieces
-together. The ODS(Operation Definition Specification) framework provides
-simplified mechanisms for [defining interfaces](OpDefinitions.md#interfaces).
+Note: Before reading this section, the reader should have some familiarity with
+the concepts described in the
+[`Operation Definition Specification`](OpDefinitions.md) documentation.
+
+As detailed above, [Interfaces](attribute-operation-type-interfaces) allow for
+attributes, operations, and types to expose method calls without requiring that
+the caller know the specific derived type. The downside to this infrastructure,
+is that it requires a bit of boiler plate to connect all of the pieces together.
+MLIR provides a mechanism with which to defines interfaces declaratively in ODS,
+and have the C++ definitions auto-generated.
As an example, using the ODS framework would allow for defining the example
interface above as:
@@ -196,19 +231,270 @@ def ExampleOpInterface : OpInterface<"ExampleOpInterface"> {
let methods = [
InterfaceMethod<
- "Get the number of inputs for the current operation.",
- "unsigned", "getNumInputs"
+ "This is an example of a non-static hook to an operation.",
+ "unsigned", "exampleInterfaceHook"
+ >,
+ StaticInterfaceMethod<
+ "This is an example of a static hook to an operation.",
+ "unsigned", "exampleStaticInterfaceHook"
>,
];
}
```
+Providing a definition of the `AttrInterface`, `OpInterface`, or `TypeInterface`
+class will auto-generate the C++ classes for the interface. Interfaces are
+comprised of the following components:
+
+* C++ Class Name (Provided via template parameter)
+ - The name of the C++ interface class.
+* Description (`description`)
+ - A string description of the interface, its invariants, example usages,
+ etc.
+* C++ Namespace (`cppNamespace`)
+ - The C++ namespace that the interface class should be generated in.
+* Methods (`methods`)
+ - The list of interface hook methods that are defined by the IR object.
+ - The structure of these methods is defined below.
+* Extra Class Declarations (Optional: `extraClassDeclaration`)
+ - Additional C++ code that is generated in the declaration of the
+ interface class. This allows for defining methods and more on the user
+ facing interface class, that do not need to hook into the IR entity.
+
+`OpInterface` classes may additionally contain the following:
+
+* Verifier (`verify`)
+ - A C++ code block containing additional verification applied to the
+ operation that the interface is attached to.
+ - The structure of this code block corresponds 1-1 with the structure of a
+ [`Trait::verifyTrait`](Traits.md) method.
+
+There are two types of methods that can be used with an interface,
+`InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the
+same core components, with the distinction that `StaticInterfaceMethod` models a
+static method on the derived IR object.
+
+Interface methods are comprised of the following components:
+
+* Description
+ - A string description of this method, its invariants, example usages,
+ etc.
+* ReturnType
+ - A string corresponding to the C++ return type of the method.
+* MethodName
+ - A string corresponding to the C++ name of the method.
+* Arguments (Optional)
+ - A dag of strings that correspond to a C++ type and variable name
+ respectively.
+* MethodBody (Optional)
+ - An optional explicit implementation of the interface method.
+ - This implementation is placed within the method defined on the `Model`
+ traits class, and is not defined by the `Trait` class that is attached
+ to the IR entity. More concretely, this body is only visible by the
+ interface class and does not affect the derived IR entity.
+ - `ConcreteAttr`/`ConcreteOp`/`ConcreteType` is an implicitly defined
+ `typename` that can be used to refer to the type of the derived IR
+ entity currently being operated on.
+ - In non-static methods, `$_op` and `$_self` may be used to refer to an
+ instance of the derived IR entity.
+* DefaultImplementation (Optional)
+ - An optional explicit default implementation of the interface method.
+ - This implementation is placed within the `Trait` class that is attached
+ to the IR entity, and does not directly affect any of the interface
+ classes. As such, this method has the same characteristics as any other
+ [`Trait`](Traits.md) method.
+ - `ConcreteAttr`/`ConcreteOp`/`ConcreteType` is an implicitly defined
+ `typename` that can be used to refer to the type of the derived IR
+ entity currently being operated on.
+
+ODS also allows for generating declarations for the `InterfaceMethod`s of an
+operation if the operation specifies the interface with
+`DeclareOpInterfaceMethods` (see an example below).
+
+Examples:
+
+~~~tablegen
+def MyInterface : OpInterface<"MyInterface"> {
+ let description = [{
+ This is the description of the interface. It provides concrete information
+ on the semantics of the interface, and how it may be used by the compiler.
+ }];
+
+ let methods = [
+ InterfaceMethod<[{
+ This method represents a simple non-static interface method with no
+ inputs, and a void return type. This method is required to be implemented
+ by all operations implementing this interface. This method roughly
+ correlates to the following on an operation implementing this interface:
+
+ ```c++
+ class ConcreteOp ... {
+ public:
+ void nonStaticMethod();
+ };
+ ```
+ }], "void", "nonStaticMethod"
+ >,
+
+ InterfaceMethod<[{
+ This method represents a non-static interface method with a non-void
+ return value, as well as an `unsigned` input named `i`. This method is
+ required to be implemented by all operations implementing this interface.
+ This method roughly correlates to the following on an operation
+ implementing this interface:
+
+ ```c++
+ class ConcreteOp ... {
+ public:
+ Value nonStaticMethod(unsigned i);
+ };
+ ```
+ }], "Value", "nonStaticMethodWithParams", (ins "unsigned":$i)
+ >,
+
+ StaticInterfaceMethod<[{
+ This method represents a static interface method with no inputs, and a
+ void return type. This method is required to be implemented by all
+ operations implementing this interface. This method roughly correlates
+ to the following on an operation implementing this interface:
+
+ ```c++
+ class ConcreteOp ... {
+ public:
+ static void staticMethod();
+ };
+ ```
+ }], "void", "staticMethod"
+ >,
+
+ StaticInterfaceMethod<[{
+ This method corresponds to a static interface method that has an explicit
+ implementation of the method body. Given that the method body has been
+ explicitly implemented, this method should not be defined by the operation
+ implementing this method. This method merely takes advantage of properties
+ already available on the operation, in this case its `build` methods. This
+ method roughly correlates to the following on the interface `Model` class:
+
+ ```c++
+ struct InterfaceTraits {
+ /// ... The `Concept` class is elided here ...
+
+ template <typename ConcreteOp>
+ struct Model : public Concept {
+ Operation *create(OpBuilder &builder, Location loc) const override {
+ return builder.create<ConcreteOp>(loc);
+ }
+ }
+ };
+ ```
+
+ Note above how no modification is required for operations implementing an
+ interface with this method.
+ }],
+ "Operation *", "create", (ins "OpBuilder &":$builder, "Location":$loc),
+ /*methodBody=*/[{
+ return builder.create<ConcreteOp>(loc);
+ }]>,
+
+ InterfaceMethod<[{
+ This method represents a non-static method that has an explicit
+ implementation of the method body. Given that the method body has been
+ explicitly implemented, this method should not be defined by the operation
+ implementing this method. This method merely takes advantage of properties
+ already available on the operation, in this case its `build` methods. This
+ method roughly correlates to the following on the interface `Model` class:
+
+ ```c++
+ struct InterfaceTraits {
+ /// ... The `Concept` class is elided here ...
+
+ template <typename ConcreteOp>
+ struct Model : public Concept {
+ Operation *create(Operation *opaqueOp, OpBuilder &builder,
+ Location loc) const override {
+ ConcreteOp op = cast<ConcreteOp>(opaqueOp);
+ return op.getNumInputs() + op.getNumOutputs();
+ }
+ }
+ };
+ ```
+
+ Note above how no modification is required for operations implementing an
+ interface with this method.
+ }],
+ "unsigned", "getNumInputsAndOutputs", (ins), /*methodBody=*/[{
+ return $_op.getNumInputs() + $_op.getNumOutputs();
+ }]>,
+
+ InterfaceMethod<[{
+ This method represents a non-static method that has a default
+ implementation of the method body. This means that the implementation
+ defined here will be placed in the trait class that is attached to every
+ operation that implements this interface. This has no effect on the
+ generated `Concept` and `Model` class. This method roughly correlates to
+ the following on the interface `Trait` class:
+
+ ```c++
+ template <typename ConcreteOp>
+ class MyTrait : public OpTrait::TraitBase<ConcreteType, MyTrait> {
+ public:
+ bool isSafeToTransform() {
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ return op.getNumInputs() + op.getNumOutputs();
+ }
+ };
+ ```
+
+ As detailed in [Traits](Traits.md), given that each operation implementing
+ this interface will also add the interface trait, the methods on this
+ interface are inherited by the derived operation. This allows for
+ injecting a default implementation of this method into each operation that
+ implements this interface, without changing the interface class itself. If
+ an operation wants to override this default implementation, it merely
+ needs to implement the method and the derived implementation will be
+ picked up transparently by the interface class.
+
+ ```c++
+ class ConcreteOp ... {
+ public:
+ bool isSafeToTransform() {
+ // Here we can override the default implementation of the hook
+ // provided by the trait.
+ }
+ };
+ ```
+ }],
+ "bool", "isSafeToTransform", (ins), /*methodBody=*/[{}],
+ /*defaultImplementation=*/[{
+ }]>,
+ ];
+}
+
+// Operation interfaces can optionally be wrapped inside
+// DeclareOpInterfaceMethods. This would result in autogenerating declarations
+// for members `foo`, `bar` and `fooStatic`. Methods with bodies are not
+// declared inside the op declaration but instead handled by the op interface
+// trait directly.
+def OpWithInferTypeInterfaceOp : Op<...
+ [DeclareOpInterfaceMethods<MyInterface>]> { ... }
+
+// Methods that have a default implementation do not have declarations
+// generated. If an operation wishes to override the default behavior, it can
+// explicitly specify the method that it wishes to override. This will force
+// the generation of a declaration for those methods.
+def OpWithOverrideInferTypeInterfaceOp : Op<...
+ [DeclareOpInterfaceMethods<MyInterface, ["getNumWithDefault"]>]> { ... }
+~~~
+
+Note: Existing operation interfaces defined in C++ can be accessed in the ODS
+framework via the `OpInterfaceTrait` class.
+
#### Operation Interface List
-MLIR includes standard interfaces providing functionality that is
-likely to be common across many
diff erent operations. Below is a list
-of some key interfaces that may be used directly by any dialect. The
-format of the header for each interface section goes as follows:
+MLIR includes standard interfaces providing functionality that is likely to be
+common across many
diff erent operations. Below is a list of some key interfaces
+that may be used directly by any dialect. The format of the header for each
+interface section goes as follows:
* `Interface class name`
- (`C++ class` -- `ODS class`(if applicable))
@@ -224,10 +510,15 @@ format of the header for each interface section goes as follows:
##### RegionKindInterfaces
* `RegionKindInterface` - Used to describe the abstract semantics of regions.
- - `RegionKind getRegionKind(unsigned index)` - Return the kind of the region with the given index inside this operation.
- - RegionKind::Graph - represents a graph region without control flow semantics
- - RegionKind::SSACFG - represents an [SSA-style control flow](LangRef.md#modeling-control-flow) region with basic blocks and reachability
- - `hasSSADominance(unsigned index)` - Return true if the region with the given index inside this operation requires dominance.
+ - `RegionKind getRegionKind(unsigned index)` - Return the kind of the
+ region with the given index inside this operation.
+ - RegionKind::Graph - represents a graph region without control flow
+ semantics
+ - RegionKind::SSACFG - represents an
+ [SSA-style control flow](LangRef.md#modeling-control-flow) region
+ with basic blocks and reachability
+ - `hasSSADominance(unsigned index)` - Return true if the region with the
+ given index inside this operation requires dominance.
##### SymbolInterfaces
diff --git a/mlir/docs/OpDefinitions.md b/mlir/docs/OpDefinitions.md
index d4f3f4a03eba..a267a60adc3e 100644
--- a/mlir/docs/OpDefinitions.md
+++ b/mlir/docs/OpDefinitions.md
@@ -340,134 +340,10 @@ currently only be specified as the last successor in the successor list.
Traits are operation properties that affect syntax or semantics. MLIR C++
models various traits in the `mlir::OpTrait` namespace.
-Both operation traits, [interfaces](#operation-interfaces), and constraints
-involving multiple operands/attributes/results are provided as the second
-template parameter to the `Op` class. They should be deriving from the `OpTrait`
-class. See [Constraints](#constraints) for more information.
-
-### Interfaces
-
-[Interfaces](Interfaces.md#attribute-operation-type-interfaces) allow for
-attributes, operations, and types to expose method calls without the caller
-needing to know the derived type. Operation interfaces defined in C++ can be
-accessed in the ODS framework via the `OpInterfaceTrait` class. Aside from using
-pre-existing interfaces in the C++ API, the ODS framework also provides a
-simplified mechanism for defining such interfaces which removes much of the
-boilerplate necessary.
-
-Providing a definition of the `AttrInterface`, `OpInterface`, or `TypeInterface`
-class will auto-generate the C++ classes for the interface. An interface
-includes a name, for the C++ class, a description, and a list of interface
-methods.
-
-```tablegen
-def MyInterface : OpInterface<"MyInterface"> {
- let description = ...;
- let methods = [...];
-}
-```
-
-There are two types of methods that can be used with an interface,
-`InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the
-same core components, with the distinction that `StaticInterfaceMethod` models a
-static method on the derived operation.
-
-An `InterfaceMethod` is comprised of the following components:
-
-* Description
- - A string description of what this method does and its invariants.
-* ReturnType
- - A string corresponding to the C++ return type of the method.
-* MethodName
- - A string corresponding to the desired name of the method.
-* Arguments (Optional)
- - A dag of strings that correspond to a C++ type and variable name
- respectively.
-* MethodBody (Optional)
- - An optional explicit implementation of the interface method.
- - `ConcreteOp` is an implicitly defined typename that can be used to refer
- to the type of the derived operation currently being operated on.
- - In non-static methods, a variable 'ConcreteOp op' is defined and may be
- used to refer to an instance of the derived operation.
-* DefaultImplementation (Optional)
- - An optional explicit default implementation of the interface method.
- - This method is placed within the `Trait` class that is attached to the
- operation. As such, this method has the same characteristics as any
- other [`Trait`](Traits.md) method.
- - `ConcreteOp` is an implicitly defined typename that can be used to refer
- to the type of the derived operation currently being operated on.
-
-ODS also allows generating the declarations for the `InterfaceMethod` of the op
-if one specifies the interface with `DeclareOpInterfaceMethods` (see example
-below).
-
-Examples:
-
-```tablegen
-def MyInterface : OpInterface<"MyInterface"> {
- let description = [{
- My interface is very interesting. ...
- }];
-
- let methods = [
- // A simple non-static method with no inputs.
- InterfaceMethod<"'foo' is a non-static method with no inputs.",
- "unsigned", "foo"
- >,
-
- // A new non-static method accepting an input argument.
- InterfaceMethod<"/*insert doc here*/",
- "Value ", "bar", (ins "unsigned":$i)
- >,
-
- // Query a static property of the derived operation.
- StaticInterfaceMethod<"'fooStatic' is a static method with no inputs.",
- "unsigned", "fooStatic"
- >,
-
- // Provide the definition of a static interface method.
- // Note: `ConcreteOp` corresponds to the derived operation typename.
- StaticInterfaceMethod<"/*insert doc here*/",
- "Operation *", "create", (ins "OpBuilder &":$builder, "Location":$loc), [{
- return builder.create<ConcreteOp>(loc);
- }]>,
-
- // Provide a definition of the non-static method.
- // Note: `op` corresponds to the derived operation variable.
- InterfaceMethod<"/*insert doc here*/",
- "unsigned", "getNumInputsAndOutputs", (ins), [{
- return op.getNumInputs() + op.getNumOutputs();
- }]>,
-
- // Provide only a default definition of the method.
- // Note: `ConcreteOp` corresponds to the derived operation typename.
- InterfaceMethod<"/*insert doc here*/",
- "unsigned", "getNumWithDefault", (ins), /*methodBody=*/[{}], [{
- ConcreteOp op = cast<ConcreteOp>(this->getOperation());
- return op.getNumInputs() + op.getNumOutputs();
- }]>,
- ];
-}
-
-// Operation interfaces can optionally be wrapped inside
-// DeclareOpInterfaceMethods. This would result in autogenerating declarations
-// for members `foo`, `bar` and `fooStatic`. Methods with bodies are not
-// declared inside the op declaration but instead handled by the op interface
-// trait directly.
-def OpWithInferTypeInterfaceOp : Op<...
- [DeclareOpInterfaceMethods<MyInterface>]> { ... }
-
-// Methods that have a default implementation do not have declarations
-// generated. If an operation wishes to override the default behavior, it can
-// explicitly specify the method that it wishes to override. This will force
-// the generation of a declaration for those methods.
-def OpWithOverrideInferTypeInterfaceOp : Op<...
- [DeclareOpInterfaceMethods<MyInterface, ["getNumWithDefault"]>]> { ... }
-```
-
-Operation interfaces may also provide a verification method on `OpInterface` by
-setting `verify`. Setting `verify` results in the generated trait having a
-`verifyTrait` method that is applied to all operations implementing the trait.
+Both operation traits, [interfaces](Interfaces.md#utilizing-the-ods-framework),
+and constraints involving multiple operands/attributes/results are provided as
+the second template parameter to the `Op` class. They should be deriving from
+the `OpTrait` class. See [Constraints](#constraints) for more information.
### Builder methods
More information about the Mlir-commits
mailing list