[Mlir-commits] [mlir] 471004c - Revert "[mlir][sparse] simplification of sparse runtime support lib"

Mehdi Amini llvmlistbot at llvm.org
Fri Sep 1 11:50:21 PDT 2023


Author: Mehdi Amini
Date: 2023-09-01T11:50:14-07:00
New Revision: 471004c5c9bbd74ccc55066fdc822b137880a405

URL: https://github.com/llvm/llvm-project/commit/471004c5c9bbd74ccc55066fdc822b137880a405
DIFF: https://github.com/llvm/llvm-project/commit/471004c5c9bbd74ccc55066fdc822b137880a405.diff

LOG: Revert "[mlir][sparse] simplification of sparse runtime support lib"

This reverts commit 14c58cf5c39a39a335893bc98493c5edc75a91b3.

The gcc7 build is broken.

Added: 
    mlir/include/mlir/ExecutionEngine/SparseTensor/Attributes.h
    mlir/include/mlir/ExecutionEngine/SparseTensor/PermutationRef.h
    mlir/lib/ExecutionEngine/SparseTensor/PermutationRef.cpp

Modified: 
    mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h
    mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h
    mlir/include/mlir/ExecutionEngine/SparseTensor/File.h
    mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
    mlir/lib/ExecutionEngine/SparseTensor/CMakeLists.txt
    mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp
    utils/bazel/llvm-project-overlay/mlir/BUILD.bazel

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h
index af31b98c1f7025..c31337a225d918 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h
@@ -6,13 +6,23 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// A collection of "safe" arithmetic helper methods.
+// This header is not part of the public API.  It is placed in the
+// includes directory only because that's required by the implementations
+// of template-classes.
+//
+// This file is part of the lightweight runtime support library for sparse
+// tensor manipulations.  The functionality of the support library is meant
+// to simplify benchmarking, testing, and debugging MLIR code operating on
+// sparse tensors.  However, the provided functionality is **not** part of
+// core MLIR itself.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ARITHMETICUTILS_H
 #define MLIR_EXECUTIONENGINE_SPARSETENSOR_ARITHMETICUTILS_H
 
+#include "mlir/ExecutionEngine/SparseTensor/Attributes.h"
+
 #include <cassert>
 #include <cinttypes>
 #include <limits>
