-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir][ODS] Optionally generate public C++ functions for type constraints #104577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
matthias-springer
merged 4 commits into
main
from
users/matthias-springer/type_constr_cpp_function
Aug 21, 2024
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Constraints | ||
|
||
[TOC] | ||
|
||
## Attribute / Type Constraints | ||
|
||
When defining the arguments of an operation in TableGen, users can specify | ||
either plain attributes/types or use attribute/type constraints to levy | ||
additional requirements on the attribute value or operand type. | ||
|
||
```tablegen | ||
def My_Type1 : MyDialect_Type<"Type1", "type1"> { ... } | ||
def My_Type2 : MyDialect_Type<"Type2", "type2"> { ... } | ||
|
||
// Plain type | ||
let arguments = (ins MyType1:$val); | ||
// Type constraint | ||
let arguments = (ins AnyTypeOf<[MyType1, MyType2]>:$val); | ||
``` | ||
|
||
`AnyTypeOf` is an example for a type constraints. Many useful type constraints | ||
can be found in `mlir/IR/CommonTypeConstraints.td`. Additional verification | ||
code is generated for type/attribute constraints. Type constraints can not only | ||
be used when defining operation arguments, but also when defining type | ||
parameters. | ||
|
||
Optionally, C++ functions can be generated, so that type constraints can be | ||
checked from C++. The name of the C++ function must be specified in the | ||
`cppFunctionName` field. If no function name is specified, no C++ function is | ||
emitted. | ||
|
||
```tablegen | ||
// Example: Element type constraint for VectorType | ||
def Builtin_VectorTypeElementType : AnyTypeOf<[AnyInteger, Index, AnyFloat]> { | ||
let cppFunctionName = "isValidVectorTypeElementType"; | ||
} | ||
``` | ||
|
||
The above example tranlates into the following C++ code: | ||
```c++ | ||
bool isValidVectorTypeElementType(::mlir::Type type) { | ||
return (((::llvm::isa<::mlir::IntegerType>(type))) || ((::llvm::isa<::mlir::IndexType>(type))) || ((::llvm::isa<::mlir::FloatType>(type)))); | ||
} | ||
``` | ||
|
||
An extra TableGen rule is needed to emit C++ code for type constraints. This | ||
will generate only the declarations/definitions of the type constaraints that | ||
are defined in the specified `.td` file, but not those that are in included | ||
`.td` files. | ||
|
||
```cmake | ||
mlir_tablegen(<Your Dialect>TypeConstraints.h.inc -gen-type-constraint-decls) | ||
mlir_tablegen(<Your Dialect>TypeConstraints.cpp.inc -gen-type-constraint-defs) | ||
``` | ||
|
||
The generated `<Your Dialect>TypeConstraints.h.inc` will need to be included | ||
whereever you are referencing the type constraint in C++. Note that no C++ | ||
namespace will be emitted by the code generator. The `#include` statements of | ||
the `.h.inc`/`.cpp.inc` files should be wrapped in C++ namespaces by the user. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// RUN: mlir-tblgen -gen-type-constraint-decls -I %S/../../include %s | FileCheck %s --check-prefix=DECL | ||
// RUN: mlir-tblgen -gen-type-constraint-defs -I %S/../../include %s | FileCheck %s --check-prefix=DEF | ||
|
||
include "mlir/IR/CommonTypeConstraints.td" | ||
|
||
def DummyConstraint : AnyTypeOf<[AnyInteger, Index, AnyFloat]> { | ||
let cppFunctionName = "isValidDummy"; | ||
} | ||
|
||
// DECL: bool isValidDummy(::mlir::Type type); | ||
|
||
// DEF: bool isValidDummy(::mlir::Type type) { | ||
// DEF: return (((::llvm::isa<::mlir::IntegerType>(type))) || ((::llvm::isa<::mlir::IndexType>(type))) || ((::llvm::isa<::mlir::FloatType>(type)))); | ||
// DEF: } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if this should go into a separate
.td
file. Otherwise there could be multiple definitions of the same C++ function ifBuiltinTypes.td
is included in another C++ file for which type constraints are also generated.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was running into something like this too, I think at least for all of these a dialect is specified. So one could either filter on dialect in generation, or we could require that every dialect has one "main" file where it sets the current dialect and then the generator would always just consider that one for given main file unless overridden (I feel like there is too much filter command line flags while the common case matches this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should do the same thing that we do for interfaces: Ignore everything not in the direct file that is being generated. I am a bit concerned about how we handle constraint generation, because there are so many of them spread across nearly every .td file. I think we need to be careful about how/which ones get generated (probably even more so than interfaces).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like a good strategy to me. I changed the implementation accordingly.
A C++ function is generated only if the
cppFunctionName
field is set to a non-empty string. By default it is empty, so this entire process is on an opt-in basis.If a constraint calls a constraint via TableGen, it is fully inlined. E.g.:
AnyTypeOf<[I32, AnyTypeOf<[I16, I64]>]>
will generate a single C++ function that checks fori32
,i16
,i64
. So this will work out of the box.If a constraint calls a constraint via
CPred<"...">
, arbitrary C++ code can be specified and I'd say it's the user's responsibility to ensure that all needed C++ functions are pre-declared. By making sure that the corresponding header file (.h
not.inc.h
) is included in the.cpp
file that contains the constraint definition. (Same as with ops that implement op interfaces: the user must include the.h
file that declares the op interface in the.h
file that contains the operation class.)