-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[mlir][linalg] Add support for vectorizing dynamic elementwise named ops #71454
Conversation
We are able to vectorize them in linalg.generic form. We just need to relax the condition, so it can also vectorize named ops.
@llvm/pr-subscribers-mlir Author: Han-Chung Wang (hanhanW) ChangesWe are able to vectorize them in linalg.generic form. We just need to relax the condition, so it can also vectorize named ops. Full diff: https://github.com/llvm/llvm-project/pull/71454.diff 2 Files Affected:
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index b427af33e3c4400..8b8eb5131669e13 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -1466,7 +1466,8 @@ static LogicalResult reductionPreconditions(LinalgOp op) {
static LogicalResult vectorizeDynamicLinalgOpPrecondition(linalg::LinalgOp op) {
// TODO: Masking only supports dynamic generic ops for now.
- if (!isa<linalg::GenericOp, linalg::FillOp, linalg::CopyOp,
+ if (!isElementwise(op) &&
+ !isa<linalg::GenericOp, linalg::FillOp, linalg::CopyOp,
linalg::ContractionOpInterface>(op.getOperation()))
return failure();
diff --git a/mlir/test/Dialect/Linalg/vectorization.mlir b/mlir/test/Dialect/Linalg/vectorization.mlir
index 7f4af344886f498..610339405d1c2c9 100644
--- a/mlir/test/Dialect/Linalg/vectorization.mlir
+++ b/mlir/test/Dialect/Linalg/vectorization.mlir
@@ -368,6 +368,34 @@ module attributes {transform.with_named_sequence} {
// -----
+// CHECK: #[[MAP:.*]] = affine_map<(d0, d1) -> (d1, d0)>
+// CHECK: func @test_masked_vectorize_linalg_transpose
+func.func @test_masked_vectorize_linalg_transpose(%arg0: tensor<?x?xf32>, %arg1: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ // CHECK: %[[C0:.*]] = arith.constant 0 : index
+ // CHECK: %[[D0:.*]] = tensor.dim %arg0, %[[C0]]
+ // CHECK: %[[C1:.*]] = arith.constant 1 : index
+ // CHECK: %[[D1:.*]] = tensor.dim %arg0, %[[C1]]
+ // CHECK: %[[MASK0:.*]] = vector.create_mask %[[D0]], %[[D1]]
+ // CHECK: %[[LOAD:.*]] = vector.mask %[[MASK0]] { vector.transfer_read %arg0{{.+}} }
+ // CHECK-SAME: vector<2x4xi1> -> vector<2x4xf32>
+ // CHECK: %[[MASK1:.*]] = vector.create_mask %[[D1]], %[[D0]]
+ // CHECK: %[[WRITE:.*]] = vector.mask %[[MASK1]] { vector.transfer_write %[[LOAD]], %arg1{{.+}} permutation_map = #[[MAP]]{{.+}} }
+ // CHECK-SAME: vector<4x2xi1> -> tensor<?x?xf32>
+ // CHECK: return %[[WRITE]]
+ %0 = linalg.transpose ins(%arg0 : tensor<?x?xf32>) outs(%arg1 : tensor<?x?xf32>) permutation = [1, 0]
+ return %0 : tensor<?x?xf32>
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.transpose"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ transform.structured.vectorize %0 vector_sizes [2, 4] : !transform.any_op
+ transform.yield
+ }
+}
+
+// -----
+
// CHECK-LABEL: func @test_masked_vectorize_linalg_copy
func.func @test_masked_vectorize_linalg_copy(%A : memref<?x?xf32>, %B : memref<?x?xf32>) {
// CHECK: %[[c0:.*]] = arith.constant 0 : index
|
@llvm/pr-subscribers-mlir-linalg Author: Han-Chung Wang (hanhanW) ChangesWe are able to vectorize them in linalg.generic form. We just need to relax the condition, so it can also vectorize named ops. Full diff: https://github.com/llvm/llvm-project/pull/71454.diff 2 Files Affected:
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index b427af33e3c4400..8b8eb5131669e13 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -1466,7 +1466,8 @@ static LogicalResult reductionPreconditions(LinalgOp op) {
static LogicalResult vectorizeDynamicLinalgOpPrecondition(linalg::LinalgOp op) {
// TODO: Masking only supports dynamic generic ops for now.
- if (!isa<linalg::GenericOp, linalg::FillOp, linalg::CopyOp,
+ if (!isElementwise(op) &&
+ !isa<linalg::GenericOp, linalg::FillOp, linalg::CopyOp,
linalg::ContractionOpInterface>(op.getOperation()))
return failure();
diff --git a/mlir/test/Dialect/Linalg/vectorization.mlir b/mlir/test/Dialect/Linalg/vectorization.mlir
index 7f4af344886f498..610339405d1c2c9 100644
--- a/mlir/test/Dialect/Linalg/vectorization.mlir
+++ b/mlir/test/Dialect/Linalg/vectorization.mlir
@@ -368,6 +368,34 @@ module attributes {transform.with_named_sequence} {
// -----
+// CHECK: #[[MAP:.*]] = affine_map<(d0, d1) -> (d1, d0)>
+// CHECK: func @test_masked_vectorize_linalg_transpose
+func.func @test_masked_vectorize_linalg_transpose(%arg0: tensor<?x?xf32>, %arg1: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ // CHECK: %[[C0:.*]] = arith.constant 0 : index
+ // CHECK: %[[D0:.*]] = tensor.dim %arg0, %[[C0]]
+ // CHECK: %[[C1:.*]] = arith.constant 1 : index
+ // CHECK: %[[D1:.*]] = tensor.dim %arg0, %[[C1]]
+ // CHECK: %[[MASK0:.*]] = vector.create_mask %[[D0]], %[[D1]]
+ // CHECK: %[[LOAD:.*]] = vector.mask %[[MASK0]] { vector.transfer_read %arg0{{.+}} }
+ // CHECK-SAME: vector<2x4xi1> -> vector<2x4xf32>
+ // CHECK: %[[MASK1:.*]] = vector.create_mask %[[D1]], %[[D0]]
+ // CHECK: %[[WRITE:.*]] = vector.mask %[[MASK1]] { vector.transfer_write %[[LOAD]], %arg1{{.+}} permutation_map = #[[MAP]]{{.+}} }
+ // CHECK-SAME: vector<4x2xi1> -> tensor<?x?xf32>
+ // CHECK: return %[[WRITE]]
+ %0 = linalg.transpose ins(%arg0 : tensor<?x?xf32>) outs(%arg1 : tensor<?x?xf32>) permutation = [1, 0]
+ return %0 : tensor<?x?xf32>
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.transpose"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ transform.structured.vectorize %0 vector_sizes [2, 4] : !transform.any_op
+ transform.yield
+ }
+}
+
+// -----
+
// CHECK-LABEL: func @test_masked_vectorize_linalg_copy
func.func @test_masked_vectorize_linalg_copy(%A : memref<?x?xf32>, %B : memref<?x?xf32>) {
// CHECK: %[[c0:.*]] = arith.constant 0 : index
|
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.
Awesome, thanks! Yes, I think we were not using named ops for elementwise ops until recently, right?
@@ -1466,7 +1466,8 @@ static LogicalResult reductionPreconditions(LinalgOp op) { | |||
|
|||
static LogicalResult vectorizeDynamicLinalgOpPrecondition(linalg::LinalgOp op) { | |||
// TODO: Masking only supports dynamic generic ops for now. |
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.
We could probably remove this TODO and add a comment on that these are the ops for which dynamic shapes vectorization is enabled.
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.
Good point, thanks! I also remove linalg.fill op from the list because it is an element-wise op.
thanks @hanhanW ! |
We are able to vectorize them in linalg.generic form. We just need to relax the condition, so it can also vectorize named ops.