| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2016 Konstantinos Margaritis <markos@freevec.org> | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_PACKET_MATH_ZVECTOR_H | |
| #define EIGEN_PACKET_MATH_ZVECTOR_H | |
| // IWYU pragma: private | |
| #include "../../InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| #ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD | |
| #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 16 | |
| #endif | |
| #ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD | |
| #define EIGEN_HAS_SINGLE_INSTRUCTION_MADD | |
| #endif | |
| #ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS | |
| #define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32 | |
| #endif | |
| typedef __vector int Packet4i; | |
| typedef __vector unsigned int Packet4ui; | |
| typedef __vector __bool int Packet4bi; | |
| typedef __vector short int Packet8i; | |
| typedef __vector unsigned char Packet16uc; | |
| typedef __vector double Packet2d; | |
| typedef __vector unsigned long long Packet2ul; | |
| typedef __vector long long Packet2l; | |
| // Z14 has builtin support for float vectors | |
| typedef __vector float Packet4f; | |
| typedef union { | |
| numext::int32_t i[4]; | |
| numext::uint32_t ui[4]; | |
| numext::int64_t l[2]; | |
| numext::uint64_t ul[2]; | |
| double d[2]; | |
| float f[4]; | |
| Packet4i v4i; | |
| Packet4ui v4ui; | |
| Packet2l v2l; | |
| Packet2ul v2ul; | |
| Packet2d v2d; | |
| Packet4f v4f; | |
| } Packet; | |
| // We don't want to write the same code all the time, but we need to reuse the constants | |
| // and it doesn't really work to declare them global, so we define macros instead | |
| #define EIGEN_DECLARE_CONST_FAST_Packet4i(NAME, X) Packet4i p4i_##NAME = reinterpret_cast<Packet4i>(vec_splat_s32(X)) | |
| #define EIGEN_DECLARE_CONST_FAST_Packet2d(NAME, X) Packet2d p2d_##NAME = reinterpret_cast<Packet2d>(vec_splat_s64(X)) | |
| #define EIGEN_DECLARE_CONST_FAST_Packet2l(NAME, X) Packet2l p2l_##NAME = reinterpret_cast<Packet2l>(vec_splat_s64(X)) | |
| #define EIGEN_DECLARE_CONST_Packet4i(NAME, X) Packet4i p4i_##NAME = pset1<Packet4i>(X) | |
| #define EIGEN_DECLARE_CONST_Packet2d(NAME, X) Packet2d p2d_##NAME = pset1<Packet2d>(X) | |
| #define EIGEN_DECLARE_CONST_Packet2l(NAME, X) Packet2l p2l_##NAME = pset1<Packet2l>(X) | |
| // These constants are endian-agnostic | |
| static EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); //{ 0, 0, 0, 0,} | |
| static EIGEN_DECLARE_CONST_FAST_Packet4i(ONE, 1); //{ 1, 1, 1, 1} | |
| static EIGEN_DECLARE_CONST_FAST_Packet2d(ZERO, 0); | |
| static EIGEN_DECLARE_CONST_FAST_Packet2l(ZERO, 0); | |
| static EIGEN_DECLARE_CONST_FAST_Packet2l(ONE, 1); | |
| static Packet2d p2d_ONE = {1.0, 1.0}; | |
| static Packet2d p2d_ZERO_ = {numext::bit_cast<double>(0x8000000000000000ull), | |
| numext::bit_cast<double>(0x8000000000000000ull)}; | |
| #define EIGEN_DECLARE_CONST_FAST_Packet4f(NAME, X) Packet4f p4f_##NAME = reinterpret_cast<Packet4f>(vec_splat_s32(X)) | |
| #define EIGEN_DECLARE_CONST_Packet4f(NAME, X) Packet4f p4f_##NAME = pset1<Packet4f>(X) | |
| #define EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME, X) \ | |
| const Packet4f p4f_##NAME = reinterpret_cast<Packet4f>(pset1<Packet4i>(X)) | |
| static EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); //{ 0.0, 0.0, 0.0, 0.0} | |
| static EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS1, -1); //{ -1, -1, -1, -1} | |
| static Packet4f p4f_MZERO = {0x80000000, 0x80000000, 0x80000000, 0x80000000}; | |
| static Packet4i p4i_COUNTDOWN = {0, 1, 2, 3}; | |
| static Packet4f p4f_COUNTDOWN = {0.0, 1.0, 2.0, 3.0}; | |
| static Packet2d p2d_COUNTDOWN = reinterpret_cast<Packet2d>( | |
| vec_sld(reinterpret_cast<Packet16uc>(p2d_ZERO), reinterpret_cast<Packet16uc>(p2d_ONE), 8)); | |
| static Packet16uc p16uc_PSET64_HI = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}; | |
| static Packet16uc p16uc_DUPLICATE32_HI = {0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7}; | |
| // Mask alignment | |
| #define EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 | |
| #define EIGEN_ALIGNED_PTR(x) ((std::ptrdiff_t)(x) & EIGEN_MASK_ALIGNMENT) | |
| // Handle endianness properly while loading constants | |
| // Define global static constants: | |
| static Packet16uc p16uc_FORWARD = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; | |
| static Packet16uc p16uc_REVERSE32 = {12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3}; | |
| static Packet16uc p16uc_REVERSE64 = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7}; | |
| static Packet16uc p16uc_PSET32_WODD = | |
| vec_sld((Packet16uc)vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc)vec_splat((Packet4ui)p16uc_FORWARD, 2), | |
| 8); //{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; | |
| static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc)vec_splat((Packet4ui)p16uc_FORWARD, 3), | |
| 8); //{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; | |
| static Packet16uc p16uc_PSET64_LO = (Packet16uc)vec_mergel( | |
| (Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; | |
| static Packet16uc p16uc_TRANSPOSE64_HI = {0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23}; | |
| static Packet16uc p16uc_TRANSPOSE64_LO = {8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31}; | |
| static Packet16uc p16uc_COMPLEX32_REV = | |
| vec_sld(p16uc_REVERSE32, p16uc_REVERSE32, 8); //{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; | |
| static Packet16uc p16uc_COMPLEX32_REV2 = | |
| vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; | |
| #if EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC | |
| #define EIGEN_ZVECTOR_PREFETCH(ADDR) __builtin_prefetch(ADDR); | |
| #else | |
| #define EIGEN_ZVECTOR_PREFETCH(ADDR) asm(" pfd [%[addr]]\n" ::[addr] "r"(ADDR) : "cc"); | |
| #endif | |
| template <> | |
| struct packet_traits<int> : default_packet_traits { | |
| typedef Packet4i type; | |
| typedef Packet4i half; | |
| enum { | |
| Vectorizable = 1, | |
| AlignedOnScalar = 1, | |
| size = 4, | |
| HasAdd = 1, | |
| HasSub = 1, | |
| HasMul = 1, | |
| HasDiv = 1, | |
| }; | |
| }; | |
| template <> | |
| struct packet_traits<float> : default_packet_traits { | |
| typedef Packet4f type; | |
| typedef Packet4f half; | |
| enum { | |
| Vectorizable = 1, | |
| AlignedOnScalar = 1, | |
| size = 4, | |
| HasCmp = 1, | |
| HasAdd = 1, | |
| HasSub = 1, | |
| HasMul = 1, | |
| HasDiv = 1, | |
| HasMin = 1, | |
| HasMax = 1, | |
| HasAbs = 1, | |
| HasSin = 0, | |
| HasCos = 0, | |
| HasLog = 0, | |
| HasExp = 1, | |
| HasSqrt = 1, | |
| HasRsqrt = 1, | |
| HasTanh = 1, | |
| HasErf = 1, | |
| HasNegate = 1, | |
| }; | |
| }; | |
| template <> | |
| struct packet_traits<double> : default_packet_traits { | |
| typedef Packet2d type; | |
| typedef Packet2d half; | |
| enum { | |
| Vectorizable = 1, | |
| AlignedOnScalar = 1, | |
| size = 2, | |
| HasAdd = 1, | |
| HasSub = 1, | |
| HasMul = 1, | |
| HasDiv = 1, | |
| HasMin = 1, | |
| HasMax = 1, | |
| HasAbs = 1, | |
| HasSin = 0, | |
| HasCos = 0, | |
| HasLog = 0, | |
| HasExp = 1, | |
| HasSqrt = 1, | |
| HasRsqrt = 1, | |
| HasNegate = 1, | |
| }; | |
| }; | |
| template <> | |
| struct unpacket_traits<Packet4i> { | |
| typedef int type; | |
| enum { | |
| size = 4, | |
| alignment = Aligned16, | |
| vectorizable = true, | |
| masked_load_available = false, | |
| masked_store_available = false | |
| }; | |
| typedef Packet4i half; | |
| }; | |
| template <> | |
| struct unpacket_traits<Packet4f> { | |
| typedef float type; | |
| enum { | |
| size = 4, | |
| alignment = Aligned16, | |
| vectorizable = true, | |
| masked_load_available = false, | |
| masked_store_available = false | |
| }; | |
| typedef Packet4f half; | |
| typedef Packet4i integer_packet; | |
| }; | |
| template <> | |
| struct unpacket_traits<Packet2d> { | |
| typedef double type; | |
| enum { | |
| size = 2, | |
| alignment = Aligned16, | |
| vectorizable = true, | |
| masked_load_available = false, | |
| masked_store_available = false | |
| }; | |
| typedef Packet2d half; | |
| typedef Packet2l integer_packet; | |
| }; | |
| // The integer_packet of Packet2d, for the generic bit-manipulation paths; int64 is not vectorized. | |
| template <> | |
| struct unpacket_traits<Packet2l> { | |
| using type = numext::int64_t; | |
| using half = Packet2l; | |
| static constexpr int size = 2; | |
| static constexpr int alignment = Aligned16; | |
| static constexpr bool vectorizable = false; | |
| static constexpr bool masked_load_available = false; | |
| static constexpr bool masked_store_available = false; | |
| }; | |
| /* Forward declaration */ | |
| EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4f, 4>& kernel); | |
| inline std::ostream& operator<<(std::ostream& s, const Packet4i& v) { | |
| Packet vt; | |
| vt.v4i = v; | |
| s << vt.i[0] << ", " << vt.i[1] << ", " << vt.i[2] << ", " << vt.i[3]; | |
| return s; | |
| } | |
| inline std::ostream& operator<<(std::ostream& s, const Packet4ui& v) { | |
| Packet vt; | |
| vt.v4ui = v; | |
| s << vt.ui[0] << ", " << vt.ui[1] << ", " << vt.ui[2] << ", " << vt.ui[3]; | |
| return s; | |
| } | |
| inline std::ostream& operator<<(std::ostream& s, const Packet2l& v) { | |
| Packet vt; | |
| vt.v2l = v; | |
| s << vt.l[0] << ", " << vt.l[1]; | |
| return s; | |
| } | |
| inline std::ostream& operator<<(std::ostream& s, const Packet2ul& v) { | |
| Packet vt; | |
| vt.v2ul = v; | |
| s << vt.ul[0] << ", " << vt.ul[1]; | |
| return s; | |
| } | |
| inline std::ostream& operator<<(std::ostream& s, const Packet2d& v) { | |
| Packet vt; | |
| vt.v2d = v; | |
| s << vt.d[0] << ", " << vt.d[1]; | |
| return s; | |
| } | |
| inline std::ostream& operator<<(std::ostream& s, const Packet4f& v) { | |
| Packet vt; | |
| vt.v4f = v; | |
| s << vt.f[0] << ", " << vt.f[1] << ", " << vt.f[2] << ", " << vt.f[3]; | |
| return s; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pload<Packet4i>(const int* from) { | |
| EIGEN_DEBUG_ALIGNED_LOAD | |
| return vec_xl(0, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pload<Packet2d>(const double* from) { | |
| EIGEN_DEBUG_ALIGNED_LOAD | |
| return vec_xl(0, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& from) { | |
| EIGEN_DEBUG_ALIGNED_STORE | |
| vec_xst(from, 0, to); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstore<double>(double* to, const Packet2d& from) { | |
| EIGEN_DEBUG_ALIGNED_STORE | |
| vec_xst(from, 0, to); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pfrexp<Packet4f>(const Packet4f& a, Packet4f& exponent) { | |
| return pfrexp_generic(a, exponent); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pfrexp<Packet2d>(const Packet2d& a, Packet2d& exponent) { | |
| return pfrexp_generic(a, exponent); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int& from) { | |
| return vec_splats(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pset1<Packet2d>(const double& from) { | |
| return vec_splats(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pset1<Packet2l>(const numext::int64_t& from) { | |
| return vec_splats(static_cast<long long>(from)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pbroadcast4<Packet4i>(const int* a, Packet4i& a0, Packet4i& a1, Packet4i& a2, Packet4i& a3) { | |
| a3 = pload<Packet4i>(a); | |
| a0 = vec_splat(a3, 0); | |
| a1 = vec_splat(a3, 1); | |
| a2 = vec_splat(a3, 2); | |
| a3 = vec_splat(a3, 3); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pbroadcast4<Packet2d>(const double* a, Packet2d& a0, Packet2d& a1, Packet2d& a2, | |
| Packet2d& a3) { | |
| a1 = pload<Packet2d>(a); | |
| a0 = vec_splat(a1, 0); | |
| a1 = vec_splat(a1, 1); | |
| a3 = pload<Packet2d>(a + 2); | |
| a2 = vec_splat(a3, 0); | |
| a3 = vec_splat(a3, 1); | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline Packet4i pgather<int, Packet4i>(const int* from, Index stride) { | |
| EIGEN_ALIGN16 int ai[4]; | |
| ai[0] = from[0 * stride]; | |
| ai[1] = from[1 * stride]; | |
| ai[2] = from[2 * stride]; | |
| ai[3] = from[3 * stride]; | |
| return pload<Packet4i>(ai); | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline Packet2d pgather<double, Packet2d>(const double* from, Index stride) { | |
| EIGEN_ALIGN16 double af[2]; | |
| af[0] = from[0 * stride]; | |
| af[1] = from[1 * stride]; | |
| return pload<Packet2d>(af); | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline void pscatter<int, Packet4i>(int* to, const Packet4i& from, Index stride) { | |
| EIGEN_ALIGN16 int ai[4]; | |
| pstore<int>((int*)ai, from); | |
| to[0 * stride] = ai[0]; | |
| to[1 * stride] = ai[1]; | |
| to[2 * stride] = ai[2]; | |
| to[3 * stride] = ai[3]; | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline void pscatter<double, Packet2d>(double* to, const Packet2d& from, Index stride) { | |
| EIGEN_ALIGN16 double af[2]; | |
| pstore<double>(af, from); | |
| to[0 * stride] = af[0]; | |
| to[1 * stride] = af[1]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i padd<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return (a + b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d padd<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return (a + b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i psub<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return (a - b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d psub<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return (a - b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pmul<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return (a * b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pmul<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return (a * b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pdiv<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return (a / b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pdiv<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return (a / b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { | |
| return (-a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { | |
| return (-a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { | |
| return padd<Packet4i>(pmul<Packet4i>(a, b), c); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { | |
| return vec_madd(a, b, c); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i plset<Packet4i>(const int& a) { | |
| return padd<Packet4i>(pset1<Packet4i>(a), p4i_COUNTDOWN); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d plset<Packet2d>(const double& a) { | |
| return padd<Packet2d>(pset1<Packet2d>(a), p2d_COUNTDOWN); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return vec_min(a, b); | |
| } | |
| // pmin/pmax follow std::min/std::max: they return a whenever either operand is NaN, so a NaN in a propagates through | |
| // clamps such as pmax(pmin(x, hi), lo). vec_min/vec_max (VFMIN/VFMAX mode 0 on z14) drop it. | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return __builtin_s390_vfmindb(a, b, 3); // mode 3: std::min | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return vec_max(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return __builtin_s390_vfmaxdb(a, b, 3); // mode 3: std::max | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pand<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return vec_and(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pand<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return vec_and(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i por<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return vec_or(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d por<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return vec_or(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pxor<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return vec_xor(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pxor<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return vec_xor(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pandnot<Packet4i>(const Packet4i& a, const Packet4i& b) { | |
| return pand<Packet4i>(a, vec_nor(b, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pandnot<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return vec_and(a, vec_nor(b, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l padd<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return (a + b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l psub<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return (a - b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pand<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return vec_and(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l por<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return vec_or(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pxor<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return vec_xor(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pandnot<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return vec_and(a, vec_nor(b, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pcmp_eq<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return reinterpret_cast<Packet2l>(vec_cmpeq(a, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pcmp_lt<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return reinterpret_cast<Packet2l>(vec_cmplt(a, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pcmp_le<Packet2l>(const Packet2l& a, const Packet2l& b) { | |
| return reinterpret_cast<Packet2l>(vec_cmple(a, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2l pselect<Packet2l>(const Packet2l& mask, const Packet2l& a, const Packet2l& b) { | |
| return vec_sel(b, a, reinterpret_cast<Packet2ul>(mask)); | |
| } | |
| template <> | |
| struct cast_impl<Packet2l, Packet2d> { | |
| EIGEN_DEVICE_FUNC static inline Packet2d run(const Packet2l& a) { return vec_double(a); } | |
| }; | |
| template <> | |
| struct cast_impl<Packet2d, Packet2l> { | |
| EIGEN_DEVICE_FUNC static inline Packet2l run(const Packet2d& a) { | |
| return vec_signed(vec_sel(p2d_ZERO, a, vec_cmpeq(a, a))); // A NaN lane converts to 0. | |
| } | |
| }; | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pround<Packet2d>(const Packet2d& a) { | |
| /* Uses non-default rounding for vec_round */ | |
| return __builtin_s390_vfidb(a, 0, 1); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pceil<Packet2d>(const Packet2d& a) { | |
| return vec_ceil(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pfloor<Packet2d>(const Packet2d& a) { | |
| return vec_floor(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d print<Packet2d>(const Packet2d& a) { | |
| // M5 = 4: round to nearest, ties to even. | |
| return __builtin_s390_vfidb(a, 4, 4); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d ptrunc<Packet2d>(const Packet2d& a) { | |
| // M5 = 5: round toward zero. | |
| return __builtin_s390_vfidb(a, 4, 5); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pcmp_lt_or_nan<Packet2d>(const Packet2d& a, const Packet2d& b) { | |
| return pnot(pcmp_le(b, a)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i ploadu<Packet4i>(const int* from) { | |
| return pload<Packet4i>(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d ploadu<Packet2d>(const double* from) { | |
| return pload<Packet2d>(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int* from) { | |
| Packet4i p = pload<Packet4i>(from); | |
| return vec_perm(p, p, p16uc_DUPLICATE32_HI); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d ploaddup<Packet2d>(const double* from) { | |
| Packet2d p = pload<Packet2d>(from); | |
| return vec_perm(p, p, p16uc_PSET64_HI); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet4i& from) { | |
| pstore<int>(to, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstoreu<double>(double* to, const Packet2d& from) { | |
| pstore<double>(to, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { | |
| EIGEN_ZVECTOR_PREFETCH(addr); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { | |
| EIGEN_ZVECTOR_PREFETCH(addr); | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet2l parithmetic_shift_right(const Packet2l& a) { | |
| return Packet2l{parithmetic_shift_right<N>(a[0]), parithmetic_shift_right<N>(a[1])}; | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet4i parithmetic_shift_right(const Packet4i& a) { | |
| return Packet4i{parithmetic_shift_right<N>(a[0]), parithmetic_shift_right<N>(a[1]), parithmetic_shift_right<N>(a[2]), | |
| parithmetic_shift_right<N>(a[3])}; | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet2l plogical_shift_right(const Packet2l& a) { | |
| return Packet2l{plogical_shift_right<N>(a[0]), plogical_shift_right<N>(a[1])}; | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet4i plogical_shift_right(const Packet4i& a) { | |
| return Packet4i{plogical_shift_right<N>(a[0]), plogical_shift_right<N>(a[1]), plogical_shift_right<N>(a[2]), | |
| plogical_shift_right<N>(a[3])}; | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet2l plogical_shift_left(const Packet2l& a) { | |
| return Packet2l{plogical_shift_left<N>(a[0]), plogical_shift_left<N>(a[1])}; | |
| } | |
| template <int N> | |
| EIGEN_STRONG_INLINE Packet4i plogical_shift_left(const Packet4i& a) { | |
| return Packet4i{plogical_shift_left<N>(a[0]), plogical_shift_left<N>(a[1]), plogical_shift_left<N>(a[2]), | |
| plogical_shift_left<N>(a[3])}; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE int pfirst<Packet4i>(const Packet4i& a) { | |
| EIGEN_ALIGN16 int x[4]; | |
| pstore(x, a); | |
| return x[0]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE double pfirst<Packet2d>(const Packet2d& a) { | |
| EIGEN_ALIGN16 double x[2]; | |
| pstore(x, a); | |
| return x[0]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { | |
| return reinterpret_cast<Packet4i>( | |
| vec_perm(reinterpret_cast<Packet16uc>(a), reinterpret_cast<Packet16uc>(a), p16uc_REVERSE32)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { | |
| return reinterpret_cast<Packet2d>( | |
| vec_perm(reinterpret_cast<Packet16uc>(a), reinterpret_cast<Packet16uc>(a), p16uc_REVERSE64)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4i pabs<Packet4i>(const Packet4i& a) { | |
| return vec_abs(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pabs<Packet2d>(const Packet2d& a) { | |
| return vec_abs(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE int predux<Packet4i>(const Packet4i& a) { | |
| Packet4i b, sum; | |
| b = vec_sld(a, a, 8); | |
| sum = padd<Packet4i>(a, b); | |
| b = vec_sld(sum, sum, 4); | |
| sum = padd<Packet4i>(sum, b); | |
| return pfirst(sum); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a) { | |
| Packet2d b, sum; | |
| b = reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4i>(a), reinterpret_cast<Packet4i>(a), 8)); | |
| sum = padd<Packet2d>(a, b); | |
| return pfirst(sum); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE bool predux_any(const Packet2d& a) { | |
| const Packet2ul zero = {0, 0}; | |
| return vec_any_ne(reinterpret_cast<Packet2ul>(a), zero); | |
| } | |
| // Other reduction functions: | |
| // mul | |
| template <> | |
| EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a) { | |
| EIGEN_ALIGN16 int aux[4]; | |
| pstore(aux, a); | |
| return aux[0] * aux[1] * aux[2] * aux[3]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE double predux_mul<Packet2d>(const Packet2d& a) { | |
| return pfirst( | |
| pmul(a, reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4i>(a), reinterpret_cast<Packet4i>(a), 8)))); | |
| } | |
| // min | |
| template <> | |
| EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a) { | |
| Packet4i b, res; | |
| b = pmin<Packet4i>(a, vec_sld(a, a, 8)); | |
| res = pmin<Packet4i>(b, vec_sld(b, b, 4)); | |
| return pfirst(res); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE double predux_min<Packet2d>(const Packet2d& a) { | |
| return pfirst(pmin<Packet2d>( | |
| a, reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4i>(a), reinterpret_cast<Packet4i>(a), 8)))); | |
| } | |
| // max | |
| template <> | |
| EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a) { | |
| Packet4i b, res; | |
| b = pmax<Packet4i>(a, vec_sld(a, a, 8)); | |
| res = pmax<Packet4i>(b, vec_sld(b, b, 4)); | |
| return pfirst(res); | |
| } | |
| // max | |
| template <> | |
| EIGEN_STRONG_INLINE double predux_max<Packet2d>(const Packet2d& a) { | |
| return pfirst(pmax<Packet2d>( | |
| a, reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4i>(a), reinterpret_cast<Packet4i>(a), 8)))); | |
| } | |
| EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4i, 4>& kernel) { | |
| Packet4i t0 = vec_mergeh(kernel.packet[0], kernel.packet[2]); | |
| Packet4i t1 = vec_mergel(kernel.packet[0], kernel.packet[2]); | |
| Packet4i t2 = vec_mergeh(kernel.packet[1], kernel.packet[3]); | |
| Packet4i t3 = vec_mergel(kernel.packet[1], kernel.packet[3]); | |
| kernel.packet[0] = vec_mergeh(t0, t2); | |
| kernel.packet[1] = vec_mergel(t0, t2); | |
| kernel.packet[2] = vec_mergeh(t1, t3); | |
| kernel.packet[3] = vec_mergel(t1, t3); | |
| } | |
| EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet2d, 2>& kernel) { | |
| Packet2d t0 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_HI); | |
| Packet2d t1 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_LO); | |
| kernel.packet[0] = t0; | |
| kernel.packet[1] = t1; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pload<Packet4f>(const float* from) { | |
| EIGEN_DEBUG_ALIGNED_LOAD | |
| return vec_xl(0, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet4f& from) { | |
| EIGEN_DEBUG_ALIGNED_STORE | |
| vec_xst(from, 0, to); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pset1<Packet4f>(const float& from) { | |
| return vec_splats(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pbroadcast4<Packet4f>(const float* a, Packet4f& a0, Packet4f& a1, Packet4f& a2, Packet4f& a3) { | |
| a3 = pload<Packet4f>(a); | |
| a0 = vec_splat(a3, 0); | |
| a1 = vec_splat(a3, 1); | |
| a2 = vec_splat(a3, 2); | |
| a3 = vec_splat(a3, 3); | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline Packet4f pgather<float, Packet4f>(const float* from, Index stride) { | |
| EIGEN_ALIGN16 float af[4]; | |
| af[0] = from[0 * stride]; | |
| af[1] = from[1 * stride]; | |
| af[2] = from[2 * stride]; | |
| af[3] = from[3 * stride]; | |
| return pload<Packet4f>(af); | |
| } | |
| template <> | |
| EIGEN_DEVICE_FUNC inline void pscatter<float, Packet4f>(float* to, const Packet4f& from, Index stride) { | |
| EIGEN_ALIGN16 float af[4]; | |
| pstore<float>((float*)af, from); | |
| to[0 * stride] = af[0]; | |
| to[1 * stride] = af[1]; | |
| to[2 * stride] = af[2]; | |
| to[3 * stride] = af[3]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f padd<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return (a + b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f psub<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return (a - b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pmul<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return (a * b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pdiv<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return (a / b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pnegate<Packet4f>(const Packet4f& a) { | |
| return (-a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pmadd<Packet4f>(const Packet4f& a, const Packet4f& b, const Packet4f& c) { | |
| return vec_madd(a, b, c); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return __builtin_s390_vfminsb(a, b, 3); // mode 3: std::min | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return __builtin_s390_vfmaxsb(a, b, 3); // mode 3: std::max | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pand<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return vec_and(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f por<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return vec_or(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return vec_xor(a, b); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pandnot<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return vec_and(a, vec_nor(b, b)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pround<Packet4f>(const Packet4f& a) { | |
| /* Uses non-default rounding for vec_round */ | |
| return __builtin_s390_vfisb(a, 0, 1); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pceil<Packet4f>(const Packet4f& a) { | |
| return vec_ceil(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pfloor<Packet4f>(const Packet4f& a) { | |
| return vec_floor(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f print<Packet4f>(const Packet4f& a) { | |
| // M5 = 4: round to nearest, ties to even. | |
| return __builtin_s390_vfisb(a, 4, 4); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f ptrunc<Packet4f>(const Packet4f& a) { | |
| // M5 = 5: round toward zero. | |
| return __builtin_s390_vfisb(a, 4, 5); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pcmp_lt_or_nan<Packet4f>(const Packet4f& a, const Packet4f& b) { | |
| return pnot(pcmp_le(b, a)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pabs<Packet4f>(const Packet4f& a) { | |
| return vec_abs(a); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { | |
| EIGEN_ALIGN16 float x[4]; | |
| pstore(x, a); | |
| return x[0]; | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f ploaddup<Packet4f>(const float* from) { | |
| Packet4f p = pload<Packet4f>(from); | |
| return vec_perm(p, p, p16uc_DUPLICATE32_HI); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { | |
| return reinterpret_cast<Packet4f>( | |
| vec_perm(reinterpret_cast<Packet16uc>(a), reinterpret_cast<Packet16uc>(a), p16uc_REVERSE32)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a) { | |
| Packet4f b, sum; | |
| b = vec_sld(a, a, 8); | |
| sum = padd<Packet4f>(a, b); | |
| b = vec_sld(sum, sum, 4); | |
| sum = padd<Packet4f>(sum, b); | |
| return pfirst(sum); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE bool predux_any(const Packet4f& a) { | |
| const Packet4ui zero = {0, 0, 0, 0}; | |
| return vec_any_ne(reinterpret_cast<Packet4ui>(a), zero); | |
| } | |
| // Other reduction functions: | |
| // mul | |
| template <> | |
| EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a) { | |
| Packet4f prod; | |
| prod = pmul(a, vec_sld(a, a, 8)); | |
| return pfirst(pmul(prod, vec_sld(prod, prod, 4))); | |
| } | |
| // min | |
| template <> | |
| EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a) { | |
| Packet4f b, res; | |
| b = pmin<Packet4f>(a, vec_sld(a, a, 8)); | |
| res = pmin<Packet4f>(b, vec_sld(b, b, 4)); | |
| return pfirst(res); | |
| } | |
| // max | |
| template <> | |
| EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a) { | |
| Packet4f b, res; | |
| b = pmax<Packet4f>(a, vec_sld(a, a, 8)); | |
| res = pmax<Packet4f>(b, vec_sld(b, b, 4)); | |
| return pfirst(res); | |
| } | |
| EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4f, 4>& kernel) { | |
| Packet4f t0 = vec_mergeh(kernel.packet[0], kernel.packet[2]); | |
| Packet4f t1 = vec_mergel(kernel.packet[0], kernel.packet[2]); | |
| Packet4f t2 = vec_mergeh(kernel.packet[1], kernel.packet[3]); | |
| Packet4f t3 = vec_mergel(kernel.packet[1], kernel.packet[3]); | |
| kernel.packet[0] = vec_mergeh(t0, t2); | |
| kernel.packet[1] = vec_mergel(t0, t2); | |
| kernel.packet[2] = vec_mergeh(t1, t3); | |
| kernel.packet[3] = vec_mergel(t1, t3); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pldexp<Packet4f>(const Packet4f& a, const Packet4f& exponent) { | |
| return pldexp_generic(a, exponent); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pldexp<Packet2d>(const Packet2d& a, const Packet2d& exponent) { | |
| // The single-rounding split of pldexp_generic on int64 exponents. | |
| const Packet2d max_exponent = pset1<Packet2d>(2099.0); | |
| const Packet2d last_max = pset1<Packet2d>(1022.0); | |
| const Packet2l e = pcast<Packet2d, Packet2l>(pmin(pmax(exponent, pnegate(max_exponent)), max_exponent)); | |
| const Packet2l b = pcast<Packet2d, Packet2l>(pmin(pmax(exponent, pnegate(last_max)), last_max)); | |
| const Packet2l bias = {1023, 1023}; | |
| const Packet2l even = {-2, -2}; | |
| const Packet2l t = psub(e, b) & even; | |
| const Packet2d c1 = reinterpret_cast<Packet2d>(plogical_shift_left<51>(t + bias + bias)); // 2^(t/2) | |
| const Packet2d c2 = reinterpret_cast<Packet2d>(plogical_shift_left<52>(psub(e, t) + bias)); // 2^(e - t) | |
| return pldexp_apply_factors(a, c1, c2); // a * 2^e | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { | |
| EIGEN_ZVECTOR_PREFETCH(addr); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from) { | |
| return pload<Packet4f>(from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) { | |
| pstore<float>(to, from); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f plset<Packet4f>(const float& a) { | |
| return padd<Packet4f>(pset1<Packet4f>(a), p4f_COUNTDOWN); | |
| } | |
| #if !defined(vec_float) || !defined(__ARCH__) || (defined(__ARCH__) && __ARCH__ < 13) | |
| #pragma GCC warning "float->int and int->float conversion is simulated. compile for z15 for improved performance" | |
| template <> | |
| struct cast_impl<Packet4i, Packet4f> { | |
| EIGEN_DEVICE_FUNC static inline Packet4f run(const Packet4i& a) { | |
| return Packet4f{float(a[0]), float(a[1]), float(a[2]), float(a[3])}; | |
| } | |
| }; | |
| template <> | |
| struct cast_impl<Packet4f, Packet4i> { | |
| // A NaN lane converts to 0: the scalar conversion would be undefined, and pexp's clamp lets NaN through. | |
| EIGEN_DEVICE_FUNC static inline Packet4i run(const Packet4f& a) { | |
| return Packet4i{to_int(a[0]), to_int(a[1]), to_int(a[2]), to_int(a[3])}; | |
| } | |
| EIGEN_DEVICE_FUNC static inline int to_int(float x) { return x == x ? int(x) : 0; } | |
| }; | |
| #else | |
| template <> | |
| struct cast_impl<Packet4i, Packet4f> { | |
| EIGEN_DEVICE_FUNC static inline Packet4f run(const Packet4i& a) { return vec_float(a); } | |
| }; | |
| template <> | |
| struct cast_impl<Packet4f, Packet4i> { | |
| EIGEN_DEVICE_FUNC static inline Packet4i run(const Packet4f& a) { | |
| return vec_signed(vec_sel(p4f_ZERO, a, vec_cmpeq(a, a))); // A NaN lane converts to 0. | |
| } | |
| }; | |
| #endif | |
| template <> | |
| EIGEN_STRONG_INLINE Packet4f pset1frombits<Packet4f>(uint32_t from) { | |
| return pset1<Packet4f>(Eigen::numext::bit_cast<float>(from)); | |
| } | |
| template <> | |
| EIGEN_STRONG_INLINE Packet2d pset1frombits<Packet2d>(uint64_t from) { | |
| return pset1<Packet2d>(Eigen::numext::bit_cast<double>(from)); | |
| } | |
| } // end namespace internal | |
| } // end namespace Eigen | |
| #endif // EIGEN_PACKET_MATH_ZVECTOR_H |