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// Do the same run, but now with SIMDization as well. This should not change the outcome.
8//
9// RUN: mlir-opt %s --sparse-compiler="vectorization-strategy=2 vl=4" | \
10// RUN: mlir-cpu-runner \
11// RUN:  -e entry -entry-point-result=void  \
12// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
13// RUN: FileCheck %s
14
15#CSR = #sparse_tensor.encoding<{ dimLevelType = [ "dense", "compressed" ] }>
16
17#trait_scale = {
18  indexing_maps = [
19    affine_map<(i,j) -> (i,j)>   // X (out)
20  ],
21  iterator_types = ["parallel", "parallel"],
22  doc = "X(i,j) = X(i,j) * 2"
23}
24
25//
26// Integration test that lowers a kernel annotated as sparse to actual sparse
27// code, initializes a matching sparse storage scheme from a dense tensor,
28// and runs the resulting code with the JIT compiler.
29//
30module {
31  //
32  // A kernel that scales a sparse matrix A by a factor of 2.0.
33  //
34  func.func @sparse_scale(%argx: tensor<8x8xf32, #CSR>
35                     {linalg.inplaceable = true}) -> tensor<8x8xf32, #CSR> {
36    %c = arith.constant 2.0 : f32
37    %0 = linalg.generic #trait_scale
38      outs(%argx: tensor<8x8xf32, #CSR>) {
39        ^bb(%x: f32):
40          %1 = arith.mulf %x, %c : f32
41          linalg.yield %1 : f32
42    } -> tensor<8x8xf32, #CSR>
43    return %0 : tensor<8x8xf32, #CSR>
44  }
45
46  //
47  // Main driver that converts a dense tensor into a sparse tensor
48  // and then calls the sparse scaling kernel with the sparse tensor
49  // as input argument.
50  //
51  func.func @entry() {
52    %c0 = arith.constant 0 : index
53    %f0 = arith.constant 0.0 : f32
54
55    // Initialize a dense tensor.
56    %0 = arith.constant dense<[
57       [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],
58       [0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
59       [0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0],
60       [0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0],
61       [0.0, 1.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0],
62       [0.0, 1.0, 1.0, 0.0, 0.0, 6.0, 0.0, 0.0],
63       [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 7.0, 1.0],
64       [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 8.0]
65    ]> : tensor<8x8xf32>
66
67    // Convert dense tensor to sparse tensor and call sparse kernel.
68    %1 = sparse_tensor.convert %0 : tensor<8x8xf32> to tensor<8x8xf32, #CSR>
69    %2 = call @sparse_scale(%1)
70      : (tensor<8x8xf32, #CSR>) -> tensor<8x8xf32, #CSR>
71
72    // Print the resulting compacted values for verification.
73    //
74    // CHECK: ( 2, 2, 2, 4, 6, 8, 2, 10, 2, 2, 12, 2, 14, 2, 2, 16 )
75    //
76    %m = sparse_tensor.values %2 : tensor<8x8xf32, #CSR> to memref<?xf32>
77    %v = vector.transfer_read %m[%c0], %f0: memref<?xf32>, vector<16xf32>
78    vector.print %v : vector<16xf32>
79
80    // Release the resources.
81    sparse_tensor.release %1 : tensor<8x8xf32, #CSR>
82
83    return
84  }
85}
86