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>)
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    %init_256 = bufferization.alloc_tensor(%c256) : tensor<?xi32>
79    %b = scf.for %i = %c0 to %c256 step %c1 iter_args(%t = %init_256) -> tensor<?xi32> {
80      %k = arith.addi %i, %c1 : index
81      %j = arith.index_cast %k : index to i32
82      %t2 = tensor.insert %j into %t[%i] : tensor<?xi32>
83      scf.yield %t2 : tensor<?xi32>
84    }
85    %init_4 = bufferization.alloc_tensor(%c4) : tensor<?xi32>
86    %x = scf.for %i = %c0 to %c4 step %c1 iter_args(%t = %init_4) -> tensor<?xi32> {
87      %t2 = tensor.insert %i0 into %t[%i] : tensor<?xi32>
88      scf.yield %t2 : tensor<?xi32>
89    }
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    %v = vector.transfer_read %0[%c0], %i0: tensor<?xi32>, vector<4xi32>
100    vector.print %v : vector<4xi32>
101
102    // Release the resources.
103    bufferization.dealloc_tensor %a : tensor<?x?xi32, #SparseMatrix>
104
105    return
106  }
107}
108