-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[MLIR] Forward generated OpTy::create arguments #170012
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
Conversation
|
@llvm/pr-subscribers-mlir-core @llvm/pr-subscribers-mlir Author: Jason Rice (ricejasonf) ChangesThe recent changes in the MLIR TableGen interface for generated OpTy::build functions involves a new OpTy::create function that is generated passing arguments without forwarding. This is problematic with arguments that are move only such as In Discord, the use of Consider the declaration in TableGen: Which currently generates: ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region>&&body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, cdr, packs, body);
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}
With this change it will generate: ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region>&&body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, static_cast<decltype(cdr)>(cdr), static_cast<decltype(packs)>(packs), static_cast<decltype(body)>(body));
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}Another option could be to make this function a template but then it would not be hidden in the generated translation unit. I don't know if that was the original intent. Thank you for your consideration. Full diff: https://github.com/llvm/llvm-project/pull/170012.diff 1 Files Affected:
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 3b10842f2a127..4f6c70e269fee 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -2641,7 +2641,14 @@ void OpEmitter::genInlineCreateBody(
std::string nonBuilderStateArgs = "";
if (!nonBuilderStateArgsList.empty()) {
llvm::raw_string_ostream nonBuilderStateArgsOS(nonBuilderStateArgs);
- interleaveComma(nonBuilderStateArgsList, nonBuilderStateArgsOS);
+ interleave(
+ nonBuilderStateArgsList,
+ [&](StringRef name) {
+ nonBuilderStateArgsOS << "static_cast<decltype(" << name << ")>("
+ << name << ')';
+ },
+ [&] { nonBuilderStateArgsOS << ", "; });
+
nonBuilderStateArgs = ", " + nonBuilderStateArgs;
}
if (cWithLoc)
|
|
Sorry noob q: what does the static_cast actually accomplish here?
Do you mean template with param pack? If so then the intent was exactly to avoid that (hiding etc was not the goal). |
🐧 Linux x64 Test Results
|
e716f03 to
60da413
Compare
|
The |
| // DEFS: FOp FOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value a) { | ||
| // DEFS: ::mlir::OperationState __state__(location, getOperationName()); | ||
| // DEFS: build(builder, __state__, a); | ||
| // DEFS: build(builder, __state__, static_cast<decltype(a)>(a)); |
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.
Wouldn't std::forward also work here? I think that's more idiomatic
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 would think that the idiomatic way would be to std::move here?
Taking the snippet from the PR description:
let builders = [
OpBuilder<(ins "::mlir::Value":$cdr,
"::mlir::ValueRange":$packs,
"std::unique_ptr<::mlir::Region>&&":$body)>
];
I would instead write this builder as:
let builders = [
OpBuilder<(ins "::mlir::Value":$cdr,
"::mlir::ValueRange":$packs,
"std::unique_ptr<::mlir::Region>":$body)>
];
That is, taking the unique_ptr by value and relying on the move.
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 move could have unexpected consequences on values passed by (non-const) reference -- IMO making arguments explicitly rvalue references and forwarding is less surprising
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.
Yeah, I will see if I can change it to std::forward. I am used to having potential auto&& placeholder types which is not possible here.
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.
In the DAG syntax, is a type strictly required? Can they put an addtional attribute or any non-type info there? I am having trouble finding where this is specified in the documentation.
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 found a comment:
// The type string is used verbatim to produce code and, therefore, must be a
// valid C++ type.
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.
If the user passes by value say T, then the std::forward<T> will cast to T&&. I think it would still be fine, but then we are casting trivial types like int to reference types (ie int&&).
I can still change it if you would like.
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 it should be std::forward<dectlype(foo)> (which will become a static cast under the hood, but IMO the intent will be more obvious)
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.
IE, I think the semantics we want is to move when either T or T&& and not move with T&.
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.
Oh right, that means I can use just std::unique_ptr<mlir::Region> without the && in the parameter list.
kuhar
left a comment
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.
LGTM but can you update the PR description?
|
I edited the original description. (I think that is what you meant) I can squash the commits if you want, but I do not have merge access so any help with that is greatly appreciated. Also, thank you for the reviewers' time on this. |
We only allow squash so it's done automatically on merge. If you're ready I can merge. |
|
Can you please add a test operation in the Test dialect with a std::unique_ptr by value? I'd like to see this being compiled actually instead of limiting to the lit test. |
The recent changes in the MLIR TableGen interface for generated
OpTy::build functions involves a new OpTy::create function that is
generated passing arguments without forwarding. This is problematic with
arguments that are move only such as `std::unique_ptr`. My particular
use case involves `std::unique_ptr<mlir::Region>` which is desirable as
the `mlir::OperationState` object accepts calls to
`addRegion(std::unique_ptr<mlir::Region>`.
In Discord, the use of `extraClassDeclarations` was suggested which I
may go with regardless since I still have to define the builder function
anyways, but perhaps you would consider this trivial change as it
supports a broader class of argument types for this approach.
Consider the declaration in TableGen:
```
let builders = [
OpBuilder<(ins "::mlir::Value":$cdr,
"::mlir::ValueRange":$packs,
"std::unique_ptr<::mlir::Region>":$body)>
];
```
Which currently generates:
```cpp
ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region> body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, std::forward<decltype(cdr)>(cdr), std::forward<decltype(packs)>(packs), std::forward<decltype(body)>(body));
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}
```
With this change it will generate:
```cpp
ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region>&&body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, static_cast<decltype(cdr)>(cdr), std::forward<decltype(packs)>(packs), std::forward<decltype(body)>(body));
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}
```
Another option could be to make this function a template but then it
would not be hidden in the generated translation unit. I don't know if
that was the original intent. Thank you for your consideration.
The recent changes in the MLIR TableGen interface for generated
OpTy::build functions involves a new OpTy::create function that is
generated passing arguments without forwarding. This is problematic with
arguments that are move only such as `std::unique_ptr`. My particular
use case involves `std::unique_ptr<mlir::Region>` which is desirable as
the `mlir::OperationState` object accepts calls to
`addRegion(std::unique_ptr<mlir::Region>`.
In Discord, the use of `extraClassDeclarations` was suggested which I
may go with regardless since I still have to define the builder function
anyways, but perhaps you would consider this trivial change as it
supports a broader class of argument types for this approach.
Consider the declaration in TableGen:
```
let builders = [
OpBuilder<(ins "::mlir::Value":$cdr,
"::mlir::ValueRange":$packs,
"std::unique_ptr<::mlir::Region>":$body)>
];
```
Which currently generates:
```cpp
ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region> body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, std::forward<decltype(cdr)>(cdr), std::forward<decltype(packs)>(packs), std::forward<decltype(body)>(body));
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}
```
With this change it will generate:
```cpp
ExpandPacksOp ExpandPacksOp::create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Value cdr, ::mlir::ValueRange packs, std::unique_ptr<::mlir::Region>&&body) {
::mlir::OperationState __state__(location, getOperationName());
build(builder, __state__, static_cast<decltype(cdr)>(cdr), std::forward<decltype(packs)>(packs), std::forward<decltype(body)>(body));
auto __res__ = ::llvm::dyn_cast<ExpandPacksOp>(builder.create(__state__));
assert(__res__ && "builder didn't return the right type");
return __res__;
}
```
Another option could be to make this function a template but then it
would not be hidden in the generated translation unit. I don't know if
that was the original intent. Thank you for your consideration.
The recent changes in the MLIR TableGen interface for generated OpTy::build functions involves a new OpTy::create function that is generated passing arguments without forwarding. This is problematic with arguments that are move only such as
std::unique_ptr. My particular use case involvesstd::unique_ptr<mlir::Region>which is desirable as themlir::OperationStateobject accepts calls toaddRegion(std::unique_ptr<mlir::Region>.In Discord, the use of
extraClassDeclarationswas suggested which I may go with regardless since I still have to define the builder function anyways, but perhaps you would consider this trivial change as it supports a broader class of argument types for this approach.Consider the declaration in TableGen:
Which currently generates:
With this change it will generate:
Another option could be to make this function a template but then it would not be hidden in the generated translation unit. I don't know if that was the original intent. Thank you for your consideration.