1// RUN: mlir-opt %s -test-vector-transfer-full-partial-split -split-input-file | FileCheck %s 2// RUN: mlir-opt %s -test-vector-transfer-full-partial-split=use-linalg-copy -split-input-file | FileCheck %s --check-prefix=LINALG 3 4// CHECK-DAG: #[[$map_p4:.*]] = affine_map<()[s0] -> (s0 + 4)> 5// CHECK-DAG: #[[$map_p8:.*]] = affine_map<()[s0] -> (s0 + 8)> 6// CHECK-DAG: #[[$map_2d_stride_1:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)> 7 8// LINALG-DAG: #[[$map_p4:.*]] = affine_map<()[s0] -> (s0 + 4)> 9// LINALG-DAG: #[[$map_p8:.*]] = affine_map<()[s0] -> (s0 + 8)> 10// LINALG-DAG: #[[$map_2d_stride_1:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)> 11// LINALG-DAG: #[[$map_2d_stride_8x1:.*]] = affine_map<(d0, d1)[s0] -> (d0 * 8 + s0 + d1)> 12// LINALG-DAG: #[[$bounds_map_4:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 4)> 13// LINALG-DAG: #[[$bounds_map_8:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 8)> 14 15// CHECK-LABEL: split_vector_transfer_read_2d( 16// CHECK-SAME: %[[A:[a-zA-Z0-9]*]]: memref 17// CHECK-SAME: %[[i:[a-zA-Z0-9]*]]: index 18// CHECK-SAME: %[[j:[a-zA-Z0-9]*]]: index 19 20// LINALG-LABEL: split_vector_transfer_read_2d( 21// LINALG-SAME: %[[A:[a-zA-Z0-9]*]]: memref 22// LINALG-SAME: %[[i:[a-zA-Z0-9]*]]: index 23// LINALG-SAME: %[[j:[a-zA-Z0-9]*]]: index 24func @split_vector_transfer_read_2d(%A: memref<?x8xf32>, %i: index, %j: index) -> vector<4x8xf32> { 25 %c0 = constant 0 : index 26 %f0 = constant 0.0 : f32 27 28 // CHECK-DAG: %[[c8:.*]] = constant 8 : index 29 // CHECK-DAG: %[[c0:.*]] = constant 0 : index 30 // alloca for boundary full tile 31 // CHECK: %[[alloc:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 32 // %i + 4 <= dim(%A, 0) 33 // CHECK: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 34 // CHECK: %[[d0:.*]] = memref.dim %[[A]], %[[c0]] : memref<?x8xf32> 35 // CHECK: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[d0]] : index 36 // %j + 8 <= dim(%A, 1) 37 // CHECK: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 38 // CHECK: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 39 // are both conds true 40 // CHECK: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 41 // CHECK: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32>, index, index) { 42 // inBounds, just yield %A 43 // CHECK: scf.yield %[[A]], %[[i]], %[[j]] : memref<?x8xf32>, index, index 44 // CHECK: } else { 45 // slow path, fill tmp alloc and yield a memref_casted version of it 46 // CHECK: %[[slow:.*]] = vector.transfer_read %[[A]][%[[i]], %[[j]]], %cst : 47 // CHECK-SAME: memref<?x8xf32>, vector<4x8xf32> 48 // CHECK: %[[cast_alloc:.*]] = vector.type_cast %[[alloc]] : 49 // CHECK-SAME: memref<4x8xf32> to memref<vector<4x8xf32>> 50 // CHECK: store %[[slow]], %[[cast_alloc]][] : memref<vector<4x8xf32>> 51 // CHECK: %[[yielded:.*]] = memref.cast %[[alloc]] : 52 // CHECK-SAME: memref<4x8xf32> to memref<?x8xf32> 53 // CHECK: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 54 // CHECK-SAME: memref<?x8xf32>, index, index 55 // CHECK: } 56 // CHECK: %[[res:.*]] = vector.transfer_read %[[ifres]]#0[%[[ifres]]#1, %[[ifres]]#2], %cst 57 // CHECK_SAME: {in_bounds = [true, true]} : memref<?x8xf32>, vector<4x8xf32> 58 59 // LINALG-DAG: %[[c0:.*]] = constant 0 : index 60 // LINALG-DAG: %[[c4:.*]] = constant 4 : index 61 // LINALG-DAG: %[[c8:.*]] = constant 8 : index 62 // alloca for boundary full tile 63 // LINALG: %[[alloc:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 64 // %i + 4 <= dim(%A, 0) 65 // LINALG: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 66 // LINALG: %[[d0:.*]] = memref.dim %[[A]], %[[c0]] : memref<?x8xf32> 67 // LINALG: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[d0]] : index 68 // %j + 8 <= dim(%A, 1) 69 // LINALG: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 70 // LINALG: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 71 // are both conds true 72 // LINALG: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 73 // LINALG: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32>, index, index) { 74 // inBounds, just yield %A 75 // LINALG: scf.yield %[[A]], %[[i]], %[[j]] : memref<?x8xf32>, index, index 76 // LINALG: } else { 77 // slow path, fill tmp alloc and yield a memref_casted version of it 78 // LINALG: linalg.fill(%[[alloc]], %cst) : memref<4x8xf32>, f32 79 // LINALG: %[[d0:.*]] = memref.dim %[[A]], %[[c0]] : memref<?x8xf32> 80 // LINALG: %[[sv0:.*]] = affine.min #[[$bounds_map_4]](%[[d0]], %[[i]], %[[c4]]) 81 // LINALG: %[[sv1:.*]] = affine.min #[[$bounds_map_8]](%[[c8]], %[[j]], %[[c8]]) 82 // LINALG: %[[sv:.*]] = memref.subview %[[A]][%[[i]], %[[j]]] [%[[sv0]], %[[sv1]]] [1, 1] 83 // LINALG-SAME: memref<?x8xf32> to memref<?x?xf32, #[[$map_2d_stride_8x1]]> 84 // LINALG: linalg.copy(%[[sv]], %[[alloc]]) : memref<?x?xf32, #[[$map_2d_stride_8x1]]>, memref<4x8xf32> 85 // LINALG: %[[yielded:.*]] = memref.cast %[[alloc]] : 86 // LINALG-SAME: memref<4x8xf32> to memref<?x8xf32> 87 // LINALG: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 88 // LINALG-SAME: memref<?x8xf32>, index, index 89 // LINALG: } 90 // LINALG: %[[res:.*]] = vector.transfer_read %[[ifres]]#0[%[[ifres]]#1, %[[ifres]]#2], %cst 91 // LINALG_SAME: {in_bounds = [true, true]} : memref<?x8xf32>, vector<4x8xf32> 92 %1 = vector.transfer_read %A[%i, %j], %f0 : memref<?x8xf32>, vector<4x8xf32> 93 94 // LINALG: return %[[res]] : vector<4x8xf32> 95 return %1: vector<4x8xf32> 96} 97 98// CHECK-LABEL: split_vector_transfer_read_strided_2d( 99// CHECK-SAME: %[[A:[a-zA-Z0-9]*]]: memref 100// CHECK-SAME: %[[i:[a-zA-Z0-9]*]]: index 101// CHECK-SAME: %[[j:[a-zA-Z0-9]*]]: index 102 103// LINALG-LABEL: split_vector_transfer_read_strided_2d( 104// LINALG-SAME: %[[A:[a-zA-Z0-9]*]]: memref 105// LINALG-SAME: %[[i:[a-zA-Z0-9]*]]: index 106// LINALG-SAME: %[[j:[a-zA-Z0-9]*]]: index 107func @split_vector_transfer_read_strided_2d( 108 %A: memref<7x8xf32, offset:?, strides:[?, 1]>, 109 %i: index, %j: index) -> vector<4x8xf32> { 110 %c0 = constant 0 : index 111 %f0 = constant 0.0 : f32 112 113 // CHECK-DAG: %[[c7:.*]] = constant 7 : index 114 // CHECK-DAG: %[[c8:.*]] = constant 8 : index 115 // CHECK-DAG: %[[c0:.*]] = constant 0 : index 116 // alloca for boundary full tile 117 // CHECK: %[[alloc:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 118 // %i + 4 <= dim(%A, 0) 119 // CHECK: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 120 // CHECK: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[c7]] : index 121 // %j + 8 <= dim(%A, 1) 122 // CHECK: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 123 // CHECK: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 124 // are both conds true 125 // CHECK: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 126 // CHECK: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index) { 127 // inBounds but not cast-compatible: yield a memref_casted form of %A 128 // CHECK: %[[casted:.*]] = memref.cast %arg0 : 129 // CHECK-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x8xf32, #[[$map_2d_stride_1]]> 130 // CHECK: scf.yield %[[casted]], %[[i]], %[[j]] : 131 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 132 // CHECK: } else { 133 // slow path, fill tmp alloc and yield a memref_casted version of it 134 // CHECK: %[[slow:.*]] = vector.transfer_read %[[A]][%[[i]], %[[j]]], %cst : 135 // CHECK-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 136 // CHECK: %[[cast_alloc:.*]] = vector.type_cast %[[alloc]] : 137 // CHECK-SAME: memref<4x8xf32> to memref<vector<4x8xf32>> 138 // CHECK: store %[[slow]], %[[cast_alloc]][] : 139 // CHECK-SAME: memref<vector<4x8xf32>> 140 // CHECK: %[[yielded:.*]] = memref.cast %[[alloc]] : 141 // CHECK-SAME: memref<4x8xf32> to memref<?x8xf32, #[[$map_2d_stride_1]]> 142 // CHECK: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 143 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 144 // CHECK: } 145 // CHECK: %[[res:.*]] = vector.transfer_read {{.*}} {in_bounds = [true, true]} : 146 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 147 148 // LINALG-DAG: %[[c0:.*]] = constant 0 : index 149 // LINALG-DAG: %[[c4:.*]] = constant 4 : index 150 // LINALG-DAG: %[[c7:.*]] = constant 7 : index 151 // LINALG-DAG: %[[c8:.*]] = constant 8 : index 152 // alloca for boundary full tile 153 // LINALG: %[[alloc:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 154 // %i + 4 <= dim(%A, 0) 155 // LINALG: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 156 // LINALG: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[c7]] : index 157 // %j + 8 <= dim(%A, 1) 158 // LINALG: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 159 // LINALG: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 160 // are both conds true 161 // LINALG: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 162 // LINALG: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index) { 163 // inBounds but not cast-compatible: yield a memref_casted form of %A 164 // LINALG: %[[casted:.*]] = memref.cast %arg0 : 165 // LINALG-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x8xf32, #[[$map_2d_stride_1]]> 166 // LINALG: scf.yield %[[casted]], %[[i]], %[[j]] : 167 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 168 // LINALG: } else { 169 // slow path, fill tmp alloc and yield a memref_casted version of it 170 // LINALG: linalg.fill(%[[alloc]], %cst) : memref<4x8xf32>, f32 171 // LINALG: %[[sv0:.*]] = affine.min #[[$bounds_map_4]](%[[c7]], %[[i]], %[[c4]]) 172 // LINALG: %[[sv1:.*]] = affine.min #[[$bounds_map_8]](%[[c8]], %[[j]], %[[c8]]) 173 // LINALG: %[[sv:.*]] = memref.subview %[[A]][%[[i]], %[[j]]] [%[[sv0]], %[[sv1]]] [1, 1] 174 // LINALG-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x?xf32, #[[$map_2d_stride_1]]> 175 // LINALG: linalg.copy(%[[sv]], %[[alloc]]) : memref<?x?xf32, #[[$map_2d_stride_1]]>, memref<4x8xf32> 176 // LINALG: %[[yielded:.*]] = memref.cast %[[alloc]] : 177 // LINALG-SAME: memref<4x8xf32> to memref<?x8xf32, #[[$map_2d_stride_1]]> 178 // LINALG: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 179 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 180 // LINALG: } 181 // LINALG: %[[res:.*]] = vector.transfer_read {{.*}} {in_bounds = [true, true]} : 182 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 183 %1 = vector.transfer_read %A[%i, %j], %f0 : 184 memref<7x8xf32, offset:?, strides:[?, 1]>, vector<4x8xf32> 185 186 // CHECK: return %[[res]] : vector<4x8xf32> 187 return %1 : vector<4x8xf32> 188} 189 190// ----- 191 192func @split_vector_transfer_write_2d(%V: vector<4x8xf32>, %A: memref<?x8xf32>, %i: index, %j: index) { 193 vector.transfer_write %V, %A[%i, %j] : 194 vector<4x8xf32>, memref<?x8xf32> 195 return 196} 197 198// CHECK-DAG: #[[MAP0:.*]] = affine_map<()[s0] -> (s0 + 4)> 199// CHECK-DAG: #[[MAP1:.*]] = affine_map<()[s0] -> (s0 + 8)> 200// CHECK: func @split_vector_transfer_write_2d( 201// CHECK-SAME: %[[VEC:.*]]: vector<4x8xf32>, 202// CHECK-SAME: %[[DEST:.*]]: memref<?x8xf32>, 203// CHECK-SAME: %[[I:.*]]: index, 204// CHECK-SAME: %[[J:.*]]: index) { 205// CHECK-DAG: %[[C8:.*]] = constant 8 : index 206// CHECK-DAG: %[[C0:.*]] = constant 0 : index 207// CHECK-DAG: %[[CT:.*]] = constant true 208// CHECK: %[[TEMP:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 209// CHECK: %[[VAL_8:.*]] = affine.apply #[[MAP0]]()[%[[I]]] 210// CHECK: %[[DIM0:.*]] = memref.dim %[[DEST]], %[[C0]] : memref<?x8xf32> 211// CHECK: %[[DIM0_IN:.*]] = cmpi sle, %[[VAL_8]], %[[DIM0]] : index 212// CHECK: %[[DIM1:.*]] = affine.apply #[[MAP1]]()[%[[J]]] 213// CHECK: %[[DIM1_IN:.*]] = cmpi sle, %[[DIM1]], %[[C8]] : index 214// CHECK: %[[IN_BOUNDS:.*]] = and %[[DIM0_IN]], %[[DIM1_IN]] : i1 215// CHECK: %[[IN_BOUND_DEST:.*]]:3 = scf.if %[[IN_BOUNDS]] -> 216// CHECK-SAME: (memref<?x8xf32>, index, index) { 217// CHECK: scf.yield %[[DEST]], %[[I]], %[[J]] : memref<?x8xf32>, index, index 218// CHECK: } else { 219// CHECK: %[[VAL_15:.*]] = memref.cast %[[TEMP]] 220// CHECK-SAME: : memref<4x8xf32> to memref<?x8xf32> 221// CHECK: scf.yield %[[VAL_15]], %[[C0]], %[[C0]] 222// CHECK-SAME: : memref<?x8xf32>, index, index 223// CHECK: } 224// CHECK: vector.transfer_write %[[VEC]], 225// CHECK-SAME: %[[IN_BOUND_DEST:.*]]#0[%[[IN_BOUND_DEST]]#1, %[[IN_BOUND_DEST]]#2] 226// CHECK-SAME: {in_bounds = [true, true]} : vector<4x8xf32>, memref<?x8xf32> 227// CHECK: %[[OUT_BOUNDS:.*]] = xor %[[IN_BOUNDS]], %[[CT]] : i1 228// CHECK: scf.if %[[OUT_BOUNDS]] { 229// CHECK: %[[CASTED:.*]] = vector.type_cast %[[TEMP]] 230// CHECK-SAME: : memref<4x8xf32> to memref<vector<4x8xf32>> 231// CHECK: %[[RESULT_COPY:.*]] = memref.load %[[CASTED]][] 232// CHECK-SAME: : memref<vector<4x8xf32>> 233// CHECK: vector.transfer_write %[[RESULT_COPY]], 234// CHECK-SAME: %[[DEST]][%[[I]], %[[J]]] 235// CHECK-SAME: : vector<4x8xf32>, memref<?x8xf32> 236// CHECK: } 237// CHECK: return 238// CHECK: } 239 240// LINALG-DAG: #[[MAP0:.*]] = affine_map<()[s0] -> (s0 + 4)> 241// LINALG-DAG: #[[MAP1:.*]] = affine_map<()[s0] -> (s0 + 8)> 242// LINALG-DAG: #[[MAP2:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 4)> 243// LINALG-DAG: #[[MAP3:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 8)> 244// LINALG-DAG: #[[MAP4:.*]] = affine_map<(d0, d1)[s0] -> (d0 * 8 + s0 + d1)> 245// LINALG: func @split_vector_transfer_write_2d( 246// LINALG-SAME: %[[VEC:.*]]: vector<4x8xf32>, 247// LINALG-SAME: %[[DEST:.*]]: memref<?x8xf32>, 248// LINALG-SAME: %[[I:.*]]: index, 249// LINALG-SAME: %[[J:.*]]: index) { 250// LINALG-DAG: %[[CT:.*]] = constant true 251// LINALG-DAG: %[[C0:.*]] = constant 0 : index 252// LINALG-DAG: %[[C4:.*]] = constant 4 : index 253// LINALG-DAG: %[[C8:.*]] = constant 8 : index 254// LINALG: %[[TEMP:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 255// LINALG: %[[IDX0:.*]] = affine.apply #[[MAP0]]()[%[[I]]] 256// LINALG: %[[DIM0:.*]] = memref.dim %[[DEST]], %[[C0]] : memref<?x8xf32> 257// LINALG: %[[DIM0_IN:.*]] = cmpi sle, %[[IDX0]], %[[DIM0]] : index 258// LINALG: %[[DIM1:.*]] = affine.apply #[[MAP1]]()[%[[J]]] 259// LINALG: %[[DIM1_IN:.*]] = cmpi sle, %[[DIM1]], %[[C8]] : index 260// LINALG: %[[IN_BOUNDS:.*]] = and %[[DIM0_IN]], %[[DIM1_IN]] : i1 261// LINALG: %[[IN_BOUND_DEST:.*]]:3 = scf.if %[[IN_BOUNDS]] 262// LINALG-SAME: -> (memref<?x8xf32>, index, index) { 263// LINALG: scf.yield %[[DEST]], %[[I]], %[[J]] : memref<?x8xf32>, index, index 264// LINALG: } else { 265// LINALG: %[[VAL_16:.*]] = memref.cast %[[TEMP]] : memref<4x8xf32> to memref<?x8xf32> 266// LINALG: scf.yield %[[VAL_16]], %[[C0]], %[[C0]] : memref<?x8xf32>, index, index 267// LINALG: } 268// LINALG: vector.transfer_write %[[VEC]], 269// LINALG-SAME: %[[IN_BOUND_DEST:.*]]#0[%[[IN_BOUND_DEST]]#1, %[[IN_BOUND_DEST]]#2] 270// LINALG-SAME: {in_bounds = [true, true]} : vector<4x8xf32>, memref<?x8xf32> 271// LINALG: %[[OUT_BOUNDS:.*]] = xor %[[IN_BOUNDS]], %[[CT]] : i1 272// LINALG: scf.if %[[OUT_BOUNDS]] { 273// LINALG: %[[VAL_19:.*]] = memref.dim %[[DEST]], %[[C0]] : memref<?x8xf32> 274// LINALG-DAG: %[[VAL_20:.*]] = affine.min #[[MAP2]](%[[VAL_19]], %[[I]], %[[C4]]) 275// LINALG-DAG: %[[VAL_21:.*]] = affine.min #[[MAP3]](%[[C8]], %[[J]], %[[C8]]) 276// LINALG: %[[VAL_22:.*]] = memref.subview %[[TEMP]] 277// LINALG-SAME: [%[[I]], %[[J]]] [%[[VAL_20]], %[[VAL_21]]] 278// LINALG-SAME: [1, 1] : memref<4x8xf32> to memref<?x?xf32, #[[MAP4]]> 279// LINALG: linalg.copy(%[[VAL_22]], %[[DEST]]) 280// LINALG-SAME: : memref<?x?xf32, #[[MAP4]]>, memref<?x8xf32> 281// LINALG: } 282// LINALG: return 283// LINALG: } 284 285// ----- 286 287func @split_vector_transfer_write_strided_2d( 288 %V: vector<4x8xf32>, %A: memref<7x8xf32, offset:?, strides:[?, 1]>, 289 %i: index, %j: index) { 290 vector.transfer_write %V, %A[%i, %j] : 291 vector<4x8xf32>, memref<7x8xf32, offset:?, strides:[?, 1]> 292 return 293} 294 295// CHECK-DAG: #[[MAP0:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)> 296// CHECK-DAG: #[[MAP1:.*]] = affine_map<()[s0] -> (s0 + 4)> 297// CHECK-DAG: #[[MAP2:.*]] = affine_map<()[s0] -> (s0 + 8)> 298// CHECK: func @split_vector_transfer_write_strided_2d( 299// CHECK-SAME: %[[VEC:.*]]: vector<4x8xf32>, 300// CHECK-SAME: %[[DEST:.*]]: memref<7x8xf32, #[[MAP0]]>, 301// CHECK-SAME: %[[I:.*]]: index, 302// CHECK-SAME: %[[J:.*]]: index) { 303// CHECK-DAG: %[[C7:.*]] = constant 7 : index 304// CHECK-DAG: %[[C8:.*]] = constant 8 : index 305// CHECK-DAG: %[[C0:.*]] = constant 0 : index 306// CHECK-DAG: %[[CT:.*]] = constant true 307// CHECK: %[[TEMP:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 308// CHECK: %[[DIM0:.*]] = affine.apply #[[MAP1]]()[%[[I]]] 309// CHECK: %[[DIM0_IN:.*]] = cmpi sle, %[[DIM0]], %[[C7]] : index 310// CHECK: %[[DIM1:.*]] = affine.apply #[[MAP2]]()[%[[J]]] 311// CHECK: %[[DIM1_IN:.*]] = cmpi sle, %[[DIM1]], %[[C8]] : index 312// CHECK: %[[IN_BOUNDS:.*]] = and %[[DIM0_IN]], %[[DIM1_IN]] : i1 313// CHECK: %[[IN_BOUND_DEST:.*]]:3 = scf.if %[[IN_BOUNDS]] 314// CHECK-SAME: -> (memref<?x8xf32, #[[MAP0]]>, index, index) { 315// CHECK: %[[VAL_15:.*]] = memref.cast %[[DEST]] 316// CHECK-SAME: : memref<7x8xf32, #[[MAP0]]> to memref<?x8xf32, #[[MAP0]]> 317// CHECK: scf.yield %[[VAL_15]], %[[I]], %[[J]] 318// CHECK-SAME: : memref<?x8xf32, #[[MAP0]]>, index, index 319// CHECK: } else { 320// CHECK: %[[VAL_16:.*]] = memref.cast %[[TEMP]] 321// CHECK-SAME: : memref<4x8xf32> to memref<?x8xf32, #[[MAP0]]> 322// CHECK: scf.yield %[[VAL_16]], %[[C0]], %[[C0]] 323// CHECK-SAME: : memref<?x8xf32, #[[MAP0]]>, index, index 324// CHECK: } 325// CHECK: vector.transfer_write %[[VEC]], 326// CHECK-SAME: %[[IN_BOUND_DEST:.*]]#0 327// CHECK-SAME: [%[[IN_BOUND_DEST]]#1, %[[IN_BOUND_DEST]]#2] 328// CHECK-SAME: {in_bounds = [true, true]} : vector<4x8xf32>, memref<?x8xf32, #[[MAP0]]> 329// CHECK: %[[OUT_BOUNDS:.*]] = xor %[[IN_BOUNDS]], %[[CT]] : i1 330// CHECK: scf.if %[[OUT_BOUNDS]] { 331// CHECK: %[[VAL_19:.*]] = vector.type_cast %[[TEMP]] 332// CHECK-SAME: : memref<4x8xf32> to memref<vector<4x8xf32>> 333// CHECK: %[[VAL_20:.*]] = memref.load %[[VAL_19]][] 334// CHECK-SAME: : memref<vector<4x8xf32>> 335// CHECK: vector.transfer_write %[[VAL_20]], %[[DEST]][%[[I]], %[[J]]] 336// CHECK-SAME: : vector<4x8xf32>, memref<7x8xf32, #[[MAP0]]> 337// CHECK: } 338// CHECK: return 339// CHECK: } 340 341// LINALG-DAG: #[[MAP0:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)> 342// LINALG-DAG: #[[MAP1:.*]] = affine_map<()[s0] -> (s0 + 4)> 343// LINALG-DAG: #[[MAP2:.*]] = affine_map<()[s0] -> (s0 + 8)> 344// LINALG-DAG: #[[MAP3:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 4)> 345// LINALG-DAG: #[[MAP4:.*]] = affine_map<(d0, d1, d2) -> (d0 - d1, 8)> 346// LINALG-DAG: #[[MAP5:.*]] = affine_map<(d0, d1)[s0] -> (d0 * 8 + s0 + d1)> 347// LINALG: func @split_vector_transfer_write_strided_2d( 348// LINALG-SAME: %[[VEC:.*]]: vector<4x8xf32>, 349// LINALG-SAME: %[[DEST:.*]]: memref<7x8xf32, #[[MAP0]]>, 350// LINALG-SAME: %[[I:.*]]: index, 351// LINALG-SAME: %[[J:.*]]: index) { 352// LINALG-DAG: %[[C0:.*]] = constant 0 : index 353// LINALG-DAG: %[[CT:.*]] = constant true 354// LINALG-DAG: %[[C7:.*]] = constant 7 : index 355// LINALG-DAG: %[[C4:.*]] = constant 4 : index 356// LINALG-DAG: %[[C8:.*]] = constant 8 : index 357// LINALG: %[[TEMP:.*]] = memref.alloca() {alignment = 32 : i64} : memref<4x8xf32> 358// LINALG: %[[DIM0:.*]] = affine.apply #[[MAP1]]()[%[[I]]] 359// LINALG: %[[DIM0_IN:.*]] = cmpi sle, %[[DIM0]], %[[C7]] : index 360// LINALG: %[[DIM1:.*]] = affine.apply #[[MAP2]]()[%[[J]]] 361// LINALG: %[[DIM1_IN:.*]] = cmpi sle, %[[DIM1]], %[[C8]] : index 362// LINALG: %[[IN_BOUNDS:.*]] = and %[[DIM0_IN]], %[[DIM1_IN]] : i1 363// LINALG: %[[IN_BOUND_DEST:.*]]:3 = scf.if %[[IN_BOUNDS]] 364// LINALG-SAME: -> (memref<?x8xf32, #[[MAP0]]>, index, index) { 365// LINALG: %[[VAL_16:.*]] = memref.cast %[[DEST]] 366// LINALG-SAME: : memref<7x8xf32, #[[MAP0]]> to memref<?x8xf32, #[[MAP0]]> 367// LINALG: scf.yield %[[VAL_16]], %[[I]], %[[J]] 368// LINALG-SAME: : memref<?x8xf32, #[[MAP0]]>, index, index 369// LINALG: } else { 370// LINALG: %[[VAL_17:.*]] = memref.cast %[[TEMP]] 371// LINALG-SAME: : memref<4x8xf32> to memref<?x8xf32, #[[MAP0]]> 372// LINALG: scf.yield %[[VAL_17]], %[[C0]], %[[C0]] 373// LINALG-SAME: : memref<?x8xf32, #[[MAP0]]>, index, index 374// LINALG: } 375// LINALG: vector.transfer_write %[[VEC]], 376// LINALG-SAME: %[[IN_BOUND_DEST:.*]]#0 377// LINALG-SAME: [%[[IN_BOUND_DEST]]#1, %[[IN_BOUND_DEST]]#2] 378// LINALG-SAME: {in_bounds = [true, true]} 379// LINALG-SAME: : vector<4x8xf32>, memref<?x8xf32, #[[MAP0]]> 380// LINALG: %[[OUT_BOUNDS:.*]] = xor %[[IN_BOUNDS]], %[[CT]] : i1 381// LINALG: scf.if %[[OUT_BOUNDS]] { 382// LINALG-DAG: %[[VAL_20:.*]] = affine.min #[[MAP3]](%[[C7]], %[[I]], %[[C4]]) 383// LINALG-DAG: %[[VAL_21:.*]] = affine.min #[[MAP4]](%[[C8]], %[[J]], %[[C8]]) 384// LINALG: %[[VAL_22:.*]] = memref.subview %[[TEMP]] 385// LINALG-SAME: [%[[I]], %[[J]]] [%[[VAL_20]], %[[VAL_21]]] 386// LINALG-SAME: [1, 1] : memref<4x8xf32> to memref<?x?xf32, #[[MAP5]]> 387// LINALG: linalg.copy(%[[VAL_22]], %[[DEST]]) 388// LINALG-SAME: : memref<?x?xf32, #[[MAP5]]>, memref<7x8xf32, #[[MAP0]]> 389// LINALG: } 390// LINALG: return 391// LINALG: } 392