/* * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. * * SPDX-License-Identifier: MIT */ #pragma once #include template struct type_and_size_and_format { using type = T; static constexpr size_t size = N; static constexpr hipArray_Format format = Format; }; // Create a map of type to scalar type, vector size and scalar type format enum. // This is useful for creating simpler function that depend on the vector size. template struct vector_info; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template <> struct vector_info : type_and_size_and_format {}; template < typename T, typename std::enable_if::value == false>::type* = nullptr> static inline __host__ __device__ constexpr int rank() { return sizeof(T) / sizeof(decltype(T::x)); } template< typename T, typename std::enable_if() == 1>::type* = nullptr> static inline bool isEqual(const T &val0, const T &val1) { return val0.x == val1.x; } template< typename T, typename std::enable_if() == 2>::type* = nullptr> static inline bool isEqual(const T &val0, const T &val1) { return val0.x == val1.x && val0.y == val1.y; } template< typename T, typename std::enable_if() == 4>::type* = nullptr> static inline bool isEqual(const T &val0, const T &val1) { return val0.x == val1.x && val0.y == val1.y && val0.z == val1.z && val0.w == val1.w; } template< typename T, typename std::enable_if::value>::type* = nullptr> static inline bool isEqual(const T &val0, const T &val1) { return val0 == val1; } template< typename T, typename std::enable_if() == 1>::type* = nullptr> const std::string getString(const T& t) { std::ostringstream os; if constexpr (std::is_same::value || std::is_same::value) { os << "(" << static_cast(t.x) << ")"; } else { os << "(" << t.x << ")"; } return os.str(); } template< typename T, typename std::enable_if() == 2>::type* = nullptr> const std::string getString(const T& t) { std::ostringstream os; if constexpr (std::is_same::value || std::is_same::value) { os << "(" << static_cast(t.x) << ", " << static_cast(t.y) << ")"; } else { os << "(" << t.x << ", " << t.y << ")"; } return os.str(); } template< typename T, typename std::enable_if() == 3>::type* = nullptr> const std::string getString(const T& t) { std::ostringstream os; if constexpr (std::is_same::value || std::is_same::value) { os << "(" << static_cast(t.x) << ", " << static_cast(t.y) << ", " << static_cast(t.z) << ")"; } else { os << "(" << t.x << ", " << t.y << ", " << t.z << ")"; } return os.str(); } template< typename T, typename std::enable_if() == 4>::type* = nullptr> const std::string getString(const T& t) { std::ostringstream os; if constexpr (std::is_same::value || std::is_same::value) { os << "(" << static_cast(t.x) << ", " << static_cast(t.y) << ", " << static_cast(t.z) << ", " << static_cast(t.w) << ")"; } else { os << "(" << t.x << ", " << t.y << ", " << t.z << ", " << t.w << ")"; } return os.str(); } template< typename T, typename std::enable_if::value>::type* = nullptr> std::string getString(const T& t) { std::ostringstream os; if constexpr (std::is_same::value || std::is_same::value) { os << static_cast(t); } else { os << t; } return os.str(); } template static inline T getRandom() { double r = 0; if (std::is_signed::value) { r = (std::rand() - RAND_MAX / 2.0) / (RAND_MAX / 2.0 + 1.); } else { r = std::rand() / (RAND_MAX + 1.); } if constexpr (std::is_floating_point::value) { // Restrict any float within (-1000, 1000) // to prevent too big float value that would make caculation sick return static_cast(r * 1000.); } else { return static_cast(std::numeric_limits::max() * r); } } template< typename T, typename std::enable_if() == 1>::type* = nullptr> static inline void initVal(T &val) { val.x = getRandom(); } template< typename T, typename std::enable_if() == 2>::type* = nullptr> static inline void initVal(T &val) { val.x = getRandom(); val.y = getRandom(); } template< typename T, typename std::enable_if() == 4>::type* = nullptr> static inline void initVal(T &val) { val.x = getRandom(); val.y = getRandom(); val.z = getRandom(); val.w = getRandom(); } template< typename T, typename std::enable_if::value>::type* = nullptr> static inline void initVal(T &val) { val = getRandom(); } /*Convert normalized floatx to typex*/ template inline __device__ T getTypeFromNormalizedFloat(const F &f) { T t; if constexpr (std::is_scalar::value) t = static_cast(f.x * std::numeric_limits::max()); else { if constexpr (rank() > 0) t.x = static_cast(f.x * std::numeric_limits::max()); if constexpr (rank() > 1) t.y = static_cast(f.y * std::numeric_limits::max()); if constexpr (rank() > 2) t.z = static_cast(f.z * std::numeric_limits::max()); if constexpr (rank() > 3) t.w = static_cast(f.w * std::numeric_limits::max()); } return t; } /*Convert typex to normalized floatx*/ template inline auto getNormalizedFloatType(const T &t) { if constexpr (std::is_scalar::value) return static_cast(t) / std::numeric_limits::max(); else { if constexpr (rank() == 1) { float1 f{static_cast(t.x) / std::numeric_limits::max()}; return f; } if constexpr (rank() == 2) { float2 f{static_cast(t.x) / std::numeric_limits::max(), static_cast(t.y) / std::numeric_limits::max()}; return f; } if constexpr (rank() == 3) { float3 f{static_cast(t.x) / std::numeric_limits::max(), static_cast(t.y) / std::numeric_limits::max(), static_cast(t.z) / std::numeric_limits::max()}; return f; } if constexpr (rank() == 4) { float4 f{static_cast(t.x) / std::numeric_limits::max(), static_cast(t.y) / std::numeric_limits::max(), static_cast(t.z) / std::numeric_limits::max(), static_cast(t.w) / std::numeric_limits::max()}; return f; } } } /*Check if T is floatx*/ template inline bool constexpr isFloat() { if constexpr (std::is_scalar::value) return std::is_floating_point::value; else { return std::is_floating_point::value; } return false; } template void getStatics(T* data, size_t N, double& mean, double* deviation = nullptr) { double t = 0; for (size_t i = 0; i < N; i++) t += static_cast(data[i]); mean = t / N; if (!deviation) return; double d = 0; for (size_t i = 0; i < N; i++) { double delta = data[i] - mean; d += delta * delta; } *deviation = sqrt(d / (N - 1)); } template bool verify(T* data, T* data1, size_t N) { for (size_t i = 0; i < N; i++) { if (!isEqual(data[i], data1[i])) { printf("Difference [ %zu ]:%s ----%s\n", i, getString(data[i]).c_str(), getString(data1[i]).c_str()); return false; } } return true; }