packetmath_test_shared.h (9016B)
1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr> 5 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> 6 // 7 // This Source Code Form is subject to the terms of the Mozilla 8 // Public License v. 2.0. If a copy of the MPL was not distributed 9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 11 #include "main.h" 12 #include <typeinfo> 13 14 #if defined __GNUC__ && __GNUC__>=6 15 #pragma GCC diagnostic ignored "-Wignored-attributes" 16 #endif 17 // using namespace Eigen; 18 19 bool g_first_pass = true; 20 21 namespace Eigen { 22 namespace internal { 23 24 template<typename T> T negate(const T& x) { return -x; } 25 26 template<typename T> 27 Map<const Array<unsigned char,sizeof(T),1> > 28 bits(const T& x) { 29 return Map<const Array<unsigned char,sizeof(T),1> >(reinterpret_cast<const unsigned char *>(&x)); 30 } 31 32 // The following implement bitwise operations on floating point types 33 template<typename T,typename Bits,typename Func> 34 T apply_bit_op(Bits a, Bits b, Func f) { 35 Array<unsigned char,sizeof(T),1> data; 36 T res; 37 for(Index i = 0; i < data.size(); ++i) 38 data[i] = f(a[i], b[i]); 39 // Note: The reinterpret_cast works around GCC's class-memaccess warnings: 40 std::memcpy(reinterpret_cast<unsigned char*>(&res), data.data(), sizeof(T)); 41 return res; 42 } 43 44 #define EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,T) \ 45 template<> T EIGEN_CAT(p,OP)(const T& a,const T& b) { \ 46 return apply_bit_op<T>(bits(a),bits(b),FUNC); \ 47 } 48 49 #define EIGEN_TEST_MAKE_BITWISE(OP,FUNC) \ 50 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,float) \ 51 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,double) \ 52 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,half) \ 53 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,bfloat16) \ 54 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,std::complex<float>) \ 55 EIGEN_TEST_MAKE_BITWISE2(OP,FUNC,std::complex<double>) 56 57 EIGEN_TEST_MAKE_BITWISE(xor,std::bit_xor<unsigned char>()) 58 EIGEN_TEST_MAKE_BITWISE(and,std::bit_and<unsigned char>()) 59 EIGEN_TEST_MAKE_BITWISE(or, std::bit_or<unsigned char>()) 60 struct bit_andnot{ 61 template<typename T> T 62 operator()(T a, T b) const { return a & (~b); } 63 }; 64 EIGEN_TEST_MAKE_BITWISE(andnot, bit_andnot()) 65 template<typename T> 66 bool biteq(T a, T b) { 67 return (bits(a) == bits(b)).all(); 68 } 69 70 } 71 72 namespace test { 73 74 // NOTE: we disable inlining for this function to workaround a GCC issue when using -O3 and the i387 FPU. 75 template<typename Scalar> EIGEN_DONT_INLINE 76 bool isApproxAbs(const Scalar& a, const Scalar& b, const typename NumTraits<Scalar>::Real& refvalue) 77 { 78 return internal::isMuchSmallerThan(a-b, refvalue); 79 } 80 81 template<typename Scalar> 82 inline void print_mismatch(const Scalar* ref, const Scalar* vec, int size) { 83 std::cout << "ref: [" << Map<const Matrix<Scalar,1,Dynamic> >(ref,size) << "]" << " != vec: [" << Map<const Matrix<Scalar,1,Dynamic> >(vec,size) << "]\n"; 84 } 85 86 template<typename Scalar> bool areApproxAbs(const Scalar* a, const Scalar* b, int size, const typename NumTraits<Scalar>::Real& refvalue) 87 { 88 for (int i=0; i<size; ++i) 89 { 90 if (!isApproxAbs(a[i],b[i],refvalue)) 91 { 92 print_mismatch(a, b, size); 93 return false; 94 } 95 } 96 return true; 97 } 98 99 template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int size) 100 { 101 for (int i=0; i<size; ++i) 102 { 103 if ( a[i]!=b[i] && !internal::isApprox(a[i],b[i]) 104 && !((numext::isnan)(a[i]) && (numext::isnan)(b[i])) ) 105 { 106 print_mismatch(a, b, size); 107 return false; 108 } 109 } 110 return true; 111 } 112 113 template<typename Scalar> bool areEqual(const Scalar* a, const Scalar* b, int size) 114 { 115 for (int i=0; i<size; ++i) 116 { 117 if ( (a[i] != b[i]) && !((numext::isnan)(a[i]) && (numext::isnan)(b[i])) ) 118 { 119 print_mismatch(a, b, size); 120 return false; 121 } 122 } 123 return true; 124 } 125 126 #define CHECK_CWISE1(REFOP, POP) { \ 127 for (int i=0; i<PacketSize; ++i) \ 128 ref[i] = REFOP(data1[i]); \ 129 internal::pstore(data2, POP(internal::pload<Packet>(data1))); \ 130 VERIFY(test::areApprox(ref, data2, PacketSize) && #POP); \ 131 } 132 133 // Checks component-wise for input of size N. All of data1, data2, and ref 134 // should have size at least ceil(N/PacketSize)*PacketSize to avoid memory 135 // access errors. 136 #define CHECK_CWISE1_N(REFOP, POP, N) { \ 137 for (int i=0; i<N; ++i) \ 138 ref[i] = REFOP(data1[i]); \ 139 for (int j=0; j<N; j+=PacketSize) \ 140 internal::pstore(data2 + j, POP(internal::pload<Packet>(data1 + j))); \ 141 VERIFY(test::areApprox(ref, data2, N) && #POP); \ 142 } 143 144 template<bool Cond,typename Packet> 145 struct packet_helper 146 { 147 template<typename T> 148 inline Packet load(const T* from) const { return internal::pload<Packet>(from); } 149 150 template<typename T> 151 inline Packet loadu(const T* from) const { return internal::ploadu<Packet>(from); } 152 153 template<typename T> 154 inline Packet load(const T* from, unsigned long long umask) const { return internal::ploadu<Packet>(from, umask); } 155 156 template<typename T> 157 inline void store(T* to, const Packet& x) const { internal::pstore(to,x); } 158 159 template<typename T> 160 inline void store(T* to, const Packet& x, unsigned long long umask) const { internal::pstoreu(to, x, umask); } 161 162 template<typename T> 163 inline Packet& forward_reference(Packet& packet, T& /*scalar*/) const { return packet; } 164 }; 165 166 template<typename Packet> 167 struct packet_helper<false,Packet> 168 { 169 template<typename T> 170 inline T load(const T* from) const { return *from; } 171 172 template<typename T> 173 inline T loadu(const T* from) const { return *from; } 174 175 template<typename T> 176 inline T load(const T* from, unsigned long long) const { return *from; } 177 178 template<typename T> 179 inline void store(T* to, const T& x) const { *to = x; } 180 181 template<typename T> 182 inline void store(T* to, const T& x, unsigned long long) const { *to = x; } 183 184 template<typename T> 185 inline T& forward_reference(Packet& /*packet*/, T& scalar) const { return scalar; } 186 }; 187 188 #define CHECK_CWISE1_IF(COND, REFOP, POP) if(COND) { \ 189 test::packet_helper<COND,Packet> h; \ 190 for (int i=0; i<PacketSize; ++i) \ 191 ref[i] = Scalar(REFOP(data1[i])); \ 192 h.store(data2, POP(h.load(data1))); \ 193 VERIFY(test::areApprox(ref, data2, PacketSize) && #POP); \ 194 } 195 196 #define CHECK_CWISE1_EXACT_IF(COND, REFOP, POP) if(COND) { \ 197 test::packet_helper<COND,Packet> h; \ 198 for (int i=0; i<PacketSize; ++i) \ 199 ref[i] = Scalar(REFOP(data1[i])); \ 200 h.store(data2, POP(h.load(data1))); \ 201 VERIFY(test::areEqual(ref, data2, PacketSize) && #POP); \ 202 } 203 204 #define CHECK_CWISE2_IF(COND, REFOP, POP) if(COND) { \ 205 test::packet_helper<COND,Packet> h; \ 206 for (int i=0; i<PacketSize; ++i) \ 207 ref[i] = Scalar(REFOP(data1[i], data1[i+PacketSize])); \ 208 h.store(data2, POP(h.load(data1),h.load(data1+PacketSize))); \ 209 VERIFY(test::areApprox(ref, data2, PacketSize) && #POP); \ 210 } 211 212 // One input, one output by reference. 213 #define CHECK_CWISE1_BYREF1_IF(COND, REFOP, POP) if(COND) { \ 214 test::packet_helper<COND,Packet> h; \ 215 for (int i=0; i<PacketSize; ++i) \ 216 ref[i] = Scalar(REFOP(data1[i], ref[i+PacketSize])); \ 217 Packet pout; \ 218 Scalar sout; \ 219 h.store(data2, POP(h.load(data1), h.forward_reference(pout, sout))); \ 220 h.store(data2+PacketSize, h.forward_reference(pout, sout)); \ 221 VERIFY(test::areApprox(ref, data2, 2 * PacketSize) && #POP); \ 222 } 223 224 #define CHECK_CWISE3_IF(COND, REFOP, POP) if (COND) { \ 225 test::packet_helper<COND, Packet> h; \ 226 for (int i = 0; i < PacketSize; ++i) \ 227 ref[i] = Scalar(REFOP(data1[i], data1[i + PacketSize], \ 228 data1[i + 2 * PacketSize])); \ 229 h.store(data2, POP(h.load(data1), h.load(data1 + PacketSize), \ 230 h.load(data1 + 2 * PacketSize))); \ 231 VERIFY(test::areApprox(ref, data2, PacketSize) && #POP); \ 232 } 233 234 // Specialize the runall struct in your test file by defining run(). 235 template< 236 typename Scalar, 237 typename PacketType, 238 bool IsComplex = NumTraits<Scalar>::IsComplex, 239 bool IsInteger = NumTraits<Scalar>::IsInteger> 240 struct runall; 241 242 template< 243 typename Scalar, 244 typename PacketType = typename internal::packet_traits<Scalar>::type, 245 bool Vectorized = internal::packet_traits<Scalar>::Vectorizable, 246 bool HasHalf = !internal::is_same<typename internal::unpacket_traits<PacketType>::half,PacketType>::value > 247 struct runner; 248 249 template<typename Scalar,typename PacketType> 250 struct runner<Scalar,PacketType,true,true> 251 { 252 static void run() { 253 runall<Scalar,PacketType>::run(); 254 runner<Scalar,typename internal::unpacket_traits<PacketType>::half>::run(); 255 } 256 }; 257 258 template<typename Scalar,typename PacketType> 259 struct runner<Scalar,PacketType,true,false> 260 { 261 static void run() { 262 runall<Scalar,PacketType>::run(); 263 } 264 }; 265 266 template<typename Scalar,typename PacketType> 267 struct runner<Scalar,PacketType,false,false> 268 { 269 static void run() { 270 runall<Scalar,PacketType>::run(); 271 } 272 }; 273 274 } 275 }