@@ -0,0 +1,388 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
#include <cute/container/tuple.hpp>
|
||||
#include <cute/numeric/integral_constant.hpp>
|
||||
#include <cute/algorithm/functional.hpp>
|
||||
#include <cute/algorithm/tuple_algorithms.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
template <class... T>
|
||||
struct ArithmeticTuple : tuple<T...>
|
||||
{
|
||||
template <class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithmeticTuple(ArithmeticTuple<U...> const& u)
|
||||
: tuple<T...>(static_cast<tuple<U...> const&>(u)) {}
|
||||
|
||||
template <class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithmeticTuple(tuple<U...> const& u)
|
||||
: tuple<T...>(u) {}
|
||||
|
||||
template <class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithmeticTuple(U const&... u)
|
||||
: tuple<T...>(u...) {}
|
||||
};
|
||||
|
||||
template <class... T>
|
||||
struct is_tuple<ArithmeticTuple<T...>> : true_type {};
|
||||
|
||||
template <class... T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
make_arithmetic_tuple(T const&... t) {
|
||||
return ArithmeticTuple<T...>(t...);
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
as_arithmetic_tuple(tuple<T...> const& t) {
|
||||
return ArithmeticTuple<T...>(t);
|
||||
}
|
||||
|
||||
//
|
||||
// Numeric operators
|
||||
//
|
||||
|
||||
// Addition
|
||||
template <class... T, class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ArithmeticTuple<T...> const& t, ArithmeticTuple<U...> const& u) {
|
||||
constexpr int R = cute::max(int(sizeof...(T)), int(sizeof...(U)));
|
||||
return transform_apply(append<R>(t,Int<0>{}), append<R>(u,Int<0>{}), plus{}, [](auto const&... a){ return make_arithmetic_tuple(a...); });
|
||||
}
|
||||
|
||||
template <class... T, class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ArithmeticTuple<T...> const& t, tuple<U...> const& u) {
|
||||
constexpr int R = cute::max(int(sizeof...(T)), int(sizeof...(U)));
|
||||
return transform_apply(append<R>(t,Int<0>{}), append<R>(u,Int<0>{}), plus{}, [](auto const&... a){ return make_arithmetic_tuple(a...); });
|
||||
}
|
||||
|
||||
template <class... T, class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(tuple<T...> const& t, ArithmeticTuple<U...> const& u) {
|
||||
constexpr int R = cute::max(int(sizeof...(T)), int(sizeof...(U)));
|
||||
return transform_apply(append<R>(t,Int<0>{}), append<R>(u,Int<0>{}), plus{}, [](auto const&... a){ return make_arithmetic_tuple(a...); });
|
||||
}
|
||||
|
||||
//
|
||||
// Special cases
|
||||
//
|
||||
|
||||
template <class T, class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(constant<T,0>, ArithmeticTuple<U...> const& u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
template <class... T, class U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ArithmeticTuple<T...> const& t, constant<U,0>) {
|
||||
return t;
|
||||
}
|
||||
|
||||
//
|
||||
// ArithmeticTupleIterator
|
||||
//
|
||||
|
||||
template <class ArithTuple>
|
||||
struct ArithmeticTupleIterator
|
||||
{
|
||||
ArithTuple coord_;
|
||||
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithmeticTupleIterator() : coord_() {}
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithmeticTupleIterator(ArithTuple const& coord) : coord_(coord) {}
|
||||
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ArithTuple const& operator*() const { return coord_; }
|
||||
|
||||
template <class Coord>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto operator+(Coord const& c) const {
|
||||
return ArithmeticTupleIterator<decltype(coord_ + c)>(coord_ + c);
|
||||
}
|
||||
|
||||
template <class Coord>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto operator[](Coord const& c) const { return *(*this + c); }
|
||||
};
|
||||
|
||||
template <class ArithTuple>
|
||||
CUTE_HOST_DEVICE void print(ArithmeticTupleIterator<ArithTuple> const& iter) {
|
||||
printf("ArithTuple"); print(iter.coord_);
|
||||
}
|
||||
|
||||
//
|
||||
// ArithmeticTuple "basis" elements
|
||||
//
|
||||
|
||||
// Abstract value:
|
||||
// A ScaledBasis<T,N> is a (at least) rank-N0 ArithmeticTuple:
|
||||
// (_0,_0,...,T,_0,...)
|
||||
|
||||
template <class T, int N>
|
||||
struct ScaledBasis : private tuple<T>
|
||||
{
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
ScaledBasis(T const& t = {}) : tuple<T>(t) {}
|
||||
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
decltype(auto) value() { return get<0>(static_cast<tuple<T> &>(*this)); }
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
decltype(auto) value() const { return get<0>(static_cast<tuple<T> const&>(*this)); }
|
||||
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
auto mode() { return Int<N>{}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_scaled_basis : false_type {};
|
||||
template <class T, int N>
|
||||
struct is_scaled_basis<ScaledBasis<T,N>> : true_type {};
|
||||
|
||||
template <class T, int N>
|
||||
struct is_integral<ScaledBasis<T,N>> : true_type {};
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr auto
|
||||
basis_value(T const& e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
template <class T, int N>
|
||||
CUTE_HOST_DEVICE constexpr auto
|
||||
basis_value(ScaledBasis<T,N> const& e) {
|
||||
return basis_value(e.value());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <int... Ns>
|
||||
struct Basis;
|
||||
|
||||
template <>
|
||||
struct Basis<> {
|
||||
using type = Int<1>;
|
||||
};
|
||||
|
||||
template <int N, int... Ns>
|
||||
struct Basis<N,Ns...> {
|
||||
using type = ScaledBasis<typename Basis<Ns...>::type, N>;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <int... N>
|
||||
using E = typename detail::Basis<N...>::type;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, int... I, int... J>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
as_arithmetic_tuple(T const& t, seq<I...>, seq<J...>) {
|
||||
return make_arithmetic_tuple((void(I),Int<0>{})..., t, (void(J),Int<0>{})...);
|
||||
}
|
||||
|
||||
template <class... T, int... I, int... J>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
as_arithmetic_tuple(ArithmeticTuple<T...> const& t, seq<I...>, seq<J...>) {
|
||||
return make_arithmetic_tuple(get<I>(t)..., (void(J),Int<0>{})...);
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
// Turn a ScaledBases<T,N> into a rank-M ArithmeticTuple
|
||||
// with N prefix 0s: (_0,_0,...N...,_0,T,_0,...,_0,_0)
|
||||
template <int M, class T, int N>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
as_arithmetic_tuple(ScaledBasis<T,N> const& t) {
|
||||
static_assert(M > N, "Mismatched ranks");
|
||||
return detail::as_arithmetic_tuple(t.value(), make_seq<N>{}, make_seq<M-N-1>{});
|
||||
}
|
||||
|
||||
// Turn an ArithmeticTuple into a rank-M ArithmeticTuple
|
||||
// with postfix 0s: (t0,t1,t2,...,_0,...,_0,_0)
|
||||
template <int M, class... T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
as_arithmetic_tuple(ArithmeticTuple<T...> const& t) {
|
||||
static_assert(M >= sizeof...(T), "Mismatched ranks");
|
||||
return detail::as_arithmetic_tuple(t, make_seq<int(sizeof...(T))>{}, make_seq<M-int(sizeof...(T))>{});
|
||||
}
|
||||
|
||||
// Return...
|
||||
template <class Shape>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
make_basis_like(Shape const& shape)
|
||||
{
|
||||
if constexpr (is_integral<Shape>::value) {
|
||||
return Int<1>{};
|
||||
} else {
|
||||
// Generate bases for each rank of shape
|
||||
return transform(tuple_seq<Shape>{}, [&](auto I) {
|
||||
// Generate bases for each rank of shape_i and add an i on front
|
||||
constexpr int i = decltype(I)::value; // NOTE: nvcc workaround
|
||||
return transform_leaf(make_basis_like(get<i>(shape)), [&](auto e) { return ScaledBasis<decltype(e),i>{}; });
|
||||
});
|
||||
}
|
||||
|
||||
CUTE_GCC_UNREACHABLE;
|
||||
}
|
||||
|
||||
// Equality
|
||||
template <class T, int N, int M>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator==(ScaledBasis<T,N>, Int<M>) {
|
||||
return false_type{};
|
||||
}
|
||||
|
||||
template <int N, class U, int M>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator==(Int<N>, ScaledBasis<U,M>) {
|
||||
return false_type{};
|
||||
}
|
||||
|
||||
template <class T, int N, class U, int M>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator==(ScaledBasis<T,N> const& t, ScaledBasis<U,M> const& u) {
|
||||
return bool_constant<M == N>{} && t.value() == u.value();
|
||||
}
|
||||
|
||||
// Multiplication
|
||||
template <class A, int N, class T,
|
||||
__CUTE_REQUIRES(cute::is_integral<A>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator*(A const& a, ScaledBasis<T,N> const& e) {
|
||||
return ScaledBasis<decltype(a*e.value()),N>{a*e.value()};
|
||||
}
|
||||
|
||||
template <int N, class T, class B,
|
||||
__CUTE_REQUIRES(cute::is_integral<B>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator*(ScaledBasis<T,N> const& e, B const& b) {
|
||||
return ScaledBasis<decltype(e.value()*b),N>{e.value()*b};
|
||||
}
|
||||
|
||||
// Addition
|
||||
template <int N, class T, class... U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ScaledBasis<T,N> const& t, ArithmeticTuple<U...> const& u) {
|
||||
constexpr int R = cute::max(N+1, int(sizeof...(U)));
|
||||
return as_arithmetic_tuple<R>(t) + as_arithmetic_tuple<R>(u);
|
||||
}
|
||||
|
||||
template <class... T, int M, class U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ArithmeticTuple<T...> const& t, ScaledBasis<U,M> const& u) {
|
||||
constexpr int R = cute::max(int(sizeof...(T)), M+1);
|
||||
return as_arithmetic_tuple<R>(t) + as_arithmetic_tuple<R>(u);
|
||||
}
|
||||
|
||||
template <int N, class T, int M, class U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ScaledBasis<T,N> const& t, ScaledBasis<U,M> const& u) {
|
||||
constexpr int R = cute::max(N+1,M+1);
|
||||
return as_arithmetic_tuple<R>(t) + as_arithmetic_tuple<R>(u);
|
||||
}
|
||||
|
||||
template <class T, class U, int M>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(constant<T,0>, ScaledBasis<U,M> const& u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
template <class T, int N, class U>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
operator+(ScaledBasis<T,N> const& t, constant<U,0>) {
|
||||
return t;
|
||||
}
|
||||
|
||||
//
|
||||
// Display utilities
|
||||
//
|
||||
|
||||
template <class T, int N>
|
||||
CUTE_HOST_DEVICE void print(ScaledBasis<T,N> const& e) {
|
||||
printf("%d:", N); print(e.value());
|
||||
}
|
||||
|
||||
template <class T, int N>
|
||||
CUTE_HOST std::ostream& operator<<(std::ostream& os, ScaledBasis<T,N> const& e) {
|
||||
return os << N << ":" << e.value();
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <class... T>
|
||||
struct tuple_size<cute::ArithmeticTuple<T...>>
|
||||
: std::integral_constant<std::size_t, sizeof...(T)>
|
||||
{};
|
||||
|
||||
template <std::size_t I, class... T>
|
||||
struct tuple_element<I, cute::ArithmeticTuple<T...>>
|
||||
: std::tuple_element<I, std::tuple<T...>>
|
||||
{};
|
||||
|
||||
} // end namespace std
|
||||
@@ -0,0 +1,51 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
#include <vector_types.h>
|
||||
#include <cutlass/numeric_types.h>
|
||||
|
||||
namespace cute {
|
||||
|
||||
using cutlass::bfloat16_t;
|
||||
|
||||
//
|
||||
// Display utilities
|
||||
//
|
||||
|
||||
CUTE_HOST std::ostream& operator<<(std::ostream& os, bfloat16_t const& v)
|
||||
{
|
||||
return os << float(v);
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,163 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
//#if defined(__CUDA_ARCH__)
|
||||
//# include <cuda/std/complex>
|
||||
//#else
|
||||
//# include <complex>
|
||||
//#endif
|
||||
|
||||
// With CUDA 11.4, builds show spurious "-Wconversion" warnings
|
||||
// on line 656 of thrust/detail/type_traits.h.
|
||||
// These pragmas suppress the warnings.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#include <thrust/complex.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
//#if defined(__CUDA_ARCH__)
|
||||
//template <class T>
|
||||
//using complex = cuda::std::complex<T>;
|
||||
//#else
|
||||
//template <class T>
|
||||
//using complex = std::complex<T>;
|
||||
//#endif
|
||||
|
||||
//template <class T>
|
||||
//using complex = thrust::complex<T>;
|
||||
|
||||
using thrust::complex;
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE
|
||||
T real(complex<T> const& z) {
|
||||
return z.real();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE
|
||||
T imag(complex<T> const& z) {
|
||||
return z.imag();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE
|
||||
complex<T> conj(complex<T> const& z) {
|
||||
return complex<T>(real(z), -imag(z));
|
||||
}
|
||||
|
||||
// cute::conj forwards scalars
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE
|
||||
T conj(T z) {
|
||||
return z;
|
||||
}
|
||||
|
||||
//CUTE_HOST_DEVICE constexpr
|
||||
//float conj(float z) { return z; }
|
||||
//CUTE_HOST_DEVICE constexpr
|
||||
//double conj(double z) { return z; }
|
||||
|
||||
/// Fused multiply-add for complex numbers
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
void
|
||||
fma(complex<T> & d,
|
||||
complex<T> const& a,
|
||||
complex<T> const& b,
|
||||
complex<T> const& c)
|
||||
{
|
||||
d.real(c.real() + a.real() * b.real());
|
||||
d.imag(c.imag() + a.real() * b.imag());
|
||||
d.real(d.real() - a.imag() * b.imag());
|
||||
d.imag(d.imag() + a.imag() * b.real());
|
||||
}
|
||||
|
||||
/// Fused multiply-add for triplets
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
void
|
||||
fma(complex<T> const& a,
|
||||
complex<T> const& b,
|
||||
complex<T> & c)
|
||||
{
|
||||
return fma(c, a, b, c);
|
||||
}
|
||||
|
||||
/// Used to determine the real-valued underlying type of a numeric type T
|
||||
template <class T>
|
||||
struct RealType {
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
/// Partial specialization for complex-valued type
|
||||
template <class T>
|
||||
struct RealType<complex<T>> {
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
struct is_complex {
|
||||
static bool const value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_complex<complex<T>> {
|
||||
static bool const value = true;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Display utilities
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST std::ostream& operator<<(std::ostream& os, complex<T> const& z)
|
||||
{
|
||||
T _r = z.real();
|
||||
T _i = z.imag();
|
||||
|
||||
if (bool(_i)) {
|
||||
return os << _r << "+i" << _i;
|
||||
} else {
|
||||
return os << _r;
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,43 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
#include <vector_types.h>
|
||||
#include <cutlass/numeric_types.h>
|
||||
|
||||
namespace cute {
|
||||
|
||||
using cutlass::float_e4m3_t;
|
||||
using cutlass::float_e5m2_t;
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,41 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
#include <vector_types.h>
|
||||
#include <cutlass/numeric_types.h>
|
||||
|
||||
namespace cute {
|
||||
|
||||
using cutlass::half_t;
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,129 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#if defined(__CUDACC_RTC__)
|
||||
#include <cuda/std/cstdint>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include <cute/numeric/integer_subbyte.hpp>
|
||||
#include <cute/numeric/uint128.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
//
|
||||
// Signed integers
|
||||
//
|
||||
|
||||
using int8_t = std::int8_t;
|
||||
using int16_t = std::int16_t;
|
||||
using int32_t = std::int32_t;
|
||||
using int64_t = std::int64_t;
|
||||
|
||||
template <int N> struct int_bit;
|
||||
template <> struct int_bit< 2> { using type = cute::int2b_t; };
|
||||
template <> struct int_bit< 4> { using type = cute::int4b_t; };
|
||||
template <> struct int_bit< 8> { using type = int8_t; };
|
||||
template <> struct int_bit< 16> { using type = int16_t; };
|
||||
template <> struct int_bit< 32> { using type = int32_t; };
|
||||
template <> struct int_bit< 64> { using type = int64_t; };
|
||||
|
||||
template <int N>
|
||||
using int_bit_t = typename int_bit<N>::type;
|
||||
|
||||
template <int N>
|
||||
using int_byte = int_bit<8*N>;
|
||||
|
||||
template <int N>
|
||||
using int_byte_t = typename int_byte<N>::type;
|
||||
|
||||
//
|
||||
// Unsigned integers
|
||||
//
|
||||
|
||||
using uint8_t = std::uint8_t;
|
||||
using uint16_t = std::uint16_t;
|
||||
using uint32_t = std::uint32_t;
|
||||
using uint64_t = std::uint64_t;
|
||||
|
||||
template <int N> struct uint_bit;
|
||||
template <> struct uint_bit< 1> { using type = cute::uint1b_t; };
|
||||
template <> struct uint_bit< 2> { using type = cute::uint2b_t; };
|
||||
template <> struct uint_bit< 4> { using type = cute::uint4b_t; };
|
||||
template <> struct uint_bit< 8> { using type = uint8_t; };
|
||||
template <> struct uint_bit< 16> { using type = uint16_t; };
|
||||
template <> struct uint_bit< 32> { using type = uint32_t; };
|
||||
template <> struct uint_bit< 64> { using type = uint64_t; };
|
||||
template <> struct uint_bit<128> { using type = cute::uint128_t; };
|
||||
|
||||
template <int N>
|
||||
using uint_bit_t = typename uint_bit<N>::type;
|
||||
|
||||
template <int N>
|
||||
using uint_byte = uint_bit<8*N>;
|
||||
|
||||
template <int N>
|
||||
using uint_byte_t = typename uint_byte<N>::type;
|
||||
|
||||
//
|
||||
// sizeof_bytes
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct sizeof_bytes {
|
||||
static constexpr std::size_t value = sizeof(T);
|
||||
};
|
||||
template <class T>
|
||||
static constexpr int sizeof_bytes_v = sizeof_bytes<T>::value;
|
||||
|
||||
//
|
||||
// sizeof_bits
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct sizeof_bits {
|
||||
static constexpr std::size_t value = sizeof(T) * 8;
|
||||
};
|
||||
template <>
|
||||
struct sizeof_bits<bool> {
|
||||
static constexpr std::size_t value = 1;
|
||||
};
|
||||
template <int Bits, bool Signed>
|
||||
struct sizeof_bits<integer_subbyte<Bits,Signed>> {
|
||||
static constexpr std::size_t value = Bits;
|
||||
};
|
||||
template <class T>
|
||||
static constexpr int sizeof_bits_v = sizeof_bits<T>::value;
|
||||
|
||||
} // namespace cute
|
||||
@@ -0,0 +1,139 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <utility> // std::integer_sequence
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
using std::integer_sequence;
|
||||
using std::make_integer_sequence;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, class S, T Begin>
|
||||
struct make_integer_range_impl;
|
||||
|
||||
template <class T, T... N, T Begin>
|
||||
struct make_integer_range_impl<T, integer_sequence<T, N...>, Begin> {
|
||||
using type = integer_sequence<T, N+Begin...>;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <class T, T Begin, T End>
|
||||
using make_integer_range = typename detail::make_integer_range_impl<
|
||||
T,
|
||||
make_integer_sequence<T, (End-Begin > 0) ? (End-Begin) : 0>,
|
||||
Begin>::type;
|
||||
|
||||
//
|
||||
// Common aliases
|
||||
//
|
||||
|
||||
// int_sequence
|
||||
|
||||
template <int... Ints>
|
||||
using int_sequence = integer_sequence<int, Ints...>;
|
||||
|
||||
template <int N>
|
||||
using make_int_sequence = make_integer_sequence<int, N>;
|
||||
|
||||
template <int Begin, int End>
|
||||
using make_int_range = make_integer_range<int, Begin, End>;
|
||||
|
||||
// index_sequence
|
||||
|
||||
template <std::size_t... Ints>
|
||||
using index_sequence = integer_sequence<std::size_t, Ints...>;
|
||||
|
||||
template <std::size_t N>
|
||||
using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
||||
|
||||
template <std::size_t Begin, std::size_t End>
|
||||
using make_index_range = make_integer_range<std::size_t, Begin, End>;
|
||||
|
||||
//
|
||||
// Shortcuts
|
||||
//
|
||||
|
||||
template <int... Ints>
|
||||
using seq = int_sequence<Ints...>;
|
||||
|
||||
template <int N>
|
||||
using make_seq = make_int_sequence<N>;
|
||||
|
||||
template <int Min, int Max>
|
||||
using make_range = make_int_range<Min, Max>;
|
||||
|
||||
template <class Tuple>
|
||||
using tuple_seq = make_seq<std::tuple_size<std::remove_reference_t<Tuple>>::value>;
|
||||
|
||||
} // end namespace cute
|
||||
|
||||
|
||||
//
|
||||
// Specialize tuple-related functionality for cute::integer_sequence
|
||||
//
|
||||
|
||||
#include <tuple>
|
||||
#include <cute/numeric/integral_constant.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
template <std::size_t I, class T, T... Ints>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
std::tuple_element_t<I, integer_sequence<T, Ints...>>
|
||||
get(integer_sequence<T, Ints...>) {
|
||||
static_assert(I < sizeof...(Ints), "Index out of range");
|
||||
return {};
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <class T, T... Ints>
|
||||
struct tuple_size<cute::integer_sequence<T, Ints...>>
|
||||
: std::integral_constant<std::size_t, sizeof...(Ints)>
|
||||
{};
|
||||
|
||||
template <std::size_t I, class T, T... Ints>
|
||||
struct tuple_element<I, cute::integer_sequence<T, Ints...>>
|
||||
: std::tuple_element<I, std::tuple<cute::integral_constant<T,Ints>...>>
|
||||
{};
|
||||
|
||||
} // end namespace std
|
||||
@@ -0,0 +1,233 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#if defined(__CUDACC_RTC__)
|
||||
#include <cuda/std/cstdint>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include <cute/config.hpp>
|
||||
#include <cute/util/type_traits.hpp>
|
||||
|
||||
namespace cute {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <int Bits, bool Signed = true>
|
||||
struct integer_subbyte
|
||||
{
|
||||
/// Storage type
|
||||
using Storage = uint8_t;
|
||||
|
||||
/// Number of bits
|
||||
static_assert(Bits <= 8*sizeof(Storage), "Require a subbyte of bits in integer_subbyte");
|
||||
|
||||
/// External type
|
||||
using xint_t = typename std::conditional<Signed, int, unsigned>::type;
|
||||
|
||||
/// Bitmask for truncation from larger integers
|
||||
static constexpr Storage bits_mask_ = Storage((1 << Bits) - 1);
|
||||
/// Bitmask for the sign bit
|
||||
static constexpr Storage sign_mask_ = Storage((Signed ? 1 : 0) << (Bits - 1));
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
Storage storage;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// No operation
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
integer_subbyte() {}
|
||||
|
||||
/// Conversion from integer type
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
integer_subbyte(int value) // NOTE: Sign extension?
|
||||
: storage(reinterpret_cast<Storage const&>(value) & bits_mask_) {}
|
||||
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
integer_subbyte(unsigned value)
|
||||
: storage(reinterpret_cast<Storage const&>(value) & bits_mask_) {}
|
||||
|
||||
/// Convert to int or unsigned
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
operator xint_t() const {
|
||||
if (sign_mask_ & storage) { // Sign extend
|
||||
return xint_t(storage) | ~xint_t(bits_mask_);
|
||||
} else {
|
||||
return xint_t(storage);
|
||||
}
|
||||
}
|
||||
|
||||
/// Equality
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator==(integer_subbyte const& rhs) const {
|
||||
return storage == rhs.storage;
|
||||
}
|
||||
|
||||
/// Inequality
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator!=(integer_subbyte const& rhs) const {
|
||||
return storage != rhs.storage;
|
||||
}
|
||||
|
||||
/// Less than or equal
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator<=(integer_subbyte const& rhs) const {
|
||||
if (sign_mask_ & storage) {
|
||||
return !(rhs.storage < storage);
|
||||
} else {
|
||||
return storage < rhs.storage;
|
||||
}
|
||||
}
|
||||
|
||||
/// Less than
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator<(integer_subbyte const& rhs) const {
|
||||
if (sign_mask_ & storage) {
|
||||
return !(rhs.storage <= storage);
|
||||
} else {
|
||||
return storage < rhs.storage;
|
||||
}
|
||||
}
|
||||
|
||||
/// Greater than or equal
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator>=(integer_subbyte const& rhs) const {
|
||||
return !(*this < rhs);
|
||||
}
|
||||
|
||||
/// Greater than
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool operator>(integer_subbyte const& rhs) const {
|
||||
return !(*this <= rhs);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// 1-bit unsigned integer type
|
||||
using uint1b_t = integer_subbyte<1, false>;
|
||||
|
||||
/// 2-bit integer type
|
||||
using int2b_t = integer_subbyte<2, true>;
|
||||
|
||||
/// 2-bit unsigned integer type
|
||||
using uint2b_t = integer_subbyte<2, false>;
|
||||
|
||||
/// 4-bit integer type
|
||||
using int4b_t = integer_subbyte<4, true>;
|
||||
|
||||
/// 4-bit unsigned integer type
|
||||
using uint4b_t = integer_subbyte<4, false>;
|
||||
|
||||
/// 1-bit binary type
|
||||
using bin1_t = bool;
|
||||
|
||||
} // namespace cute
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(__CUDACC_RTC__)
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct numeric_limits<cute::uint1b_t> {
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint1b_t const lowest() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint1b_t const min() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint1b_t const max() noexcept { return 1; }
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_signed = false;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<cute::int2b_t> {
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int2b_t lowest() noexcept { return -2; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int2b_t min() noexcept { return -2; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int2b_t max() noexcept { return 1; }
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_signed = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<cute::uint2b_t> {
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint2b_t const lowest() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint2b_t const min() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint2b_t const max() noexcept { return 3; }
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_signed = false;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<cute::int4b_t> {
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int4b_t lowest() noexcept { return -8; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int4b_t min() noexcept { return -8; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::int4b_t max() noexcept { return 7; }
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_signed = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<cute::uint4b_t> {
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint4b_t const lowest() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint4b_t const min() noexcept { return 0; }
|
||||
CUTE_HOST_DEVICE static constexpr
|
||||
cute::uint4b_t const max() noexcept { return 15; }
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_signed = false;
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,414 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
#include <cute/util/type_traits.hpp>
|
||||
#include <cute/numeric/math.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
template <class T, T v>
|
||||
struct constant : std::integral_constant<T,v> {
|
||||
static constexpr T value = v;
|
||||
using value_type = T;
|
||||
using type = constant<T,v>;
|
||||
CUTE_HOST_DEVICE constexpr operator value_type() const noexcept { return value; }
|
||||
CUTE_HOST_DEVICE constexpr value_type operator()() const noexcept { return value; }
|
||||
};
|
||||
|
||||
template <class T, T v>
|
||||
using integral_constant = constant<T,v>;
|
||||
|
||||
template <bool b>
|
||||
using bool_constant = constant<bool,b>;
|
||||
|
||||
using true_type = bool_constant<true>;
|
||||
using false_type = bool_constant<false>;
|
||||
|
||||
//
|
||||
// Traits
|
||||
//
|
||||
|
||||
// Use std::is_integral<T> to match built-in integral types (int, int64_t, unsigned, etc)
|
||||
// Use cute::is_integral<T> to match both built-in integral types AND constant<T,t>
|
||||
|
||||
template <class T>
|
||||
struct is_integral : bool_constant<std::is_integral<T>::value> {};
|
||||
template <class T, T v>
|
||||
struct is_integral<constant<T,v>> : true_type {};
|
||||
|
||||
// is_static detects if an (abstract) value is defined completely by it's type (no members)
|
||||
|
||||
template <class T>
|
||||
struct is_static : bool_constant<std::is_empty<T>::value> {};
|
||||
|
||||
// is_constant detects if a type is a constant<T,v> and if v is equal to a value
|
||||
|
||||
template <auto n, class T>
|
||||
struct is_constant : false_type {};
|
||||
template <auto n, class T, T v>
|
||||
struct is_constant<n, constant<T,v> > : bool_constant<v == n> {};
|
||||
template <auto n, class T, T v>
|
||||
struct is_constant<n, constant<T,v> const > : bool_constant<v == n> {};
|
||||
template <auto n, class T, T v>
|
||||
struct is_constant<n, constant<T,v> const&> : bool_constant<v == n> {};
|
||||
template <auto n, class T, T v>
|
||||
struct is_constant<n, constant<T,v> &> : bool_constant<v == n> {};
|
||||
template <auto n, class T, T v>
|
||||
struct is_constant<n, constant<T,v> &&> : bool_constant<v == n> {};
|
||||
|
||||
//
|
||||
// Specializations
|
||||
//
|
||||
|
||||
template <int v>
|
||||
using Int = constant<int,v>;
|
||||
|
||||
using _m32 = Int<-32>;
|
||||
using _m24 = Int<-24>;
|
||||
using _m16 = Int<-16>;
|
||||
using _m12 = Int<-12>;
|
||||
using _m10 = Int<-10>;
|
||||
using _m9 = Int<-9>;
|
||||
using _m8 = Int<-8>;
|
||||
using _m7 = Int<-7>;
|
||||
using _m6 = Int<-6>;
|
||||
using _m5 = Int<-5>;
|
||||
using _m4 = Int<-4>;
|
||||
using _m3 = Int<-3>;
|
||||
using _m2 = Int<-2>;
|
||||
using _m1 = Int<-1>;
|
||||
using _0 = Int<0>;
|
||||
using _1 = Int<1>;
|
||||
using _2 = Int<2>;
|
||||
using _3 = Int<3>;
|
||||
using _4 = Int<4>;
|
||||
using _5 = Int<5>;
|
||||
using _6 = Int<6>;
|
||||
using _7 = Int<7>;
|
||||
using _8 = Int<8>;
|
||||
using _9 = Int<9>;
|
||||
using _10 = Int<10>;
|
||||
using _12 = Int<12>;
|
||||
using _16 = Int<16>;
|
||||
using _24 = Int<24>;
|
||||
using _32 = Int<32>;
|
||||
using _64 = Int<64>;
|
||||
using _96 = Int<96>;
|
||||
using _128 = Int<128>;
|
||||
using _192 = Int<192>;
|
||||
using _256 = Int<256>;
|
||||
using _512 = Int<512>;
|
||||
using _1024 = Int<1024>;
|
||||
using _2048 = Int<2048>;
|
||||
using _4096 = Int<4096>;
|
||||
using _8192 = Int<8192>;
|
||||
|
||||
/***************/
|
||||
/** Operators **/
|
||||
/***************/
|
||||
|
||||
#define CUTE_LEFT_UNARY_OP(OP) \
|
||||
template <class T, T t> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
constant<decltype(OP t), (OP t)> \
|
||||
operator OP (constant<T,t>) { \
|
||||
return {}; \
|
||||
}
|
||||
#define CUTE_RIGHT_UNARY_OP(OP) \
|
||||
template <class T, T t> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
constant<decltype(t OP), (t OP)> \
|
||||
operator OP (constant<T,t>) { \
|
||||
return {}; \
|
||||
}
|
||||
|
||||
#define CUTE_BINARY_OP(OP) \
|
||||
template <class T, T t, class U, U u> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
constant<decltype(t OP u), (t OP u)> \
|
||||
operator OP (constant<T,t>, constant<U,u>) { \
|
||||
return {}; \
|
||||
}
|
||||
|
||||
CUTE_LEFT_UNARY_OP(+);
|
||||
CUTE_LEFT_UNARY_OP(-);
|
||||
CUTE_LEFT_UNARY_OP(~);
|
||||
CUTE_LEFT_UNARY_OP(!);
|
||||
CUTE_LEFT_UNARY_OP(*);
|
||||
|
||||
CUTE_BINARY_OP( +);
|
||||
CUTE_BINARY_OP( -);
|
||||
CUTE_BINARY_OP( *);
|
||||
CUTE_BINARY_OP( /);
|
||||
CUTE_BINARY_OP( %);
|
||||
CUTE_BINARY_OP( &);
|
||||
CUTE_BINARY_OP( |);
|
||||
CUTE_BINARY_OP( ^);
|
||||
CUTE_BINARY_OP(<<);
|
||||
CUTE_BINARY_OP(>>);
|
||||
|
||||
CUTE_BINARY_OP(&&);
|
||||
CUTE_BINARY_OP(||);
|
||||
|
||||
CUTE_BINARY_OP(==);
|
||||
CUTE_BINARY_OP(!=);
|
||||
CUTE_BINARY_OP( >);
|
||||
CUTE_BINARY_OP( <);
|
||||
CUTE_BINARY_OP(>=);
|
||||
CUTE_BINARY_OP(<=);
|
||||
|
||||
#undef CUTE_BINARY_OP
|
||||
#undef CUTE_LEFT_UNARY_OP
|
||||
#undef CUTE_RIGHT_UNARY_OP
|
||||
|
||||
//
|
||||
// Mixed static-dynamic special cases
|
||||
//
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator*(constant<T, 0>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class U, class T,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator*(U, constant<T, 0>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator/(constant<T, 0>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class U, class T,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator%(U, constant<T, 1>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class U, class T,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator%(U, constant<T,-1>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator%(constant<T, 0>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator&(constant<T, 0>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<T, 0>
|
||||
operator&(U, constant<T, 0>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, T t, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value && !bool(t))>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<bool, false>
|
||||
operator&&(constant<T, t>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, T t, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value && !bool(t))>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<bool, false>
|
||||
operator&&(U, constant<T, t>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U, T t,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value && bool(t))>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<bool, true>
|
||||
operator||(constant<T, t>, U) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, class U, T t,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value && bool(t))>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<bool, true>
|
||||
operator||(U, constant<T, t>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
//
|
||||
// Named functions from math.hpp
|
||||
//
|
||||
|
||||
#define CUTE_NAMED_UNARY_FN(OP) \
|
||||
template <class T, T t> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
constant<decltype(OP(t)), OP(t)> \
|
||||
OP (constant<T,t>) { \
|
||||
return {}; \
|
||||
}
|
||||
|
||||
#define CUTE_NAMED_BINARY_FN(OP) \
|
||||
template <class T, T t, class U, U u> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
constant<decltype(OP(t,u)), OP(t,u)> \
|
||||
OP (constant<T,t>, constant<U,u>) { \
|
||||
return {}; \
|
||||
} \
|
||||
\
|
||||
template <class T, T t, class U, \
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
auto \
|
||||
OP (constant<T,t>, U u) { \
|
||||
return OP(t,u); \
|
||||
} \
|
||||
\
|
||||
template <class T, class U, U u, \
|
||||
__CUTE_REQUIRES(std::is_integral<T>::value)> \
|
||||
CUTE_HOST_DEVICE constexpr \
|
||||
auto \
|
||||
OP (T t, constant<U,u>) { \
|
||||
return OP(t,u); \
|
||||
}
|
||||
|
||||
CUTE_NAMED_UNARY_FN(abs);
|
||||
CUTE_NAMED_UNARY_FN(signum);
|
||||
CUTE_NAMED_UNARY_FN(has_single_bit);
|
||||
|
||||
CUTE_NAMED_BINARY_FN(max);
|
||||
CUTE_NAMED_BINARY_FN(min);
|
||||
CUTE_NAMED_BINARY_FN(shiftl);
|
||||
CUTE_NAMED_BINARY_FN(shiftr);
|
||||
CUTE_NAMED_BINARY_FN(gcd);
|
||||
CUTE_NAMED_BINARY_FN(lcm);
|
||||
|
||||
#undef CUTE_NAMED_UNARY_FN
|
||||
#undef CUTE_NAMED_BINARY_FN
|
||||
|
||||
//
|
||||
// Other functions
|
||||
//
|
||||
|
||||
template <class T, T t, class U, U u>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
constant<decltype(t / u), t / u>
|
||||
safe_div(constant<T, t>, constant<U, u>) {
|
||||
static_assert(t % u == 0, "Static safe_div requires t % u == 0");
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T, T t, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
safe_div(constant<T, t>, U u) {
|
||||
return t / u;
|
||||
}
|
||||
|
||||
template <class T, class U, U u,
|
||||
__CUTE_REQUIRES(std::is_integral<T>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
safe_div(T t, constant<U, u>) {
|
||||
return t / u;
|
||||
}
|
||||
|
||||
// cute::true_type prefers standard conversion to std::true_type
|
||||
// over user-defined conversion to bool
|
||||
template <class TrueType, class FalseType>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
decltype(auto)
|
||||
conditional_return(std::true_type, TrueType&& t, FalseType&&) {
|
||||
return static_cast<TrueType&&>(t);
|
||||
}
|
||||
|
||||
// cute::false_type prefers standard conversion to std::false_type
|
||||
// over user-defined conversion to bool
|
||||
template <class TrueType, class FalseType>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
decltype(auto)
|
||||
conditional_return(std::false_type, TrueType&&, FalseType&& f) {
|
||||
return static_cast<FalseType&&>(f);
|
||||
}
|
||||
|
||||
// TrueType and FalseType must have a common type
|
||||
template <class TrueType, class FalseType>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
conditional_return(bool b, TrueType const& t, FalseType const& f) {
|
||||
return b ? t : f;
|
||||
}
|
||||
|
||||
//
|
||||
// Display utilities
|
||||
//
|
||||
|
||||
template <class T, T N>
|
||||
CUTE_HOST_DEVICE void print(integral_constant<T,N> const&) {
|
||||
printf("_%d", N);
|
||||
}
|
||||
|
||||
template <class T, T N>
|
||||
CUTE_HOST std::ostream& operator<<(std::ostream& os, integral_constant<T,N> const&) {
|
||||
return os << "_" << N;
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,319 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
|
||||
#if defined(__CUDACC_RTC__)
|
||||
#include <cuda/std/cstdint>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
//
|
||||
// Common Operations
|
||||
//
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_arithmetic<T>::value &&
|
||||
std::is_arithmetic<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
max(T const& t, U const& u) {
|
||||
return t < u ? u : t;
|
||||
}
|
||||
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_arithmetic<T>::value &&
|
||||
std::is_arithmetic<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
min(T const& t, U const& u) {
|
||||
return t < u ? t : u;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
__CUTE_REQUIRES(std::is_arithmetic<T>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
abs(T const& t) {
|
||||
if constexpr (std::is_signed<T>::value) {
|
||||
return t < T(0) ? -t : t;
|
||||
} else {
|
||||
return t;
|
||||
}
|
||||
|
||||
CUTE_GCC_UNREACHABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// C++17 <numeric> operations
|
||||
//
|
||||
|
||||
// Greatest common divisor of two integers
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<T>::value &&
|
||||
std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
gcd(T t, U u) {
|
||||
while (true) {
|
||||
if (t == 0) { return u; }
|
||||
u %= t;
|
||||
if (u == 0) { return t; }
|
||||
t %= u;
|
||||
}
|
||||
}
|
||||
|
||||
// Least common multiple of two integers
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<T>::value &&
|
||||
std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
lcm(T const& t, U const& u) {
|
||||
return (t / gcd(t,u)) * u;
|
||||
}
|
||||
|
||||
//
|
||||
// C++20 <bit> operations
|
||||
//
|
||||
|
||||
// Checks if a number is an integral power of two
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
bool
|
||||
has_single_bit(T x) {
|
||||
return x != 0 && (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
// Smallest number of bits needed to represent the given value
|
||||
// bit_width( 0b0000 ) = 0
|
||||
// bit_width( 0b0001 ) = 1
|
||||
// bit_width( 0b0010 ) = 2
|
||||
// bit_width( 0b0011 ) = 2
|
||||
// bit_width( 0b0100 ) = 3
|
||||
// bit_width( 0b0101 ) = 3
|
||||
// bit_width( 0b0110 ) = 3
|
||||
// bit_width( 0b0111 ) = 3
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
bit_width(T x) {
|
||||
static_assert(std::is_unsigned<T>::value, "Only to be used for unsigned types.");
|
||||
constexpr int N = (std::numeric_limits<T>::digits == 64 ? 6 :
|
||||
(std::numeric_limits<T>::digits == 32 ? 5 :
|
||||
(std::numeric_limits<T>::digits == 16 ? 4 :
|
||||
(std::numeric_limits<T>::digits == 8 ? 3 : (assert(false),0)))));
|
||||
T r = 0;
|
||||
for (int i = N - 1; i >= 0; --i) {
|
||||
T shift = (x > ((T(1) << (T(1) << i))-1)) << i;
|
||||
x >>= shift;
|
||||
r |= shift;
|
||||
}
|
||||
return r + (x != 0);
|
||||
}
|
||||
|
||||
// Smallest integral power of two not less than the given value
|
||||
// bit_ceil( 0b00000000 ) = 0b00000001
|
||||
// bit_ceil( 0b00000001 ) = 0b00000001
|
||||
// bit_ceil( 0b00000010 ) = 0b00000010
|
||||
// bit_ceil( 0b00000011 ) = 0b00000100
|
||||
// bit_ceil( 0b00000100 ) = 0b00000100
|
||||
// bit_ceil( 0b00000101 ) = 0b00001000
|
||||
// bit_ceil( 0b00000110 ) = 0b00001000
|
||||
// bit_ceil( 0b00000111 ) = 0b00001000
|
||||
// bit_ceil( 0b00001000 ) = 0b00001000
|
||||
// bit_ceil( 0b00001001 ) = 0b00010000
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
bit_ceil(T x) {
|
||||
return x == 0 ? T(1) : (T(1) << bit_width(x - 1));
|
||||
}
|
||||
|
||||
// Largest integral power of two not greater than the given value
|
||||
// bit_floor( 0b00000000 ) = 0b00000000
|
||||
// bit_floor( 0b00000001 ) = 0b00000001
|
||||
// bit_floor( 0b00000010 ) = 0b00000010
|
||||
// bit_floor( 0b00000011 ) = 0b00000010
|
||||
// bit_floor( 0b00000100 ) = 0b00000100
|
||||
// bit_floor( 0b00000101 ) = 0b00000100
|
||||
// bit_floor( 0b00000110 ) = 0b00000100
|
||||
// bit_floor( 0b00000111 ) = 0b00000100
|
||||
// bit_floor( 0b00001000 ) = 0b00001000
|
||||
// bit_floor( 0b00001001 ) = 0b00001000
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
bit_floor(T x) {
|
||||
return x == 0 ? 0 : (T(1) << (bit_width(x) - 1));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr T rotl(T x, int s);
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr T rotr(T x, int s);
|
||||
|
||||
// Computes the result of circular bitwise left-rotation
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
rotl(T x, int s) {
|
||||
constexpr int N = std::numeric_limits<T>::digits;
|
||||
return s == 0 ? x : s > 0 ? (x << s) | (x >> (N - s)) : rotr(x, -s);
|
||||
}
|
||||
|
||||
// Computes the result of circular bitwise right-rotation
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
rotr(T x, int s) {
|
||||
constexpr int N = std::numeric_limits<T>::digits;
|
||||
return s == 0 ? x : s > 0 ? (x >> s) | (x << (N - s)) : rotl(x, -s);
|
||||
}
|
||||
|
||||
// Counts the number of consecutive 0 bits, starting from the most significant bit
|
||||
// countl_zero( 0b00000000 ) = 8
|
||||
// countl_zero( 0b11111111 ) = 0
|
||||
// countl_zero( 0b00011100 ) = 3
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
countl_zero(T x) {
|
||||
return std::numeric_limits<T>::digits - bit_width(x);
|
||||
}
|
||||
|
||||
// Counts the number of consecutive 1 bits, starting from the most significant bit
|
||||
// countl_one( 0b00000000 ) = 0
|
||||
// countl_one( 0b11111111 ) = 8
|
||||
// countl_one( 0b11100011 ) = 3
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
countl_one(T x) {
|
||||
return countl_zero(~x);
|
||||
}
|
||||
|
||||
// Counts the number of consecutive 0 bits, starting from the least significant bit
|
||||
// countr_zero( 0b00000000 ) = 8
|
||||
// countr_zero( 0b11111111 ) = 0
|
||||
// countr_zero( 0b00011100 ) = 2
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
countr_zero(T x) {
|
||||
return x == 0 ? std::numeric_limits<T>::digits : bit_width(T(x & T(-x))) - 1; // bit_width of the LSB
|
||||
}
|
||||
|
||||
// Counts the number of consecutive 1 bits, starting from the least significant bit
|
||||
// countr_one( 0b00000000 ) = 0
|
||||
// countr_one( 0b11111111 ) = 8
|
||||
// countr_one( 0b11100011 ) = 2
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
countr_one(T x) {
|
||||
return countr_zero(~x);
|
||||
}
|
||||
|
||||
// Counts the number of 1 bits in an unsigned integer
|
||||
// popcount( 0b00000000 ) = 0
|
||||
// popcount( 0b11111111 ) = 8
|
||||
// popcount( 0b00011101 ) = 4
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
int
|
||||
popcount(T x) {
|
||||
int c = 0;
|
||||
while (x) {
|
||||
++c;
|
||||
x &= x - 1; // clear the least significant bit set
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//
|
||||
// Custom operations
|
||||
//
|
||||
|
||||
// Computes the result of bitwise left-shift
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
shiftl(T x, int s) {
|
||||
return s >= 0 ? (x << s) : (x >> -s);
|
||||
}
|
||||
|
||||
// Computes the result of bitwise right-shift
|
||||
template <class T>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
T
|
||||
shiftr(T x, int s) {
|
||||
return s >= 0 ? (x >> s) : (x << -s);
|
||||
}
|
||||
|
||||
// Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
|
||||
template <class T,
|
||||
__CUTE_REQUIRES(std::is_unsigned<T>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
int
|
||||
signum(T const& x) {
|
||||
return T(0) < x;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
__CUTE_REQUIRES(not std::is_unsigned<T>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
int
|
||||
signum(T const& x) {
|
||||
return (T(0) < x) - (x < T(0));
|
||||
}
|
||||
|
||||
// Safe divide
|
||||
// @pre t % u == 0
|
||||
// @result t / u
|
||||
template <class T, class U,
|
||||
__CUTE_REQUIRES(std::is_integral<T>::value &&
|
||||
std::is_integral<U>::value)>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
auto
|
||||
safe_div(T const& t, U const& u) {
|
||||
//assert(t % u == 0);
|
||||
return t / u;
|
||||
}
|
||||
|
||||
} // namespace cute
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
/// Generic fused multiply-add
|
||||
template <class D, class A, class B, class C>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
void
|
||||
fma(D& d, A const& a, B const& b, C const& c)
|
||||
{
|
||||
d = a * b + c;
|
||||
}
|
||||
|
||||
/// Fused multiply-add for triplets
|
||||
template <class A, class B, class C>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
void
|
||||
fma(A const& a, B const& b, C& c)
|
||||
{
|
||||
return fma(c, a, b, c);
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,51 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
#include <vector_types.h>
|
||||
#include <cutlass/numeric_types.h>
|
||||
|
||||
namespace cute {
|
||||
|
||||
using cutlass::tfloat32_t;
|
||||
|
||||
//
|
||||
// Display utilities
|
||||
//
|
||||
|
||||
CUTE_HOST std::ostream& operator<<(std::ostream& os, tfloat32_t const& v)
|
||||
{
|
||||
return os << float(v);
|
||||
}
|
||||
|
||||
} // end namespace cute
|
||||
@@ -0,0 +1,259 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#if defined(__CUDACC_RTC__)
|
||||
#include <cuda/std/cstdint>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
|
||||
#include <cute/config.hpp>
|
||||
|
||||
/// Optionally enable GCC's built-in type
|
||||
#if defined(__x86_64) && !defined(__CUDA_ARCH__)
|
||||
# if defined(__GNUC__) && 0
|
||||
# define CUTE_UINT128_NATIVE
|
||||
# elif defined(_MSC_VER)
|
||||
# define CUTE_INT128_ARITHMETIC
|
||||
# include <intrin.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cute {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///! Unsigned 128b integer type
|
||||
struct alignas(16) uint128_t
|
||||
{
|
||||
/// Size of one part of the uint's storage in bits
|
||||
static constexpr int storage_bits_ = 64;
|
||||
|
||||
struct hilo
|
||||
{
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
};
|
||||
|
||||
// Use a union to store either low and high parts or, if present, a built-in 128b integer type.
|
||||
union
|
||||
{
|
||||
struct hilo hilo_;
|
||||
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
unsigned __int128 native;
|
||||
#endif // defined(CUTE_UINT128_NATIVE)
|
||||
};
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Default ctor
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t() : hilo_{0, 0} {}
|
||||
|
||||
/// Constructor from uint64
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t(uint64_t lo_) : hilo_{lo_, 0} {}
|
||||
|
||||
/// Constructor from two 64b unsigned integers
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t(uint64_t lo_, uint64_t hi_) : hilo_{lo_, hi_} {}
|
||||
|
||||
/// Optional constructor from native value
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
uint128_t(unsigned __int128 value) : native(value) { }
|
||||
#endif
|
||||
|
||||
/// Lossily cast to uint64
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
explicit operator uint64_t() const
|
||||
{
|
||||
return hilo_.lo;
|
||||
}
|
||||
|
||||
template <class Dummy = bool>
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
static void exception()
|
||||
{
|
||||
//static_assert(sizeof(Dummy) == 0, "Not implemented exception!");
|
||||
//abort();
|
||||
//printf("uint128 not implemented!\n");
|
||||
}
|
||||
|
||||
/// Add
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t operator+(uint128_t const& rhs) const
|
||||
{
|
||||
uint128_t y;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
y.native = native + rhs.native;
|
||||
#else
|
||||
y.hilo_.lo = hilo_.lo + rhs.hilo_.lo;
|
||||
y.hilo_.hi = hilo_.hi + rhs.hilo_.hi + (!y.hilo_.lo && (rhs.hilo_.lo));
|
||||
#endif
|
||||
return y;
|
||||
}
|
||||
|
||||
/// Subtract
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t operator-(uint128_t const& rhs) const
|
||||
{
|
||||
uint128_t y;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
y.native = native - rhs.native;
|
||||
#else
|
||||
y.hilo_.lo = hilo_.lo - rhs.hilo_.lo;
|
||||
y.hilo_.hi = hilo_.hi - rhs.hilo_.hi - (rhs.hilo_.lo && y.hilo_.lo > hilo_.lo);
|
||||
#endif
|
||||
return y;
|
||||
}
|
||||
|
||||
/// Multiply by unsigned 64b integer yielding 128b integer
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t operator*(uint64_t const& rhs) const
|
||||
{
|
||||
uint128_t y;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
y.native = native * rhs;
|
||||
#elif defined(CUTE_INT128_ARITHMETIC)
|
||||
// Multiply by the low part
|
||||
y.hilo_.lo = _umul128(hilo_.lo, rhs, &y.hilo_.hi);
|
||||
|
||||
// Add the high part and ignore the overflow
|
||||
uint64_t overflow;
|
||||
y.hilo_.hi += _umul128(hilo_.hi, rhs, &overflow);
|
||||
#else
|
||||
exception();
|
||||
#endif
|
||||
return y;
|
||||
}
|
||||
|
||||
/// Divide 128b operation by 64b operation yielding a 64b quotient
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint64_t operator/(uint64_t const& divisor) const
|
||||
{
|
||||
uint64_t quotient = 0;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
quotient = uint64_t(native / divisor);
|
||||
#elif defined(CUTE_INT128_ARITHMETIC)
|
||||
// implemented using MSVC's arithmetic intrinsics
|
||||
uint64_t remainder = 0;
|
||||
quotient = _udiv128(hilo_.hi, hilo_.lo, divisor, &remainder);
|
||||
#else
|
||||
exception();
|
||||
#endif
|
||||
return quotient;
|
||||
}
|
||||
|
||||
/// Divide 128b operation by 64b operation yielding a 64b quotient
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint64_t operator%(uint64_t const& divisor) const
|
||||
{
|
||||
uint64_t remainder = 0;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
remainder = uint64_t(native % divisor);
|
||||
#elif defined(CUTE_INT128_ARITHMETIC)
|
||||
// implemented using MSVC's arithmetic intrinsics
|
||||
(void)_udiv128(hilo_.hi, hilo_.lo, divisor, &remainder);
|
||||
#else
|
||||
exception();
|
||||
#endif
|
||||
return remainder;
|
||||
}
|
||||
|
||||
/// Computes the quotient and remainder in a single method.
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint64_t divmod(uint64_t &remainder, uint64_t divisor) const
|
||||
{
|
||||
uint64_t quotient = 0;
|
||||
#if defined(CUTE_UINT128_NATIVE)
|
||||
quotient = uint64_t(native / divisor);
|
||||
remainder = uint64_t(native % divisor);
|
||||
#elif defined(CUTE_INT128_ARITHMETIC)
|
||||
// implemented using MSVC's arithmetic intrinsics
|
||||
quotient = _udiv128(hilo_.hi, hilo_.lo, divisor, &remainder);
|
||||
#else
|
||||
exception();
|
||||
#endif
|
||||
return quotient;
|
||||
}
|
||||
|
||||
/// Left-shifts a 128b unsigned integer
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t operator<<(int sh) const
|
||||
{
|
||||
if (sh == 0) {
|
||||
return *this;
|
||||
}
|
||||
else if (sh >= storage_bits_) {
|
||||
return uint128_t(0, hilo_.lo << (sh - storage_bits_));
|
||||
}
|
||||
else {
|
||||
return uint128_t(
|
||||
(hilo_.lo << sh),
|
||||
(hilo_.hi << sh) | uint64_t(hilo_.lo >> (storage_bits_ - sh))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Right-shifts a 128b unsigned integer
|
||||
CUTE_HOST_DEVICE constexpr
|
||||
uint128_t operator>>(int sh) const
|
||||
{
|
||||
if (sh == 0) {
|
||||
return *this;
|
||||
}
|
||||
else if (sh >= storage_bits_) {
|
||||
return uint128_t((hilo_.hi >> (sh - storage_bits_)), 0);
|
||||
}
|
||||
else {
|
||||
return uint128_t(
|
||||
(hilo_.lo >> sh) | (hilo_.hi << (storage_bits_ - sh)),
|
||||
(hilo_.hi >> sh)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace cute
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Reference in New Issue
Block a user