1// RUN: mlir-opt %s -test-vector-transfer-full-partial-split | FileCheck %s 2// RUN: mlir-opt %s -test-vector-transfer-full-partial-split=use-linalg-copy | 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: %[[c0:.*]] = constant 0 : index 29 // CHECK-DAG: %[[c8:.*]] = constant 8 : index 30 // CHECK-DAG: %[[cst:.*]] = constant 0.000000e+00 : f32 31 // alloca for boundary full tile 32 // CHECK: %[[alloc:.*]] = alloca() {alignment = 32 : i64} : memref<4x8xf32> 33 // %i + 4 <= dim(%A, 0) 34 // CHECK: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 35 // CHECK: %[[d0:.*]] = dim %[[A]], %[[c0]] : memref<?x8xf32> 36 // CHECK: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[d0]] : index 37 // %j + 8 <= dim(%A, 1) 38 // CHECK: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 39 // CHECK: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 40 // are both conds true 41 // CHECK: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 42 // CHECK: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32>, index, index) { 43 // inBounds, just yield %A 44 // CHECK: scf.yield %[[A]], %[[i]], %[[j]] : memref<?x8xf32>, index, index 45 // CHECK: } else { 46 // slow path, fill tmp alloc and yield a memref_casted version of it 47 // CHECK: %[[slow:.*]] = vector.transfer_read %[[A]][%[[i]], %[[j]]], %cst : 48 // CHECK-SAME: memref<?x8xf32>, vector<4x8xf32> 49 // CHECK: %[[cast_alloc:.*]] = vector.type_cast %[[alloc]] : 50 // CHECK-SAME: memref<4x8xf32> to memref<vector<4x8xf32>> 51 // CHECK: store %[[slow]], %[[cast_alloc]][] : memref<vector<4x8xf32>> 52 // CHECK: %[[yielded:.*]] = memref_cast %[[alloc]] : 53 // CHECK-SAME: memref<4x8xf32> to memref<?x8xf32> 54 // CHECK: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 55 // CHECK-SAME: memref<?x8xf32>, index, index 56 // CHECK: } 57 // CHECK: %[[res:.*]] = vector.transfer_read %[[ifres]]#0[%[[ifres]]#1, %[[ifres]]#2], %[[cst]] 58 // CHECK_SAME: {masked = [false, false]} : memref<?x8xf32>, vector<4x8xf32> 59 60 // LINALG-DAG: %[[c0:.*]] = constant 0 : index 61 // LINALG-DAG: %[[c4:.*]] = constant 4 : index 62 // LINALG-DAG: %[[c8:.*]] = constant 8 : index 63 // LINALG-DAG: %[[cst:.*]] = constant 0.000000e+00 : f32 64 // alloca for boundary full tile 65 // LINALG: %[[alloc:.*]] = alloca() {alignment = 32 : i64} : memref<4x8xf32> 66 // %i + 4 <= dim(%A, 0) 67 // LINALG: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 68 // LINALG: %[[d0:.*]] = dim %[[A]], %[[c0]] : memref<?x8xf32> 69 // LINALG: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[d0]] : index 70 // %j + 8 <= dim(%A, 1) 71 // LINALG: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 72 // LINALG: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 73 // are both conds true 74 // LINALG: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 75 // LINALG: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32>, index, index) { 76 // inBounds, just yield %A 77 // LINALG: scf.yield %[[A]], %[[i]], %[[j]] : memref<?x8xf32>, index, index 78 // LINALG: } else { 79 // slow path, fill tmp alloc and yield a memref_casted version of it 80 // LINALG: linalg.fill(%[[alloc]], %[[cst]]) : memref<4x8xf32>, f32 81 // LINALG: %[[d0:.*]] = dim %[[A]], %[[c0]] : memref<?x8xf32> 82 // LINALG: %[[sv0:.*]] = affine.min #[[$bounds_map_4]](%[[d0]], %[[i]], %[[c4]]) 83 // LINALG: %[[sv1:.*]] = affine.min #[[$bounds_map_8]](%[[c8]], %[[j]], %[[c8]]) 84 // LINALG: %[[sv:.*]] = subview %[[A]][%[[i]], %[[j]]] [%[[sv0]], %[[sv1]]] [1, 1] 85 // LINALG-SAME: memref<?x8xf32> to memref<?x?xf32, #[[$map_2d_stride_8x1]]> 86 // LINALG: linalg.copy(%[[sv]], %[[alloc]]) : memref<?x?xf32, #[[$map_2d_stride_8x1]]>, memref<4x8xf32> 87 // LINALG: %[[yielded:.*]] = memref_cast %[[alloc]] : 88 // LINALG-SAME: memref<4x8xf32> to memref<?x8xf32> 89 // LINALG: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 90 // LINALG-SAME: memref<?x8xf32>, index, index 91 // LINALG: } 92 // LINALG: %[[res:.*]] = vector.transfer_read %[[ifres]]#0[%[[ifres]]#1, %[[ifres]]#2], %[[cst]] 93 // LINALG_SAME: {masked = [false, false]} : memref<?x8xf32>, vector<4x8xf32> 94 %1 = vector.transfer_read %A[%i, %j], %f0 : memref<?x8xf32>, vector<4x8xf32> 95 96 // LINALG: return %[[res]] : vector<4x8xf32> 97 return %1: vector<4x8xf32> 98} 99 100// CHECK-LABEL: split_vector_transfer_read_strided_2d( 101// CHECK-SAME: %[[A:[a-zA-Z0-9]*]]: memref 102// CHECK-SAME: %[[i:[a-zA-Z0-9]*]]: index 103// CHECK-SAME: %[[j:[a-zA-Z0-9]*]]: index 104 105// LINALG-LABEL: split_vector_transfer_read_strided_2d( 106// LINALG-SAME: %[[A:[a-zA-Z0-9]*]]: memref 107// LINALG-SAME: %[[i:[a-zA-Z0-9]*]]: index 108// LINALG-SAME: %[[j:[a-zA-Z0-9]*]]: index 109func @split_vector_transfer_read_strided_2d( 110 %A: memref<7x8xf32, offset:?, strides:[?, 1]>, 111 %i: index, %j: index) -> vector<4x8xf32> { 112 %c0 = constant 0 : index 113 %f0 = constant 0.0 : f32 114 115 // CHECK-DAG: %[[c0:.*]] = constant 0 : index 116 // CHECK-DAG: %[[c7:.*]] = constant 7 : index 117 // CHECK-DAG: %[[c8:.*]] = constant 8 : index 118 // CHECK-DAG: %[[cst:.*]] = constant 0.000000e+00 : f32 119 // alloca for boundary full tile 120 // CHECK: %[[alloc:.*]] = alloca() {alignment = 32 : i64} : memref<4x8xf32> 121 // %i + 4 <= dim(%A, 0) 122 // CHECK: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 123 // CHECK: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[c7]] : index 124 // %j + 8 <= dim(%A, 1) 125 // CHECK: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 126 // CHECK: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 127 // are both conds true 128 // CHECK: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 129 // CHECK: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index) { 130 // inBounds but not cast-compatible: yield a memref_casted form of %A 131 // CHECK: %[[casted:.*]] = memref_cast %arg0 : 132 // CHECK-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x8xf32, #[[$map_2d_stride_1]]> 133 // CHECK: scf.yield %[[casted]], %[[i]], %[[j]] : 134 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 135 // CHECK: } else { 136 // slow path, fill tmp alloc and yield a memref_casted version of it 137 // CHECK: %[[slow:.*]] = vector.transfer_read %[[A]][%[[i]], %[[j]]], %cst : 138 // CHECK-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 139 // CHECK: %[[cast_alloc:.*]] = vector.type_cast %[[alloc]] : 140 // CHECK-SAME: memref<4x8xf32> to memref<vector<4x8xf32>> 141 // CHECK: store %[[slow]], %[[cast_alloc]][] : 142 // CHECK-SAME: memref<vector<4x8xf32>> 143 // CHECK: %[[yielded:.*]] = memref_cast %[[alloc]] : 144 // CHECK-SAME: memref<4x8xf32> to memref<?x8xf32, #[[$map_2d_stride_1]]> 145 // CHECK: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 146 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 147 // CHECK: } 148 // CHECK: %[[res:.*]] = vector.transfer_read {{.*}} {masked = [false, false]} : 149 // CHECK-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 150 151 // LINALG-DAG: %[[c0:.*]] = constant 0 : index 152 // LINALG-DAG: %[[c4:.*]] = constant 4 : index 153 // LINALG-DAG: %[[c7:.*]] = constant 7 : index 154 // LINALG-DAG: %[[c8:.*]] = constant 8 : index 155 // LINALG-DAG: %[[cst:.*]] = constant 0.000000e+00 : f32 156 // alloca for boundary full tile 157 // LINALG: %[[alloc:.*]] = alloca() {alignment = 32 : i64} : memref<4x8xf32> 158 // %i + 4 <= dim(%A, 0) 159 // LINALG: %[[idx0:.*]] = affine.apply #[[$map_p4]]()[%[[i]]] 160 // LINALG: %[[cmp0:.*]] = cmpi sle, %[[idx0]], %[[c7]] : index 161 // %j + 8 <= dim(%A, 1) 162 // LINALG: %[[idx1:.*]] = affine.apply #[[$map_p8]]()[%[[j]]] 163 // LINALG: %[[cmp1:.*]] = cmpi sle, %[[idx1]], %[[c8]] : index 164 // are both conds true 165 // LINALG: %[[cond:.*]] = and %[[cmp0]], %[[cmp1]] : i1 166 // LINALG: %[[ifres:.*]]:3 = scf.if %[[cond]] -> (memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index) { 167 // inBounds but not cast-compatible: yield a memref_casted form of %A 168 // LINALG: %[[casted:.*]] = memref_cast %arg0 : 169 // LINALG-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x8xf32, #[[$map_2d_stride_1]]> 170 // LINALG: scf.yield %[[casted]], %[[i]], %[[j]] : 171 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 172 // LINALG: } else { 173 // slow path, fill tmp alloc and yield a memref_casted version of it 174 // LINALG: linalg.fill(%[[alloc]], %[[cst]]) : memref<4x8xf32>, f32 175 // LINALG: %[[sv0:.*]] = affine.min #[[$bounds_map_4]](%[[c7]], %[[i]], %[[c4]]) 176 // LINALG: %[[sv1:.*]] = affine.min #[[$bounds_map_8]](%[[c8]], %[[j]], %[[c8]]) 177 // LINALG: %[[sv:.*]] = subview %[[A]][%[[i]], %[[j]]] [%[[sv0]], %[[sv1]]] [1, 1] 178 // LINALG-SAME: memref<7x8xf32, #[[$map_2d_stride_1]]> to memref<?x?xf32, #[[$map_2d_stride_1]]> 179 // LINALG: linalg.copy(%[[sv]], %[[alloc]]) : memref<?x?xf32, #[[$map_2d_stride_1]]>, memref<4x8xf32> 180 // LINALG: %[[yielded:.*]] = memref_cast %[[alloc]] : 181 // LINALG-SAME: memref<4x8xf32> to memref<?x8xf32, #[[$map_2d_stride_1]]> 182 // LINALG: scf.yield %[[yielded]], %[[c0]], %[[c0]] : 183 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, index, index 184 // LINALG: } 185 // LINALG: %[[res:.*]] = vector.transfer_read {{.*}} {masked = [false, false]} : 186 // LINALG-SAME: memref<?x8xf32, #[[$map_2d_stride_1]]>, vector<4x8xf32> 187 %1 = vector.transfer_read %A[%i, %j], %f0 : 188 memref<7x8xf32, offset:?, strides:[?, 1]>, vector<4x8xf32> 189 190 // CHECK: return %[[res]] : vector<4x8xf32> 191 return %1 : vector<4x8xf32> 192} 193