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