1// RUN: mlir-opt %s --sparse-compiler | \
2// RUN: TENSOR0="%mlir_integration_test_dir/data/wide.mtx" \
3// RUN: mlir-cpu-runner \
4// RUN:  -e entry -entry-point-result=void  \
5// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
6// RUN: FileCheck %s
7//
8// Do the same run, but now with SIMDization as well. This should not change the outcome.
9//
10// RUN: mlir-opt %s \
11// RUN:   --sparse-compiler="vectorization-strategy=2 vl=16 enable-simd-index32" | \
12// RUN: TENSOR0="%mlir_integration_test_dir/data/wide.mtx" \
13// RUN: mlir-cpu-runner \
14// RUN:  -e entry -entry-point-result=void  \
15// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
16// RUN: FileCheck %s
17
18!Filename = !llvm.ptr<i8>
19
20#SparseMatrix = #sparse_tensor.encoding<{
21  dimLevelType = [ "dense", "compressed" ],
22  pointerBitWidth = 8,
23  indexBitWidth = 8
24}>
25
26#matvec = {
27  indexing_maps = [
28    affine_map<(i,j) -> (i,j)>, // A
29    affine_map<(i,j) -> (j)>,   // b
30    affine_map<(i,j) -> (i)>    // x (out)
31  ],
32  iterator_types = ["parallel", "reduction"],
33  doc = "X(i) += A(i,j) * B(j)"
34}
35
36//
37// Integration test that lowers a kernel annotated as sparse to
38// actual sparse code, initializes a matching sparse storage scheme
39// from file, and runs the resulting code with the JIT compiler.
40//
41module {
42  //
43  // A kernel that multiplies a sparse matrix A with a dense vector b
44  // into a dense vector x.
45  //
46  func.func @kernel_matvec(%arga: tensor<?x?xi32, #SparseMatrix>,
47                      %argb: tensor<?xi32>,
48                      %argx: tensor<?xi32> {linalg.inplaceable = true})
49		      -> tensor<?xi32> {
50    %0 = linalg.generic #matvec
51      ins(%arga, %argb: tensor<?x?xi32, #SparseMatrix>, tensor<?xi32>)
52      outs(%argx: tensor<?xi32>) {
53      ^bb(%a: i32, %b: i32, %x: i32):
54        %0 = arith.muli %a, %b : i32
55        %1 = arith.addi %x, %0 : i32
56        linalg.yield %1 : i32
57    } -> tensor<?xi32>
58    return %0 : tensor<?xi32>
59  }
60
61  func.func private @getTensorFilename(index) -> (!Filename)
62
63  //
64  // Main driver that reads matrix from file and calls the sparse kernel.
65  //
66  func.func @entry() {
67    %i0 = arith.constant 0 : i32
68    %c0 = arith.constant 0 : index
69    %c1 = arith.constant 1 : index
70    %c4 = arith.constant 4 : index
71    %c256 = arith.constant 256 : index
72
73    // Read the sparse matrix from file, construct sparse storage.
74    %fileName = call @getTensorFilename(%c0) : (index) -> (!Filename)
75    %a = sparse_tensor.new %fileName : !Filename to tensor<?x?xi32, #SparseMatrix>
76
77    // Initialize dense vectors.
78    %bdata = memref.alloc(%c256) : memref<?xi32>
79    %xdata = memref.alloc(%c4) : memref<?xi32>
80    scf.for %i = %c0 to %c256 step %c1 {
81      %k = arith.addi %i, %c1 : index
82      %j = arith.index_cast %k : index to i32
83      memref.store %j, %bdata[%i] : memref<?xi32>
84    }
85    scf.for %i = %c0 to %c4 step %c1 {
86      memref.store %i0, %xdata[%i] : memref<?xi32>
87    }
88    %b = bufferization.to_tensor %bdata : memref<?xi32>
89    %x = bufferization.to_tensor %xdata : memref<?xi32>
90
91    // Call kernel.
92    %0 = call @kernel_matvec(%a, %b, %x)
93      : (tensor<?x?xi32, #SparseMatrix>, tensor<?xi32>, tensor<?xi32>) -> tensor<?xi32>
94
95    // Print the result for verification.
96    //
97    // CHECK: ( 889, 1514, -21, -3431 )
98    //
99    %m = bufferization.to_memref %0 : memref<?xi32>
100    %v = vector.transfer_read %m[%c0], %i0: memref<?xi32>, vector<4xi32>
101    vector.print %v : vector<4xi32>
102
103    // Release the resources.
104    memref.dealloc %bdata : memref<?xi32>
105    memref.dealloc %xdata : memref<?xi32>
106    sparse_tensor.release %a : tensor<?x?xi32, #SparseMatrix>
107
108    return
109  }
110}
111