ut_carray.cpp (9031B)
1 /* 2 Copyright 2010-2011, D. E. Shaw Research. 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are 7 met: 8 9 * Redistributions of source code must retain the above copyright 10 notice, this list of conditions, and the following disclaimer. 11 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions, and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 16 * Neither the name of D. E. Shaw Research nor the names of its 17 contributors may be used to endorse or promote products derived from 18 this software without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 #include <Random123/array.h> 33 #include <iostream> 34 #include <typeinfo> 35 #include <sstream> 36 #include <limits> 37 #include <assert.h> 38 #include <vector> 39 #include "util_demangle.hpp" 40 41 using namespace std; 42 43 template<typename T> 44 inline static T zero(){ return 0; } 45 46 template<typename T> 47 inline static T fff(){ return ~T(0); } 48 49 template<typename T> 50 inline R123_ULONG_LONG ull(const T& t){ return static_cast<R123_ULONG_LONG>(t); } 51 52 template <typename T> 53 inline uint32_t get32(const T& t, size_t n){ 54 return t>>(n*32); 55 } 56 57 #if R123_USE_SSE 58 template<> 59 inline r123m128i zero<r123m128i>(){ r123m128i M; M.m=_mm_setzero_si128(); return M;} 60 61 template<> 62 inline r123m128i fff<r123m128i>(){ r123m128i M; M.m=_mm_set_epi32(~0, ~0, ~0, ~0); return M;} 63 64 template<> 65 inline R123_ULONG_LONG ull<r123m128i>(const r123m128i& t){ 66 return _mm_extract_lo64(t.m); 67 } 68 69 template <> 70 inline uint32_t get32<r123m128i>(const r123m128i& t, size_t n){ 71 switch(n){ 72 case 3: return _mm_cvtsi128_si32(_mm_srli_si128(t.m, 12)); 73 case 2: return _mm_cvtsi128_si32(_mm_srli_si128(t.m, 8)); 74 case 1: return _mm_cvtsi128_si32(_mm_srli_si128(t.m, 4)); 75 } 76 return _mm_cvtsi128_si32(t.m); 77 } 78 #endif 79 80 struct dummySeedSeq{ 81 typedef uint32_t result_type; 82 template <typename ITER> 83 void generate(ITER b, ITER e){ 84 uint32_t v = 0xdeadbeef; 85 for(; b!=e; ++b){ 86 *b = v; 87 v += 0xbaddecaf; 88 } 89 } 90 }; 91 92 template <typename AType> 93 void doit(size_t N, size_t W){ 94 AType uninitialized; 95 typedef AType atype; 96 typedef typename atype::value_type vtype; 97 typedef typename atype::iterator itype; 98 99 assert( R123_W(AType) == W ); 100 101 cout << "doit<" << demangle(uninitialized) << ">"; 102 // size 103 assert(uninitialized.size() == N); 104 105 // width 106 assert(sizeof(vtype)*8 == W); 107 // data 108 assert(uninitialized.data() == &uninitialized.v[0]); 109 110 // front 111 assert(&uninitialized.front() == uninitialized.data()); 112 113 // back 114 assert(&uninitialized.back() == uninitialized.data()+(N-1)); 115 116 // The ut_carray Random123 unit test uses an empty initializer list to 117 // construct instances of different r123 arrays, in a test that's 118 // templated on array type. This works fine for all of the r123 array 119 // types except r123array1xm128i---i.e., an "array" consisting of a single 120 // __m128i value. GCC defines __m128i as a single long long, 121 // 122 // typedef long long __m128i __attribute__ ((__vector_size__ (16), 123 // __may_alias__)); 124 // 125 // while Intel defines it as a union, 126 // 127 // typedef union _MMINTRIN_TYPE(16) __m128i { 128 // #if !defined(_MSC_VER) 129 // /* 130 // * To support GNU compatible intialization with initializers list, 131 // * make first union member to be of int64 type. 132 // */ 133 // __int64 m128i_gcc_compatibility[2]; 134 // #endif 135 // /* 136 // * Although we do not recommend using these directly, they are here 137 // * for better MS compatibility. 138 // */ 139 // __int8 m128i_i8[16]; 140 // __int16 m128i_i16[8]; 141 // __int32 m128i_i32[4]; 142 // __int64 m128i_i64[2]; 143 // unsigned __int8 m128i_u8[16]; 144 // unsigned __int16 m128i_u16[8]; 145 // unsigned __int32 m128i_u32[4]; 146 // unsigned __int64 m128i_u64[2]; 147 // 148 // /* 149 // * This is what we used to have here alone. 150 // * Leave for backward compatibility. 151 // */ 152 // char c[16]; 153 // } __m128i; 154 // 155 // but PGI defines __m128i as a struct, 156 // 157 // typedef struct { 158 // private: long long m128i_i64[2]; 159 // } __attribute__((aligned(16))) __m128i; 160 // 161 // which can't be initialized with initializer lists before C++11. 162 163 // constructor with initializer. [], at 164 #ifndef __PGI 165 AType z = {{}}; 166 #else 167 AType z; 168 z.fill(zero<vtype>()); 169 #endif 170 for(unsigned i=0; i<N; ++i){ 171 assert(!z[i]); 172 assert(!z.at(i)); 173 uninitialized[i] = z[i]; 174 uninitialized[i] += (i+1); 175 } 176 177 // Copy-assignment 178 atype iota = uninitialized; 179 180 // begin/end 181 for(itype p=iota.begin(); p!=iota.end(); ++p){ 182 assert((int)ull(*p) == 1+ (p-iota.begin())); 183 } 184 // cbegin/cend 185 for(typename atype::const_iterator p=iota.cbegin(); p!=iota.cend(); ++p){ 186 assert((int)ull(*p) == 1+ (p-iota.cbegin())); 187 } 188 189 // rbegin/rend 190 for(typename atype::reverse_iterator p=iota.rbegin(); p!=iota.rend(); ++p){ 191 assert((int)ull(*p) == iota.rend()-p); 192 } 193 194 // crbegin/crend 195 for(typename atype::const_reverse_iterator p=iota.crbegin(); p!=iota.crend(); ++p){ 196 assert((int)ull(*p) == iota.crend()-p); 197 } 198 199 // == and != 200 assert(iota == uninitialized); 201 assert(!(iota != uninitialized)); 202 203 for(size_t i=0; i<N; ++i){ 204 atype notequal = iota; 205 ++notequal[i]; 206 assert(notequal != iota); 207 assert(!(notequal == iota)); 208 } 209 210 // Sep 2011 - clang in the fink build of llvm-2.9.1 on MacOS 10.5.8 211 // fails to catch anything, and hence fails this test. I suspect 212 // a problem with the packaging/installation rather than a bug 213 // in llvm. However, if it shows up in other contexts, some 214 // kind of #ifndef might be appropriate. N.B. There's another 215 // exception test below and one in ut_M128.cpp 216 // check that at throws 217 bool caught = false; 218 try{ 219 iota.at(N); 220 }catch(std::out_of_range&){ 221 caught = true; 222 } 223 assert(caught); 224 225 // fill 226 vtype one = zero<vtype>(); 227 ++one; 228 atype aone; 229 aone.fill(one); 230 for(size_t i=0; i<N; ++i){ 231 assert(aone[i] == one); 232 } 233 234 // swap 235 aone.swap(z); 236 for(size_t i=0; i<N; ++i){ 237 assert(aone[i] == zero<vtype>()); 238 assert(z[i] == one); 239 } 240 241 // seed 242 dummySeedSeq seedseq; 243 aone = atype::seed(seedseq); 244 vector<uint32_t> v32( N*((W+31)/32) ); 245 seedseq.generate(v32.begin(), v32.end()); 246 size_t jj=0; 247 uint32_t mask = 0xffffffff; 248 if( W < 32 ) 249 mask >>= (32-W); 250 for(size_t i=0; i<N; ++i){ 251 for(size_t j=0; j<W; j+=32){ 252 uint32_t aj = get32(aone[i], j/32); 253 assert( aj == (mask&v32.at(jj)) ); 254 jj++; 255 } 256 } 257 258 // incr 259 260 #ifndef __PGI 261 atype a = {{}}; 262 #else 263 atype a; 264 a.fill(zero<vtype>()); 265 #endif 266 a.incr(); 267 a.incr(); 268 a.incr(); 269 a.incr(); 270 assert( ull(a[0]) == 4u ); 271 assert( N<2 || ull(a[1]) == 0u ); 272 273 a.incr(0xbadcafe); 274 assert( ull(a[0]) == (mask&(4u+0xbadcafe)) ); 275 276 // Set the zero'th entry to fff and then increment 277 a[0] = fff<vtype>(); 278 a.incr(); 279 assert( a[0] == zero<vtype>() ); 280 assert( N<2 || ull(a[1]) == (W>8?1u:0xcc)); 281 282 a.incr(); 283 assert( ull(a[0]) == 1u ); 284 assert( N<2 || ull(a[1]) == (W>8?1u:0xcc) ); 285 286 R123_ULONG_LONG ulfff = ull(fff<vtype>()); 287 288 a.incr(ulfff); 289 a.incr(ulfff - 5u); 290 a.incr(2); 291 a.incr(2); 292 a.incr(2); 293 a.incr(2); 294 295 // operator<< and operator>> 296 297 std::stringstream ss; 298 ss << a; 299 AType b; 300 ss >> b; 301 assert(a == b); 302 cout << " OK\n"; 303 } 304 305 306 int main(int, char **){ 307 #if R123_USE_SSE 308 doit<r123array1xm128i>(1, 128); 309 #endif 310 doit<r123array2x32>(2, 32); 311 doit<r123array4x32>(4, 32); 312 #if R123_USE_64BIT 313 doit<r123array2x64>(2, 64); 314 doit<r123array4x64>(4, 64); 315 #endif 316 doit<r123array16x8>(16, 8); 317 return 0; 318 } 319