[mlir][sparse] fix conversion bug when changing pointer/index sizes
authorAart Bik <ajcbik@google.com>
Thu, 28 Oct 2021 23:12:41 +0000 (16:12 -0700)
committerAart Bik <ajcbik@google.com>
Fri, 29 Oct 2021 00:24:38 +0000 (17:24 -0700)
Reviewed By: wrengr

Differential Revision: https://reviews.llvm.org/D112770

mlir/lib/Dialect/SparseTensor/Transforms/SparseTensorConversion.cpp
mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_conversion_dyn.mlir [moved from mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_convert.mlir with 100% similarity]
mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_conversion_ptr.mlir [new file with mode: 0644]

index 5d6f165..02bb88d 100644 (file)
@@ -582,8 +582,18 @@ class SparseTensorConvertConverter : public OpConversionPattern<ConvertOp> {
       SmallVector<Value, 8> params;
       sizesFromPtr(rewriter, sizes, op, encSrc, srcType.cast<ShapedType>(),
                    src);
-      newParams(rewriter, params, op, encDst, kToCOO, sizes, src);
+      // Set up encoding with right mix of src and dst so that the two
+      // method calls can share most parameters, while still providing
+      // the correct sparsity information to either of them.
+      auto enc = SparseTensorEncodingAttr::get(
+          op->getContext(), encDst.getDimLevelType(), encDst.getDimOrdering(),
+          encSrc.getPointerBitWidth(), encSrc.getIndexBitWidth());
+      newParams(rewriter, params, op, enc, kToCOO, sizes, src);
       Value coo = genNewCall(rewriter, op, params);
+      params[3] = constantI32(
+          rewriter, loc, getOverheadTypeEncoding(encDst.getPointerBitWidth()));
+      params[4] = constantI32(
+          rewriter, loc, getOverheadTypeEncoding(encDst.getIndexBitWidth()));
       params[6] = constantI32(rewriter, loc, kFromCOO);
       params[7] = coo;
       rewriter.replaceOp(op, genNewCall(rewriter, op, params));
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_conversion_ptr.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_conversion_ptr.mlir
new file mode 100644 (file)
index 0000000..d6b57d3
--- /dev/null
@@ -0,0 +1,85 @@
+// RUN: mlir-opt %s \
+// RUN:   --sparsification --sparse-tensor-conversion \
+// RUN:   --linalg-bufferize --convert-linalg-to-loops \
+// RUN:   --convert-vector-to-scf --convert-scf-to-std \
+// RUN:   --func-bufferize --tensor-constant-bufferize --tensor-bufferize \
+// RUN:   --std-bufferize --finalizing-bufferize --lower-affine \
+// RUN:   --convert-vector-to-llvm --convert-memref-to-llvm --convert-math-to-llvm \
+// RUN:   --convert-std-to-llvm --reconcile-unrealized-casts | \
+// RUN: mlir-cpu-runner \
+// RUN:  -e entry -entry-point-result=void  \
+// RUN:  -shared-libs=%mlir_integration_test_dir/libmlir_c_runner_utils%shlibext | \
+// RUN: FileCheck %s
+
+#DCSR  = #sparse_tensor.encoding<{
+  dimLevelType = [ "compressed", "compressed" ],
+  pointerBitWidth = 8,
+  indexBitWidth = 8
+}>
+
+#DCSC  = #sparse_tensor.encoding<{
+  dimLevelType = [ "compressed", "compressed" ],
+  dimOrdering = affine_map<(i,j) -> (j,i)>,
+  pointerBitWidth = 64,
+  indexBitWidth = 64
+}>
+
+//
+// Integration test that tests conversions between sparse tensors,
+// where the pointer and index sizes in the overhead storage change
+// in addition to layout.
+//
+module {
+
+  //
+  // Helper method to print values array. The transfer actually
+  // reads more than required to verify size of buffer as well.
+  //
+  func @dump(%arg0: memref<?xf64>) {
+    %c = arith.constant 0 : index
+    %d = arith.constant -1.0 : f64
+    %0 = vector.transfer_read %arg0[%c], %d: memref<?xf64>, vector<8xf64>
+    vector.print %0 : vector<8xf64>
+    return
+  }
+
+  func @entry() {
+    %t1 = arith.constant sparse<
+      [ [0,0], [0,1], [0,63], [1,0], [1,1], [31,0], [31,63] ],
+        [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]> : tensor<32x64xf64>
+    %t2 = tensor.cast %t1 : tensor<32x64xf64> to tensor<?x?xf64>
+
+    // Dense to sparse.
+    %1 = sparse_tensor.convert %t1 : tensor<32x64xf64> to tensor<32x64xf64, #DCSR>
+    %2 = sparse_tensor.convert %t1 : tensor<32x64xf64> to tensor<32x64xf64, #DCSC>
+
+    // Sparse to sparse.
+    %3 = sparse_tensor.convert %1 : tensor<32x64xf64, #DCSR> to tensor<32x64xf64, #DCSC>
+    %4 = sparse_tensor.convert %2 : tensor<32x64xf64, #DCSC> to tensor<32x64xf64, #DCSR>
+
+    //
+    // All proper row-/column-wise?
+    //
+    // CHECK: ( 1, 2, 3, 4, 5, 6, 7, -1 )
+    // CHECK: ( 1, 4, 6, 2, 5, 3, 7, -1 )
+    // CHECK: ( 1, 4, 6, 2, 5, 3, 7, -1 )
+    // CHECK: ( 1, 2, 3, 4, 5, 6, 7, -1 )
+    //
+    %m1 = sparse_tensor.values %1 : tensor<32x64xf64, #DCSR> to memref<?xf64>
+    %m2 = sparse_tensor.values %2 : tensor<32x64xf64, #DCSC> to memref<?xf64>
+    %m3 = sparse_tensor.values %3 : tensor<32x64xf64, #DCSC> to memref<?xf64>
+    %m4 = sparse_tensor.values %4 : tensor<32x64xf64, #DCSR> to memref<?xf64>
+    call @dump(%m1) : (memref<?xf64>) -> ()
+    call @dump(%m2) : (memref<?xf64>) -> ()
+    call @dump(%m3) : (memref<?xf64>) -> ()
+    call @dump(%m4) : (memref<?xf64>) -> ()
+
+    // Release the resources.
+    sparse_tensor.release %1 : tensor<32x64xf64, #DCSR>
+    sparse_tensor.release %2 : tensor<32x64xf64, #DCSC>
+    sparse_tensor.release %3 : tensor<32x64xf64, #DCSC>
+    sparse_tensor.release %4 : tensor<32x64xf64, #DCSR>
+
+    return
+  }
+}