xref: /llvm-project/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_tensor_mul.mlir (revision eb206e9ea84eff0a0596fed2de8316d924f946d1)
1//--------------------------------------------------------------------------------------------------
2// WHEN CREATING A NEW TEST, PLEASE JUST COPY & PASTE WITHOUT EDITS.
3//
4// Set-up that's shared across all tests in this directory. In principle, this
5// config could be moved to lit.local.cfg. However, there are downstream users that
6//  do not use these LIT config files. Hence why this is kept inline.
7//
8// DEFINE: %{sparsifier_opts} = enable-runtime-library=true
9// DEFINE: %{sparsifier_opts_sve} = enable-arm-sve=true %{sparsifier_opts}
10// DEFINE: %{compile} = mlir-opt %s --sparsifier="%{sparsifier_opts}"
11// DEFINE: %{compile_sve} = mlir-opt %s --sparsifier="%{sparsifier_opts_sve}"
12// DEFINE: %{run_libs} = -shared-libs=%mlir_c_runner_utils,%mlir_runner_utils
13// DEFINE: %{run_libs_sve} = -shared-libs=%native_mlir_runner_utils,%native_mlir_c_runner_utils
14// DEFINE: %{run_opts} = -e main -entry-point-result=void
15// DEFINE: %{run} = mlir-runner %{run_opts} %{run_libs}
16// DEFINE: %{run_sve} = %mcr_aarch64_cmd --march=aarch64 --mattr="+sve" %{run_opts} %{run_libs_sve}
17//
18// DEFINE: %{env} =
19//--------------------------------------------------------------------------------------------------
20
21// RUN: %{compile} | %{run} | FileCheck %s
22//
23// Do the same run, but now with direct IR generation.
24// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false
25// RUN: %{compile} | %{run} | FileCheck %s
26//
27// Do the same run, but now with vectorization.
28// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false vl=2 reassociate-fp-reductions=true enable-index-optimizations=true
29// RUN: %{compile} | %{run} | FileCheck %s
30//
31// Do the same run, but now with  VLA vectorization.
32// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | FileCheck %s %}
33
34#ST = #sparse_tensor.encoding<{map = (d0, d1, d2) -> (d0 : compressed, d1 : compressed, d2 : compressed)}>
35
36//
37// Trait for 3-d tensor element wise multiplication.
38//
39#trait_mul = {
40  indexing_maps = [
41    affine_map<(i,j,k) -> (i,j,k)>,  // A (in)
42    affine_map<(i,j,k) -> (i,j,k)>,  // B (in)
43    affine_map<(i,j,k) -> (i,j,k)>   // X (out)
44  ],
45  iterator_types = ["parallel", "parallel", "parallel"],
46  doc = "X(i,j,k) = A(i,j,k) * B(i,j,k)"
47}
48
49module {
50  // Multiplies two 3-d sparse tensors element-wise into a new sparse tensor.
51  func.func @tensor_mul(%arga: tensor<?x?x?xf64, #ST>,
52                        %argb: tensor<?x?x?xf64, #ST>) -> tensor<?x?x?xf64, #ST> {
53    %c0 = arith.constant 0 : index
54    %c1 = arith.constant 1 : index
55    %c2 = arith.constant 2 : index
56    %d0 = tensor.dim %arga, %c0 : tensor<?x?x?xf64, #ST>
57    %d1 = tensor.dim %arga, %c1 : tensor<?x?x?xf64, #ST>
58    %d2 = tensor.dim %arga, %c2 : tensor<?x?x?xf64, #ST>
59    %xt = tensor.empty(%d0, %d1, %d2) : tensor<?x?x?xf64, #ST>
60    %0 = linalg.generic #trait_mul
61       ins(%arga, %argb: tensor<?x?x?xf64, #ST>, tensor<?x?x?xf64, #ST>)
62        outs(%xt: tensor<?x?x?xf64, #ST>) {
63        ^bb(%a: f64, %b: f64, %x: f64):
64          %1 = arith.mulf %a, %b : f64
65          linalg.yield %1 : f64
66    } -> tensor<?x?x?xf64, #ST>
67    return %0 : tensor<?x?x?xf64, #ST>
68  }
69
70  // Driver method to call and verify tensor multiplication kernel.
71  func.func @main() {
72    %c0 = arith.constant 0 : index
73    %default_val = arith.constant -1.0 : f64
74
75    // Setup sparse tensor A
76    %ta = arith.constant dense<
77      [ [ [1.0, 0.0, 0.0, 0.0, 0.0 ],
78          [0.0, 0.0, 0.0, 0.0, 0.0 ],
79          [1.2, 0.0, 3.5, 0.0, 0.0 ] ],
80        [ [0.0, 0.0, 0.0, 0.0, 0.0 ],
81          [0.0, 0.0, 0.0, 0.0, 0.0 ],
82          [0.0, 0.0, 0.0, 0.0, 0.0 ] ],
83        [ [2.0, 0.0, 0.0, 0.0, 0.0 ],
84          [0.0, 0.0, 0.0, 0.0, 0.0 ],
85          [0.0, 0.0, 4.0, 0.0, 0.0 ]] ]> : tensor<3x3x5xf64>
86
87    // Setup sparse tensor B
88    %tb = arith.constant dense<
89      [ [ [0.0, 0.0, 0.0, 0.0, 4.0 ],
90          [0.0, 0.0, 0.0, 0.0, 0.0 ],
91          [2.0, 0.0, 1.0, 0.0, 0.0 ] ],
92        [ [0.0, 0.0, 0.0, 0.0, 9.0 ],
93          [0.0, 0.0, 0.0, 0.0, 0.0 ],
94          [0.0, 7.0, 0.0, 0.0, 0.0 ] ],
95        [ [1.0, 0.0, 0.0, 0.0, 0.0 ],
96          [0.0, 0.0, 0.0, 0.0, 0.0 ],
97          [0.0, 0.0, 2.0, 0.0, 0.0 ]] ]> : tensor<3x3x5xf64>
98
99    %sta = sparse_tensor.convert %ta : tensor<3x3x5xf64> to tensor<?x?x?xf64, #ST>
100    %stb = sparse_tensor.convert %tb : tensor<3x3x5xf64> to tensor<?x?x?xf64, #ST>
101
102
103    // Call sparse tensor multiplication kernel.
104    %0 = call @tensor_mul(%sta, %stb)
105      : (tensor<?x?x?xf64, #ST>, tensor<?x?x?xf64, #ST>) -> tensor<?x?x?xf64, #ST>
106
107    //
108    // Verify results.
109    //
110    // CHECK:      ---- Sparse Tensor ----
111    // CHECK-NEXT: nse = 4
112    // CHECK-NEXT: dim = ( 3, 3, 5 )
113    // CHECK-NEXT: lvl = ( 3, 3, 5 )
114    // CHECK-NEXT: pos[0] : ( 0, 2 )
115    // CHECK-NEXT: crd[0] : ( 0, 2 )
116    // CHECK-NEXT: pos[1] : ( 0, 1, 3 )
117    // CHECK-NEXT: crd[1] : ( 2, 0, 2 )
118    // CHECK-NEXT: pos[2] : ( 0, 2, 3, 4 )
119    // CHECK-NEXT: crd[2] : ( 0, 2, 0, 2 )
120    // CHECK-NEXT: values : ( 2.4, 3.5, 2, 8 )
121    // CHECK-NEXT: ----
122    //
123    sparse_tensor.print %0 : tensor<?x?x?xf64, #ST>
124
125    // Release the resources.
126    bufferization.dealloc_tensor %sta : tensor<?x?x?xf64, #ST>
127    bufferization.dealloc_tensor %stb : tensor<?x?x?xf64, #ST>
128    bufferization.dealloc_tensor %0  : tensor<?x?x?xf64, #ST>
129
130    return
131  }
132}
133