1// RUN: mlir-opt %s --sparse-compiler | \ 2// RUN: mlir-cpu-runner \ 3// RUN: -e entry -entry-point-result=void \ 4// RUN: -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \ 5// RUN: FileCheck %s 6 7#SparseVector = #sparse_tensor.encoding<{dimLevelType = ["compressed"]}> 8#DenseVector = #sparse_tensor.encoding<{dimLevelType = ["dense"]}> 9 10#trait_vec_op = { 11 indexing_maps = [ 12 affine_map<(i) -> (i)>, // a (in) 13 affine_map<(i) -> (i)>, // b (in) 14 affine_map<(i) -> (i)> // x (out) 15 ], 16 iterator_types = ["parallel"] 17} 18 19module { 20 // Creates a dense vector using the minimum values from two input sparse vectors. 21 // When there is no overlap, include the present value in the output. 22 func.func @vector_min(%arga: tensor<?xf16, #SparseVector>, 23 %argb: tensor<?xf16, #SparseVector>) -> tensor<?xf16, #DenseVector> { 24 %c = arith.constant 0 : index 25 %d = tensor.dim %arga, %c : tensor<?xf16, #SparseVector> 26 %xv = bufferization.alloc_tensor (%d) : tensor<?xf16, #DenseVector> 27 %0 = linalg.generic #trait_vec_op 28 ins(%arga, %argb: tensor<?xf16, #SparseVector>, tensor<?xf16, #SparseVector>) 29 outs(%xv: tensor<?xf16, #DenseVector>) { 30 ^bb(%a: f16, %b: f16, %x: f16): 31 %1 = sparse_tensor.binary %a, %b : f16, f16 to f16 32 overlap={ 33 ^bb0(%a0: f16, %b0: f16): 34 %cmp = arith.cmpf "olt", %a0, %b0 : f16 35 %2 = arith.select %cmp, %a0, %b0: f16 36 sparse_tensor.yield %2 : f16 37 } 38 left=identity 39 right=identity 40 linalg.yield %1 : f16 41 } -> tensor<?xf16, #DenseVector> 42 return %0 : tensor<?xf16, #DenseVector> 43 } 44 45 // Dumps a dense vector of type f16. 46 func.func @dump_vec(%arg0: tensor<?xf16, #DenseVector>) { 47 // Dump the values array to verify only sparse contents are stored. 48 %c0 = arith.constant 0 : index 49 %d0 = arith.constant -1.0 : f16 50 %0 = sparse_tensor.values %arg0 : tensor<?xf16, #DenseVector> to memref<?xf16> 51 %1 = vector.transfer_read %0[%c0], %d0: memref<?xf16>, vector<32xf16> 52 %f1 = arith.extf %1: vector<32xf16> to vector<32xf32> 53 vector.print %f1 : vector<32xf32> 54 return 55 } 56 57 // Driver method to call and verify the kernel. 58 func.func @entry() { 59 %c0 = arith.constant 0 : index 60 61 // Setup sparse vectors. 62 %v1 = arith.constant sparse< 63 [ [0], [3], [11], [17], [20], [21], [28], [29], [31] ], 64 [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ] 65 > : tensor<32xf16> 66 %v2 = arith.constant sparse< 67 [ [1], [3], [4], [10], [16], [18], [21], [28], [29], [31] ], 68 [11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 ] 69 > : tensor<32xf16> 70 %sv1 = sparse_tensor.convert %v1 : tensor<32xf16> to tensor<?xf16, #SparseVector> 71 %sv2 = sparse_tensor.convert %v2 : tensor<32xf16> to tensor<?xf16, #SparseVector> 72 73 // Call the sparse vector kernel. 74 %0 = call @vector_min(%sv1, %sv2) 75 : (tensor<?xf16, #SparseVector>, 76 tensor<?xf16, #SparseVector>) -> tensor<?xf16, #DenseVector> 77 78 // 79 // Verify the result. 80 // 81 // CHECK: ( 1, 11, 0, 2, 13, 0, 0, 0, 0, 0, 14, 3, 0, 0, 0, 0, 15, 4, 16, 0, 5, 6, 0, 0, 0, 0, 0, 0, 7, 8, 0, 9 ) 82 call @dump_vec(%0) : (tensor<?xf16, #DenseVector>) -> () 83 84 // Release the resources. 85 bufferization.dealloc_tensor %sv1 : tensor<?xf16, #SparseVector> 86 bufferization.dealloc_tensor %sv2 : tensor<?xf16, #SparseVector> 87 bufferization.dealloc_tensor %0 : tensor<?xf16, #DenseVector> 88 return 89 } 90} 91