#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION) #pragma once #include #include namespace at::vec { inline namespace CPU_CAPABILITY { template < typename dst_t, int dst_n, typename src_t, int src_n, typename Enabled = void> struct VecConvert { static inline VectorizedN apply( const VectorizedN& src) { constexpr int count = std::min( VectorizedN::size(), VectorizedN::size()); __at_align__ src_t src_buf[VectorizedN::size()]; src.store(src_buf); __at_align__ dst_t dst_buf[VectorizedN::size()]; for (int i = 0; i < count; i++) { dst_buf[i] = static_cast(src_buf[i]); } return VectorizedN::loadu(dst_buf, count); } }; // Specialized for float-to-int vector conversion. // It ensures the result staying within the destination // type's limits without any undefined behavior. template < typename dst_t, int dst_n, typename src_t, int src_n, typename = std::enable_if_t && is_floating_point_v>> struct VecRoundConvert { static inline VectorizedN apply( const VectorizedN& src) { constexpr int count = std::min( VectorizedN::size(), VectorizedN::size()); __at_align__ src_t src_buf[VectorizedN::size()]; src.store(src_buf); __at_align__ dst_t dst_buf[VectorizedN::size()]; constexpr auto min_val = static_cast(std::numeric_limits::min()); constexpr auto max_val = static_cast(std::numeric_limits::max()); for (int i = 0; i < count; i++) { dst_buf[i] = static_cast( std::min(std::max(std::round(src_buf[i]), min_val), max_val)); } return VectorizedN::loadu(dst_buf, count); } }; template struct VecConvert< dst_t, dst_n, src_t, src_n, std::enable_if_t && dst_n == src_n>> { static inline VectorizedN apply( const VectorizedN& src) { return src; } }; template inline std::enable_if_t, Vectorized> convert( const Vectorized& src) { return src; } template inline std::enable_if_t, Vectorized> round_convert(const Vectorized& src) { return src; } template inline std::enable_if_t, Vectorized> convert(const Vectorized& src) { return VecConvert::apply(src); } template inline std::enable_if_t, Vectorized> round_convert(const Vectorized& src) { return VecRoundConvert::apply(src); } template < typename dst_t, int dst_n, typename src_t, int src_n, std::enable_if_t = 0> inline VectorizedN convert(const VectorizedN& src) { return VecConvert::apply(src); } template < typename dst_t, int dst_n, typename src_t, int src_n, std::enable_if_t = 0> inline VectorizedN round_convert( const VectorizedN& src) { return VecRoundConvert::apply(src); } template < typename dst_t, int dst_n, typename src_t, int src_n, bool keep = false, std::enable_if_t = 0> inline std::conditional_t, Vectorized> convert(const VectorizedN& src) { return VecConvert::apply(src); } template < typename dst_t, int dst_n, typename src_t, int src_n, bool keep = false, std::enable_if_t = 0> inline std::conditional_t, Vectorized> round_convert(const VectorizedN& src) { return VecRoundConvert::apply(src); } } // namespace CPU_CAPABILITY template < typename scalar_t, typename std::enable_if_t, int> = 0> inline std::tuple, Vectorized> convert_to_float( const Vectorized&); template < typename scalar_t, typename std::enable_if_t, int> = 0> inline Vectorized convert_from_float( const Vectorized&, const Vectorized&); } // namespace at::vec #else #error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined." #endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)