Skip to content
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

A light functional rewrite API in C++ #157

Merged
merged 1 commit into from
Jan 12, 2022
Merged

Conversation

Mogball
Copy link
Contributor

@Mogball Mogball commented Jan 8, 2022

Depends on #156

Introduce a lightweight functional rewrite API in C++ and some utility functions that can be used to build a fully-featured functional rewrite system moving forward (e.g. #149).

Simplifies the linalg transform interpreter, as operation handles can be passed around directly instead of relying on attributes.

@Mogball Mogball force-pushed the functional branch 3 times, most recently from 3c90b2e to 25f4b7f Compare January 10, 2022 23:52
/// match at all.
template <typename PatternT, typename... Args,
bool = PatternConcept<PatternT>::verify()>
auto applyEach(Operation *scope, PatternT &&pattern, Args &&...args) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto applyToEachInScope(ScopeOp scope, ... ) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that you want this to be general but I'd argue that you could have ScopeOp now and when generalizing you
should have a ScopeOpInterface anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A ScopeOpInterface would be any op that is isolated from above.... which might be useful to have actually. I'll look at introducing one in a later patch.

template <typename OpT, typename SequenceT, typename... Args,
bool = PatternConcept<SequenceT>::verify()>
auto applySequenceAt(OpT op, SequenceT &&sequence, Args &&...args) {
Operation *scope = findNearestScope(op);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment re ScopeOp vs Operation* and future with interfaces.
But I won't insist anymore if you fell more strongly here :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll introduce an interface

SmallVector<std::unique_ptr<Region>> backup = cloneRegionsOf(scope);

rewriter.setInsertionPoint(op);
auto result = std::forward<SequenceT>(sequence)(op, rewriter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here to say what this is forwarded to? I am not clear which of the other functions can get called as the result of that.

I am asking because this relates to your generic findNearestScope but I am wondering whether some paths may bottom out on the wrap/unwrap whose impl. is very specific to ScopeOp.
Outlining generic isolated form above ops can get quite painful (i.e. finding and reconciling terminators)

using namespace mlir;
using functional::impl::SequencePattern;

Operation *mlir::functional::findNearestScope(Operation *op) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I get it now that I see the impl.
Do you already see your mechanisms apply to generic isolated form above?
I am also wondering how this relates to the ScopeOp if at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This predates ScopeOp (which is a special case/utility op) but I removed some of these changes since they aren't needed (for now). I.e. Scope op might be something specific to linalg, whereas the rewrite system in general will work on any op isolated from above (the name is confusing...)

tileOp, nextTargets)))
return failure();
}
auto tileSeq = functional::SequenceBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful!

callFunctional<LinalgGeneralizationPattern>(tileOp.getContext());
return [pattern = std::move(pattern)](
LinalgOp op, PatternRewriter &rewriter) -> FailureOr<LinalgOp> {
FailureOr<GenericOp> result = pattern(op, rewriter);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to make LinalgGeneralizationPattern::returningMatchAndRewrite return FailureOr upstream if you think it is better.

Copy link
Contributor Author

@Mogball Mogball Jan 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extra logic is mainly to covert GenericOp to LinalgOp. I can clean it up a little.

Copy link
Contributor

@nicolasvasilache nicolasvasilache left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@Mogball Mogball force-pushed the functional branch 3 times, most recently from 3b7d475 to 60892be Compare January 12, 2022 03:06
Change the linalg transform interpreter to use functional-style patterns
instead of relying on attributes to communicate information.
@Mogball Mogball merged commit c56e648 into iree-org:main Jan 12, 2022
@Mogball Mogball deleted the functional branch January 12, 2022 05:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants