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>) -> tensor<8x8xf32, #CSR> {
35    %c = arith.constant 2.0 : f32
36    %0 = linalg.generic #trait_scale
37      outs(%argx: tensor<8x8xf32, #CSR>) {
38        ^bb(%x: f32):
39          %1 = arith.mulf %x, %c : f32
40          linalg.yield %1 : f32
41    } -> tensor<8x8xf32, #CSR>
42    return %0 : tensor<8x8xf32, #CSR>
43  }
44
45  //
46  // Main driver that converts a dense tensor into a sparse tensor
47  // and then calls the sparse scaling kernel with the sparse tensor
48  // as input argument.
49  //
50  func.func @entry() {
51    %c0 = arith.constant 0 : index
52    %f0 = arith.constant 0.0 : f32
53
54    // Initialize a dense tensor.
55    %0 = arith.constant dense<[
56       [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],
57       [0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
58       [0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0],
59       [0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0],
60       [0.0, 1.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0],
61       [0.0, 1.0, 1.0, 0.0, 0.0, 6.0, 0.0, 0.0],
62       [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 7.0, 1.0],
63       [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 8.0]
64    ]> : tensor<8x8xf32>
65
66    // Convert dense tensor to sparse tensor and call sparse kernel.
67    %1 = sparse_tensor.convert %0 : tensor<8x8xf32> to tensor<8x8xf32, #CSR>
68    %2 = call @sparse_scale(%1)
69      : (tensor<8x8xf32, #CSR>) -> tensor<8x8xf32, #CSR>
70
71    // Print the resulting compacted values for verification.
72    //
73    // CHECK: ( 2, 2, 2, 4, 6, 8, 2, 10, 2, 2, 12, 2, 14, 2, 2, 16 )
74    //
75    %m = sparse_tensor.values %2 : tensor<8x8xf32, #CSR> to memref<?xf32>
76    %v = vector.transfer_read %m[%c0], %f0: memref<?xf32>, vector<16xf32>
77    vector.print %v : vector<16xf32>
78
79    // Release the resources.
80    bufferization.dealloc_tensor %1 : tensor<8x8xf32, #CSR>
81
82    return
83  }
84}
85