1// RUN: mlir-opt %s \
2// RUN:   --sparsification --sparse-tensor-conversion \
3// RUN:   --convert-vector-to-scf --convert-scf-to-std \
4// RUN:   --func-bufferize --tensor-constant-bufferize --tensor-bufferize \
5// RUN:   --std-bufferize --finalizing-bufferize --lower-affine \
6// RUN:   --convert-vector-to-llvm --convert-memref-to-llvm --convert-std-to-llvm --reconcile-unrealized-casts | \
7// RUN: TENSOR0="%mlir_integration_test_dir/data/mttkrp_b.tns" \
8// RUN: mlir-cpu-runner \
9// RUN:  -e entry -entry-point-result=void  \
10// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
11// RUN: FileCheck %s
12//
13// Do the same run, but now with SIMDization as well. This should not change the outcome.
14//
15// RUN: mlir-opt %s \
16// RUN:   --sparsification="vectorization-strategy=2 vl=4" --sparse-tensor-conversion \
17// RUN:   --convert-vector-to-scf --convert-scf-to-std \
18// RUN:   --func-bufferize --tensor-constant-bufferize --tensor-bufferize \
19// RUN:   --std-bufferize --finalizing-bufferize --lower-affine \
20// RUN:   --convert-vector-to-llvm --convert-memref-to-llvm --convert-std-to-llvm --reconcile-unrealized-casts | \
21// RUN: TENSOR0="%mlir_integration_test_dir/data/mttkrp_b.tns" \
22// RUN: mlir-cpu-runner \
23// RUN:  -e entry -entry-point-result=void  \
24// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
25// RUN: FileCheck %s
26
27!Filename = type !llvm.ptr<i8>
28
29#SparseTensor = #sparse_tensor.encoding<{
30  dimLevelType = [ "compressed", "compressed", "compressed" ]
31}>
32
33#mttkrp = {
34  indexing_maps = [
35    affine_map<(i,j,k,l) -> (i,k,l)>, // B
36    affine_map<(i,j,k,l) -> (k,j)>,   // C
37    affine_map<(i,j,k,l) -> (l,j)>,   // D
38    affine_map<(i,j,k,l) -> (i,j)>    // A (out)
39  ],
40  iterator_types = ["parallel", "parallel", "reduction", "reduction"],
41  doc = "A(i,j) += B(i,k,l) * D(l,j) * C(k,j)"
42}
43
44//
45// Integration test that lowers a kernel annotated as sparse to
46// actual sparse code, initializes a matching sparse storage scheme
47// from file, and runs the resulting code with the JIT compiler.
48//
49module {
50  //
51  // Computes Matricized Tensor Times Khatri-Rao Product (MTTKRP) kernel. See
52  // http://tensor-compiler.org/docs/data_analytics/index.html.
53  //
54  func @kernel_mttkrp(%argb: tensor<?x?x?xf64, #SparseTensor>,
55                      %argc: tensor<?x?xf64>,
56                      %argd: tensor<?x?xf64>,
57                      %arga: tensor<?x?xf64> {linalg.inplaceable = true})
58		      -> tensor<?x?xf64> {
59    %0 = linalg.generic #mttkrp
60      ins(%argb, %argc, %argd:
61            tensor<?x?x?xf64, #SparseTensor>, tensor<?x?xf64>, tensor<?x?xf64>)
62      outs(%arga: tensor<?x?xf64>) {
63      ^bb(%b: f64, %c: f64, %d: f64, %a: f64):
64        %0 = arith.mulf %b, %c : f64
65        %1 = arith.mulf %d, %0 : f64
66        %2 = arith.addf %a, %1 : f64
67        linalg.yield %2 : f64
68    } -> tensor<?x?xf64>
69    return %0 : tensor<?x?xf64>
70  }
71
72  func private @getTensorFilename(index) -> (!Filename)
73
74  //
75  // Main driver that reads matrix from file and calls the sparse kernel.
76  //
77  func @entry() {
78    %f0 = arith.constant 0.0 : f64
79    %c0 = arith.constant 0 : index
80    %c1 = arith.constant 1 : index
81    %c2 = arith.constant 2 : index
82
83    // Read the sparse input tensor B from a file.
84    %fileName = call @getTensorFilename(%c0) : (index) -> (!Filename)
85    %b = sparse_tensor.new %fileName
86          : !Filename to tensor<?x?x?xf64, #SparseTensor>
87
88    // Get sizes from B, pick a fixed size for dim-2 of A.
89    %isz = tensor.dim %b, %c0 : tensor<?x?x?xf64, #SparseTensor>
90    %jsz = arith.constant 5 : index
91    %ksz = tensor.dim %b, %c1 : tensor<?x?x?xf64, #SparseTensor>
92    %lsz = tensor.dim %b, %c2 : tensor<?x?x?xf64, #SparseTensor>
93
94    // Initialize dense input matrix C.
95    %cdata = memref.alloc(%ksz, %jsz) : memref<?x?xf64>
96    scf.for %k = %c0 to %ksz step %c1 {
97      scf.for %j = %c0 to %jsz step %c1 {
98        %k0 = arith.muli %k, %jsz : index
99        %k1 = arith.addi %k0, %j : index
100        %k2 = arith.index_cast %k1 : index to i32
101        %kf = arith.sitofp %k2 : i32 to f64
102        memref.store %kf, %cdata[%k, %j] : memref<?x?xf64>
103      }
104    }
105    %c = bufferization.to_tensor %cdata : memref<?x?xf64>
106
107    // Initialize dense input matrix D.
108    %ddata = memref.alloc(%lsz, %jsz) : memref<?x?xf64>
109    scf.for %l = %c0 to %lsz step %c1 {
110      scf.for %j = %c0 to %jsz step %c1 {
111        %k0 = arith.muli %l, %jsz : index
112        %k1 = arith.addi %k0, %j : index
113        %k2 = arith.index_cast %k1 : index to i32
114        %kf = arith.sitofp %k2 : i32 to f64
115        memref.store %kf, %ddata[%l, %j] : memref<?x?xf64>
116      }
117    }
118    %d = bufferization.to_tensor %ddata : memref<?x?xf64>
119
120    // Initialize dense output matrix A.
121    %adata = memref.alloc(%isz, %jsz) : memref<?x?xf64>
122    scf.for %i = %c0 to %isz step %c1 {
123      scf.for %j = %c0 to %jsz step %c1 {
124        memref.store %f0, %adata[%i, %j] : memref<?x?xf64>
125      }
126    }
127    %a = bufferization.to_tensor %adata : memref<?x?xf64>
128
129    // Call kernel.
130    %0 = call @kernel_mttkrp(%b, %c, %d, %a)
131      : (tensor<?x?x?xf64, #SparseTensor>,
132        tensor<?x?xf64>, tensor<?x?xf64>, tensor<?x?xf64>) -> tensor<?x?xf64>
133
134    // Print the result for verification.
135    //
136    // CHECK: ( ( 16075, 21930, 28505, 35800, 43815 ),
137    // CHECK:   ( 10000, 14225, 19180, 24865, 31280 ) )
138    //
139    %m = bufferization.to_memref %0 : memref<?x?xf64>
140    %v = vector.transfer_read %m[%c0, %c0], %f0
141          : memref<?x?xf64>, vector<2x5xf64>
142    vector.print %v : vector<2x5xf64>
143
144    // Release the resources.
145    memref.dealloc %adata : memref<?x?xf64>
146    memref.dealloc %cdata : memref<?x?xf64>
147    memref.dealloc %ddata : memref<?x?xf64>
148    sparse_tensor.release %b : tensor<?x?x?xf64, #SparseTensor>
149
150    return
151  }
152}
153