1// RUN: mlir-opt %s \ 2// RUN: --linalg-generalize-named-ops --linalg-fuse-elementwise-ops \ 3// RUN: --sparse-compiler | \ 4// RUN: mlir-cpu-runner \ 5// RUN: -e entry -entry-point-result=void \ 6// RUN: -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \ 7// RUN: FileCheck %s 8// 9 10#CSR = #sparse_tensor.encoding<{ 11 dimLevelType = [ "dense", "compressed" ], 12 dimOrdering = affine_map<(i,j) -> (i,j)> 13}> 14 15#DCSR = #sparse_tensor.encoding<{ 16 dimLevelType = [ "compressed", "compressed" ], 17 dimOrdering = affine_map<(i,j) -> (i,j)> 18}> 19 20module { 21 // 22 // Computes C = A x B with all matrices dense. 23 // 24 func @matmul1(%A: tensor<4x8xf64>, 25 %B: tensor<8x4xf64>) -> tensor<4x4xf64> { 26 %C = arith.constant dense<0.0> : tensor<4x4xf64> 27 %D = linalg.matmul 28 ins(%A, %B: tensor<4x8xf64>, tensor<8x4xf64>) 29 outs(%C: tensor<4x4xf64>) -> tensor<4x4xf64> 30 return %D: tensor<4x4xf64> 31 } 32 33 // 34 // Computes C = A x B with all matrices sparse (SpMSpM) in CSR. 35 // 36 func @matmul2(%A: tensor<4x8xf64, #CSR>, 37 %B: tensor<8x4xf64, #CSR>) -> tensor<4x4xf64, #CSR> { 38 %c4 = arith.constant 4 : index 39 %C = sparse_tensor.init [%c4, %c4] : tensor<4x4xf64, #CSR> 40 %D = linalg.matmul 41 ins(%A, %B: tensor<4x8xf64, #CSR>, tensor<8x4xf64, #CSR>) 42 outs(%C: tensor<4x4xf64, #CSR>) -> tensor<4x4xf64, #CSR> 43 return %D: tensor<4x4xf64, #CSR> 44 } 45 46 // 47 // Computes C = A x B with all matrices sparse (SpMSpM) in DCSR. 48 // 49 func @matmul3(%A: tensor<4x8xf64, #DCSR>, 50 %B: tensor<8x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> { 51 %c4 = arith.constant 4 : index 52 %C = sparse_tensor.init [%c4, %c4] : tensor<4x4xf64, #DCSR> 53 %D = linalg.matmul 54 ins(%A, %B: tensor<4x8xf64, #DCSR>, tensor<8x4xf64, #DCSR>) 55 outs(%C: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> 56 return %D: tensor<4x4xf64, #DCSR> 57 } 58 59 // 60 // Main driver. 61 // 62 func @entry() { 63 %c0 = arith.constant 0 : index 64 %d1 = arith.constant -1.0 : f64 65 66 // Initialize various matrices, dense for stress testing, 67 // and sparse to verify correct nonzero structure. 68 %da = arith.constant dense<[ 69 [ 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1 ], 70 [ 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2 ], 71 [ 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3 ], 72 [ 1.4, 2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4 ] 73 ]> : tensor<4x8xf64> 74 %db = arith.constant dense<[ 75 [ 10.1, 11.1, 12.1, 13.1 ], 76 [ 10.2, 11.2, 12.2, 13.2 ], 77 [ 10.3, 11.3, 12.3, 13.3 ], 78 [ 10.4, 11.4, 12.4, 13.4 ], 79 [ 10.5, 11.5, 12.5, 13.5 ], 80 [ 10.6, 11.6, 12.6, 13.6 ], 81 [ 10.7, 11.7, 12.7, 13.7 ], 82 [ 10.8, 11.8, 12.8, 13.8 ] 83 ]> : tensor<8x4xf64> 84 %sa = arith.constant dense<[ 85 [ 0.0, 2.1, 0.0, 0.0, 0.0, 6.1, 0.0, 0.0 ], 86 [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], 87 [ 0.0, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], 88 [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] 89 ]> : tensor<4x8xf64> 90 %sb = arith.constant dense<[ 91 [ 0.0, 0.0, 0.0, 1.0 ], 92 [ 0.0, 0.0, 2.0, 0.0 ], 93 [ 0.0, 3.0, 0.0, 0.0 ], 94 [ 4.0, 0.0, 0.0, 0.0 ], 95 [ 0.0, 0.0, 0.0, 0.0 ], 96 [ 0.0, 5.0, 0.0, 0.0 ], 97 [ 0.0, 0.0, 6.0, 0.0 ], 98 [ 0.0, 0.0, 7.0, 8.0 ] 99 ]> : tensor<8x4xf64> 100 101 // Convert all these matrices to sparse format. 102 %a1 = sparse_tensor.convert %da : tensor<4x8xf64> to tensor<4x8xf64, #CSR> 103 %a2 = sparse_tensor.convert %da : tensor<4x8xf64> to tensor<4x8xf64, #DCSR> 104 %a3 = sparse_tensor.convert %sa : tensor<4x8xf64> to tensor<4x8xf64, #CSR> 105 %a4 = sparse_tensor.convert %sa : tensor<4x8xf64> to tensor<4x8xf64, #DCSR> 106 %b1 = sparse_tensor.convert %db : tensor<8x4xf64> to tensor<8x4xf64, #CSR> 107 %b2 = sparse_tensor.convert %db : tensor<8x4xf64> to tensor<8x4xf64, #DCSR> 108 %b3 = sparse_tensor.convert %sb : tensor<8x4xf64> to tensor<8x4xf64, #CSR> 109 %b4 = sparse_tensor.convert %sb : tensor<8x4xf64> to tensor<8x4xf64, #DCSR> 110 111 // Call kernels with dense. 112 %0 = call @matmul1(%da, %db) 113 : (tensor<4x8xf64>, tensor<8x4xf64>) -> tensor<4x4xf64> 114 %1 = call @matmul2(%a1, %b1) 115 : (tensor<4x8xf64, #CSR>, 116 tensor<8x4xf64, #CSR>) -> tensor<4x4xf64, #CSR> 117 %2 = call @matmul3(%a2, %b2) 118 : (tensor<4x8xf64, #DCSR>, 119 tensor<8x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> 120 121 // Call kernels with one sparse. 122 %3 = call @matmul1(%sa, %db) 123 : (tensor<4x8xf64>, tensor<8x4xf64>) -> tensor<4x4xf64> 124 %4 = call @matmul2(%a3, %b1) 125 : (tensor<4x8xf64, #CSR>, 126 tensor<8x4xf64, #CSR>) -> tensor<4x4xf64, #CSR> 127 %5 = call @matmul3(%a4, %b2) 128 : (tensor<4x8xf64, #DCSR>, 129 tensor<8x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> 130 131 // Call kernels with sparse. 132 %6 = call @matmul1(%sa, %sb) 133 : (tensor<4x8xf64>, tensor<8x4xf64>) -> tensor<4x4xf64> 134 %7 = call @matmul2(%a3, %b3) 135 : (tensor<4x8xf64, #CSR>, 136 tensor<8x4xf64, #CSR>) -> tensor<4x4xf64, #CSR> 137 %8 = call @matmul3(%a4, %b4) 138 : (tensor<4x8xf64, #DCSR>, 139 tensor<8x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> 140 141 // 142 // CHECK: ( ( 388.76, 425.56, 462.36, 499.16 ), 143 // CHECK-SAME: ( 397.12, 434.72, 472.32, 509.92 ), 144 // CHECK-SAME: ( 405.48, 443.88, 482.28, 520.68 ), 145 // CHECK-SAME: ( 413.84, 453.04, 492.24, 531.44 ) ) 146 // 147 %m0 = bufferization.to_memref %0 : memref<4x4xf64> 148 %v0 = vector.transfer_read %m0[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 149 vector.print %v0 : vector<4x4xf64> 150 151 // 152 // CHECK: ( ( 388.76, 425.56, 462.36, 499.16 ), 153 // CHECK-SAME: ( 397.12, 434.72, 472.32, 509.92 ), 154 // CHECK-SAME: ( 405.48, 443.88, 482.28, 520.68 ), 155 // CHECK-SAME: ( 413.84, 453.04, 492.24, 531.44 ) ) 156 // 157 %c1 = sparse_tensor.convert %1 : tensor<4x4xf64, #CSR> to tensor<4x4xf64> 158 %m1 = bufferization.to_memref %c1 : memref<4x4xf64> 159 %v1 = vector.transfer_read %m1[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 160 vector.print %v1 : vector<4x4xf64> 161 162 // 163 // CHECK: ( ( 388.76, 425.56, 462.36, 499.16 ), 164 // CHECK-SAME: ( 397.12, 434.72, 472.32, 509.92 ), 165 // CHECK-SAME: ( 405.48, 443.88, 482.28, 520.68 ), 166 // CHECK-SAME: ( 413.84, 453.04, 492.24, 531.44 ) ) 167 // 168 %c2 = sparse_tensor.convert %2 : tensor<4x4xf64, #DCSR> to tensor<4x4xf64> 169 %m2 = bufferization.to_memref %c2 : memref<4x4xf64> 170 %v2 = vector.transfer_read %m2[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 171 vector.print %v2 : vector<4x4xf64> 172 173 // 174 // CHECK: ( ( 86.08, 94.28, 102.48, 110.68 ), 175 // CHECK-SAME: ( 0, 0, 0, 0 ), 176 // CHECK-SAME: ( 23.46, 25.76, 28.06, 30.36 ), 177 // CHECK-SAME: ( 10.8, 11.8, 12.8, 13.8 ) ) 178 // 179 %m3 = bufferization.to_memref %3 : memref<4x4xf64> 180 %v3 = vector.transfer_read %m3[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 181 vector.print %v3 : vector<4x4xf64> 182 183 // 184 // CHECK: ( ( 86.08, 94.28, 102.48, 110.68 ), 185 // CHECK-SAME: ( 0, 0, 0, 0 ), 186 // CHECK-SAME: ( 23.46, 25.76, 28.06, 30.36 ), 187 // CHECK-SAME: ( 10.8, 11.8, 12.8, 13.8 ) ) 188 // 189 %c4 = sparse_tensor.convert %4 : tensor<4x4xf64, #CSR> to tensor<4x4xf64> 190 %m4 = bufferization.to_memref %c4 : memref<4x4xf64> 191 %v4 = vector.transfer_read %m4[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 192 vector.print %v4 : vector<4x4xf64> 193 194 // 195 // CHECK: ( ( 86.08, 94.28, 102.48, 110.68 ), 196 // CHECK-SAME: ( 0, 0, 0, 0 ), 197 // CHECK-SAME: ( 23.46, 25.76, 28.06, 30.36 ), 198 // CHECK-SAME: ( 10.8, 11.8, 12.8, 13.8 ) ) 199 // 200 %c5 = sparse_tensor.convert %5 : tensor<4x4xf64, #DCSR> to tensor<4x4xf64> 201 %m5 = bufferization.to_memref %c5 : memref<4x4xf64> 202 %v5 = vector.transfer_read %m5[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 203 vector.print %v5 : vector<4x4xf64> 204 205 // 206 // CHECK: ( ( 0, 30.5, 4.2, 0 ), ( 0, 0, 0, 0 ), ( 0, 0, 4.6, 0 ), ( 0, 0, 7, 8 ) ) 207 // 208 %m6 = bufferization.to_memref %6 : memref<4x4xf64> 209 %v6 = vector.transfer_read %m6[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 210 vector.print %v6 : vector<4x4xf64> 211 212 // 213 // CHECK: ( ( 0, 30.5, 4.2, 0 ), ( 0, 0, 0, 0 ), ( 0, 0, 4.6, 0 ), ( 0, 0, 7, 8 ) ) 214 // 215 %c7 = sparse_tensor.convert %7 : tensor<4x4xf64, #CSR> to tensor<4x4xf64> 216 %m7 = bufferization.to_memref %c7 : memref<4x4xf64> 217 %v7 = vector.transfer_read %m7[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 218 vector.print %v7 : vector<4x4xf64> 219 220 // 221 // CHECK: ( ( 0, 30.5, 4.2, 0 ), ( 0, 0, 0, 0 ), ( 0, 0, 4.6, 0 ), ( 0, 0, 7, 8 ) ) 222 // 223 %c8 = sparse_tensor.convert %8 : tensor<4x4xf64, #DCSR> to tensor<4x4xf64> 224 %m8 = bufferization.to_memref %c8 : memref<4x4xf64> 225 %v8 = vector.transfer_read %m8[%c0, %c0], %d1 : memref<4x4xf64>, vector<4x4xf64> 226 vector.print %v8 : vector<4x4xf64> 227 228 // 229 // Sanity check on nonzeros. 230 // 231 // CHECK: ( 30.5, 4.2, 4.6, 7, 8, -1, -1, -1 ) 232 // CHECK: ( 30.5, 4.2, 4.6, 7, 8, -1, -1, -1 ) 233 // 234 %val7 = sparse_tensor.values %7 : tensor<4x4xf64, #CSR> to memref<?xf64> 235 %val8 = sparse_tensor.values %8 : tensor<4x4xf64, #DCSR> to memref<?xf64> 236 %nz7 = vector.transfer_read %val7[%c0], %d1 : memref<?xf64>, vector<8xf64> 237 %nz8 = vector.transfer_read %val8[%c0], %d1 : memref<?xf64>, vector<8xf64> 238 vector.print %nz7 : vector<8xf64> 239 vector.print %nz8 : vector<8xf64> 240 241 // Release the resources. 242 sparse_tensor.release %a1 : tensor<4x8xf64, #CSR> 243 sparse_tensor.release %a2 : tensor<4x8xf64, #DCSR> 244 sparse_tensor.release %a3 : tensor<4x8xf64, #CSR> 245 sparse_tensor.release %a4 : tensor<4x8xf64, #DCSR> 246 sparse_tensor.release %b1 : tensor<8x4xf64, #CSR> 247 sparse_tensor.release %b2 : tensor<8x4xf64, #DCSR> 248 sparse_tensor.release %b3 : tensor<8x4xf64, #CSR> 249 sparse_tensor.release %b4 : tensor<8x4xf64, #DCSR> 250 sparse_tensor.release %1 : tensor<4x4xf64, #CSR> 251 sparse_tensor.release %2 : tensor<4x4xf64, #DCSR> 252 sparse_tensor.release %4 : tensor<4x4xf64, #CSR> 253 sparse_tensor.release %5 : tensor<4x4xf64, #DCSR> 254 sparse_tensor.release %7 : tensor<4x4xf64, #CSR> 255 sparse_tensor.release %8 : tensor<4x4xf64, #DCSR> 256 memref.dealloc %m0 : memref<4x4xf64> 257 memref.dealloc %m1 : memref<4x4xf64> 258 memref.dealloc %m2 : memref<4x4xf64> 259 memref.dealloc %m3 : memref<4x4xf64> 260 memref.dealloc %m4 : memref<4x4xf64> 261 memref.dealloc %m5 : memref<4x4xf64> 262 memref.dealloc %m6 : memref<4x4xf64> 263 memref.dealloc %m7 : memref<4x4xf64> 264 memref.dealloc %m8 : memref<4x4xf64> 265 266 return 267 } 268} 269