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

Canonicalization of TTIR ops #1670

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open

Canonicalization of TTIR ops #1670

wants to merge 23 commits into from

Conversation

azecevicTT
Copy link
Contributor

Canonicalization can be roughly divided into three forms:

  1. Traits (properties) of some ops that allows them to be folded (Involution, Idempotence)
  2. Per op foldings
  3. Per op canonicalization (pattern rewriters)

The first one allows us to decleratively add folding for a large class of ops. While traits like Involution already exists in MLIR infrastructure it doesn't account for DPS, so I added a new one that takes care of it.
The second one allows us in practice to define some simple graph rewritings where we replace the producing value of op with some existing value (or constant).
The third one gives us the most freedom, where we can do arbitrary graph rewritings, we usually use it when we have to create a new op during rewriting.

I added a canonicalize pass both before and after ttir-to-ttir-decomposition-pass in ttir-to-ttnn-backend-pipeline, as there are many graph rewritings during that pass, so we might benefit form canonicalization both before and after.

I plan to cover one big part of canonicalization in the future, and that's constant folding. I will also write a short document on adding a canonicalization for new and existing ops. While this PR covers a lot of patterns, it's definitely not an exhaustive list. This MLIR doc is already a great source of information, I just believe we might also benefit from the additional context of TTIR dialect.

This PR should cover a big part of #1264, as I said the missing part is constant folding.

- added InvolutionTrait
- added IdempotentTrait
- TODO: address other folders
- TODO: refactor check into the separate function
- TODO: added -canonicalize into the pipeline
- TODO: add tests for involution and idempotence
- fixed some tests that failed due to canonicalization
- fixed test for fork-join: changed relu to gelu
- added a traits on few other ops as well
- TODO: tests for ReverseOp canonicalization
- few op traits modifed
- TODO: add tests for bitwise xor op canonicalization
- Broadcast noop folder
- op should be replaced instead of producer op
- tests for PermuteOp canonicalization
- improved comments in few places
Copy link
Contributor Author

@azecevicTT azecevicTT left a comment

Choose a reason for hiding this comment

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

Few comments regarding some changes that are not clear without the context.

@@ -41,6 +43,28 @@ def TTIR_Dialect : Dialect {
//===----------------------------------------------------------------------===//

class TTIR_Op<string mnemonic, list<Trait> traits = []> :
Op<TTIR_Dialect, mnemonic, !listconcat(traits, [Pure])>;
Op<TTIR_Dialect, mnemonic, !listconcat([Pure], traits)>;
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've changed the order of listconcatarguments everywhere, because of dependent trait list for traits like TTIR_Involution. Otherwise it fails long before compiling (it check for existence of this traits while still parsing .td file), so it doesn't see a trait/interface like DestinationStyleOpInterface on ops that has it, because it builds list in bottom-up fashion ([trait_of_op, trait_of_ops_class, trait_op_ops_class_class,...]).

From what I saw it doesn't make any difference in generated C++ code. @nsmithtt Did you have an experience with this?

@@ -1,18 +1,5 @@
// RUN: ttmlir-opt --ttir-to-ttnn-backend-pipeline %s | FileCheck %s
module {
func.func @linear_1d_1d(%arg0: tensor<128xbf16>, %arg1: tensor<128xbf16>) -> tensor<1xbf16> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There have been a few tests that have failed due to canonicalization changing the graph. I have removed them and wrote tests that specifically check for the correctness of rewriting.

@@ -27,15 +27,15 @@ module attributes {} {
// CHECK: %{{.*}} = "ttnn.relu"{{.*}} -> tensor<64x64xbf16, #[[LAYOUT_3]]>
%1 = "ttir.relu"(%arg0, %0) <{operandSegmentSizes = array<i32: 1, 1>}> : (tensor<64x64xbf16>, tensor<64x64xbf16>) -> tensor<64x64xbf16>
%2 = tensor.empty() : tensor<64x64xbf16>
%3 = "ttir.relu"(%1, %2) <{operandSegmentSizes = array<i32: 1, 1>}> : (tensor<64x64xbf16>, tensor<64x64xbf16>) -> tensor<64x64xbf16>
%3 = "ttir.gelu"(%1, %2) <{operandSegmentSizes = array<i32: 1, 1>}> : (tensor<64x64xbf16>, tensor<64x64xbf16>) -> tensor<64x64xbf16>
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've synced offline with @fbajraktariTT regarding this, due to RELU being idempotent op, two consecutive RELUs result in rewriting, so I've just replaced one RELU with GELU, as concrete op wasn't a concern in this test.

Copy link
Contributor

@odjuricicTT odjuricicTT left a comment

Choose a reason for hiding this comment

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

Optimizer test changes are fine :)

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.

2 participants