ut_features.cpp (11207B)
1 /* 2 Copyright 2010-2016, 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 // This "unit test" is basically a test of the completeness 33 // of compilerfeatures.hpp. Each of the pp-symbols in compilerfeatures.hpp 34 // is supposed to have a definition. We check them all, and 35 // in some cases, emit some appropriate code to check that 36 // they reflect reality. 37 #include <assert.h> 38 #include <Random123/features/compilerfeatures.h> 39 #include <iostream> 40 41 struct Outputter{ 42 Outputter(const char *name, int value){ 43 std::cout << name << " " << value << std::endl; 44 } 45 }; 46 47 // Many symbols rely on the pp-convention of 48 // expanding undefined values in arithmetic expressions to 0. 49 // Thus, we can't do something terse like: 50 // #define Out(Sym) Outputter outputter##Sym(#Sym, Sym) 51 // Instead, we have to force the preprocessor to evaluate 52 // the symbol. 53 // #if Sym 54 // Otrue(Sym) 55 // #else 56 // Ofalse(Sym) 57 // #endif 58 #define Otrue(Sym) Outputter outputter##Sym(#Sym, true) 59 #define Ofalse(Sym) Outputter outputter##Sym(#Sym, false) 60 61 #ifndef R123_USE_X86INTRIN_H 62 #error "No R123_USE_X86INTRIN_H" 63 #endif 64 #if R123_USE_X86INTRIN_H 65 #include <x86intrin.h> 66 Otrue(R123_USE_X86INTRIN_H); 67 #else 68 Ofalse(R123_USE_X86INTRIN_H); 69 #endif 70 71 #ifndef R123_USE_IA32INTRIN_H 72 #error "No R123_USE_IA32INTRIN_H" 73 #endif 74 #if R123_USE_IA32INTRIN_H 75 Otrue(R123_USE_IA32INTRIN_H); 76 #include <ia32intrin.h> 77 #else 78 Ofalse(R123_USE_IA32INTRIN_H); 79 #endif 80 81 #ifndef R123_USE_XMMINTRIN_H 82 #error "No R123_USE_XMMINTRIN_H" 83 #endif 84 #if R123_USE_XMMINTRIN_H 85 #include <xmmintrin.h> 86 Otrue(R123_USE_XMMINTRIN_H); 87 #else 88 Ofalse(R123_USE_XMMINTRIN_H); 89 #endif 90 91 #ifndef R123_USE_EMMINTRIN_H 92 #error "No R123_USE_EMMINTRIN_H" 93 #endif 94 #if R123_USE_EMMINTRIN_H 95 #include <emmintrin.h> 96 Otrue(R123_USE_EMMINTRIN_H); 97 #else 98 Ofalse(R123_USE_EMMINTRIN_H); 99 #endif 100 101 #ifndef R123_USE_SMMINTRIN_H 102 #error "No R123_USE_SMMINTRIN_H" 103 #endif 104 #if R123_USE_SMMINTRIN_H 105 Otrue(R123_USE_SMMINTRIN_H); 106 #include <smmintrin.h> 107 #else 108 Ofalse(R123_USE_SMMINTRIN_H); 109 #endif 110 111 #ifndef R123_USE_WMMINTRIN_H 112 #error "No R123_USE_WMMINTRIN_H" 113 #endif 114 #if R123_USE_WMMINTRIN_H 115 Otrue(R123_USE_WMMINTRIN_H); 116 #include <wmmintrin.h> 117 #else 118 Ofalse(R123_USE_WMMINTRIN_H); 119 #endif 120 121 #ifndef R123_USE_INTRIN_H 122 #error "No R123_USE_INTRIN_H" 123 #endif 124 #if R123_USE_INTRIN_H 125 Otrue(R123_USE_INTRIN_H); 126 #include <intrin.h> 127 #else 128 Ofalse(R123_USE_INTRIN_H); 129 #endif 130 131 #ifndef R123_USE_SSE 132 #error "No R123_USE_SSE" 133 #endif 134 #if R123_USE_SSE 135 Otrue(R123_USE_SSE); 136 #include <Random123/features/sse.h> 137 __m128i mm; 138 #else 139 Ofalse(R123_USE_SSE); 140 #endif 141 142 #ifndef R123_CUDA_DEVICE 143 #error "No R123_CUDA_DEVICE" 144 #endif 145 R123_CUDA_DEVICE void cuda_device_func(){} 146 147 // C++11 features 148 #ifndef R123_USE_CXX11_UNRESTRICTED_UNIONS 149 #error "No R123_USE_CXX11_UNRESTRICTED_UNIONS" 150 #endif 151 #if R123_USE_CXX11_UNRESTRICTED_UNIONS 152 Otrue(R123_USE_CXX11_UNRESTRICTED_UNIONS); 153 struct defaulted_ctor{ 154 int i; 155 defaulted_ctor()=default; 156 defaulted_ctor(const defaulted_ctor& d) : i(d.i){} 157 }; 158 union unrestricted{ 159 int i; 160 defaulted_ctor dc; 161 }; 162 #else 163 Ofalse(R123_USE_CXX11_UNRESTRICTED_UNIONS); 164 #endif 165 166 #ifndef R123_USE_CXX11_STATIC_ASSERT 167 #error "No R123_USE_CXX11_STATIC_ASSERT" 168 #endif 169 #if R123_USE_CXX11_STATIC_ASSERT 170 Otrue(R123_USE_CXX11_STATIC_ASSERT); 171 static_assert(true, "this shouldn't be a problem"); 172 #else 173 Ofalse(R123_USE_CXX11_STATIC_ASSERT); 174 #endif 175 176 #ifndef R123_USE_CXX11_CONSTEXPR 177 #error "No R123_USE_CXX11_CONSTEXPR" 178 #endif 179 #if R123_USE_CXX11_CONSTEXPR 180 Otrue(R123_USE_CXX11_CONSTEXPR); 181 constexpr int zero() {return 0;} 182 #else 183 Ofalse(R123_USE_CXX11_CONSTEXPR); 184 #endif 185 186 #ifndef R123_USE_CXX11_EXPLICIT_CONVERSIONS 187 #error "No R123_USE_CXX11_EXPLICIT_CONVERSIONS" 188 #endif 189 #if R123_USE_CXX11_EXPLICIT_CONVERSIONS 190 Otrue(R123_USE_CXX11_EXPLICIT_CONVERSIONS); 191 struct explicit_converter{ 192 explicit operator bool() const {return true;} 193 }; 194 #else 195 Ofalse(R123_USE_CXX11_EXPLICIT_CONVERSIONS); 196 #endif 197 198 #ifndef R123_USE_CXX11_RANDOM 199 #error "No R123_USE_CXX11_RANDOM" 200 #endif 201 #if R123_USE_CXX11_RANDOM 202 Otrue(R123_USE_CXX11_RANDOM); 203 #include <random> 204 #else 205 Ofalse(R123_USE_CXX11_RANDOM); 206 #endif 207 208 #ifndef R123_USE_CXX11_TYPE_TRAITS 209 #error "No R123_USE_CXX11_TYPE_TRAITS" 210 #endif 211 #if R123_USE_CXX11_TYPE_TRAITS 212 Otrue(R123_USE_CXX11_TYPE_TRAITS); 213 #include <type_traits> 214 #else 215 Ofalse(R123_USE_CXX11_TYPE_TRAITS); 216 #endif 217 218 #ifndef R123_USE_CXX11_LONG_LONG 219 #error "No R123_USE_CXX11_LONG_LONG" 220 #endif 221 #if R123_USE_CXX11_LONG_LONG 222 Otrue(R123_USE_CXX11_LONG_LONG); 223 unsigned long long ull; 224 #else 225 Ofalse(R123_USE_CXX11_LONG_LONG); 226 #endif 227 228 #ifndef R123_USE_CXX11_STD_ARRAY 229 #error "No R123_USE_CXX11_STD_ARRAY" 230 #endif 231 #if R123_USE_CXX11_STD_ARRAY 232 Otrue(R123_USE_CXX11_STD_ARRAY); 233 #include <array> 234 std::array<int, 4> sai4; 235 #else 236 Ofalse(R123_USE_CXX11_STD_ARRAY); 237 #endif 238 239 #ifndef R123_FORCE_INLINE 240 #error "No R123_FORCE_INLINE" 241 #endif 242 inline R123_FORCE_INLINE(int forcibly_inlined(int i)); 243 inline int forcibly_inlined(int i){ return i+1;} 244 245 #ifndef R123_USE_AES_NI 246 #error "No R123_USE_AES_NI" 247 #endif 248 #if R123_USE_AES_NI 249 Otrue(R123_USE_AES_NI); 250 __m128i aes(__m128i in){ 251 if( haveAESNI() ) 252 return _mm_aesenc_si128(in, in); 253 else 254 return _mm_setzero_si128(); 255 } 256 #else 257 Ofalse(R123_USE_AES_NI); 258 #endif 259 260 #ifndef R123_USE_SSE4_2 261 #error "No R123_USE_SSE4_2" 262 #endif 263 #if R123_USE_SSE4_2 264 Otrue(R123_USE_SSE4_2); 265 __m128i sse42(__m128i in){ 266 return _mm_cmpgt_epi64(in, in); 267 } 268 #else 269 Ofalse(R123_USE_SSE4_2); 270 #endif 271 272 #ifndef R123_USE_SSE4_1 273 #error "No R123_USE_SSE4_1" 274 #endif 275 #if R123_USE_SSE4_1 276 Otrue(R123_USE_SSE4_1); 277 int sse41(__m128i in){ 278 return _mm_testz_si128(in, in); 279 } 280 #else 281 Ofalse(R123_USE_SSE4_1); 282 #endif 283 284 #ifndef R123_USE_AES_OPENSSL 285 #error "No R123_USE_AES_OPENSSL" 286 #endif 287 #if R123_USE_AES_OPENSSL 288 Otrue(R123_USE_AES_OPENSSL); 289 #include <openssl/aes.h> 290 #else 291 Ofalse(R123_USE_AES_OPENSSL); 292 #endif 293 294 #ifndef R123_USE_GNU_UINT128 295 #error "No R123_USE_GNU_UINT128" 296 #endif 297 #if R123_USE_GNU_UINT128 298 Otrue(R123_USE_GNU_UINT128); 299 __uint128_t u128; 300 #else 301 Ofalse(R123_USE_GNU_UINT128); 302 #endif 303 304 #ifndef R123_USE_ASM_GNU 305 #error "No R123_USE_ASM_GNU" 306 #endif 307 #if R123_USE_ASM_GNU 308 Otrue(R123_USE_ASM_GNU); 309 #if defined(__x86_64__) || defined(__i386__) 310 int use_gnu_asm(){ 311 unsigned int eax, ebx, ecx, edx; 312 __asm__ __volatile__ ("cpuid": "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : 313 "a" (1)); 314 return (ecx>>25) & 1; 315 } 316 #else 317 int use_gnu_asm(){ return 0; } 318 #endif 319 #else 320 Ofalse(R123_USE_ASM_GNU); 321 #endif 322 323 #ifndef R123_USE_CPUID_MSVC 324 #error "No R123_USE_CPUID_MSVC" 325 #endif 326 #if R123_USE_CPUID_MSVC 327 Otrue(R123_USE_CPUID_MSVC); 328 int chkcpuid(){ 329 int CPUInfo[4]; 330 __cpuid(CPUInfo, 1); 331 return CPUInfo[2]&(1<<25); 332 } 333 #else 334 Ofalse(R123_USE_CPUID_MSVC); 335 #endif 336 337 #ifndef R123_USE_MULHILO32_ASM 338 #error "No R123_USE_MULHILO32_ASM" 339 #endif 340 #if R123_USE_MULHILO32_ASM 341 Otrue(R123_USE_MULHILO32_ASM); 342 #else 343 Ofalse(R123_USE_MULHILO32_ASM); 344 #endif 345 346 #ifndef R123_USE_MULHILO64_ASM 347 #error "No R123_USE_MULHILO64_ASM" 348 #endif 349 #if R123_USE_MULHILO64_ASM 350 Otrue(R123_USE_MULHILO64_ASM); 351 #else 352 Ofalse(R123_USE_MULHILO64_ASM); 353 #endif 354 355 #ifndef R123_USE_MULHILO64_MSVC_INTRIN 356 #error "No R123_USE_MULHILO_MSVC_INTRIN" 357 #endif 358 #if R123_USE_MULHILO64_MSVC_INTRIN 359 Otrue(R123_USE_MULHILO64_MSVC_INTRIN); 360 #include <cstdint> 361 void msvc64mul(){ 362 uint64_t a=1000000000000000000; 363 uint64_t b=a; 364 uint64_t h, l; 365 l = _umul128(a, b, &h); 366 assert( l == a*b); 367 assert( h == 54210108624275221ULL ); 368 } 369 #else 370 Ofalse(R123_USE_MULHILO64_MSVC_INTRIN); 371 #endif 372 373 #ifndef R123_USE_MULHILO64_CUDA_INTRIN 374 #error "No R123_USE_MULHILO64_CUDA_INTRIN" 375 #endif 376 #if R123_USE_MULHILO64_CUDA_INTRIN 377 Otrue(R123_USE_MULHILO64_CUDA_INTRIN); 378 #else 379 Ofalse(R123_USE_MULHILO64_CUDA_INTRIN); 380 #endif 381 382 #ifndef R123_USE_MULHILO64_OPENCL_INTRIN 383 #error "No R123_USE_MULHILO64_OPENCL_INTRIN" 384 #endif 385 #if R123_USE_MULHILO64_OPENCL_INTRIN 386 Otrue(R123_USE_MULHILO64_OPENCL_INTRIN); 387 #else 388 Ofalse(R123_USE_MULHILO64_OPENCL_INTRIN); 389 #endif 390 391 #ifndef R123_USE_MULHILO64_MULHI_INTRIN 392 #error "No R123_USE_MULHILO64_MULHI_INTRIN" 393 #endif 394 #if R123_USE_MULHILO64_MULHI_INTRIN 395 Otrue(R123_USE_MULHILO64_MULHI_INTRIN); 396 static int test_mulhilo64_intrin(){ 397 uint64_t a = R123_64BIT(0x1234567887654321); 398 uint64_t b = R123_64BIT(0x8765432112345678); 399 uint64_t c = R123_MULHILO64_MULHI_INTRIN(a, b); 400 assert( c == R123_64BIT(0x09A0CD05B99FE92E) ); 401 return c == R123_64BIT(0x09A0CD05B99FE92E); 402 } 403 int mulhilo64_intrin_ok = test_mulhilo64_intrin(); 404 #else 405 Ofalse(R123_USE_MULHILO64_MULHI_INTRIN); 406 #endif 407 408 #ifndef R123_USE_MULHILO32_MULHI_INTRIN 409 #error "No R123_USE_MULHILO32_MULHI_INTRIN" 410 #endif 411 #if R123_USE_MULHILO32_MULHI_INTRIN 412 Otrue(R123_USE_MULHILO32_MULHI_INTRIN); 413 static int test_mulhilo32_intrin(){ 414 uint64_t a32 = 0x12345678; 415 uint64_t b32 = 0x87654321; 416 uint64_t c32 = R123_MULHILO32_MULHI_INTRIN(a32, b32); 417 assert( c32 == 0x09A0CD05 ); 418 return c32 == 0x09A0CD05; 419 } 420 int mulhilo32_intrin_ok = test_mulhilo32_intrin(); 421 #else 422 Ofalse(R123_USE_MULHILO32_MULHI_INTRIN); 423 #endif 424 425 #ifndef R123_USE_MULHILO64_C99 426 #error "No R123_USE_MULHILO64_C99" 427 #endif 428 #if R123_USE_MULHILO64_C99 429 Otrue(R123_USE_MULHILO64_C99); 430 #else 431 Ofalse(R123_USE_MULHILO64_C99); 432 #endif 433 434 #ifndef R123_64BIT 435 #error "No R123_64BIT" 436 #else 437 void xx() { 438 uint64_t a = R123_64BIT(0x1234567890abcdef); 439 assert ( (a >> 60) == 0x1 ); 440 } 441 #endif 442 443 #ifndef R123_USE_PHILOX_64BIT 444 #error "No R123_USE_PHILOX_64BIT" 445 #endif 446 #if R123_USE_PHILOX_64BIT 447 Otrue(R123_USE_PHILOX_64BIT); 448 #else 449 Ofalse(R123_USE_PHILOX_64BIT); 450 #endif 451 452 #ifndef R123_ASSERT 453 #error "No R123_ASSERT" 454 #else 455 void chkassert(){ 456 R123_ASSERT(1); 457 } 458 #endif 459 460 #ifndef R123_STATIC_ASSERT 461 #error "No R123_STATIC_ASSERT" 462 #else 463 R123_STATIC_ASSERT(1, "looks true to me"); 464 void chkstaticassert(){ 465 R123_STATIC_ASSERT(1, "it's ok inside a function too"); 466 } 467 #endif 468 469 int main(int , char **){return 0;}