xref: /llvm-project/mlir/test/Dialect/Vector/vector-transfer-permutation-lowering.mlir (revision 3b001db4f9668cfa29572e5f1911ec7cef8b0ac2)
1// RUN: mlir-opt %s --transform-interpreter --split-input-file | FileCheck %s
2
3///----------------------------------------------------------------------------------------
4/// vector.transfer_write -> vector.transpose + vector.transfer_write
5/// [Pattern: TransferWritePermutationLowering]
6///----------------------------------------------------------------------------------------
7/// Input:
8///   * vector.transfer_write op with a permutation that under a transpose
9///     _would be_ a minor identity permutation map
10/// Output:
11///   * vector.transpose + vector.transfer_write with a permutation map which
12///     _is_ a minor identity
13
14// CHECK-LABEL:   func.func @xfer_write_transposing_permutation_map
15// CHECK-SAME:      %[[VEC:.*]]: vector<4x8xi16>,
16// CHECK-SAME:      %[[MEM:.*]]: memref<2x2x8x4xi16>
17// CHECK:           %[[TR:.*]] = vector.transpose %[[VEC]], [1, 0] : vector<4x8xi16> to vector<8x4xi16>
18// CHECK:           vector.transfer_write
19// CHECK-NOT:       permutation_map
20// CHECK-SAME:      %[[TR]], %[[MEM]]{{.*}} {in_bounds = [true, true]} : vector<8x4xi16>, memref<2x2x8x4xi16>
21func.func @xfer_write_transposing_permutation_map(
22    %vec: vector<4x8xi16>,
23    %mem: memref<2x2x8x4xi16>,
24    %idx: index) {
25
26  vector.transfer_write %vec, %mem[%idx, %idx, %idx, %idx] {
27    in_bounds = [true, true],
28    permutation_map = affine_map<(d0, d1, d2, d3) -> (d3, d2)>
29  } : vector<4x8xi16>, memref<2x2x8x4xi16>
30
31  return
32}
33
34// Even with out-of-bounds accesses, it is safe to apply this pattern
35
36// CHECK-LABEL:   func.func @xfer_write_transposing_permutation_map_out_of_bounds
37// CHECK-SAME:      %[[VEC:.*]]: vector<4x8xi16>,
38// CHECK-SAME:      %[[MEM:.*]]: memref<2x2x?x?xi16>,
39// CHECK-SAME:      %[[IDX:.*]]: index) {
40// CHECK:           %[[TR:.*]] = vector.transpose %[[VEC]], [1, 0] : vector<4x8xi16> to vector<8x4xi16>
41// Expect the in_bounds attribute to be preserved. Since we don't print it when
42// all flags are "false", it should not appear in the output.
43// CHECK-NOT:       in_bounds
44// CHECK:           vector.transfer_write
45// CHECK-NOT:       permutation_map
46// CHECK-SAME:      %[[TR]], %[[MEM]][%[[IDX]], %[[IDX]], %[[IDX]], %[[IDX]]] : vector<8x4xi16>, memref<2x2x?x?xi16>
47func.func @xfer_write_transposing_permutation_map_out_of_bounds(
48    %vec: vector<4x8xi16>,
49    %mem: memref<2x2x?x?xi16>,
50    %idx: index) {
51
52  vector.transfer_write %vec, %mem[%idx, %idx, %idx, %idx] {
53    in_bounds = [false, false],
54    permutation_map = affine_map<(d0, d1, d2, d3) -> (d3, d2)>
55  } : vector<4x8xi16>, memref<2x2x?x?xi16>
56
57  return
58}
59
60// CHECK-LABEL:   func.func @xfer_write_transposing_permutation_map_with_mask_scalable
61// CHECK-SAME:      %[[VEC:.*]]: vector<4x[8]xi16>,
62// CHECK-SAME:      %[[MEM:.*]]: memref<2x2x?x4xi16>,
63// CHECK-SAME:      %[[MASK:.*]]: vector<[8]x4xi1>
64// CHECK:           %[[TR:.*]] = vector.transpose %[[VEC]], [1, 0] : vector<4x[8]xi16> to vector<[8]x4xi16>
65// CHECK:           vector.transfer_write
66// CHECK-NOT:       permutation_map
67// CHECK-SAME:      %[[TR]], %[[MEM]]{{.*}}, %[[MASK]] {in_bounds = [true, true]} : vector<[8]x4xi16>, memref<2x2x?x4xi16>
68func.func @xfer_write_transposing_permutation_map_with_mask_scalable(
69    %vec: vector<4x[8]xi16>,
70    %mem: memref<2x2x?x4xi16>,
71    %mask: vector<[8]x4xi1>,
72    %idx: index) {
73
74  %c0 = arith.constant 0 : index
75  vector.transfer_write %vec, %mem[%idx, %idx, %idx, %idx], %mask {
76    in_bounds = [true, true],
77    permutation_map = affine_map<(d0, d1, d2, d3) -> (d3, d2)>
78  } : vector<4x[8]xi16>, memref<2x2x?x4xi16>
79
80  return
81}
82
83// Masked version is not supported
84
85// CHECK-LABEL:   func.func @xfer_write_transposing_permutation_map_masked
86// CHECK-NOT: vector.transpose
87func.func @xfer_write_transposing_permutation_map_masked(
88    %vec: vector<4x8xi16>,
89    %mem: memref<2x2x8x4xi16>,
90    %mask: vector<8x4xi1>,
91    %idx: index) {
92
93  %c0 = arith.constant 0 : index
94  vector.mask %mask {
95    vector.transfer_write %vec, %mem[%idx, %idx, %idx, %idx] {
96      in_bounds = [true, true],
97      permutation_map = affine_map<(d0, d1, d2, d3) -> (d3, d2)>
98    } : vector<4x8xi16>, memref<2x2x8x4xi16>
99  } : vector<8x4xi1>
100
101  return
102}
103
104///----------------------------------------------------------------------------------------
105/// vector.transfer_write -> vector.broadcast + vector.transpose + vector.transfer_write
106/// [Patterns: TransferWriteNonPermutationLowering + TransferWritePermutationLowering]
107///----------------------------------------------------------------------------------------
108/// Input:
109///   * vector.transfer_write op with a map which _is not_ a permutation of a
110///     minor identity
111/// Output:
112///   * vector.broadcast + vector.transpose + vector.transfer_write with a map
113///     which _is_ a permutation of a minor identity
114
115// CHECK-LABEL:   func.func @xfer_write_non_transposing_permutation_map(
116// CHECK-SAME:      %[[MEM:.*]]: memref<?x?xf32>,
117// CHECK-SAME:      %[[VEC:.*]]: vector<7xf32>,
118// CHECK-SAME:      %[[IDX_1:.*]]: index, %[[IDX_2:.*]]: index) {
119// CHECK:           %[[BC:.*]] = vector.broadcast %[[VEC]] : vector<7xf32> to vector<1x7xf32>
120// CHECK:           %[[TR:.*]] = vector.transpose %[[BC]], [1, 0] : vector<1x7xf32> to vector<7x1xf32>
121// CHECK:           vector.transfer_write %[[TR]], %[[MEM]]{{\[}}%[[IDX_1]], %[[IDX_2]]] {in_bounds = [false, true]} : vector<7x1xf32>, memref<?x?xf32>
122func.func @xfer_write_non_transposing_permutation_map(
123    %mem : memref<?x?xf32>,
124    %vec : vector<7xf32>,
125    %idx_1 : index,
126    %idx_2 : index) {
127
128  vector.transfer_write %vec, %mem[%idx_1, %idx_2] {
129    permutation_map = affine_map<(d0, d1) -> (d0)>
130  } : vector<7xf32>, memref<?x?xf32>
131
132  return
133}
134
135// Even with out-of-bounds accesses, it is safe to apply this pattern
136
137// CHECK-LABEL:   func.func @xfer_write_non_transposing_permutation_map_with_mask_out_of_bounds(
138// CHECK-SAME:      %[[MEM:.*]]: memref<?x?xf32>,
139// CHECK-SAME:      %[[VEC:.*]]: vector<7xf32>,
140// CHECK-SAME:      %[[IDX_1:.*]]: index, %[[IDX_2:.*]]: index,
141// CHECK-SAME:      %[[MASK:.*]]: vector<7xi1>) {
142// CHECK:           %[[BC_VEC:.*]] = vector.broadcast %[[VEC]] : vector<7xf32> to vector<1x7xf32>
143// CHECK:           %[[BC_MASK:.*]] = vector.broadcast %[[MASK]] : vector<7xi1> to vector<1x7xi1>
144// CHECK:           %[[TR_MASK:.*]] = vector.transpose %[[BC_MASK]], [1, 0] : vector<1x7xi1> to vector<7x1xi1>
145// CHECK:           %[[TR_VEC:.*]] = vector.transpose %[[BC_VEC]], [1, 0] : vector<1x7xf32> to vector<7x1xf32>
146// CHECK:           vector.transfer_write %[[TR_VEC]], %[[MEM]]{{\[}}%[[IDX_1]], %[[IDX_2]]], %[[TR_MASK]] {in_bounds = [false, true]} : vector<7x1xf32>, memref<?x?xf32>
147func.func @xfer_write_non_transposing_permutation_map_with_mask_out_of_bounds(
148    %mem : memref<?x?xf32>,
149    %vec : vector<7xf32>,
150    %idx_1 : index,
151    %idx_2 : index,
152    %mask : vector<7xi1>) {
153
154  vector.transfer_write %vec, %mem[%idx_1, %idx_2], %mask {
155    permutation_map = affine_map<(d0, d1) -> (d0)>,
156    in_bounds = [false]
157  } : vector<7xf32>, memref<?x?xf32>
158
159  return
160}
161
162// CHECK:           func.func @permutation_with_mask_xfer_write_scalable(
163// CHECK-SAME:        %[[VEC:.*]]: vector<4x[8]xi16>,
164// CHECK-SAME:        %[[MEM:.*]]: memref<1x4x?x1xi16>,
165// CHECK-SAME:        %[[MASK:.*]]: vector<4x[8]xi1>
166// CHECK:             %[[BC_1:.*]] = vector.broadcast %[[VEC]] : vector<4x[8]xi16> to vector<1x4x[8]xi16>
167// CHECK:             %[[BC_2:.*]] = vector.broadcast %[[MASK]] : vector<4x[8]xi1> to vector<1x4x[8]xi1>
168// CHECK:             %[[TRANSPOSE_1:.*]] =  vector.transpose %[[BC_2]], [1, 2, 0] : vector<1x4x[8]xi1> to vector<4x[8]x1xi1>
169// CHECK:             %[[TRANSPOSE_2:.*]] =  vector.transpose %[[BC_1]], [1, 2, 0] : vector<1x4x[8]xi16> to vector<4x[8]x1xi16>
170// CHECK:             vector.transfer_write %[[TRANSPOSE_2]], %[[MEM]]{{.*}}, %[[TRANSPOSE_1]] {in_bounds = [true, true, true]} : vector<4x[8]x1xi16>, memref<1x4x?x1xi16>
171func.func @permutation_with_mask_xfer_write_scalable(
172    %vec: vector<4x[8]xi16>,
173    %mem: memref<1x4x?x1xi16>,
174    %mask: vector<4x[8]xi1>,
175    %idx: index){
176
177  vector.transfer_write %vec, %mem[%idx, %idx, %idx, %idx], %mask {
178    in_bounds = [true, true],
179    permutation_map = affine_map<(d0, d1, d2, d3) -> (d1, d2)>
180  } : vector<4x[8]xi16>, memref<1x4x?x1xi16>
181
182  return
183}
184
185// Masked version is not supported
186
187// CHECK-LABEL: func @masked_permutation_xfer_write_fixed_width
188//  CHECK-SAME:   %[[DEST:.*]]: tensor<?x?xf32>,
189//  CHECK-SAME:   %[[VEC:.*]]: vector<16xf32>,
190//  CHECK-SAME:   %[[IDX:.*]]: index,
191//  CHECK-SAME:   %[[MASK:.*]]: vector<16xi1>
192//   CHECK-NOT:   vector.transpose
193//       CHECK:   vector.mask %[[MASK]] { vector.transfer_write %[[VEC]], %[[DEST]]{{.*}} vector<16xf32>, tensor<?x?xf32> } : vector<16xi1> -> tensor<?x?xf32>
194func.func @masked_permutation_xfer_write_fixed_width(
195    %dest: tensor<?x?xf32>,
196    %vec: vector<16xf32>,
197    %idx: index,
198    %mask: vector<16xi1>) -> tensor<?x?xf32> {
199
200  %res = vector.mask %mask {
201    vector.transfer_write %vec, %dest[%idx, %idx] {
202      permutation_map = affine_map<(d0, d1) -> (d0)>
203    } : vector<16xf32>, tensor<?x?xf32>
204  } : vector<16xi1> -> tensor<?x?xf32>
205
206  return %res : tensor<?x?xf32>
207}
208
209// CHECK-LABEL: func.func @masked_permutation_xfer_write_scalable(
210//  CHECK-SAME:   %[[VEC:.*]]: vector<4x[8]xi16>,
211//  CHECK-SAME:   %[[DEST:.*]]: tensor<?x?x?x?xf32>,
212//  CHECK-SAME:   %[[MASK:.*]]: vector<4x[8]xi1>
213//  CHECK-SAME:   -> tensor<?x?x?x?xf32> {
214//   CHECK-NOT:   vector.transpose
215//       CHECK:   vector.mask %[[MASK]] { vector.transfer_write %[[VEC]], %[[DEST]]{{.*}} : vector<4x[8]xi16>, tensor<?x?x?x?xf32> } : vector<4x[8]xi1> -> tensor<?x?x?x?xf32>
216func.func @masked_permutation_xfer_write_scalable(
217    %vec: vector<4x[8]xi16>,
218    %dest: tensor<?x?x?x?xf32>,
219    %mask:  vector<4x[8]xi1>,
220    %idx: index) -> tensor<?x?x?x?xf32> {
221
222  %c0 = arith.constant 0 : index
223  %res = vector.mask %mask {
224    vector.transfer_write %vec, %dest[%idx, %idx, %idx, %idx] {
225      in_bounds = [true, true],
226      permutation_map = affine_map<(d0, d1, d2, d3) -> (d1, d2)>
227    } : vector<4x[8]xi16>, tensor<?x?x?x?xf32>
228  } : vector<4x[8]xi1> -> tensor<?x?x?x?xf32>
229
230  return %res : tensor<?x?x?x?xf32>
231}
232
233// Masked version is not supported
234
235// CHECK-LABEL: func @masked_non_permutation_xfer_write_fixed_width
236//  CHECK-SAME:   %[[DEST:.*]]: tensor<?x?x?x?xf32>
237//  CHECK-SAME:   %[[VEC:.*]]: vector<14x8x16xf32>
238//  CHECK-SAME:   %[[DIM:.*]]: index, %[[IDX:.*]]: index) -> tensor<?x?x?x?xf32>
239//   CHECK-NOT:   vector.broadcast
240//       CHECK:   vector.mask %0 { vector.transfer_write %[[VEC]], %[[DEST]]{{.*}} : vector<14x8x16xf32>, tensor<?x?x?x?xf32> } : vector<14x8x16xi1> -> tensor<?x?x?x?xf32>
241func.func @masked_non_permutation_xfer_write_fixed_width(
242    %dest : tensor<?x?x?x?xf32>,
243    %vec : vector<14x8x16xf32>,
244    %dim : index,
245    %idx: index) -> tensor<?x?x?x?xf32> {
246
247  %mask = vector.create_mask %dim, %dim, %dim : vector<14x8x16xi1>
248  %res = vector.mask %mask {
249    vector.transfer_write %vec, %dest[%idx, %idx, %idx, %idx] {
250      in_bounds = [false, false, true],
251      permutation_map = affine_map<(d0, d1, d2, d3) -> (d0, d1, d3)>
252    } : vector<14x8x16xf32>, tensor<?x?x?x?xf32>
253  } : vector<14x8x16xi1> -> tensor<?x?x?x?xf32>
254
255  return %res : tensor<?x?x?x?xf32>
256}
257
258///----------------------------------------------------------------------------------------
259/// vector.transfer_read
260///----------------------------------------------------------------------------------------
261/// Input:
262///   * vector.transfer_read op with a permutation map
263/// Output:
264///   * vector.transfer_read with a permutation map composed of leading zeros followed by a minor identiy +
265///     vector.transpose op
266
267// CHECK-LABEL:   func.func @permutation_with_mask_xfer_read_fixed_width(
268// CHECK-SAME:      %[[MEM:.*]]: memref<?x?xf32>,
269// CHECK-SAME:      %[[DIM_1:.*]]: index, %[[DIM_2:.*]]: index, %[[IDX:.*]]: index) -> vector<8x4x2xf32> {
270// CHECK:           %[[PASS_THROUGH:.*]] = arith.constant 0.000000e+00 : f32
271// CHECK:           %[[MASK:.*]] = vector.create_mask %[[DIM_2]], %[[DIM_1]] : vector<2x4xi1>
272// CHECK:           %[[T_READ:.*]] = vector.transfer_read %[[MEM]]{{\[}}%[[IDX]], %[[IDX]]], %[[PASS_THROUGH]], %[[MASK]] {in_bounds = [true, true]} : memref<?x?xf32>, vector<2x4xf32>
273// CHECK:           %[[BCAST:.*]] = vector.broadcast %[[T_READ]] : vector<2x4xf32> to vector<8x2x4xf32>
274// CHECK:           %[[TRANSPOSE:.*]] = vector.transpose %[[BCAST]], [0, 2, 1] : vector<8x2x4xf32> to vector<8x4x2xf32>
275// CHECK:           return %[[TRANSPOSE]] : vector<8x4x2xf32>
276func.func @permutation_with_mask_xfer_read_fixed_width(
277    %mem: memref<?x?xf32>,
278    %dim_1: index,
279    %dim_2: index,
280    %idx: index) -> (vector<8x4x2xf32>) {
281
282  %pad = arith.constant 0.000000e+00 : f32
283
284  %mask = vector.create_mask %dim_2, %dim_1 : vector<2x4xi1>
285  %res = vector.transfer_read %mem[%idx, %idx], %pad, %mask {
286    in_bounds = [true, true, true],
287    permutation_map = affine_map<(d0, d1) -> (0, d1, d0)>
288  } : memref<?x?xf32>, vector<8x4x2xf32>
289
290  return %res : vector<8x4x2xf32>
291}
292
293// CHECK-LABEL:   func.func @permutation_with_mask_xfer_read_scalable(
294// CHECK-SAME:      %[[MEM:.*]]: memref<?x?xf32>,
295// CHECK-SAME:      %[[DIM_1:.*]]: index, %[[DIM_2:.*]]: index, %[[IDX:.*]]: index) -> vector<8x[4]x2xf32> {
296// CHECK:           %[[PAD:.*]] = arith.constant 0.000000e+00 : f32
297// CHECK:           %[[MASK:.*]] = vector.create_mask %[[DIM_2]], %[[DIM_1]] : vector<2x[4]xi1>
298// CHECK:           %[[T_READ:.*]] = vector.transfer_read %[[MEM]]{{\[}}%[[IDX]], %[[IDX]]], %[[PAD]], %[[MASK]] {in_bounds = [true, true]} : memref<?x?xf32>, vector<2x[4]xf32>
299// CHECK:           %[[BCAST:.*]] = vector.broadcast %[[T_READ]] : vector<2x[4]xf32> to vector<8x2x[4]xf32>
300// CHECK:           %[[TRANSPOSE:.*]] = vector.transpose %[[BCAST]], [0, 2, 1] : vector<8x2x[4]xf32> to vector<8x[4]x2xf32>
301// CHECK:           return %[[TRANSPOSE]] : vector<8x[4]x2xf32>
302func.func @permutation_with_mask_xfer_read_scalable(
303    %mem: memref<?x?xf32>,
304    %dim_1: index,
305    %dim_2: index,
306    %idx: index) -> (vector<8x[4]x2xf32>) {
307
308  %pad = arith.constant 0.000000e+00 : f32
309
310  %mask = vector.create_mask %dim_2, %dim_1 : vector<2x[4]xi1>
311  %res = vector.transfer_read %mem[%idx, %idx], %pad, %mask {
312    in_bounds = [true, true, true],
313    permutation_map = affine_map<(d0, d1) -> (0, d1, d0)>
314  } : memref<?x?xf32>, vector<8x[4]x2xf32>
315
316  return %res : vector<8x[4]x2xf32>
317}
318
319// Masked version is not supported
320
321// CHECK-LABEL: func @masked_permutation_xfer_read_fixed_width
322//  CHECK-SAME:   %[[DEST:.*]]: tensor<?x1xf32>,
323//  CHECK-SAME:   %[[MASK:.*]]: vector<4x1xi1>
324//   CHECK-NOT:   vector.transpose
325//       CHECK:   vector.mask %[[MASK]] { vector.transfer_read %[[DEST]]{{.*}}: tensor<?x1xf32>, vector<1x4x4xf32> } : vector<4x1xi1> -> vector<1x4x4xf32>
326func.func @masked_permutation_xfer_read_fixed_width(
327    %dest: tensor<?x1xf32>,
328    %mask : vector<4x1xi1>,
329    %idx: index) {
330
331  %pad = arith.constant 0.000000e+00 : f32
332  %3 = vector.mask %mask {
333    vector.transfer_read %dest[%idx, %idx], %pad {
334      permutation_map = affine_map<(d0, d1) -> (d1, 0, d0)>
335    } : tensor<?x1xf32>, vector<1x4x4xf32>
336  } : vector<4x1xi1> -> vector<1x4x4xf32>
337
338  "test.some_use"(%3) : (vector<1x4x4xf32>) -> ()
339  return
340}
341
342// CHECK-LABEL:  func.func @masked_permutation_xfer_read_scalable(
343//  CHECK-SAME:    %[[DEST:.*]]: tensor<?x?xf32>,
344//  CHECK-SAME:    %[[MASK:.*]]: vector<2x[4]xi1>
345//   CHECK-NOT:    vector.transpose
346//       CHECK:    %[[T_READ:.*]] = vector.mask %[[MASK]] { vector.transfer_read %[[DEST]]{{.*}} : tensor<?x?xf32>, vector<8x[4]x2xf32> } : vector<2x[4]xi1> -> vector<8x[4]x2xf32>
347func.func @masked_permutation_xfer_read_scalable(
348  %dest: tensor<?x?xf32>,
349  %mask : vector<2x[4]xi1>,
350  %idx: index) -> vector<8x[4]x2xf32> {
351
352  %pad = arith.constant 0.000000e+00 : f32
353
354  %res = vector.mask %mask {
355    vector.transfer_read %dest[%idx, %idx], %pad {
356      in_bounds = [true, true, true],
357      permutation_map = affine_map<(d0, d1) -> (0, d1, d0)>
358    } : tensor<?x?xf32>, vector<8x[4]x2xf32>
359  } :vector<2x[4]xi1> -> vector<8x[4]x2xf32>
360
361  return %res : vector<8x[4]x2xf32>
362}
363
364module attributes {transform.with_named_sequence} {
365  transform.named_sequence @__transform_main(%module_op: !transform.any_op {transform.readonly}) {
366    %f = transform.structured.match ops{["func.func"]} in %module_op
367      : (!transform.any_op) -> !transform.any_op
368    transform.apply_patterns to %f {
369      transform.apply_patterns.vector.transfer_permutation_patterns
370    } : !transform.any_op
371    transform.yield
372  }
373}
374
375// -----
376
377///----------------------------------------------------------------------------------------
378/// vector.transfer_read
379///----------------------------------------------------------------------------------------
380/// TODO: Review and categorize
381
382//       CHECK:   #[[MAP:.*]] = affine_map<(d0, d1, d2, d3) -> (d1, 0, d3)>
383//       CHECK:   func.func @transfer_read_reduce_rank_scalable(
384//  CHECK-SAME:     %[[MEM:.*]]: memref<?x?x?x?xf32>, %[[IDX:.*]]: index) -> vector<8x[4]x2x3xf32> {
385//       CHECK:     %[[T_READ:.*]] = vector.transfer_read %[[MEM]][%[[IDX]], %[[IDX]], %[[IDX]], %[[IDX]]]{{.*}} permutation_map = #[[MAP]]} : memref<?x?x?x?xf32>, vector<[4]x2x3xf32>
386//       CHECK:     %[[BC:.*]] = vector.broadcast %[[T_READ]] : vector<[4]x2x3xf32> to vector<8x[4]x2x3xf32>
387//       CHECK:     return %[[BC]] : vector<8x[4]x2x3xf32>
388func.func @transfer_read_reduce_rank_scalable(
389    %mem: memref<?x?x?x?xf32>, %idx: index) -> vector<8x[4]x2x3xf32> {
390
391  %pad = arith.constant 0.000000e+00 : f32
392
393  %res = vector.transfer_read %mem[%idx, %idx, %idx, %idx], %pad {
394    in_bounds = [true, true, true, true],
395    permutation_map = affine_map<(d0, d1, d2, d3) -> (0, d1, 0, d3)>
396  } : memref<?x?x?x?xf32>, vector<8x[4]x2x3xf32>
397
398  return %res : vector<8x[4]x2x3xf32>
399}
400
401// Masked version is not supported
402
403// CHECK-LABEL:   func.func @masked_transfer_read_reduce_rank(
404//  CHECK-SAME:     %[[MEM:.*]]: memref<?x?x?x?xf32>,
405//  CHECK-SAME:     %[[DIM:.*]]: index,
406//  CHECK-SAME:     %[[IDX:.*]]: index) -> vector<8x[4]x2x3xf32> {
407//   CHECK-NOT:     vector.broadcast
408//       CHECK:     %[[MASK:.*]] = vector.mask %0 { vector.transfer_read %[[MEM]]{{.*}} : memref<?x?x?x?xf32>, vector<8x[4]x2x3xf32> } : vector<[4]x3xi1> -> vector<8x[4]x2x3xf32>
409func.func @masked_transfer_read_reduce_rank(
410    %mem: memref<?x?x?x?xf32>,
411    %dim: index,
412    %idx: index) -> vector<8x[4]x2x3xf32> {
413
414  %pad = arith.constant 0.000000e+00 : f32
415  %mask = vector.create_mask %dim, %dim: vector<[4]x3xi1>
416
417  %res = vector.mask %mask {
418    vector.transfer_read %mem[%idx, %idx, %idx, %idx], %pad {
419      in_bounds = [true, true, true, true],
420      permutation_map = affine_map<(d0, d1, d2, d3) -> (0, d1, 0, d3)>
421    } : memref<?x?x?x?xf32>, vector<8x[4]x2x3xf32>
422  } : vector<[4]x3xi1> -> vector<8x[4]x2x3xf32>
423
424  return %res : vector<8x[4]x2x3xf32>
425}
426
427module attributes {transform.with_named_sequence} {
428  transform.named_sequence @__transform_main(%module_op: !transform.any_op {transform.readonly}) {
429    %f = transform.structured.match ops{["func.func"]} in %module_op
430      : (!transform.any_op) -> !transform.any_op
431    transform.apply_patterns to %f {
432      transform.apply_patterns.vector.transfer_permutation_patterns
433    } : !transform.any_op
434    transform.yield
435  }
436}
437