Rename and restructure tiling-related transform ops from the structured extension to be more homogeneous. In particular, all ops now follow a consistent naming scheme: - `transform.structured.tile_using_for`; - `transform.structured.tile_using_forall`; - `transform.structured.tile_reduction_using_for`; - `transform.structured.tile_reduction_using_forall`. This drops the "_op" naming artifact from `tile_to_forall_op` that shouldn't have been included in the first place, consistently specifies the name of the control flow op to be produced for loops (instead of `tile_reduction_using_scf` since `scf.forall` also belongs to `scf`), and opts for the `using` connector to avoid ambiguity. The loops produced by tiling are now systematically placed as *trailing* results of the transform op. While this required changing 3 out of 4 ops (except for `tile_using_for`), this is the only choice that makes sense when producing multiple `scf.for` ops that can be associated with a variadic number of handles. This choice is also most consistent with *other* transform ops from the structured extension, in particular with fusion ops, that produce the structured op as the leading result and the loop as the trailing result.
220 lines
12 KiB
MLIR
220 lines
12 KiB
MLIR
// RUN: mlir-opt %s -test-transform-dialect-interpreter -test-linalg-transform-patterns=test-patterns -split-input-file | FileCheck %s
|
|
|
|
func.func @dot(%x: memref<?xf32, strided<[1], offset: ?>>,
|
|
%y: memref<?xf32, strided<[1], offset: ?>>,
|
|
%v: memref<f32>) {
|
|
linalg.dot ins(%x, %y: memref<?xf32, strided<[1], offset: ?>>,
|
|
memref<?xf32, strided<[1], offset: ?>>)
|
|
outs(%v: memref<f32>)
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb0(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.dot"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
%1, %loop = transform.structured.tile_using_for %0 [8000] : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
|
|
}
|
|
|
|
// CHECK-LABEL: func @dot
|
|
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
|
// CHECK-DAG: %[[c8000:.*]] = arith.constant 8000 : index
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c8000]] {
|
|
// CHECK: linalg.dot
|
|
|
|
// -----
|
|
|
|
func.func @matvec(%A: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%x: memref<?xf32, strided<[1], offset: ?>>,
|
|
%y: memref<?xf32, strided<[1], offset: ?>>) {
|
|
linalg.matvec
|
|
ins(%A, %x: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
memref<?xf32, strided<[1], offset: ?>>)
|
|
outs(%y: memref<?xf32, strided<[1], offset: ?>>)
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb0(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.matvec"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
%1, %loops:2 = transform.structured.tile_using_for %0 [5, 6] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
|
|
}
|
|
|
|
// CHECK-LABEL: func @matvec
|
|
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
|
// CHECK-DAG: %[[c5:.*]] = arith.constant 5 : index
|
|
// CHECK-DAG: %[[c6:.*]] = arith.constant 6 : index
|
|
// CHECK: scf.for {{.*}} step %[[c5]]
|
|
// CHECK: scf.for {{.*}} step %[[c6]]
|
|
// CHECK: linalg.matvec
|
|
// CHECK: ins({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>, memref<?xf32, strided<[1], offset: ?>>)
|
|
// CHECK: outs({{.*}}: memref<?xf32, strided<[1], offset: ?>>)
|
|
|
|
// -----
|
|
|
|
func.func @matmul(%A: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%B: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%C: memref<?x?xf32, strided<[?, 1], offset: ?>>) {
|
|
linalg.matmul ins(%A, %B: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
outs(%C: memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb0(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.matmul"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
%1, %loops:3 = transform.structured.tile_using_for %0 [2000, 3000, 4000] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
%2, %loops_2:3 = transform.structured.tile_using_for %1 [200, 300, 400] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
%3, %loops_3:3 = transform.structured.tile_using_for %2 [20, 30, 40] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
%4, %loops_4:3 = transform.structured.tile_using_for %3 [2, 3, 4] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
}
|
|
|
|
// CHECK-LABEL: func @matmul
|
|
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
|
// CHECK-DAG: %[[c2:.*]] = arith.constant 2 : index
|
|
// CHECK-DAG: %[[c3:.*]] = arith.constant 3 : index
|
|
// CHECK-DAG: %[[c4:.*]] = arith.constant 4 : index
|
|
// CHECK-DAG: %[[c20:.*]] = arith.constant 20 : index
|
|
// CHECK-DAG: %[[c30:.*]] = arith.constant 30 : index
|
|
// CHECK-DAG: %[[c40:.*]] = arith.constant 40 : index
|
|
// CHECK-DAG: %[[c200:.*]] = arith.constant 200 : index
|
|
// CHECK-DAG: %[[c300:.*]] = arith.constant 300 : index
|
|
// CHECK-DAG: %[[c400:.*]] = arith.constant 400 : index
|
|
// CHECK-DAG: %[[c2000:.*]] = arith.constant 2000 : index
|
|
// CHECK-DAG: %[[c3000:.*]] = arith.constant 3000 : index
|
|
// CHECK-DAG: %[[c4000:.*]] = arith.constant 4000 : index
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c200]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c300]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c400]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c20]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c30]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c40]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c2]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c3]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c4]] {
|
|
// CHECK: linalg.matmul
|
|
// CHECK: ins({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>, memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
// CHECK: outs({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
|
|
// -----
|
|
|
|
// Map corresponding to a 2D memory access where the stride along the last dim is known to be 1.
|
|
// CHECK-DAG: #[[$kn:.*]] = affine_map<(d0, d1, d2) -> (d2, d1)>
|
|
// CHECK-DAG: #[[$nm:.*]] = affine_map<(d0, d1, d2) -> (d1, d0)>
|
|
// CHECK-DAG: #[[$km:.*]] = affine_map<(d0, d1, d2) -> (d2, d0)>
|
|
|
|
#matmul_accesses = [
|
|
affine_map<(m, n, k) -> (m, k)>,
|
|
affine_map<(m, n, k) -> (k, n)>,
|
|
affine_map<(m, n, k) -> (m, n)>
|
|
]
|
|
#generic_matmul_trait = {
|
|
args_in = 2,
|
|
args_out = 1,
|
|
indexing_maps = #matmul_accesses,
|
|
library_call = "linalg_matmul",
|
|
iterator_types = ["parallel", "parallel", "reduction"]
|
|
}
|
|
func.func @permute_generic(%A: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%B: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%C: memref<?x?xf32, strided<[?, 1], offset: ?>>) {
|
|
linalg.generic #generic_matmul_trait
|
|
ins(%A, %B : memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
outs(%C : memref<?x?xf32, strided<[?, 1], offset: ?>>) {
|
|
^bb(%a: f32, %b: f32, %c: f32):
|
|
%d = arith.mulf %a, %b: f32
|
|
%e = arith.addf %c, %d: f32
|
|
linalg.yield %e: f32
|
|
}
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb1(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.generic"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
transform.structured.interchange %0 iterator_interchange = [1, 2, 0] : (!transform.any_op) -> !transform.any_op
|
|
}
|
|
|
|
// CHECK-LABEL: func @permute_generic
|
|
// CHECK: linalg.generic {
|
|
// CHECK-SAME: indexing_maps = [#[[$kn]], #[[$nm]], #[[$km]]],
|
|
// CHECK-SAME: iterator_types = ["parallel", "reduction", "parallel"],
|
|
// CHECK-SAME: library_call = "linalg_matmul"}
|
|
// CHECK: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
// CHECK-SAME: memref<?x?xf32, strided<[?, 1], offset: ?>>
|
|
// CHECK-SAME: memref<?x?xf32, strided<[?, 1], offset: ?>>
|
|
|
|
// -----
|
|
|
|
func.func @matvec_perm(%A: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%x: memref<?xf32, strided<[1], offset: ?>>,
|
|
%y: memref<?xf32, strided<[1], offset: ?>>) {
|
|
linalg.matvec ins(%A, %x: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
memref<?xf32, strided<[1], offset: ?>>)
|
|
outs(%y: memref<?xf32, strided<[1], offset: ?>>)
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb0(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.matvec"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
%1, %loops:2 = transform.structured.tile_using_for %0 [5, 6] {interchange = [1, 0]} : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
|
|
}
|
|
|
|
// CHECK-LABEL: func @matvec_perm
|
|
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
|
// CHECK-DAG: %[[c5:.*]] = arith.constant 5 : index
|
|
// CHECK-DAG: %[[c6:.*]] = arith.constant 6 : index
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c6]]
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c5]]
|
|
// CHECK: linalg.matvec
|
|
// CHECK: ins({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>, memref<?xf32, strided<[1], offset: ?>>)
|
|
// CHECK: outs({{.*}}: memref<?xf32, strided<[1], offset: ?>>)
|
|
|
|
// -----
|
|
|
|
func.func @matmul_perm(%A: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%B: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
%C: memref<?x?xf32, strided<[?, 1], offset: ?>>) {
|
|
linalg.matmul ins(%A, %B: memref<?x?xf32, strided<[?, 1], offset: ?>>,
|
|
memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
outs(%C : memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
return
|
|
}
|
|
|
|
transform.sequence failures(propagate) {
|
|
^bb0(%arg1: !transform.any_op):
|
|
%0 = transform.structured.match ops{["linalg.matmul"]} in %arg1 : (!transform.any_op) -> !transform.any_op
|
|
%1, %loops:3 = transform.structured.tile_using_for %0 [2000, 3000, 4000] {interchange = [1, 2, 0]} : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
%2, %loops_2:3 = transform.structured.tile_using_for %1 [200, 300, 400] {interchange = [1, 0, 2]} : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
%3, %loops_3:3 = transform.structured.tile_using_for %2 [20, 30, 40] : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op, !transform.any_op)
|
|
}
|
|
|
|
// CHECK-LABEL: func @matmul_perm
|
|
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
|
// CHECK-DAG: %[[c20:.*]] = arith.constant 20 : index
|
|
// CHECK-DAG: %[[c30:.*]] = arith.constant 30 : index
|
|
// CHECK-DAG: %[[c40:.*]] = arith.constant 40 : index
|
|
// CHECK-DAG: %[[c200:.*]] = arith.constant 200 : index
|
|
// CHECK-DAG: %[[c300:.*]] = arith.constant 300 : index
|
|
// CHECK-DAG: %[[c400:.*]] = arith.constant 400 : index
|
|
// CHECK-DAG: %[[c2000:.*]] = arith.constant 2000 : index
|
|
// CHECK-DAG: %[[c3000:.*]] = arith.constant 3000 : index
|
|
// CHECK-DAG: %[[c4000:.*]] = arith.constant 4000 : index
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c300]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c200]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c400]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c20]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c30]] {
|
|
// CHECK: scf.for {{.*}} = %[[c0]] to {{.*}} step %[[c40]] {
|
|
// CHECK: linalg.matmul
|
|
// CHECK: ins({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>, memref<?x?xf32, strided<[?, 1], offset: ?>>)
|
|
// CHECK: outs({{.*}}: memref<?x?xf32, strided<[?, 1], offset: ?>>)
|