This change allows folds to be done on a newly introduced involution trait rather than having to manually rewrite this optimization for every instance of an involution
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Can you split this commit into two? You seem to be adding core infra that isnt documented in your commit title or description, and is arguably more important than adding an involution trait.
This is great!
@rriddle what about renaming the revision Add a foldTrait() mechanism to allow traits to define folding and test it with an Involution trait"? I agree that the involution is completely secondary here.
I agree with Mehdi on keeping it as one PR but updating the name since making a separate PR with just the trait folding would require writing code for its test that's almost the same as what's required for involution anyways
mlir/test/lib/Dialect/Test/TestTraits.cpp | ||
---|---|---|
11–13 | Should these imports be removed? |
mlir/include/mlir/IR/OpBase.td | ||
---|---|---|
1726 | I think you mean op op X == X ? |
mlir/include/mlir/IR/OpBase.td | ||
---|---|---|
1737 | These two shouldn't be needed as users don't need to write them, they are redundant with arguments and results specification and automatically inserted. | |
mlir/include/mlir/IR/OpDefinition.h | ||
1438 | ||
mlir/test/lib/Dialect/Test/TestOps.td | ||
801 | ODS automatically inserts OneResult and OneOperand, so these need not be manually specified here. (same below) (see OpEmitter::genTraits) |
Keeping them together is fine if you are using involution as a driving test case given that it is rather simple.
mlir/docs/Traits.md | ||
---|---|---|
69 | The format of trait folding hooks should be the same as the general form for operations, unless you want to use template meta-programming to allow a trait to define either. This form here looks specific to a certain type of operation, i.e. single result operations, which does not encompass all operation types. | |
mlir/include/mlir/IR/OpDefinition.h | ||
1030 | Are involution operations allowed to be folded if they are side effecting? | |
mlir/test/lib/Dialect/Test/TestOps.td | ||
801 | Please wrap .td files at 80 characters, just like other source files. | |
mlir/test/lib/Dialect/Test/TestTraits.cpp | ||
2 | This should be 80 characters long, the title here is also off. | |
11 | Please remove commented out code. | |
15 | This file doesn't use dialect conversion or anything from FoldUtils, these shouldn't be necessary. | |
36 | nit: Drop the newline here. | |
mlir/test/mlir-tblgen/trait.mlir | ||
23 | Please use a consistent format for the check lines, either all before or all after. (More preference to before than after). |
Added no side effect requirement to involution, changed fold to two different signatures to be consistent with existing fold functionality, and fixed issues addressed by comments
mlir/include/mlir/IR/OpDefinition.h | ||
---|---|---|
1030 | good catch, I added the requirement of no side effects being present |
mlir/lib/IR/Operation.cpp | ||
---|---|---|
737 | Nit: remove braces | |
mlir/test/lib/Dialect/Test/TestOps.td | ||
806 | Do we need to provide this "hasFolder"? |
The limitation on side-effect is a bit unfortunate: I suspect we'd want lmhlo involution operation on buffers. But we can leave this for future work.
What do you think of adding detection for in-place folds and continuing to fold in such cases? If an operation is folded in-place, we don't necessarily have to stop the folding process prematurely.
mlir/docs/Traits.md | ||
---|---|---|
62 | The *must* here is too strong, the second form should still be valid even if the operation isn't single result. Otherwise that limits how general a trait can be, e.g. what if we extend involution to more than just single operand/result? At that point the trait would provide a general folding implementation using the second form. | |
76 | nit: Otherwise, | |
84 | The OpFoldResult should be LogicalResult here. | |
mlir/include/mlir/IR/OpDefinition.h | ||
450 | Can you call into the general form here as a default implementation? That would allow for traits to implement the general form if they want. | |
1366 | Is it possible for these to be made private? | |
mlir/test/lib/Dialect/Test/TestTraits.cpp | ||
22 | nit: Please capitalize the start of comments, and end with proper punctuation. |
mlir/test/lib/Dialect/Test/TestOps.td | ||
---|---|---|
806 | No it just emphasizes that when op folding fails the trait folding takes over. I added a separate test to clearly highlight this is not needed |
Thanks, LGTM after resolving the remaining comments.
mlir/include/mlir/IR/OpDefinition.h | ||
---|---|---|
343 | Please fix the naming violations here and above. | |
344 | Can you inline the variable definition into the if here and below? | |
452 | nit: Drop the newline here. | |
455 | nit: Drop else after return. | |
457 | nit: Add a message to the assert. | |
1443 | Please fix the naming style issues here and below. | |
mlir/lib/IR/Operation.cpp | ||
685 | nit: Drop the newline here. | |
mlir/tools/mlir-opt/mlir-opt.cpp | ||
140 | nit: Please use a registerTest* naming scheme for this method. |
I don't have push access so if you get a chance to push my code and its good please do, thanks!
Pushed a revert in 16580d791f3b ; can you try to build after configuring cmake with -DBUILD_SHARED_LIBS=ON ?
It seems there's an issue with using MemoryEffectOpInterface::getEffects in Operation.cpp where I get an undefined reference to this call. I tried adding MLIRSideEffectInterfaces under LINK_LIBS for IR/CMakeLists but I get a cyclic dependency is only allowed among static libraries error. Is there something else I can try or is there a way to check an op has no side effects with using getEffects?
For now I would drop the check on non-side effecting and add a FIXME to add it back later. The actual fix, IMO, is to either:
a) Add a new Traits/ directory and start moving traits there.
b) Rename the Interfaces/ directory to something more general, and start moving traits there.
We should be funneling all of the traits into IR because it isn't scalable, and it also prevents depending on other libraries(such as in this instance). I don't have a big preference on whether we should do a) or b) in the long run.
The *must* here is too strong, the second form should still be valid even if the operation isn't single result. Otherwise that limits how general a trait can be, e.g. what if we extend involution to more than just single operand/result? At that point the trait would provide a general folding implementation using the second form.