Program Listing for File base_details.h#
↰ Return to documentation for file (tvm/ffi/base_details.h
)
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef TVM_FFI_BASE_DETAILS_H_
#define TVM_FFI_BASE_DETAILS_H_
#include <tvm/ffi/c_api.h>
#include <tvm/ffi/endian.h>
#include <cstddef>
#include <utility>
#if defined(_MSC_VER)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#ifdef ERROR
#undef ERROR
#endif
#endif
#if defined(_MSC_VER)
#define TVM_FFI_INLINE [[msvc::forceinline]] inline
#else
#define TVM_FFI_INLINE [[gnu::always_inline]] inline
#endif
#if defined(_MSC_VER)
#define TVM_FFI_NO_INLINE [[msvc::noinline]]
#else
#define TVM_FFI_NO_INLINE [[gnu::noinline]]
#endif
#if defined(_MSC_VER)
#define TVM_FFI_UNREACHABLE() __assume(false)
#else
#define TVM_FFI_UNREACHABLE() __builtin_unreachable()
#endif
#define TVM_FFI_STR_CONCAT_(__x, __y) __x##__y
#define TVM_FFI_STR_CONCAT(__x, __y) TVM_FFI_STR_CONCAT_(__x, __y)
#if defined(__GNUC__) || defined(__clang__)
#define TVM_FFI_FUNC_SIG __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define TVM_FFI_FUNC_SIG __FUNCSIG__
#else
#define TVM_FFI_FUNC_SIG __func__
#endif
#if defined(__GNUC__)
// gcc and clang and attribute constructor
#define TVM_FFI_STATIC_INIT_BLOCK_DEF_(FnName) __attribute__((constructor)) static void FnName()
/*
* \brief Macro that defines a block that will be called during static initialization.
*
* \code
* TVM_FFI_STATIC_INIT_BLOCK() {
* RegisterFunctions();
* }
* \endcode
*/
#define TVM_FFI_STATIC_INIT_BLOCK() \
TVM_FFI_STATIC_INIT_BLOCK_DEF_(TVM_FFI_STR_CONCAT(__TVMFFIStaticInitFunc, __COUNTER__))
#else
// for other compilers, use the variable trick
#define TVM_FFI_STATIC_INIT_BLOCK_DEF_(FnName, RegVar) \
static void FnName(); \
[[maybe_unused]] static inline int RegVar = []() { \
FnName(); \
return 0; \
}(); \
static void FnName()
#define TVM_FFI_STATIC_INIT_BLOCK() \
TVM_FFI_STATIC_INIT_BLOCK_DEF_(TVM_FFI_STR_CONCAT(__TVMFFIStaticInitFunc, __COUNTER__), \
TVM_FFI_STR_CONCAT(__TVMFFIStaticInitReg, __COUNTER__))
#endif
/*
* \brief Define the default copy/move constructor and assign operator
* \param TypeName The class typename.
*/
#define TVM_FFI_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName) \
TypeName(const TypeName& other) = default; \
TypeName(TypeName&& other) = default; \
TypeName& operator=(const TypeName& other) = default; \
TypeName& operator=(TypeName&& other) = default;
#define TVM_FFI_LOG_EXCEPTION_CALL_BEGIN() \
try { \
(void)0
#define TVM_FFI_LOG_EXCEPTION_CALL_END(Name) \
} \
catch (const std::exception& err) { \
std::cerr << "Exception caught during " << #Name << ":\n" << err.what() << std::endl; \
exit(-1); \
}
#define TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result) \
if constexpr (sizeof((result)->v_obj) != sizeof((result)->v_int64)) { \
(result)->v_int64 = 0; \
}
namespace tvm {
namespace ffi {
namespace details {
// for each iterator
struct for_each_dispatcher {
template <typename F, typename... Args, size_t... I>
static void run(std::index_sequence<I...>, const F& f, Args&&... args) { // NOLINT(*)
(f(I, std::forward<Args>(args)), ...);
}
};
template <typename F, typename... Args>
void for_each(const F& f, Args&&... args) { // NOLINT(*)
for_each_dispatcher::run(std::index_sequence_for<Args...>{}, f, std::forward<Args>(args)...);
}
template <typename T, std::enable_if_t<std::is_convertible<T, uint64_t>::value, bool> = true>
TVM_FFI_INLINE uint64_t StableHashCombine(uint64_t key, const T& value) {
// XXX: do not use std::hash in this function. This hash must be stable
// across different platforms and std::hash is implementation dependent.
return key ^ (uint64_t(value) + 0x9e3779b9 + (key << 6) + (key >> 2));
}
TVM_FFI_INLINE uint64_t StableHashBytes(const void* data_ptr, size_t size) {
const char* data = reinterpret_cast<const char*>(data_ptr);
const constexpr uint64_t kMultiplier = 1099511628211ULL;
const constexpr uint64_t kMod = 2147483647ULL;
union Union {
uint8_t a[8];
uint64_t b;
} u;
static_assert(sizeof(Union) == sizeof(uint64_t), "sizeof(Union) != sizeof(uint64_t)");
const char* it = data;
const char* end = it + size;
uint64_t result = 0;
if constexpr (TVM_FFI_IO_NO_ENDIAN_SWAP) {
// if alignment requirement is met, directly use load
if (reinterpret_cast<uintptr_t>(it) % 8 == 0) {
for (; it + 8 <= end; it += 8) {
u.b = *reinterpret_cast<const uint64_t*>(it);
result = (result * kMultiplier + u.b) % kMod;
}
} else {
// unaligned version
for (; it + 8 <= end; it += 8) {
u.a[0] = it[0];
u.a[1] = it[1];
u.a[2] = it[2];
u.a[3] = it[3];
u.a[4] = it[4];
u.a[5] = it[5];
u.a[6] = it[6];
u.a[7] = it[7];
result = (result * kMultiplier + u.b) % kMod;
}
}
} else {
// need endian swap
for (; it + 8 <= end; it += 8) {
u.a[0] = it[7];
u.a[1] = it[6];
u.a[2] = it[5];
u.a[3] = it[4];
u.a[4] = it[3];
u.a[5] = it[2];
u.a[6] = it[1];
u.a[7] = it[0];
result = (result * kMultiplier + u.b) % kMod;
}
}
if (it < end) {
u.b = 0;
uint8_t* a = u.a;
if (it + 4 <= end) {
a[0] = it[0];
a[1] = it[1];
a[2] = it[2];
a[3] = it[3];
it += 4;
a += 4;
}
if (it + 2 <= end) {
a[0] = it[0];
a[1] = it[1];
it += 2;
a += 2;
}
if (it + 1 <= end) {
a[0] = it[0];
it += 1;
a += 1;
}
if constexpr (!TVM_FFI_IO_NO_ENDIAN_SWAP) {
std::swap(u.a[0], u.a[7]);
std::swap(u.a[1], u.a[6]);
std::swap(u.a[2], u.a[5]);
std::swap(u.a[3], u.a[4]);
}
result = (result * kMultiplier + u.b) % kMod;
}
return result;
}
TVM_FFI_INLINE uint64_t StableHashSmallStrBytes(const TVMFFIAny* data) {
if constexpr (TVM_FFI_IO_NO_ENDIAN_SWAP) {
// fast path, no endian swap, simply hash as uint64_t
const constexpr uint64_t kMod = 2147483647ULL;
return data->v_uint64 % kMod;
}
return StableHashBytes(reinterpret_cast<const void*>(data), sizeof(data->v_uint64));
}
} // namespace details
} // namespace ffi
} // namespace tvm
#endif // TVM_FFI_BASE_DETAILS_H_