@@ -98,6 +108,12 @@ constexpr bool safelyGE(T t, U u) noexcept {
 //
 //===----------------------------------------------------------------------===//
 
+// TODO: we would like to be able to pass in custom error messages, to
+// improve the user experience.  We should be able to use something like
+// `assert(((void)(msg ? msg : defaultMsg), cond))`; but I'm not entirely
+// sure that'll work as intended when done within a function-definition
+// rather than within a macro-definition.
+
 /// A version of `static_cast<To>` which checks for overflow/underflow.
 /// The implementation avoids performing runtime assertions whenever
 /// the types alone are sufficient to statically prove that overflow
@@ -124,8 +140,7 @@ inline uint64_t checkedMul(uint64_t lhs, uint64_t rhs) {
   // If assertions are enabled and we have the intrinsic, then use it to
   // avoid the expensive division.  If assertions are disabled, then don't
   // bother with intrinsics (to avoid any possible slowdown vs `operator*`).
-#if !defined(NDEBUG) && defined(__has_builtin) &&                              \
-    __has_builtin(__builtin_mul_overflow)
+#if !defined(NDEBUG) && MLIR_SPARSETENSOR_HAS_BUILTIN(__builtin_mul_overflow)
   uint64_t result;
   bool overflowed = __builtin_mul_overflow(lhs, rhs, &result);
   assert(!overflowed && "Integer overflow");

diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/Attributes.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/Attributes.h
new file mode 100644
index 00000000000000..681eba60d2c90a
--- /dev/null
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/Attributes.h
@@ -0,0 +1,85 @@
+//===- Attributes.h - C++ attributes for SparseTensorRuntime ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines various macros for using C++ attributes whenever
+// they're supported by the compiler.  These macros are the same as the
+// versions in the LLVMSupport library, but we define our own versions
+// in order to avoid introducing that dependency just for the sake of
+// these macros.  (If we ever do end up depending on LLVMSupport, then
+// we should remove this header and use "llvm/Support/Compiler.h" instead.)
+//
+// This file is part of the lightweight runtime support library for sparse
+// tensor manipulations.  The functionality of the support library is meant
+// to simplify benchmarking, testing, and debugging MLIR code operating on
+// sparse tensors.  However, the provided functionality is **not** part of
+// core MLIR itself.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H
+#define MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H
+
+// A wrapper around `__has_cpp_attribute` for C++11 style attributes,
+// which are defined by ISO C++ SD-6.
+// <https://en.cppreference.com/w/cpp/experimental/feature_test>
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+// NOTE: The __cplusplus requirement should be unnecessary, but guards
+// against issues with GCC <https://bugs.llvm.org/show_bug.cgi?id=23435>.
+#define MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+#define MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+
+// A wrapper around `__has_attribute`, which is defined by GCC 5+ and Clang.
+// GCC: <https://gcc.gnu.org/gcc-5/changes.html>
+// Clang: <https://clang.llvm.org/docs/LanguageExtensions.html>
+#ifdef __has_attribute
+#define MLIR_SPARSETENSOR_HAS_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define MLIR_SPARSETENSOR_HAS_ATTRIBUTE(x) 0
+#endif
+
+// A wrapper around `__has_builtin`, which is defined by GCC and Clang
+// but is missing on some versions of MSVC.
+// GCC: <https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fbuiltin.html>
+// Clang: <https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin>
+#ifdef __has_builtin
+#define MLIR_SPARSETENSOR_HAS_BUILTIN(x) __has_builtin(x)
+#else
+#define MLIR_SPARSETENSOR_HAS_BUILTIN(x) 0
+#endif
+
+// An attribute for non-owning classes (like `PermutationRef`) to enable
+// lifetime warnings.
+#if MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(gsl::Pointer)
+#define MLIR_SPARSETENSOR_GSL_POINTER [[gsl::Pointer]]
+#else
+#define MLIR_SPARSETENSOR_GSL_POINTER
+#endif
+
+// An attribute for functions which are "pure" in the following sense:
+// * the result depends only on the function arguments
+// * pointer arguments are allowed to be read from, but not written to
+// * has no observable effects other than the return value
+//
+// This allows the compiler to avoid repeated function calls whenever
+// it can determine that the arguments are the same and that memory has
+// not changed.
+//
+// This macro is called `LLVM_READONLY` by LLVMSupport.  This definition
+// 
diff ers slightly from the LLVM version by using `gnu::pure` when
+// available, like Abseil's `ABSL_ATTRIBUTE_PURE_FUNCTION`.
+#if MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(gnu::pure)
+#define MLIR_SPARSETENSOR_PURE [[gnu::pure]]
+#elif MLIR_SPARSETENSOR_HAS_ATTRIBUTE(pure) || defined(__GNUC__)
+#define MLIR_SPARSETENSOR_PURE __attribute__((pure))
+#else
+#define MLIR_SPARSETENSOR_PURE
+#endif
+
+#endif // MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H

diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h
index 6b39526211c77d..e0385ffdd84f87 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h
@@ -6,10 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 //
+// This header is not part of the public API.  It is placed in the
+// includes directory only because that's required by the implementations
+// of template-classes.
+//
 // This file defines an extremely lightweight API for fatal errors (not
 // arising from assertions).  The API does not attempt to be sophisticated
 // in any way, it's just the usual "I give up" style of error reporting.
 //
+// This file is part of the lightweight runtime support library for sparse
+// tensor manipulations.  The functionality of the support library is meant
+// to simplify benchmarking, testing, and debugging MLIR code operating on
+// sparse tensors.  However, the provided functionality is **not** part of
+// core MLIR itself.
+//
 //===----------------------------------------------------------------------===//
 
 #ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ERRORHANDLING_H

diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/File.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/File.h
index 1b6736b0cdd1d1..8d5eb48f38048e 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/File.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/File.h
@@ -15,11 +15,18 @@
 // (2) Formidable Repository of Open Sparse Tensors and Tools (FROSTT): *.tns
 //     http://frostt.io/tensors/file-formats.html
 //
+// This file is part of the lightweight runtime support library for sparse
+// tensor manipulations.  The functionality of the support library is meant
+// to simplify benchmarking, testing, and debugging MLIR code operating on
+// sparse tensors.  However, the provided functionality is **not** part of
+// core MLIR itself.
+//
 //===----------------------------------------------------------------------===//
 
 #ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_FILE_H
 #define MLIR_EXECUTIONENGINE_SPARSETENSOR_FILE_H
 
+#include "mlir/ExecutionEngine/SparseTensor/PermutationRef.h"
 #include "mlir/ExecutionEngine/SparseTensor/Storage.h"
 
 #include <fstream>
@@ -77,6 +84,13 @@ inline V readValue(char **linePtr, bool isPattern) {
 
 //===----------------------------------------------------------------------===//
 
+// TODO: benchmark whether to keep various methods inline vs moving them
+// off to the cpp file.
+
+// TODO: consider distinguishing separate classes for before vs
+// after reading the header; so as to statically avoid the need
+// to `assert(isValid())`.
+
 /// This class abstracts over the information stored in file headers,
 /// as well as providing the buffers and methods for parsing those headers.
 class SparseTensorReader final {

diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/PermutationRef.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/PermutationRef.h
new file mode 100644
index 00000000000000..313470d27a38c0
--- /dev/null
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/PermutationRef.h
@@ -0,0 +1,141 @@
+//===- PermutationRef.h - Permutation reference wrapper ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This header is not part of the public API.  It is placed in the
+// includes directory only because that's required by the implementations
+// of template-classes.
+//
+// This file is part of the lightweight runtime support library for sparse
+// tensor manipulations.  The functionality of the support library is meant
+// to simplify benchmarking, testing, and debugging MLIR code operating on
+// sparse tensors.  However, the provided functionality is **not** part of
+// core MLIR itself.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H
+#define MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H
+
+#include "mlir/ExecutionEngine/SparseTensor/Attributes.h"
+#include "mlir/ExecutionEngine/SparseTensor/ErrorHandling.h"
+
+#include <cassert>
+#include <cinttypes>
+#include <vector>
+
+namespace mlir {
+namespace sparse_tensor {
+namespace detail {
+
+/// Checks whether the `perm` array is a permutation of `[0 .. size)`.
+MLIR_SPARSETENSOR_PURE bool isPermutation(uint64_t size, const uint64_t *perm);
+
+/// Wrapper around `isPermutation` to ensure consistent error messages.
+inline void assertIsPermutation(uint64_t size, const uint64_t *perm) {
+#ifndef NDEBUG
+  if (!isPermutation(size, perm))
+    MLIR_SPARSETENSOR_FATAL("Not a permutation of [0..%" PRIu64 ")\n", size);
+#endif
+}
+
+// TODO: To implement things like `inverse` and `compose` while preserving
+// the knowledge that `isPermutation` is true, we'll need to also have
+// an owning version of `PermutationRef`.  (Though ideally we'll really
+// want to defunctionalize those methods so that we can avoid intermediate
+// arrays/copies and only materialize the data on request.)
+
+/// A non-owning class for capturing the knowledge that `isPermutation`
+/// is true, to avoid needing to assert it repeatedly.
+class MLIR_SPARSETENSOR_GSL_POINTER [[nodiscard]] PermutationRef final {
+public:
+  /// Asserts `isPermutation` and returns the witness to that being true.
+  //
+  // TODO: For now the assertive ctor is sufficient, but in principle
+  // we'll want a factory that can optionally construct the object
+  // (so callers can handle errors themselves).
+  explicit PermutationRef(uint64_t size, const uint64_t *perm)
+      : permSize(size), perm(perm) {
+    assertIsPermutation(size, perm);
+  }
+
+  uint64_t size() const { return permSize; }
+
+  const uint64_t *data() const { return perm; }
+
+  const uint64_t &operator[](uint64_t i) const {
+    assert(i < permSize && "index is out of bounds");
+    return perm[i];
+  }
+
+  /// Constructs a pushforward array of values.  This method is the inverse
+  /// of `permute` in the sense that for all `p` and `xs` we have:
+  /// * `p.permute(p.pushforward(xs)) == xs`
+  /// * `p.pushforward(p.permute(xs)) == xs`
+  template <typename T>
+  inline std::vector<T> pushforward(const std::vector<T> &values) const {
+    return pushforward(values.size(), values.data());
+  }
+
+  template <typename T>
+  inline std::vector<T> pushforward(uint64_t size, const T *values) const {
+    std::vector<T> out(permSize);
+    pushforward(size, values, out.data());
+    return out;
+  }
+
+  // NOTE: This form of the method is required by `toMLIRSparseTensor`,
+  // so it can reuse the `out` buffer for each iteration of a loop.
+  template <typename T>
+  inline void pushforward(uint64_t size, const T *values, T *out) const {
+    assert(size == permSize && "size mismatch");
+    for (uint64_t i = 0; i < permSize; ++i)
+      out[perm[i]] = values[i];
+  }
+
+  // NOTE: this is only needed by `toMLIRSparseTensor`, which in
+  // turn only needs it as a vector to hand off to `newSparseTensor`.
+  // Otherwise we would want the result to be an owning-permutation,
+  // to retain the knowledge that `isPermutation` is true.
+  //
+  /// Constructs the inverse permutation.  This is equivalent to calling
+  /// `pushforward` with `std::iota` for the values.
+  std::vector<uint64_t> inverse() const;
+
+  /// Constructs a permuted array of values.  This method is the inverse
+  /// of `pushforward` in the sense that for all `p` and `xs` we have:
+  /// * `p.permute(p.pushforward(xs)) == xs`
+  /// * `p.pushforward(p.permute(xs)) == xs`
+  template <typename T>
+  inline std::vector<T> permute(const std::vector<T> &values) const {
+    return permute(values.size(), values.data());
+  }
+
+  template <typename T>
+  inline std::vector<T> permute(uint64_t size, const T *values) const {
+    std::vector<T> out(permSize);
+    permute(size, values, out.data());
+    return out;
+  }
+
+  template <typename T>
+  inline void permute(uint64_t size, const T *values, T *out) const {
+    assert(size == permSize && "size mismatch");
+    for (uint64_t i = 0; i < permSize; ++i)
+      out[i] = values[perm[i]];
+  }
+
+private:
+  const uint64_t permSize;
+  const uint64_t *const perm; // non-owning pointer.
+};
+
+} // namespace detail
+} // namespace sparse_tensor
+} // namespace mlir
+
+#endif // MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H

diff  --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
index 4e995cbcf0f0f9..ff61a0d035a2f1 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
@@ -36,133 +36,13 @@
 #include "mlir/Dialect/SparseTensor/IR/Enums.h"
 #include "mlir/ExecutionEngine/Float16bits.h"
 #include "mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h"
+#include "mlir/ExecutionEngine/SparseTensor/Attributes.h"
 #include "mlir/ExecutionEngine/SparseTensor/COO.h"
 #include "mlir/ExecutionEngine/SparseTensor/ErrorHandling.h"
 
-#if defined(__cplusplus) && defined(__has_cpp_attribute) &&                    \
-    __has_cpp_attribute(gsl::Pointer)
-#define MLIR_SPARSETENSOR_GSL_POINTER [[gsl::Pointer]]
-#else
-#define MLIR_SPARSETENSOR_GSL_POINTER
-#endif
-
 namespace mlir {
 namespace sparse_tensor {
 
-namespace detail {
-
-/// Checks whether the `perm` array is a permutation of `[0 .. size)`.
-inline bool isPermutation(uint64_t size, const uint64_t *perm) {
-  assert(perm && "Got nullptr for permutation");
-  std::vector<bool> seen(size, false);
-  for (uint64_t i = 0; i < size; ++i) {
-    const uint64_t j = perm[i];
-    if (j >= size || seen[j])
-      return false;
-    seen[j] = true;
-  }
-  for (uint64_t i = 0; i < size; ++i)
-    if (!seen[i])
-      return false;
-  return true;
-}
-
-/// Wrapper around `isPermutation` to ensure consistent error messages.
-inline void assertIsPermutation(uint64_t size, const uint64_t *perm) {
-#ifndef NDEBUG
-  if (!isPermutation(size, perm))
-    MLIR_SPARSETENSOR_FATAL("Not a permutation of [0..%" PRIu64 ")\n", size);
-#endif
-}
-
-/// A non-owning class for capturing the knowledge that `isPermutation`
-/// is true, to avoid needing to assert it repeatedly.
-class MLIR_SPARSETENSOR_GSL_POINTER [[nodiscard]] PermutationRef final {
-public:
-  /// Asserts `isPermutation` and returns the witness to that being true.
-  explicit PermutationRef(uint64_t size, const uint64_t *perm)
-      : permSize(size), perm(perm) {
-    assertIsPermutation(size, perm);
-  }
-
-  uint64_t size() const { return permSize; }
-
-  const uint64_t *data() const { return perm; }
-
-  const uint64_t &operator[](uint64_t i) const {
-    assert(i < permSize && "index is out of bounds");
-    return perm[i];
-  }
-
-  /// Constructs a pushforward array of values.  This method is the inverse
-  /// of `permute` in the sense that for all `p` and `xs` we have:
-  /// * `p.permute(p.pushforward(xs)) == xs`
-  /// * `p.pushforward(p.permute(xs)) == xs`
-  template <typename T>
-  inline std::vector<T> pushforward(const std::vector<T> &values) const {
-    return pushforward(values.size(), values.data());
-  }
-
-  template <typename T>
-  inline std::vector<T> pushforward(uint64_t size, const T *values) const {
-    std::vector<T> out(permSize);
-    pushforward(size, values, out.data());
-    return out;
-  }
-
-  // NOTE: This form of the method is required by `toMLIRSparseTensor`,
-  // so it can reuse the `out` buffer for each iteration of a loop.
-  template <typename T>
-  inline void pushforward(uint64_t size, const T *values, T *out) const {
-    assert(size == permSize && "size mismatch");
-    for (uint64_t i = 0; i < permSize; ++i)
-      out[perm[i]] = values[i];
-  }
-
-  // NOTE: this is only needed by `toMLIRSparseTensor`, which in
-  // turn only needs it as a vector to hand off to `newSparseTensor`.
-  // Otherwise we would want the result to be an owning-permutation,
-  // to retain the knowledge that `isPermutation` is true.
-  //
-  /// Constructs the inverse permutation.  This is equivalent to calling
-  /// `pushforward` with `std::iota` for the values.
-  inline std::vector<uint64_t> inverse() const {
-    std::vector<uint64_t> out(permSize);
-    for (uint64_t i = 0; i < permSize; ++i)
-      out[perm[i]] = i;
-    return out;
-  }
-
-  /// Constructs a permuted array of values.  This method is the inverse
-  /// of `pushforward` in the sense that for all `p` and `xs` we have:
-  /// * `p.permute(p.pushforward(xs)) == xs`
-  /// * `p.pushforward(p.permute(xs)) == xs`
-  template <typename T>
-  inline std::vector<T> permute(const std::vector<T> &values) const {
-    return permute(values.size(), values.data());
-  }
-
-  template <typename T>
-  inline std::vector<T> permute(uint64_t size, const T *values) const {
-    std::vector<T> out(permSize);
-    permute(size, values, out.data());
-    return out;
-  }
-
-  template <typename T>
-  inline void permute(uint64_t size, const T *values, T *out) const {
-    assert(size == permSize && "size mismatch");
-    for (uint64_t i = 0; i < permSize; ++i)
-      out[i] = values[perm[i]];
-  }
-
-private:
-  const uint64_t permSize;
-  const uint64_t *const perm; // non-owning pointer.
-};
-
-} // namespace detail
-
 //===----------------------------------------------------------------------===//
 // This forward decl is sufficient to split `SparseTensorStorageBase` into
 // its own header, but isn't sufficient for `SparseTensorStorage` to join it.
@@ -662,6 +542,8 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
   /// the previous position and smaller than `coordinates[lvl].capacity()`).
   void appendPos(uint64_t lvl, uint64_t pos, uint64_t count = 1) {
     ASSERT_COMPRESSED_LVL(lvl);
+    // TODO: we'd like to recover the nicer error message:
+    // "Position value is too large for the P-type"
     positions[lvl].insert(positions[lvl].end(), count,
                           detail::checkOverflowCast<P>(pos));
   }
@@ -678,6 +560,8 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
   void appendCrd(uint64_t lvl, uint64_t full, uint64_t crd) {
     const auto dlt = getLvlType(lvl); // Avoid redundant bounds checking.
     if (isCompressedDLT(dlt) || isSingletonDLT(dlt)) {
+      // TODO: we'd like to recover the nicer error message:
+      // "Coordinate value is too large for the C-type"
       coordinates[lvl].push_back(detail::checkOverflowCast<C>(crd));
     } else { // Dense level.
       ASSERT_DENSE_DLT(dlt);
@@ -701,6 +585,8 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
     // entry has been initialized; thus we must be sure to check `size()`
     // here, instead of `capacity()` as would be ideal.
     assert(pos < coordinates[lvl].size() && "Position is out of bounds");
+    // TODO: we'd like to recover the nicer error message:
+    // "Coordinate value is too large for the C-type"
     coordinates[lvl][pos] = detail::checkOverflowCast<C>(crd);
   }
 

diff  --git a/mlir/lib/ExecutionEngine/SparseTensor/CMakeLists.txt b/mlir/lib/ExecutionEngine/SparseTensor/CMakeLists.txt
index 085d83634a702a..ac04ef31423e27 100644
--- a/mlir/lib/ExecutionEngine/SparseTensor/CMakeLists.txt
+++ b/mlir/lib/ExecutionEngine/SparseTensor/CMakeLists.txt
@@ -8,6 +8,7 @@
 add_mlir_library(MLIRSparseTensorRuntime
   File.cpp
   NNZ.cpp
+  PermutationRef.cpp
   Storage.cpp
 
   EXCLUDE_FROM_LIBMLIR
@@ -18,6 +19,8 @@ add_mlir_library(MLIRSparseTensorRuntime
   )
 set_property(TARGET MLIRSparseTensorRuntime PROPERTY CXX_STANDARD 17)
 
+# To make sure we adhere to the style guide:
+# <https://llvm.org/docs/CodingStandards.html#provide-a-virtual-method-anchor-for-classes-in-headers>
 check_cxx_compiler_flag(-Wweak-vtables
   COMPILER_SUPPORTS_WARNING_WEAK_VTABLES)
 if(COMPILER_SUPPORTS_WARNING_WEAK_VTABLES)

diff  --git a/mlir/lib/ExecutionEngine/SparseTensor/PermutationRef.cpp b/mlir/lib/ExecutionEngine/SparseTensor/PermutationRef.cpp
new file mode 100644
index 00000000000000..0230095ec8ca48
--- /dev/null
+++ b/mlir/lib/ExecutionEngine/SparseTensor/PermutationRef.cpp
@@ -0,0 +1,38 @@
+//===- PermutationRef.cpp - Permutation reference wrapper -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/ExecutionEngine/SparseTensor/PermutationRef.h"
+
+#include <cassert>
+#include <cinttypes>
+#include <vector>
+
+bool mlir::sparse_tensor::detail::isPermutation(uint64_t size,
+                                                const uint64_t *perm) {
+  assert(perm && "Got nullptr for permutation");
+  // TODO: If we ever depend on LLVMSupport, then use `llvm::BitVector` instead.
+  std::vector<bool> seen(size, false);
+  for (uint64_t i = 0; i < size; ++i) {
+    const uint64_t j = perm[i];
+    if (j >= size || seen[j])
+      return false;
+    seen[j] = true;
+  }
+  for (uint64_t i = 0; i < size; ++i)
+    if (!seen[i])
+      return false;
+  return true;
+}
+
+std::vector<uint64_t>
+mlir::sparse_tensor::detail::PermutationRef::inverse() const {
+  std::vector<uint64_t> out(permSize);
+  for (uint64_t i = 0; i < permSize; ++i)
+    out[perm[i]] = i;
+  return out;
+}

diff  --git a/mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp b/mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp
index d76a34564c47a4..ef68ae293e61cf 100644
--- a/mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp
+++ b/mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp
@@ -54,6 +54,7 @@
 #include "mlir/ExecutionEngine/SparseTensor/COO.h"
 #include "mlir/ExecutionEngine/SparseTensor/ErrorHandling.h"
 #include "mlir/ExecutionEngine/SparseTensor/File.h"
+#include "mlir/ExecutionEngine/SparseTensor/PermutationRef.h"
 #include "mlir/ExecutionEngine/SparseTensor/Storage.h"
 
 #include <cstring>

diff  --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
index 630fb1988bb08d..dac68a7049b350 100644
--- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
@@ -8519,13 +8519,16 @@ cc_library(
     srcs = [
         "lib/ExecutionEngine/SparseTensor/File.cpp",
         "lib/ExecutionEngine/SparseTensor/NNZ.cpp",
+        "lib/ExecutionEngine/SparseTensor/PermutationRef.cpp",
         "lib/ExecutionEngine/SparseTensor/Storage.cpp",
     ],
     hdrs = [
         "include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h",
+        "include/mlir/ExecutionEngine/SparseTensor/Attributes.h",
         "include/mlir/ExecutionEngine/SparseTensor/COO.h",
         "include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h",
         "include/mlir/ExecutionEngine/SparseTensor/File.h",
+        "include/mlir/ExecutionEngine/SparseTensor/PermutationRef.h",
         "include/mlir/ExecutionEngine/SparseTensor/Storage.h",
     ],
     includes = ["include"],


        


More information about the Mlir-commits mailing list