xref: /llvm-project/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_binary.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 enable-buffer-initialization=true
25// RUN: %{compile} | %{run} | FileCheck %s
26//
27// Do the same run, but now with direct IR generation and vectorization.
28// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false enable-buffer-initialization=true 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 direct IR generation and VLA vectorization.
32// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | FileCheck %s %}
33
34#SparseVector = #sparse_tensor.encoding<{map = (d0) -> (d0 : compressed)}>
35#DCSR = #sparse_tensor.encoding<{map = (d0, d1) -> (d0 : compressed, d1 : compressed)}>
36
37//
38// Traits for tensor operations.
39//
40#trait_vec_scale = {
41  indexing_maps = [
42    affine_map<(i) -> (i)>,  // a (in)
43    affine_map<(i) -> (i)>   // x (out)
44  ],
45  iterator_types = ["parallel"]
46}
47#trait_vec_op = {
48  indexing_maps = [
49    affine_map<(i) -> (i)>,  // a (in)
50    affine_map<(i) -> (i)>,  // b (in)
51    affine_map<(i) -> (i)>   // x (out)
52  ],
53  iterator_types = ["parallel"]
54}
55#trait_mat_op = {
56  indexing_maps = [
57    affine_map<(i,j) -> (i,j)>,  // A (in)
58    affine_map<(i,j) -> (i,j)>,  // B (in)
59    affine_map<(i,j) -> (i,j)>   // X (out)
60  ],
61  iterator_types = ["parallel", "parallel"],
62  doc = "X(i,j) = A(i,j) OP B(i,j)"
63}
64
65//
66// Contains test cases for the sparse_tensor.binary operator (different cases when left/right/overlap
67// is empty/identity, etc).
68//
69
70module {
71  // Creates a new sparse vector using the minimum values from two input sparse vectors.
72  // When there is no overlap, include the present value in the output.
73  func.func @vector_min(%arga: tensor<?xi32, #SparseVector>,
74                        %argb: tensor<?xi32, #SparseVector>) -> tensor<?xi32, #SparseVector> {
75    %c = arith.constant 0 : index
76    %d = tensor.dim %arga, %c : tensor<?xi32, #SparseVector>
77    %xv = tensor.empty(%d) : tensor<?xi32, #SparseVector>
78    %0 = linalg.generic #trait_vec_op
79       ins(%arga, %argb: tensor<?xi32, #SparseVector>, tensor<?xi32, #SparseVector>)
80        outs(%xv: tensor<?xi32, #SparseVector>) {
81        ^bb(%a: i32, %b: i32, %x: i32):
82          %1 = sparse_tensor.binary %a, %b : i32, i32 to i32
83            overlap={
84              ^bb0(%a0: i32, %b0: i32):
85                %2 = arith.minsi %a0, %b0: i32
86                sparse_tensor.yield %2 : i32
87            }
88            left=identity
89            right=identity
90          linalg.yield %1 : i32
91    } -> tensor<?xi32, #SparseVector>
92    return %0 : tensor<?xi32, #SparseVector>
93  }
94
95  // Creates a new sparse vector by multiplying a sparse vector with a dense vector.
96  // When there is no overlap, leave the result empty.
97  func.func @vector_mul(%arga: tensor<?xf64, #SparseVector>,
98                        %argb: tensor<?xf64>) -> tensor<?xf64, #SparseVector> {
99    %c = arith.constant 0 : index
100    %d = tensor.dim %arga, %c : tensor<?xf64, #SparseVector>
101    %xv = tensor.empty(%d) : tensor<?xf64, #SparseVector>
102    %0 = linalg.generic #trait_vec_op
103       ins(%arga, %argb: tensor<?xf64, #SparseVector>, tensor<?xf64>)
104        outs(%xv: tensor<?xf64, #SparseVector>) {
105        ^bb(%a: f64, %b: f64, %x: f64):
106          %1 = sparse_tensor.binary %a, %b : f64, f64 to f64
107            overlap={
108              ^bb0(%a0: f64, %b0: f64):
109                %ret = arith.mulf %a0, %b0 : f64
110                sparse_tensor.yield %ret : f64
111            }
112            left={}
113            right={}
114          linalg.yield %1 : f64
115    } -> tensor<?xf64, #SparseVector>
116    return %0 : tensor<?xf64, #SparseVector>
117  }
118
119  // Take a set difference of two sparse vectors. The result will include only those
120  // sparse elements present in the first, but not the second vector.
121  func.func @vector_setdiff(%arga: tensor<?xf64, #SparseVector>,
122                            %argb: tensor<?xf64, #SparseVector>) -> tensor<?xf64, #SparseVector> {
123    %c = arith.constant 0 : index
124    %d = tensor.dim %arga, %c : tensor<?xf64, #SparseVector>
125    %xv = tensor.empty(%d) : tensor<?xf64, #SparseVector>
126    %0 = linalg.generic #trait_vec_op
127       ins(%arga, %argb: tensor<?xf64, #SparseVector>, tensor<?xf64, #SparseVector>)
128        outs(%xv: tensor<?xf64, #SparseVector>) {
129        ^bb(%a: f64, %b: f64, %x: f64):
130          %1 = sparse_tensor.binary %a, %b : f64, f64 to f64
131            overlap={}
132            left=identity
133            right={}
134          linalg.yield %1 : f64
135    } -> tensor<?xf64, #SparseVector>
136    return %0 : tensor<?xf64, #SparseVector>
137  }
138
139  // Return the index of each entry
140  func.func @vector_index(%arga: tensor<?xf64, #SparseVector>) -> tensor<?xi32, #SparseVector> {
141    %c = arith.constant 0 : index
142    %d = tensor.dim %arga, %c : tensor<?xf64, #SparseVector>
143    %xv = tensor.empty(%d) : tensor<?xi32, #SparseVector>
144    %0 = linalg.generic #trait_vec_scale
145       ins(%arga: tensor<?xf64, #SparseVector>)
146        outs(%xv: tensor<?xi32, #SparseVector>) {
147        ^bb(%a: f64, %x: i32):
148          %idx = linalg.index 0 : index
149          %1 = sparse_tensor.binary %a, %idx : f64, index to i32
150            overlap={
151              ^bb0(%x0: f64, %i: index):
152                %ret = arith.index_cast %i : index to i32
153                sparse_tensor.yield %ret : i32
154            }
155            left={}
156            right={}
157          linalg.yield %1 : i32
158    } -> tensor<?xi32, #SparseVector>
159    return %0 : tensor<?xi32, #SparseVector>
160  }
161
162  // Adds two sparse matrices when they intersect. Where they don't intersect,
163  // negate the 2nd argument's values; ignore 1st argument-only values.
164  func.func @matrix_intersect(%arga: tensor<?x?xf64, #DCSR>,
165                              %argb: tensor<?x?xf64, #DCSR>) -> tensor<?x?xf64, #DCSR> {
166    %c0 = arith.constant 0 : index
167    %c1 = arith.constant 1 : index
168    %d0 = tensor.dim %arga, %c0 : tensor<?x?xf64, #DCSR>
169    %d1 = tensor.dim %arga, %c1 : tensor<?x?xf64, #DCSR>
170    %xv = tensor.empty(%d0, %d1) : tensor<?x?xf64, #DCSR>
171    %0 = linalg.generic #trait_mat_op
172       ins(%arga, %argb: tensor<?x?xf64, #DCSR>, tensor<?x?xf64, #DCSR>)
173        outs(%xv: tensor<?x?xf64, #DCSR>) {
174        ^bb(%a: f64, %b: f64, %x: f64):
175          %1 = sparse_tensor.binary %a, %b: f64, f64 to f64
176            overlap={
177              ^bb0(%x0: f64, %y0: f64):
178                %ret = arith.addf %x0, %y0 : f64
179                sparse_tensor.yield %ret : f64
180            }
181            left={}
182            right={
183              ^bb0(%x1: f64):
184                %lret = arith.negf %x1 : f64
185                sparse_tensor.yield %lret : f64
186            }
187          linalg.yield %1 : f64
188    } -> tensor<?x?xf64, #DCSR>
189    return %0 : tensor<?x?xf64, #DCSR>
190  }
191
192  // Tensor addition (use semi-ring binary operation).
193  func.func @add_tensor_1(%A: tensor<4x4xf64, #DCSR>,
194                          %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> {
195    %C = tensor.empty() : tensor<4x4xf64, #DCSR>
196    %0 = linalg.generic #trait_mat_op
197      ins(%A, %B: tensor<4x4xf64, #DCSR>,
198                  tensor<4x4xf64, #DCSR>)
199      outs(%C: tensor<4x4xf64, #DCSR>) {
200        ^bb0(%a: f64, %b: f64, %c: f64) :
201          %result = sparse_tensor.binary %a, %b : f64, f64 to f64
202            overlap={
203              ^bb0(%x: f64, %y: f64):
204                %ret = arith.addf %x, %y : f64
205                sparse_tensor.yield %ret : f64
206            }
207            left=identity
208            right=identity
209          linalg.yield %result : f64
210      } -> tensor<4x4xf64, #DCSR>
211    return %0 : tensor<4x4xf64, #DCSR>
212  }
213
214  // Same as @add_tensor_1, but use sparse_tensor.yield instead of identity to yield value.
215  func.func @add_tensor_2(%A: tensor<4x4xf64, #DCSR>,
216                          %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> {
217    %C = tensor.empty() : tensor<4x4xf64, #DCSR>
218    %0 = linalg.generic #trait_mat_op
219      ins(%A, %B: tensor<4x4xf64, #DCSR>,
220                  tensor<4x4xf64, #DCSR>)
221      outs(%C: tensor<4x4xf64, #DCSR>) {
222        ^bb0(%a: f64, %b: f64, %c: f64) :
223          %result = sparse_tensor.binary %a, %b : f64, f64 to f64
224            overlap={
225              ^bb0(%x: f64, %y: f64):
226                %ret = arith.addf %x, %y : f64
227                sparse_tensor.yield %ret : f64
228            }
229            left={
230              ^bb0(%x: f64):
231                sparse_tensor.yield %x : f64
232            }
233            right={
234              ^bb0(%y: f64):
235                sparse_tensor.yield %y : f64
236            }
237          linalg.yield %result : f64
238      } -> tensor<4x4xf64, #DCSR>
239    return %0 : tensor<4x4xf64, #DCSR>
240  }
241
242  // Performs triangular add/sub operation (using semi-ring binary op).
243  func.func @triangular(%A: tensor<4x4xf64, #DCSR>,
244                        %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> {
245    %C = tensor.empty() : tensor<4x4xf64, #DCSR>
246    %0 = linalg.generic #trait_mat_op
247      ins(%A, %B: tensor<4x4xf64, #DCSR>,
248                  tensor<4x4xf64, #DCSR>)
249      outs(%C: tensor<4x4xf64, #DCSR>) {
250        ^bb0(%a: f64, %b: f64, %c: f64) :
251          %row = linalg.index 0 : index
252          %col = linalg.index 1 : index
253          %result = sparse_tensor.binary %a, %b : f64, f64 to f64
254            overlap={
255              ^bb0(%x: f64, %y: f64):
256                %cmp = arith.cmpi "uge", %col, %row : index
257                %upperTriangleResult = arith.addf %x, %y : f64
258                %lowerTriangleResult = arith.subf %x, %y : f64
259                %ret = arith.select %cmp, %upperTriangleResult, %lowerTriangleResult : f64
260                sparse_tensor.yield %ret : f64
261            }
262            left=identity
263            right={
264              ^bb0(%y: f64):
265                %cmp = arith.cmpi "uge", %col, %row : index
266                %lowerTriangleResult = arith.negf %y : f64
267                %ret = arith.select %cmp, %y, %lowerTriangleResult : f64
268                sparse_tensor.yield %ret : f64
269            }
270          linalg.yield %result : f64
271      } -> tensor<4x4xf64, #DCSR>
272    return %0 : tensor<4x4xf64, #DCSR>
273  }
274
275  // Perform sub operation (using semi-ring binary op) with a constant threshold.
276  func.func @sub_with_thres(%A: tensor<4x4xf64, #DCSR>,
277                            %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> {
278    %C = tensor.empty() : tensor<4x4xf64, #DCSR>
279    // Defines out-block constant bounds.
280    %thres_out_up = arith.constant 2.0 : f64
281    %thres_out_lo = arith.constant -2.0 : f64
282
283    %0 = linalg.generic #trait_mat_op
284      ins(%A, %B: tensor<4x4xf64, #DCSR>,
285                  tensor<4x4xf64, #DCSR>)
286      outs(%C: tensor<4x4xf64, #DCSR>) {
287        ^bb0(%a: f64, %b: f64, %c: f64) :
288          %result = sparse_tensor.binary %a, %b : f64, f64 to f64
289            overlap={
290              ^bb0(%x: f64, %y: f64):
291                // Defines in-block constant bounds.
292                %thres_up = arith.constant 1.0 : f64
293                %thres_lo = arith.constant -1.0 : f64
294                %result = arith.subf %x, %y : f64
295                %cmp = arith.cmpf "oge", %result, %thres_up : f64
296                %tmp = arith.select %cmp, %thres_up, %result : f64
297                %cmp1 = arith.cmpf "ole", %tmp, %thres_lo : f64
298                %ret = arith.select %cmp1, %thres_lo, %tmp : f64
299                sparse_tensor.yield %ret : f64
300            }
301            left={
302              ^bb0(%x: f64):
303                // Uses out-block constant bounds.
304                %cmp = arith.cmpf "oge", %x, %thres_out_up : f64
305                %tmp = arith.select %cmp, %thres_out_up, %x : f64
306                %cmp1 = arith.cmpf "ole", %tmp, %thres_out_lo : f64
307                %ret = arith.select %cmp1, %thres_out_lo, %tmp : f64
308                sparse_tensor.yield %ret : f64
309            }
310            right={
311              ^bb0(%y: f64):
312                %ny = arith.negf %y : f64
313                %cmp = arith.cmpf "oge", %ny, %thres_out_up : f64
314                %tmp = arith.select %cmp, %thres_out_up, %ny : f64
315                %cmp1 = arith.cmpf "ole", %tmp, %thres_out_lo : f64
316                %ret = arith.select %cmp1, %thres_out_lo, %tmp : f64
317                sparse_tensor.yield %ret : f64
318            }
319          linalg.yield %result : f64
320      } -> tensor<4x4xf64, #DCSR>
321    return %0 : tensor<4x4xf64, #DCSR>
322  }
323
324  // Performs isEqual only on intersecting elements.
325  func.func @intersect_equal(%A: tensor<4x4xf64, #DCSR>,
326                             %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xi8, #DCSR> {
327    %C = tensor.empty() : tensor<4x4xi8, #DCSR>
328    %0 = linalg.generic #trait_mat_op
329      ins(%A, %B: tensor<4x4xf64, #DCSR>,
330                  tensor<4x4xf64, #DCSR>)
331      outs(%C: tensor<4x4xi8, #DCSR>) {
332        ^bb0(%a: f64, %b: f64, %c: i8) :
333          %result = sparse_tensor.binary %a, %b : f64, f64 to i8
334            overlap={
335              ^bb0(%x: f64, %y: f64):
336                %cmp = arith.cmpf "oeq", %x, %y : f64
337                %ret = arith.extui %cmp : i1 to i8
338                sparse_tensor.yield %ret : i8
339            }
340            left={}
341            right={}
342          linalg.yield %result : i8
343      } -> tensor<4x4xi8, #DCSR>
344    return %0 : tensor<4x4xi8, #DCSR>
345  }
346
347  // Keeps values on left, negate value on right, ignore value when overlapping.
348  func.func @only_left_right(%A: tensor<4x4xf64, #DCSR>,
349                             %B: tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR> {
350    %C = tensor.empty() : tensor<4x4xf64, #DCSR>
351    %0 = linalg.generic #trait_mat_op
352      ins(%A, %B: tensor<4x4xf64, #DCSR>,
353                  tensor<4x4xf64, #DCSR>)
354      outs(%C: tensor<4x4xf64, #DCSR>) {
355        ^bb0(%a: f64, %b: f64, %c: f64) :
356          %result = sparse_tensor.binary %a, %b : f64, f64 to f64
357            overlap={}
358            left=identity
359            right={
360              ^bb0(%y: f64):
361                %ret = arith.negf %y : f64
362                sparse_tensor.yield %ret : f64
363            }
364          linalg.yield %result : f64
365      } -> tensor<4x4xf64, #DCSR>
366    return %0 : tensor<4x4xf64, #DCSR>
367  }
368
369  // Driver method to call and verify kernels.
370  func.func @main() {
371    %c0 = arith.constant 0 : index
372
373    // Setup sparse vectors.
374    %v1 = arith.constant sparse<
375       [ [0], [3], [11], [17], [20], [21], [28], [29], [31] ],
376         [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]
377    > : tensor<32xf64>
378    %v2 = arith.constant sparse<
379       [ [1], [3], [4], [10], [16], [18], [21], [28], [29], [31] ],
380         [11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 ]
381    > : tensor<32xf64>
382    %v3 = arith.constant dense<
383      [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.,
384       0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 0., 1.]
385    > : tensor<32xf64>
386    %v1_si = arith.fptosi %v1 : tensor<32xf64> to tensor<32xi32>
387    %v2_si = arith.fptosi %v2 : tensor<32xf64> to tensor<32xi32>
388
389    %sv1 = sparse_tensor.convert %v1 : tensor<32xf64> to tensor<?xf64, #SparseVector>
390    %sv2 = sparse_tensor.convert %v2 : tensor<32xf64> to tensor<?xf64, #SparseVector>
391    %sv1_si = sparse_tensor.convert %v1_si : tensor<32xi32> to tensor<?xi32, #SparseVector>
392    %sv2_si = sparse_tensor.convert %v2_si : tensor<32xi32> to tensor<?xi32, #SparseVector>
393    %dv3 = tensor.cast %v3 : tensor<32xf64> to tensor<?xf64>
394
395    // Setup sparse matrices.
396    %m1 = arith.constant sparse<
397       [ [0,0], [0,1], [1,7], [2,2], [2,4], [2,7], [3,0], [3,2], [3,3] ],
398         [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]
399    > : tensor<4x8xf64>
400    %m2 = arith.constant sparse<
401       [ [0,0], [0,7], [1,0], [1,6], [2,1], [2,7] ],
402         [6.0, 5.0, 4.0, 3.0, 2.0, 1.0 ]
403    > : tensor<4x8xf64>
404    %sm1 = sparse_tensor.convert %m1 : tensor<4x8xf64> to tensor<?x?xf64, #DCSR>
405    %sm2 = sparse_tensor.convert %m2 : tensor<4x8xf64> to tensor<?x?xf64, #DCSR>
406
407    %m3 = arith.constant dense<
408      [ [ 1.0, 0.0, 3.0, 0.0],
409        [ 0.0, 2.0, 0.0, 0.0],
410        [ 0.0, 0.0, 0.0, 4.0],
411        [ 3.0, 4.0, 0.0, 0.0] ]> : tensor<4x4xf64>
412    %m4 = arith.constant dense<
413      [ [ 1.0, 0.0, 1.0, 1.0],
414        [ 0.0, 0.5, 0.0, 0.0],
415        [ 1.0, 5.0, 2.0, 0.0],
416        [ 2.0, 0.0, 0.0, 0.0] ]> : tensor<4x4xf64>
417
418    %sm3 = sparse_tensor.convert %m3 : tensor<4x4xf64> to tensor<4x4xf64, #DCSR>
419    %sm4 = sparse_tensor.convert %m4 : tensor<4x4xf64> to tensor<4x4xf64, #DCSR>
420
421    // Call sparse vector kernels.
422    %0 = call @vector_min(%sv1_si, %sv2_si)
423       : (tensor<?xi32, #SparseVector>,
424          tensor<?xi32, #SparseVector>) -> tensor<?xi32, #SparseVector>
425    %1 = call @vector_mul(%sv1, %dv3)
426      : (tensor<?xf64, #SparseVector>,
427         tensor<?xf64>) -> tensor<?xf64, #SparseVector>
428    %2 = call @vector_setdiff(%sv1, %sv2)
429       : (tensor<?xf64, #SparseVector>,
430          tensor<?xf64, #SparseVector>) -> tensor<?xf64, #SparseVector>
431    %3 = call @vector_index(%sv1)
432       : (tensor<?xf64, #SparseVector>) -> tensor<?xi32, #SparseVector>
433
434    // Call sparse matrix kernels.
435    %5 = call @matrix_intersect(%sm1, %sm2)
436      : (tensor<?x?xf64, #DCSR>, tensor<?x?xf64, #DCSR>) -> tensor<?x?xf64, #DCSR>
437    %6 = call @add_tensor_1(%sm3, %sm4)
438      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR>
439    %7 = call @add_tensor_2(%sm3, %sm4)
440      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR>
441    %8 = call @triangular(%sm3, %sm4)
442      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR>
443    %9 = call @sub_with_thres(%sm3, %sm4)
444      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR>
445    %10 = call @intersect_equal(%sm3, %sm4)
446      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xi8, #DCSR>
447    %11 = call @only_left_right(%sm3, %sm4)
448      : (tensor<4x4xf64, #DCSR>, tensor<4x4xf64, #DCSR>) -> tensor<4x4xf64, #DCSR>
449
450    //
451    // Verify the results.
452    //
453    // CHECK:      ---- Sparse Tensor ----
454    // CHECK-NEXT: nse = 9
455    // CHECK-NEXT: dim = ( 32 )
456    // CHECK-NEXT: lvl = ( 32 )
457    // CHECK-NEXT: pos[0] : ( 0, 9 )
458    // CHECK-NEXT: crd[0] : ( 0, 3, 11, 17, 20, 21, 28, 29, 31 )
459    // CHECK-NEXT: values : ( 1, 2, 3, 4, 5, 6, 7, 8, 9 )
460    // CHECK-NEXT: ----
461    //
462    // CHECK-NEXT: ---- Sparse Tensor ----
463    // CHECK-NEXT: nse = 10
464    // CHECK-NEXT: dim = ( 32 )
465    // CHECK-NEXT: lvl = ( 32 )
466    // CHECK-NEXT: pos[0] : ( 0, 10 )
467    // CHECK-NEXT: crd[0] : ( 1, 3, 4, 10, 16, 18, 21, 28, 29, 31 )
468    // CHECK-NEXT: values : ( 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 )
469    // CHECK-NEXT: ----
470    //
471    // CHECK-NEXT: ---- Sparse Tensor ----
472    // CHECK-NEXT: nse = 14
473    // CHECK-NEXT: dim = ( 32 )
474    // CHECK-NEXT: lvl = ( 32 )
475    // CHECK-NEXT: pos[0] : ( 0, 14 )
476    // CHECK-NEXT: crd[0] : ( 0, 1, 3, 4, 10, 11, 16, 17, 18, 20, 21, 28, 29, 31 )
477    // CHECK-NEXT: values : ( 1, 11, 2, 13, 14, 3, 15, 4, 16, 5, 6, 7, 8, 9 )
478    // CHECK-NEXT: ----
479    //
480    // CHECK-NEXT: ---- Sparse Tensor ----
481    // CHECK-NEXT: nse = 9
482    // CHECK-NEXT: dim = ( 32 )
483    // CHECK-NEXT: lvl = ( 32 )
484    // CHECK-NEXT: pos[0] : ( 0, 9 )
485    // CHECK-NEXT: crd[0] : ( 0, 3, 11, 17, 20, 21, 28, 29, 31 )
486    // CHECK-NEXT: values : ( 0, 6, 3, 28, 0, 6, 56, 72, 9 )
487    // CHECK-NEXT: ----
488    //
489    // CHECK-NEXT: ---- Sparse Tensor ----
490    // CHECK-NEXT: nse = 4
491    // CHECK-NEXT: dim = ( 32 )
492    // CHECK-NEXT: lvl = ( 32 )
493    // CHECK-NEXT: pos[0] : ( 0, 4 )
494    // CHECK-NEXT: crd[0] : ( 0, 11, 17, 20 )
495    // CHECK-NEXT: values : ( 1, 3, 4, 5 )
496    // CHECK-NEXT: ----
497    //
498    // CHECK-NEXT: ---- Sparse Tensor ----
499    // CHECK-NEXT: nse = 9
500    // CHECK-NEXT: dim = ( 32 )
501    // CHECK-NEXT: lvl = ( 32 )
502    // CHECK-NEXT: pos[0] : ( 0, 9 )
503    // CHECK-NEXT: crd[0] : ( 0, 3, 11, 17, 20, 21, 28, 29, 31 )
504    // CHECK-NEXT: values : ( 0, 3, 11, 17, 20, 21, 28, 29, 31 )
505    // CHECK-NEXT: ----
506    //
507    // CHECK-NEXT: ---- Sparse Tensor ----
508    // CHECK-NEXT: nse = 6
509    // CHECK-NEXT: dim = ( 4, 8 )
510    // CHECK-NEXT: lvl = ( 4, 8 )
511    // CHECK-NEXT: pos[0] : ( 0, 3 )
512    // CHECK-NEXT: crd[0] : ( 0, 1, 2 )
513    // CHECK-NEXT: pos[1] : ( 0, 2, 4, 6 )
514    // CHECK-NEXT: crd[1] : ( 0, 7, 0, 6, 1, 7 )
515    // CHECK-NEXT: values : ( 7, -5, -4, -3, -2, 7 )
516    // CHECK-NEXT: ----
517    //
518    // CHECK-NEXT: ---- Sparse Tensor ----
519    // CHECK-NEXT: nse = 10
520    // CHECK-NEXT: dim = ( 4, 4 )
521    // CHECK-NEXT: lvl = ( 4, 4 )
522    // CHECK-NEXT: pos[0] : ( 0, 4 )
523    // CHECK-NEXT: crd[0] : ( 0, 1, 2, 3 )
524    // CHECK-NEXT: pos[1] : ( 0, 3, 4, 8, 10 )
525    // CHECK-NEXT: crd[1] : ( 0, 2, 3, 1, 0, 1, 2, 3, 0, 1 )
526    // CHECK-NEXT: values : ( 2, 4, 1, 2.5, 1, 5, 2, 4, 5, 4 )
527    // CHECK-NEXT: ----
528    //
529    // CHECK-NEXT: ---- Sparse Tensor ----
530    // CHECK-NEXT: nse = 10
531    // CHECK-NEXT: dim = ( 4, 4 )
532    // CHECK-NEXT: lvl = ( 4, 4 )
533    // CHECK-NEXT: pos[0] : ( 0, 4 )
534    // CHECK-NEXT: crd[0] : ( 0, 1, 2, 3 )
535    // CHECK-NEXT: pos[1] : ( 0, 3, 4, 8, 10 )
536    // CHECK-NEXT: crd[1] : ( 0, 2, 3, 1, 0, 1, 2, 3, 0, 1 )
537    // CHECK-NEXT: values : ( 2, 4, 1, 2.5, 1, 5, 2, 4, 5, 4 )
538    // CHECK-NEXT: ----
539    //
540    // CHECK-NEXT: ---- Sparse Tensor ----
541    // CHECK-NEXT: nse = 10
542    // CHECK-NEXT: dim = ( 4, 4 )
543    // CHECK-NEXT: lvl = ( 4, 4 )
544    // CHECK-NEXT: pos[0] : ( 0, 4 )
545    // CHECK-NEXT: crd[0] : ( 0, 1, 2, 3 )
546    // CHECK-NEXT: pos[1] : ( 0, 3, 4, 8, 10 )
547    // CHECK-NEXT: crd[1] : ( 0, 2, 3, 1, 0, 1, 2, 3, 0, 1 )
548    // CHECK-NEXT: values : ( 2, 4, 1, 2.5, -1, -5, 2, 4, 1, 4 )
549    // CHECK-NEXT: ----
550    //
551    // CHECK-NEXT: ---- Sparse Tensor ----
552    // CHECK-NEXT: nse = 10
553    // CHECK-NEXT: dim = ( 4, 4 )
554    // CHECK-NEXT: lvl = ( 4, 4 )
555    // CHECK-NEXT: pos[0] : ( 0, 4 )
556    // CHECK-NEXT: crd[0] : ( 0, 1, 2, 3 )
557    // CHECK-NEXT: pos[1] : ( 0, 3, 4, 8, 10 )
558    // CHECK-NEXT: crd[1] : ( 0, 2, 3, 1, 0, 1, 2, 3, 0, 1 )
559    // CHECK-NEXT: values : ( 0, 1, -1, 1, -1, -2, -2, 2, 1, 2 )
560    // CHECK-NEXT: ----
561    //
562    // CHECK-NEXT: ---- Sparse Tensor ----
563    // CHECK-NEXT: nse = 4
564    // CHECK-NEXT: dim = ( 4, 4 )
565    // CHECK-NEXT: lvl = ( 4, 4 )
566    // CHECK-NEXT: pos[0] : ( 0, 3 )
567    // CHECK-NEXT: crd[0] : ( 0, 1, 3 )
568    // CHECK-NEXT: pos[1] : ( 0, 2, 3, 4 )
569    // CHECK-NEXT: crd[1] : ( 0, 2, 1, 0 )
570    // CHECK-NEXT: values : ( 1, 0, 0, 0 )
571    // CHECK-NEXT: ----
572    //
573    // CHECK-NEXT: ---- Sparse Tensor ----
574    // CHECK-NEXT: nse = 6
575    // CHECK-NEXT: dim = ( 4, 4 )
576    // CHECK-NEXT: lvl = ( 4, 4 )
577    // CHECK-NEXT: pos[0] : ( 0, 3 )
578    // CHECK-NEXT: crd[0] : ( 0, 2, 3 )
579    // CHECK-NEXT: pos[1] : ( 0, 1, 5, 6 )
580    // CHECK-NEXT: crd[1] : ( 3, 0, 1, 2, 3, 1 )
581    // CHECK-NEXT: values : ( -1, -1, -5, -2, 4, 4 )
582    //
583    sparse_tensor.print %sv1 : tensor<?xf64, #SparseVector>
584    sparse_tensor.print %sv2 : tensor<?xf64, #SparseVector>
585    sparse_tensor.print %0   : tensor<?xi32, #SparseVector>
586    sparse_tensor.print %1   : tensor<?xf64, #SparseVector>
587    sparse_tensor.print %2   : tensor<?xf64, #SparseVector>
588    sparse_tensor.print %3   : tensor<?xi32, #SparseVector>
589    sparse_tensor.print %5   : tensor<?x?xf64, #DCSR>
590    sparse_tensor.print %6   : tensor<4x4xf64, #DCSR>
591    sparse_tensor.print %7   : tensor<4x4xf64, #DCSR>
592    sparse_tensor.print %8   : tensor<4x4xf64, #DCSR>
593    sparse_tensor.print %9   : tensor<4x4xf64, #DCSR>
594    sparse_tensor.print %10  : tensor<4x4xi8, #DCSR>
595    sparse_tensor.print %11  : tensor<4x4xf64, #DCSR>
596
597    // Release the resources.
598    bufferization.dealloc_tensor %sv1 : tensor<?xf64, #SparseVector>
599    bufferization.dealloc_tensor %sv2 : tensor<?xf64, #SparseVector>
600    bufferization.dealloc_tensor %sv1_si : tensor<?xi32, #SparseVector>
601    bufferization.dealloc_tensor %sv2_si : tensor<?xi32, #SparseVector>
602    bufferization.dealloc_tensor %sm1 : tensor<?x?xf64, #DCSR>
603    bufferization.dealloc_tensor %sm2 : tensor<?x?xf64, #DCSR>
604    bufferization.dealloc_tensor %sm3 : tensor<4x4xf64, #DCSR>
605    bufferization.dealloc_tensor %sm4 : tensor<4x4xf64, #DCSR>
606    bufferization.dealloc_tensor %0 : tensor<?xi32, #SparseVector>
607    bufferization.dealloc_tensor %1 : tensor<?xf64, #SparseVector>
608    bufferization.dealloc_tensor %2 : tensor<?xf64, #SparseVector>
609    bufferization.dealloc_tensor %3 : tensor<?xi32, #SparseVector>
610    bufferization.dealloc_tensor %5 : tensor<?x?xf64, #DCSR>
611    bufferization.dealloc_tensor %6 : tensor<4x4xf64, #DCSR>
612    bufferization.dealloc_tensor %7 : tensor<4x4xf64, #DCSR>
613    bufferization.dealloc_tensor %8 : tensor<4x4xf64, #DCSR>
614    bufferization.dealloc_tensor %9 : tensor<4x4xf64, #DCSR>
615    bufferization.dealloc_tensor %10 : tensor<4x4xi8, #DCSR>
616    bufferization.dealloc_tensor %11 : tensor<4x4xf64, #DCSR>
617    return
618  }
619}
620