[Mlir-commits] [mlir] [mlir][sparse] fix bug with all-dense assembler (PR #108615)
Aart Bik
llvmlistbot at llvm.org
Fri Sep 13 11:24:10 PDT 2024
https://github.com/aartbik updated https://github.com/llvm/llvm-project/pull/108615
>From e7d51a434d6e88ef0918a014e4245fb119665ea0 Mon Sep 17 00:00:00 2001
From: Aart Bik <ajcbik at google.com>
Date: Fri, 13 Sep 2024 10:44:14 -0700
Subject: [PATCH 1/3] [mlir][sparse] fix bug with all-dense assembler
When only all-dense "sparse" tensors occur in a function
prototype, the assembler would skip the method conversion
purely based on input/output counts. It should rewrite
based on the presence of any annotation, however.
---
.../Transforms/SparseAssembler.cpp | 14 ++-
.../Dialect/SparseTensor/python/test_SDDMM.py | 3 +-
.../Dialect/SparseTensor/python/test_SpMM.py | 2 +-
.../SparseTensor/python/test_all_dense.py | 96 +++++++++++++++++++
.../SparseTensor/python/test_output.py | 2 +-
.../SparseTensor/python/test_stress.py | 3 +-
.../SparseTensor/python/tools/sparsifier.py | 13 ++-
7 files changed, 122 insertions(+), 11 deletions(-)
create mode 100644 mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/SparseAssembler.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/SparseAssembler.cpp
index a53bce16dad860..5461987fb49d93 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/SparseAssembler.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/SparseAssembler.cpp
@@ -24,7 +24,8 @@ using namespace sparse_tensor;
//===----------------------------------------------------------------------===//
// Convert type range to new types range, with sparse tensors externalized.
-static void convTypes(TypeRange types, SmallVectorImpl<Type> &convTypes,
+static void convTypes(bool &hasAnnotation, TypeRange types,
+ SmallVectorImpl<Type> &convTypes,
SmallVectorImpl<Type> *extraTypes, bool directOut) {
for (auto type : types) {
// All "dense" data passes through unmodified.
@@ -32,6 +33,7 @@ static void convTypes(TypeRange types, SmallVectorImpl<Type> &convTypes,
convTypes.push_back(type);
continue;
}
+ hasAnnotation = true;
// Convert the external representations of the pos/crd/val arrays.
const SparseTensorType stt(cast<RankedTensorType>(type));
@@ -176,12 +178,14 @@ struct SparseFuncAssembler : public OpRewritePattern<func::FuncOp> {
SmallVector<Type> inputTypes;
SmallVector<Type> outputTypes;
SmallVector<Type> extraTypes;
- convTypes(funcOp.getArgumentTypes(), inputTypes, nullptr, false);
- convTypes(funcOp.getResultTypes(), outputTypes, &extraTypes, directOut);
+ bool hasAnnotation = false;
+ convTypes(hasAnnotation, funcOp.getArgumentTypes(), inputTypes, nullptr,
+ false);
+ convTypes(hasAnnotation, funcOp.getResultTypes(), outputTypes, &extraTypes,
+ directOut);
// Only sparse inputs or outputs need a wrapper method.
- if (inputTypes.size() == funcOp.getArgumentTypes().size() &&
- outputTypes.size() == funcOp.getResultTypes().size())
+ if (!hasAnnotation)
return failure();
// Modify the original method into an internal, private method.
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
index e2050b98728f21..5ffb910e02d46d 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
@@ -163,7 +163,8 @@ def main():
)
opt = f"parallelization-strategy=none"
compiler = sparsifier.Sparsifier(
- options=opt, opt_level=0, shared_libs=[support_lib]
+ extras="", options=opt, opt_level=0,
+ shared_libs=[support_lib]
)
build_compile_and_run_SDDMMM(attr, compiler)
count = count + 1
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
index e7354c24d619e0..65fc6a0bdbe46b 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
@@ -141,7 +141,7 @@ def main():
]
bitwidths = [0]
compiler = sparsifier.Sparsifier(
- options=opt, opt_level=0, shared_libs=[support_lib]
+ extra="", options=opt, opt_level=0, shared_libs=[support_lib]
)
for level in levels:
for ordering in orderings:
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
new file mode 100644
index 00000000000000..eebed3afd7084b
--- /dev/null
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
@@ -0,0 +1,96 @@
+# RUN: env SUPPORT_LIB=%mlir_c_runner_utils \
+# RUN: %PYTHON %s | FileCheck %s
+
+import ctypes
+import os
+import sys
+import tempfile
+
+from mlir import ir
+from mlir import runtime as rt
+from mlir.dialects import builtin
+from mlir.dialects import sparse_tensor as st
+import numpy as np
+
+_SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
+sys.path.append(_SCRIPT_PATH)
+from tools import sparsifier
+
+
+def boilerplate():
+ """Returns boilerplate main method."""
+ return """
+#Dense = #sparse_tensor.encoding<{
+ map = (i, j) -> (i: dense, j: dense)
+}>
+
+#map = affine_map<(d0, d1) -> (d0, d1)>
+func.func @add(%st_0 : tensor<3x4xf64, #Dense>,
+ %st_1 : tensor<3x4xf64, #Dense>) attributes { llvm.emit_c_interface } {
+ %out_st = tensor.empty() : tensor<3x4xf64, #Dense>
+ %res = linalg.generic {indexing_maps = [#map, #map, #map],
+ iterator_types = ["parallel", "parallel"]}
+ ins(%st_0, %st_1 : tensor<3x4xf64, #Dense>, tensor<3x4xf64, #Dense>)
+ outs(%out_st : tensor<3x4xf64, #Dense>) {
+ ^bb0(%in_0: f64, %in_1: f64, %out: f64):
+ %2 = sparse_tensor.binary %in_0, %in_1 : f64, f64 to f64
+ overlap = {
+ ^bb0(%arg1: f64, %arg2: f64):
+ %3 = arith.addf %arg1, %arg2 : f64
+ sparse_tensor.yield %3 : f64
+ }
+ left = {
+ ^bb0(%arg1: f64):
+ sparse_tensor.yield %arg1 : f64
+ }
+ right = {
+ ^bb0(%arg1: f64):
+ sparse_tensor.yield %arg1 : f64
+ }
+ linalg.yield %2 : f64
+ } -> tensor<3x4xf64, #Dense>
+ sparse_tensor.print %res : tensor<3x4xf64, #Dense>
+ return
+}
+"""
+
+
+def main():
+ support_lib = os.getenv("SUPPORT_LIB")
+ assert support_lib is not None, "SUPPORT_LIB is undefined"
+ if not os.path.exists(support_lib):
+ raise FileNotFoundError(
+ errno.ENOENT, os.strerror(errno.ENOENT), support_lib
+ )
+
+ # CHECK-LABEL: TEST: all dense
+ # CHECK: ---- Sparse Tensor ----
+ # CHECK: nse = 12
+ # CHECK: dim = ( 3, 4 )
+ # CHECK: lvl = ( 3, 4 )
+ # CHECK: values : ( 1, 1, 0, 1, 0, 6, 2, 3, 0, 0, 0, 2 )
+ # CHECK: ----
+ print("\nTEST: all dense")
+ with ir.Context() as ctx, ir.Location.unknown():
+ compiler = sparsifier.Sparsifier(
+ extras="sparse-assembler,",
+ options="enable-runtime-library=false",
+ opt_level=2,
+ shared_libs=[support_lib],
+ )
+ module = ir.Module.parse(boilerplate())
+ engine = compiler.compile_and_jit(module)
+ print(module)
+
+ a = np.array([1, 0, 0, 1, 0, 2, 2, 0, 0, 0, 0, 1], dtype=np.float64)
+ b = np.array([0, 1, 0, 0, 0, 4, 0, 3, 0, 0, 0, 1], dtype=np.float64)
+ mem_a = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(a)))
+ mem_b = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(b)))
+
+ # Invoke the kernel and get numpy output.
+ # Built-in bufferization uses in-out buffers.
+ engine.invoke("add", mem_a, mem_b)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_output.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_output.py
index 7da05303c7e1e1..544273eb18835e 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_output.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_output.py
@@ -139,7 +139,7 @@ def main():
]
bitwidths = [8, 64]
compiler = sparsifier.Sparsifier(
- options="", opt_level=2, shared_libs=[support_lib]
+ extras="", options="", opt_level=2, shared_libs=[support_lib]
)
for level in levels:
for ordering, id_map in orderings:
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
index ce3516e2edaf03..9db00454053481 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
@@ -195,7 +195,8 @@ def main():
with ir.Context() as ctx, ir.Location.unknown():
sparsification_options = f"parallelization-strategy=none "
compiler = sparsifier.Sparsifier(
- options=sparsification_options, opt_level=0, shared_libs=[support_lib]
+ extras="", options=sparsification_options, opt_level=0,
+ shared_libs=[support_lib]
)
f64 = ir.F64Type.get()
# Be careful about increasing this because
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/tools/sparsifier.py b/mlir/test/Integration/Dialect/SparseTensor/python/tools/sparsifier.py
index ab7208f23f61b6..91d1fb22542d4a 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/tools/sparsifier.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/tools/sparsifier.py
@@ -13,8 +13,17 @@
class Sparsifier:
"""Sparsifier class for compiling and building MLIR modules."""
- def __init__(self, options: str, opt_level: int, shared_libs: Sequence[str]):
- pipeline = f"builtin.module(sparsifier{{{options} reassociate-fp-reductions=1 enable-index-optimizations=1}})"
+ def __init__(
+ self,
+ extras: str,
+ options: str,
+ opt_level: int,
+ shared_libs: Sequence[str],
+ ):
+ pipeline = (
+ f"builtin.module({extras}sparsifier{{{options} reassociate-fp-reductions=1"
+ " enable-index-optimizations=1})"
+ )
self.pipeline = pipeline
self.opt_level = opt_level
self.shared_libs = shared_libs
>From d6660dd4309500e2b7c33e3b3e24dae382d77e59 Mon Sep 17 00:00:00 2001
From: Aart Bik <ajcbik at google.com>
Date: Fri, 13 Sep 2024 10:56:28 -0700
Subject: [PATCH 2/3] lint
---
.../Dialect/SparseTensor/python/test_SDDMM.py | 6 +-
.../SparseTensor/python/test_all_dense.py | 66 +++++++++----------
.../SparseTensor/python/test_stress.py | 6 +-
3 files changed, 40 insertions(+), 38 deletions(-)
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
index 5ffb910e02d46d..b6f61a47dec1ec 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_SDDMM.py
@@ -163,8 +163,10 @@ def main():
)
opt = f"parallelization-strategy=none"
compiler = sparsifier.Sparsifier(
- extras="", options=opt, opt_level=0,
- shared_libs=[support_lib]
+ extras="",
+ options=opt,
+ opt_level=0,
+ shared_libs=[support_lib],
)
build_compile_and_run_SDDMMM(attr, compiler)
count = count + 1
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
index eebed3afd7084b..9ab374ac820714 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_all_dense.py
@@ -18,8 +18,8 @@
def boilerplate():
- """Returns boilerplate main method."""
- return """
+ """Returns boilerplate main method."""
+ return """
#Dense = #sparse_tensor.encoding<{
map = (i, j) -> (i: dense, j: dense)
}>
@@ -56,41 +56,39 @@ def boilerplate():
def main():
- support_lib = os.getenv("SUPPORT_LIB")
- assert support_lib is not None, "SUPPORT_LIB is undefined"
- if not os.path.exists(support_lib):
- raise FileNotFoundError(
- errno.ENOENT, os.strerror(errno.ENOENT), support_lib
- )
+ support_lib = os.getenv("SUPPORT_LIB")
+ assert support_lib is not None, "SUPPORT_LIB is undefined"
+ if not os.path.exists(support_lib):
+ raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), support_lib)
- # CHECK-LABEL: TEST: all dense
- # CHECK: ---- Sparse Tensor ----
- # CHECK: nse = 12
- # CHECK: dim = ( 3, 4 )
- # CHECK: lvl = ( 3, 4 )
- # CHECK: values : ( 1, 1, 0, 1, 0, 6, 2, 3, 0, 0, 0, 2 )
- # CHECK: ----
- print("\nTEST: all dense")
- with ir.Context() as ctx, ir.Location.unknown():
- compiler = sparsifier.Sparsifier(
- extras="sparse-assembler,",
- options="enable-runtime-library=false",
- opt_level=2,
- shared_libs=[support_lib],
- )
- module = ir.Module.parse(boilerplate())
- engine = compiler.compile_and_jit(module)
- print(module)
+ # CHECK-LABEL: TEST: all dense
+ # CHECK: ---- Sparse Tensor ----
+ # CHECK: nse = 12
+ # CHECK: dim = ( 3, 4 )
+ # CHECK: lvl = ( 3, 4 )
+ # CHECK: values : ( 1, 1, 0, 1, 0, 6, 2, 3, 0, 0, 0, 2 )
+ # CHECK: ----
+ print("\nTEST: all dense")
+ with ir.Context() as ctx, ir.Location.unknown():
+ compiler = sparsifier.Sparsifier(
+ extras="sparse-assembler,",
+ options="enable-runtime-library=false",
+ opt_level=2,
+ shared_libs=[support_lib],
+ )
+ module = ir.Module.parse(boilerplate())
+ engine = compiler.compile_and_jit(module)
+ print(module)
- a = np.array([1, 0, 0, 1, 0, 2, 2, 0, 0, 0, 0, 1], dtype=np.float64)
- b = np.array([0, 1, 0, 0, 0, 4, 0, 3, 0, 0, 0, 1], dtype=np.float64)
- mem_a = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(a)))
- mem_b = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(b)))
+ a = np.array([1, 0, 0, 1, 0, 2, 2, 0, 0, 0, 0, 1], dtype=np.float64)
+ b = np.array([0, 1, 0, 0, 0, 4, 0, 3, 0, 0, 0, 1], dtype=np.float64)
+ mem_a = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(a)))
+ mem_b = ctypes.pointer(ctypes.pointer(rt.get_ranked_memref_descriptor(b)))
- # Invoke the kernel and get numpy output.
- # Built-in bufferization uses in-out buffers.
- engine.invoke("add", mem_a, mem_b)
+ # Invoke the kernel and get numpy output.
+ # Built-in bufferization uses in-out buffers.
+ engine.invoke("add", mem_a, mem_b)
if __name__ == "__main__":
- main()
+ main()
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
index 9db00454053481..dfaa4f462660b7 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_stress.py
@@ -195,8 +195,10 @@ def main():
with ir.Context() as ctx, ir.Location.unknown():
sparsification_options = f"parallelization-strategy=none "
compiler = sparsifier.Sparsifier(
- extras="", options=sparsification_options, opt_level=0,
- shared_libs=[support_lib]
+ extras="",
+ options=sparsification_options,
+ opt_level=0,
+ shared_libs=[support_lib],
)
f64 = ir.F64Type.get()
# Be careful about increasing this because
>From 5a085397b2607b40d93bc5a78885d76c810d932f Mon Sep 17 00:00:00 2001
From: Aart Bik <ajcbik at google.com>
Date: Fri, 13 Sep 2024 11:23:51 -0700
Subject: [PATCH 3/3] typo
---
mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py b/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
index 65fc6a0bdbe46b..bf2e62b653339f 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
+++ b/mlir/test/Integration/Dialect/SparseTensor/python/test_SpMM.py
@@ -141,7 +141,7 @@ def main():
]
bitwidths = [0]
compiler = sparsifier.Sparsifier(
- extra="", options=opt, opt_level=0, shared_libs=[support_lib]
+ extras="", options=opt, opt_level=0, shared_libs=[support_lib]
)
for level in levels:
for ordering in orderings:
More information about the Mlir-commits
mailing list