Skip to content

Commit 471004c

Browse files
committed
Revert "[mlir][sparse] simplification of sparse runtime support lib"
This reverts commit 14c58cf. The gcc7 build is broken.
1 parent dd7429a commit 471004c

File tree

10 files changed

+320
-124
lines changed

10 files changed

+320
-124
lines changed

mlir/include/mlir/ExecutionEngine/SparseTensor/ArithmeticUtils.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,23 @@
66
//
77
//===----------------------------------------------------------------------===//
88
//
9-
// A collection of "safe" arithmetic helper methods.
9+
// This header is not part of the public API. It is placed in the
10+
// includes directory only because that's required by the implementations
11+
// of template-classes.
12+
//
13+
// This file is part of the lightweight runtime support library for sparse
14+
// tensor manipulations. The functionality of the support library is meant
15+
// to simplify benchmarking, testing, and debugging MLIR code operating on
16+
// sparse tensors. However, the provided functionality is **not** part of
17+
// core MLIR itself.
1018
//
1119
//===----------------------------------------------------------------------===//
1220

1321
#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ARITHMETICUTILS_H
1422
#define MLIR_EXECUTIONENGINE_SPARSETENSOR_ARITHMETICUTILS_H
1523

24+
#include "mlir/ExecutionEngine/SparseTensor/Attributes.h"
25+
1626
#include <cassert>
1727
#include <cinttypes>
1828
#include <limits>
@@ -98,6 +108,12 @@ constexpr bool safelyGE(T t, U u) noexcept {
98108
//
99109
//===----------------------------------------------------------------------===//
100110

111+
// TODO: we would like to be able to pass in custom error messages, to
112+
// improve the user experience. We should be able to use something like
113+
// `assert(((void)(msg ? msg : defaultMsg), cond))`; but I'm not entirely
114+
// sure that'll work as intended when done within a function-definition
115+
// rather than within a macro-definition.
116+
101117
/// A version of `static_cast<To>` which checks for overflow/underflow.
102118
/// The implementation avoids performing runtime assertions whenever
103119
/// the types alone are sufficient to statically prove that overflow
@@ -124,8 +140,7 @@ inline uint64_t checkedMul(uint64_t lhs, uint64_t rhs) {
124140
// If assertions are enabled and we have the intrinsic, then use it to
125141
// avoid the expensive division. If assertions are disabled, then don't
126142
// bother with intrinsics (to avoid any possible slowdown vs `operator*`).
127-
#if !defined(NDEBUG) && defined(__has_builtin) && \
128-
__has_builtin(__builtin_mul_overflow)
143+
#if !defined(NDEBUG) && MLIR_SPARSETENSOR_HAS_BUILTIN(__builtin_mul_overflow)
129144
uint64_t result;
130145
bool overflowed = __builtin_mul_overflow(lhs, rhs, &result);
131146
assert(!overflowed && "Integer overflow");
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===- Attributes.h - C++ attributes for SparseTensorRuntime ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This header defines various macros for using C++ attributes whenever
10+
// they're supported by the compiler. These macros are the same as the
11+
// versions in the LLVMSupport library, but we define our own versions
12+
// in order to avoid introducing that dependency just for the sake of
13+
// these macros. (If we ever do end up depending on LLVMSupport, then
14+
// we should remove this header and use "llvm/Support/Compiler.h" instead.)
15+
//
16+
// This file is part of the lightweight runtime support library for sparse
17+
// tensor manipulations. The functionality of the support library is meant
18+
// to simplify benchmarking, testing, and debugging MLIR code operating on
19+
// sparse tensors. However, the provided functionality is **not** part of
20+
// core MLIR itself.
21+
//
22+
//===----------------------------------------------------------------------===//
23+
24+
#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H
25+
#define MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H
26+
27+
// A wrapper around `__has_cpp_attribute` for C++11 style attributes,
28+
// which are defined by ISO C++ SD-6.
29+
// <https://en.cppreference.com/w/cpp/experimental/feature_test>
30+
#if defined(__cplusplus) && defined(__has_cpp_attribute)
31+
// NOTE: The __cplusplus requirement should be unnecessary, but guards
32+
// against issues with GCC <https://bugs.llvm.org/show_bug.cgi?id=23435>.
33+
#define MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
34+
#else
35+
#define MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(x) 0
36+
#endif
37+
38+
// A wrapper around `__has_attribute`, which is defined by GCC 5+ and Clang.
39+
// GCC: <https://gcc.gnu.org/gcc-5/changes.html>
40+
// Clang: <https://clang.llvm.org/docs/LanguageExtensions.html>
41+
#ifdef __has_attribute
42+
#define MLIR_SPARSETENSOR_HAS_ATTRIBUTE(x) __has_attribute(x)
43+
#else
44+
#define MLIR_SPARSETENSOR_HAS_ATTRIBUTE(x) 0
45+
#endif
46+
47+
// A wrapper around `__has_builtin`, which is defined by GCC and Clang
48+
// but is missing on some versions of MSVC.
49+
// GCC: <https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fbuiltin.html>
50+
// Clang: <https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin>
51+
#ifdef __has_builtin
52+
#define MLIR_SPARSETENSOR_HAS_BUILTIN(x) __has_builtin(x)
53+
#else
54+
#define MLIR_SPARSETENSOR_HAS_BUILTIN(x) 0
55+
#endif
56+
57+
// An attribute for non-owning classes (like `PermutationRef`) to enable
58+
// lifetime warnings.
59+
#if MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(gsl::Pointer)
60+
#define MLIR_SPARSETENSOR_GSL_POINTER [[gsl::Pointer]]
61+
#else
62+
#define MLIR_SPARSETENSOR_GSL_POINTER
63+
#endif
64+
65+
// An attribute for functions which are "pure" in the following sense:
66+
// * the result depends only on the function arguments
67+
// * pointer arguments are allowed to be read from, but not written to
68+
// * has no observable effects other than the return value
69+
//
70+
// This allows the compiler to avoid repeated function calls whenever
71+
// it can determine that the arguments are the same and that memory has
72+
// not changed.
73+
//
74+
// This macro is called `LLVM_READONLY` by LLVMSupport. This definition
75+
// differs slightly from the LLVM version by using `gnu::pure` when
76+
// available, like Abseil's `ABSL_ATTRIBUTE_PURE_FUNCTION`.
77+
#if MLIR_SPARSETENSOR_HAS_CPP_ATTRIBUTE(gnu::pure)
78+
#define MLIR_SPARSETENSOR_PURE [[gnu::pure]]
79+
#elif MLIR_SPARSETENSOR_HAS_ATTRIBUTE(pure) || defined(__GNUC__)
80+
#define MLIR_SPARSETENSOR_PURE __attribute__((pure))
81+
#else
82+
#define MLIR_SPARSETENSOR_PURE
83+
#endif
84+
85+
#endif // MLIR_EXECUTIONENGINE_SPARSETENSOR_ATTRIBUTES_H

mlir/include/mlir/ExecutionEngine/SparseTensor/ErrorHandling.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,20 @@
66
//
77
//===----------------------------------------------------------------------===//
88
//
9+
// This header is not part of the public API. It is placed in the
10+
// includes directory only because that's required by the implementations
11+
// of template-classes.
12+
//
913
// This file defines an extremely lightweight API for fatal errors (not
1014
// arising from assertions). The API does not attempt to be sophisticated
1115
// in any way, it's just the usual "I give up" style of error reporting.
1216
//
17+
// This file is part of the lightweight runtime support library for sparse
18+
// tensor manipulations. The functionality of the support library is meant
19+
// to simplify benchmarking, testing, and debugging MLIR code operating on
20+
// sparse tensors. However, the provided functionality is **not** part of
21+
// core MLIR itself.
22+
//
1323
//===----------------------------------------------------------------------===//
1424

1525
#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_ERRORHANDLING_H

mlir/include/mlir/ExecutionEngine/SparseTensor/File.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@
1515
// (2) Formidable Repository of Open Sparse Tensors and Tools (FROSTT): *.tns
1616
// http://frostt.io/tensors/file-formats.html
1717
//
18+
// This file is part of the lightweight runtime support library for sparse
19+
// tensor manipulations. The functionality of the support library is meant
20+
// to simplify benchmarking, testing, and debugging MLIR code operating on
21+
// sparse tensors. However, the provided functionality is **not** part of
22+
// core MLIR itself.
23+
//
1824
//===----------------------------------------------------------------------===//
1925

2026
#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_FILE_H
2127
#define MLIR_EXECUTIONENGINE_SPARSETENSOR_FILE_H
2228

29+
#include "mlir/ExecutionEngine/SparseTensor/PermutationRef.h"
2330
#include "mlir/ExecutionEngine/SparseTensor/Storage.h"
2431

2532
#include <fstream>
@@ -77,6 +84,13 @@ inline V readValue(char **linePtr, bool isPattern) {
7784

7885
//===----------------------------------------------------------------------===//
7986

87+
// TODO: benchmark whether to keep various methods inline vs moving them
88+
// off to the cpp file.
89+
90+
// TODO: consider distinguishing separate classes for before vs
91+
// after reading the header; so as to statically avoid the need
92+
// to `assert(isValid())`.
93+
8094
/// This class abstracts over the information stored in file headers,
8195
/// as well as providing the buffers and methods for parsing those headers.
8296
class SparseTensorReader final {
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//===- PermutationRef.h - Permutation reference wrapper ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This header is not part of the public API. It is placed in the
10+
// includes directory only because that's required by the implementations
11+
// of template-classes.
12+
//
13+
// This file is part of the lightweight runtime support library for sparse
14+
// tensor manipulations. The functionality of the support library is meant
15+
// to simplify benchmarking, testing, and debugging MLIR code operating on
16+
// sparse tensors. However, the provided functionality is **not** part of
17+
// core MLIR itself.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H
22+
#define MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H
23+
24+
#include "mlir/ExecutionEngine/SparseTensor/Attributes.h"
25+
#include "mlir/ExecutionEngine/SparseTensor/ErrorHandling.h"
26+
27+
#include <cassert>
28+
#include <cinttypes>
29+
#include <vector>
30+
31+
namespace mlir {
32+
namespace sparse_tensor {
33+
namespace detail {
34+
35+
/// Checks whether the `perm` array is a permutation of `[0 .. size)`.
36+
MLIR_SPARSETENSOR_PURE bool isPermutation(uint64_t size, const uint64_t *perm);
37+
38+
/// Wrapper around `isPermutation` to ensure consistent error messages.
39+
inline void assertIsPermutation(uint64_t size, const uint64_t *perm) {
40+
#ifndef NDEBUG
41+
if (!isPermutation(size, perm))
42+
MLIR_SPARSETENSOR_FATAL("Not a permutation of [0..%" PRIu64 ")\n", size);
43+
#endif
44+
}
45+
46+
// TODO: To implement things like `inverse` and `compose` while preserving
47+
// the knowledge that `isPermutation` is true, we'll need to also have
48+
// an owning version of `PermutationRef`. (Though ideally we'll really
49+
// want to defunctionalize those methods so that we can avoid intermediate
50+
// arrays/copies and only materialize the data on request.)
51+
52+
/// A non-owning class for capturing the knowledge that `isPermutation`
53+
/// is true, to avoid needing to assert it repeatedly.
54+
class MLIR_SPARSETENSOR_GSL_POINTER [[nodiscard]] PermutationRef final {
55+
public:
56+
/// Asserts `isPermutation` and returns the witness to that being true.
57+
//
58+
// TODO: For now the assertive ctor is sufficient, but in principle
59+
// we'll want a factory that can optionally construct the object
60+
// (so callers can handle errors themselves).
61+
explicit PermutationRef(uint64_t size, const uint64_t *perm)
62+
: permSize(size), perm(perm) {
63+
assertIsPermutation(size, perm);
64+
}
65+
66+
uint64_t size() const { return permSize; }
67+
68+
const uint64_t *data() const { return perm; }
69+
70+
const uint64_t &operator[](uint64_t i) const {
71+
assert(i < permSize && "index is out of bounds");
72+
return perm[i];
73+
}
74+
75+
/// Constructs a pushforward array of values. This method is the inverse
76+
/// of `permute` in the sense that for all `p` and `xs` we have:
77+
/// * `p.permute(p.pushforward(xs)) == xs`
78+
/// * `p.pushforward(p.permute(xs)) == xs`
79+
template <typename T>
80+
inline std::vector<T> pushforward(const std::vector<T> &values) const {
81+
return pushforward(values.size(), values.data());
82+
}
83+
84+
template <typename T>
85+
inline std::vector<T> pushforward(uint64_t size, const T *values) const {
86+
std::vector<T> out(permSize);
87+
pushforward(size, values, out.data());
88+
return out;
89+
}
90+
91+
// NOTE: This form of the method is required by `toMLIRSparseTensor`,
92+
// so it can reuse the `out` buffer for each iteration of a loop.
93+
template <typename T>
94+
inline void pushforward(uint64_t size, const T *values, T *out) const {
95+
assert(size == permSize && "size mismatch");
96+
for (uint64_t i = 0; i < permSize; ++i)
97+
out[perm[i]] = values[i];
98+
}
99+
100+
// NOTE: this is only needed by `toMLIRSparseTensor`, which in
101+
// turn only needs it as a vector to hand off to `newSparseTensor`.
102+
// Otherwise we would want the result to be an owning-permutation,
103+
// to retain the knowledge that `isPermutation` is true.
104+
//
105+
/// Constructs the inverse permutation. This is equivalent to calling
106+
/// `pushforward` with `std::iota` for the values.
107+
std::vector<uint64_t> inverse() const;
108+
109+
/// Constructs a permuted array of values. This method is the inverse
110+
/// of `pushforward` in the sense that for all `p` and `xs` we have:
111+
/// * `p.permute(p.pushforward(xs)) == xs`
112+
/// * `p.pushforward(p.permute(xs)) == xs`
113+
template <typename T>
114+
inline std::vector<T> permute(const std::vector<T> &values) const {
115+
return permute(values.size(), values.data());
116+
}
117+
118+
template <typename T>
119+
inline std::vector<T> permute(uint64_t size, const T *values) const {
120+
std::vector<T> out(permSize);
121+
permute(size, values, out.data());
122+
return out;
123+
}
124+
125+
template <typename T>
126+
inline void permute(uint64_t size, const T *values, T *out) const {
127+
assert(size == permSize && "size mismatch");
128+
for (uint64_t i = 0; i < permSize; ++i)
129+
out[i] = values[perm[i]];
130+
}
131+
132+
private:
133+
const uint64_t permSize;
134+
const uint64_t *const perm; // non-owning pointer.
135+
};
136+
137+
} // namespace detail
138+
} // namespace sparse_tensor
139+
} // namespace mlir
140+
141+
#endif // MLIR_EXECUTIONENGINE_SPARSETENSOR_PERMUTATIONREF_H

0 commit comments

Comments
 (0)