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: %[[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: {masked = [false, false]} : 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: {masked = [false, false]} : 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 {{.*}} {masked = [false, false]} : 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 {{.*}} {masked = [false, false]} : 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