1 1.1 mrg /* Implementation of the RANDOM intrinsics 2 1.1.1.4 mrg Copyright (C) 2002-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Lars Segerlund <seger (at) linuxmail.org>, 4 1.1 mrg Steve Kargl and Janne Blomqvist. 5 1.1 mrg 6 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 7 1.1 mrg 8 1.1 mrg Libgfortran is free software; you can redistribute it and/or 9 1.1 mrg modify it under the terms of the GNU General Public 10 1.1 mrg License as published by the Free Software Foundation; either 11 1.1 mrg version 3 of the License, or (at your option) any later version. 12 1.1 mrg 13 1.1 mrg Ligbfortran is distributed in the hope that it will be useful, 14 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 mrg GNU General Public License for more details. 17 1.1 mrg 18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 19 1.1 mrg permissions described in the GCC Runtime Library Exception, version 20 1.1 mrg 3.1, as published by the Free Software Foundation. 21 1.1 mrg 22 1.1 mrg You should have received a copy of the GNU General Public License and 23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25 1.1 mrg <http://www.gnu.org/licenses/>. */ 26 1.1 mrg 27 1.1 mrg /* For rand_s. */ 28 1.1 mrg #define _CRT_RAND_S 29 1.1 mrg 30 1.1 mrg #include "libgfortran.h" 31 1.1 mrg #include <gthr.h> 32 1.1 mrg #include <string.h> 33 1.1 mrg 34 1.1 mrg #ifdef HAVE_UNISTD_H 35 1.1 mrg #include <unistd.h> 36 1.1 mrg #endif 37 1.1 mrg #include <sys/stat.h> 38 1.1 mrg #include <fcntl.h> 39 1.1 mrg #include "time_1.h" 40 1.1 mrg #ifdef HAVE_SYS_RANDOM_H 41 1.1 mrg #include <sys/random.h> 42 1.1 mrg #endif 43 1.1 mrg 44 1.1 mrg #ifdef __MINGW32__ 45 1.1 mrg #define HAVE_GETPID 1 46 1.1 mrg #include <process.h> 47 1.1 mrg #include <_mingw.h> /* For __MINGW64_VERSION_MAJOR */ 48 1.1 mrg #endif 49 1.1 mrg 50 1.1 mrg extern void random_r4 (GFC_REAL_4 *); 51 1.1 mrg iexport_proto(random_r4); 52 1.1 mrg 53 1.1 mrg extern void random_r8 (GFC_REAL_8 *); 54 1.1 mrg iexport_proto(random_r8); 55 1.1 mrg 56 1.1 mrg extern void arandom_r4 (gfc_array_r4 *); 57 1.1 mrg export_proto(arandom_r4); 58 1.1 mrg 59 1.1 mrg extern void arandom_r8 (gfc_array_r8 *); 60 1.1 mrg export_proto(arandom_r8); 61 1.1 mrg 62 1.1 mrg #ifdef HAVE_GFC_REAL_10 63 1.1 mrg 64 1.1 mrg extern void random_r10 (GFC_REAL_10 *); 65 1.1 mrg iexport_proto(random_r10); 66 1.1 mrg 67 1.1 mrg extern void arandom_r10 (gfc_array_r10 *); 68 1.1 mrg export_proto(arandom_r10); 69 1.1 mrg 70 1.1 mrg #endif 71 1.1 mrg 72 1.1 mrg #ifdef HAVE_GFC_REAL_16 73 1.1 mrg 74 1.1 mrg extern void random_r16 (GFC_REAL_16 *); 75 1.1 mrg iexport_proto(random_r16); 76 1.1 mrg 77 1.1 mrg extern void arandom_r16 (gfc_array_r16 *); 78 1.1 mrg export_proto(arandom_r16); 79 1.1 mrg 80 1.1 mrg #endif 81 1.1 mrg 82 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17 83 1.1.1.3 mrg 84 1.1.1.3 mrg extern void random_r17 (GFC_REAL_17 *); 85 1.1.1.3 mrg iexport_proto(random_r17); 86 1.1.1.3 mrg 87 1.1.1.3 mrg extern void arandom_r17 (gfc_array_r17 *); 88 1.1.1.3 mrg export_proto(arandom_r17); 89 1.1.1.3 mrg 90 1.1.1.3 mrg #endif 91 1.1.1.3 mrg 92 1.1 mrg #ifdef __GTHREAD_MUTEX_INIT 93 1.1 mrg static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT; 94 1.1 mrg #else 95 1.1 mrg static __gthread_mutex_t random_lock; 96 1.1 mrg #endif 97 1.1 mrg 98 1.1 mrg /* Helper routines to map a GFC_UINTEGER_* to the corresponding 99 1.1 mrg GFC_REAL_* types in the range of [0,1). If GFC_REAL_*_RADIX are 2 100 1.1 mrg or 16, respectively, we mask off the bits that don't fit into the 101 1.1 mrg correct GFC_REAL_*, convert to the real type, then multiply by the 102 1.1 mrg correct offset. */ 103 1.1 mrg 104 1.1 mrg 105 1.1 mrg static void 106 1.1 mrg rnumber_4 (GFC_REAL_4 *f, GFC_UINTEGER_4 v) 107 1.1 mrg { 108 1.1 mrg GFC_UINTEGER_4 mask; 109 1.1 mrg #if GFC_REAL_4_RADIX == 2 110 1.1 mrg mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS); 111 1.1 mrg #elif GFC_REAL_4_RADIX == 16 112 1.1 mrg mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4); 113 1.1 mrg #else 114 1.1 mrg #error "GFC_REAL_4_RADIX has unknown value" 115 1.1 mrg #endif 116 1.1 mrg v = v & mask; 117 1.1 mrg *f = (GFC_REAL_4) v * GFC_REAL_4_LITERAL(0x1.p-32); 118 1.1 mrg } 119 1.1 mrg 120 1.1 mrg static void 121 1.1 mrg rnumber_8 (GFC_REAL_8 *f, GFC_UINTEGER_8 v) 122 1.1 mrg { 123 1.1 mrg GFC_UINTEGER_8 mask; 124 1.1 mrg #if GFC_REAL_8_RADIX == 2 125 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_8_DIGITS); 126 1.1 mrg #elif GFC_REAL_8_RADIX == 16 127 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (16 - GFC_REAL_8_DIGITS) * 4); 128 1.1 mrg #else 129 1.1 mrg #error "GFC_REAL_8_RADIX has unknown value" 130 1.1 mrg #endif 131 1.1 mrg v = v & mask; 132 1.1 mrg *f = (GFC_REAL_8) v * GFC_REAL_8_LITERAL(0x1.p-64); 133 1.1 mrg } 134 1.1 mrg 135 1.1 mrg #ifdef HAVE_GFC_REAL_10 136 1.1 mrg 137 1.1 mrg static void 138 1.1 mrg rnumber_10 (GFC_REAL_10 *f, GFC_UINTEGER_8 v) 139 1.1 mrg { 140 1.1 mrg GFC_UINTEGER_8 mask; 141 1.1 mrg #if GFC_REAL_10_RADIX == 2 142 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_10_DIGITS); 143 1.1 mrg #elif GFC_REAL_10_RADIX == 16 144 1.1 mrg mask = ~ (GFC_UINTEGER_10) 0u << ((16 - GFC_REAL_10_DIGITS) * 4); 145 1.1 mrg #else 146 1.1 mrg #error "GFC_REAL_10_RADIX has unknown value" 147 1.1 mrg #endif 148 1.1 mrg v = v & mask; 149 1.1 mrg *f = (GFC_REAL_10) v * GFC_REAL_10_LITERAL(0x1.p-64); 150 1.1 mrg } 151 1.1 mrg #endif 152 1.1 mrg 153 1.1 mrg #ifdef HAVE_GFC_REAL_16 154 1.1 mrg 155 1.1 mrg /* For REAL(KIND=16), we only need to mask off the lower bits. */ 156 1.1 mrg 157 1.1 mrg static void 158 1.1 mrg rnumber_16 (GFC_REAL_16 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2) 159 1.1 mrg { 160 1.1 mrg GFC_UINTEGER_8 mask; 161 1.1 mrg #if GFC_REAL_16_RADIX == 2 162 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_16_DIGITS); 163 1.1 mrg #elif GFC_REAL_16_RADIX == 16 164 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_16_DIGITS) * 4); 165 1.1 mrg #else 166 1.1 mrg #error "GFC_REAL_16_RADIX has unknown value" 167 1.1 mrg #endif 168 1.1 mrg v2 = v2 & mask; 169 1.1 mrg *f = (GFC_REAL_16) v1 * GFC_REAL_16_LITERAL(0x1.p-64) 170 1.1 mrg + (GFC_REAL_16) v2 * GFC_REAL_16_LITERAL(0x1.p-128); 171 1.1 mrg } 172 1.1 mrg #endif 173 1.1 mrg 174 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17 175 1.1.1.3 mrg 176 1.1.1.3 mrg /* For REAL(KIND=16), we only need to mask off the lower bits. */ 177 1.1.1.3 mrg 178 1.1.1.3 mrg static void 179 1.1.1.3 mrg rnumber_17 (GFC_REAL_17 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2) 180 1.1.1.3 mrg { 181 1.1.1.3 mrg GFC_UINTEGER_8 mask; 182 1.1.1.3 mrg #if GFC_REAL_17_RADIX == 2 183 1.1.1.3 mrg mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_17_DIGITS); 184 1.1.1.3 mrg #elif GFC_REAL_17_RADIX == 16 185 1.1.1.3 mrg mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_17_DIGITS) * 4); 186 1.1.1.3 mrg #else 187 1.1.1.3 mrg #error "GFC_REAL_17_RADIX has unknown value" 188 1.1.1.3 mrg #endif 189 1.1.1.3 mrg v2 = v2 & mask; 190 1.1.1.3 mrg *f = (GFC_REAL_17) v1 * GFC_REAL_17_LITERAL(0x1.p-64) 191 1.1.1.3 mrg + (GFC_REAL_17) v2 * GFC_REAL_17_LITERAL(0x1.p-128); 192 1.1.1.3 mrg } 193 1.1.1.3 mrg #endif 194 1.1.1.3 mrg 195 1.1 mrg 196 1.1 mrg /* 197 1.1 mrg 198 1.1.1.2 mrg We use the xoshiro256** generator, a fast high-quality generator 199 1.1 mrg that: 200 1.1 mrg 201 1.1 mrg - passes TestU1 without any failures 202 1.1 mrg 203 1.1 mrg - provides a "jump" function making it easy to provide many 204 1.1 mrg independent parallel streams. 205 1.1 mrg 206 1.1.1.2 mrg - Long period of 2**256 - 1 207 1.1 mrg 208 1.1 mrg A description can be found at 209 1.1 mrg 210 1.1.1.2 mrg http://prng.di.unimi.it/ 211 1.1 mrg 212 1.1 mrg or 213 1.1 mrg 214 1.1.1.2 mrg https://arxiv.org/abs/1805.01407 215 1.1 mrg 216 1.1 mrg The paper includes public domain source code which is the basis for 217 1.1 mrg the implementation below. 218 1.1 mrg 219 1.1 mrg */ 220 1.1 mrg typedef struct 221 1.1 mrg { 222 1.1 mrg bool init; 223 1.1.1.2 mrg uint64_t s[4]; 224 1.1 mrg } 225 1.1.1.2 mrg prng_state; 226 1.1 mrg 227 1.1 mrg 228 1.1.1.2 mrg /* master_state is the only variable protected by random_lock. */ 229 1.1.1.2 mrg static prng_state master_state = { .init = false, .s = { 230 1.1.1.2 mrg 0xad63fa1ed3b55f36ULL, 0xd94473e78978b497ULL, 0xbc60592a98172477ULL, 231 1.1.1.2 mrg 0xa3de7c6e81265301ULL } 232 1.1 mrg }; 233 1.1 mrg 234 1.1 mrg 235 1.1 mrg static __gthread_key_t rand_state_key; 236 1.1 mrg 237 1.1.1.2 mrg static prng_state* 238 1.1 mrg get_rand_state (void) 239 1.1 mrg { 240 1.1 mrg /* For single threaded apps. */ 241 1.1.1.2 mrg static prng_state rand_state; 242 1.1 mrg 243 1.1 mrg if (__gthread_active_p ()) 244 1.1 mrg { 245 1.1 mrg void* p = __gthread_getspecific (rand_state_key); 246 1.1 mrg if (!p) 247 1.1 mrg { 248 1.1.1.2 mrg p = xcalloc (1, sizeof (prng_state)); 249 1.1 mrg __gthread_setspecific (rand_state_key, p); 250 1.1 mrg } 251 1.1 mrg return p; 252 1.1 mrg } 253 1.1 mrg else 254 1.1 mrg return &rand_state; 255 1.1 mrg } 256 1.1 mrg 257 1.1.1.2 mrg static inline uint64_t 258 1.1.1.2 mrg rotl (const uint64_t x, int k) 259 1.1.1.2 mrg { 260 1.1.1.2 mrg return (x << k) | (x >> (64 - k)); 261 1.1.1.2 mrg } 262 1.1.1.2 mrg 263 1.1 mrg 264 1.1 mrg static uint64_t 265 1.1.1.2 mrg prng_next (prng_state* rs) 266 1.1 mrg { 267 1.1.1.2 mrg const uint64_t result = rotl(rs->s[1] * 5, 7) * 9; 268 1.1.1.2 mrg 269 1.1.1.2 mrg const uint64_t t = rs->s[1] << 17; 270 1.1.1.2 mrg 271 1.1.1.2 mrg rs->s[2] ^= rs->s[0]; 272 1.1.1.2 mrg rs->s[3] ^= rs->s[1]; 273 1.1.1.2 mrg rs->s[1] ^= rs->s[2]; 274 1.1.1.2 mrg rs->s[0] ^= rs->s[3]; 275 1.1.1.2 mrg 276 1.1.1.2 mrg rs->s[2] ^= t; 277 1.1.1.2 mrg 278 1.1.1.2 mrg rs->s[3] = rotl(rs->s[3], 45); 279 1.1.1.2 mrg 280 1.1.1.2 mrg return result; 281 1.1 mrg } 282 1.1 mrg 283 1.1 mrg 284 1.1 mrg /* This is the jump function for the generator. It is equivalent to 285 1.1.1.2 mrg 2^128 calls to prng_next(); it can be used to generate 2^128 286 1.1 mrg non-overlapping subsequences for parallel computations. */ 287 1.1 mrg 288 1.1 mrg static void 289 1.1.1.2 mrg jump (prng_state* rs) 290 1.1 mrg { 291 1.1.1.2 mrg static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c }; 292 1.1 mrg 293 1.1.1.2 mrg uint64_t s0 = 0; 294 1.1.1.2 mrg uint64_t s1 = 0; 295 1.1.1.2 mrg uint64_t s2 = 0; 296 1.1.1.2 mrg uint64_t s3 = 0; 297 1.1 mrg for(size_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++) 298 1.1.1.2 mrg for(int b = 0; b < 64; b++) { 299 1.1.1.2 mrg if (JUMP[i] & UINT64_C(1) << b) { 300 1.1.1.2 mrg s0 ^= rs->s[0]; 301 1.1.1.2 mrg s1 ^= rs->s[1]; 302 1.1.1.2 mrg s2 ^= rs->s[2]; 303 1.1.1.2 mrg s3 ^= rs->s[3]; 304 1.1 mrg } 305 1.1.1.2 mrg prng_next (rs); 306 1.1.1.2 mrg } 307 1.1.1.2 mrg 308 1.1.1.2 mrg rs->s[0] = s0; 309 1.1.1.2 mrg rs->s[1] = s1; 310 1.1.1.2 mrg rs->s[2] = s2; 311 1.1.1.2 mrg rs->s[3] = s3; 312 1.1 mrg } 313 1.1 mrg 314 1.1 mrg 315 1.1.1.2 mrg /* Splitmix64 recommended by xoshiro author for initializing. After 316 1.1 mrg getting one uint64_t value from the OS, this is used to fill in the 317 1.1.1.2 mrg rest of the xoshiro state. */ 318 1.1 mrg 319 1.1 mrg static uint64_t 320 1.1 mrg splitmix64 (uint64_t x) 321 1.1 mrg { 322 1.1 mrg uint64_t z = (x += 0x9e3779b97f4a7c15); 323 1.1 mrg z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; 324 1.1 mrg z = (z ^ (z >> 27)) * 0x94d049bb133111eb; 325 1.1 mrg return z ^ (z >> 31); 326 1.1 mrg } 327 1.1 mrg 328 1.1 mrg 329 1.1.1.2 mrg /* Get some bytes from the operating system in order to seed 330 1.1 mrg the PRNG. */ 331 1.1 mrg 332 1.1 mrg static int 333 1.1 mrg getosrandom (void *buf, size_t buflen) 334 1.1 mrg { 335 1.1 mrg /* rand_s is available in MinGW-w64 but not plain MinGW. */ 336 1.1 mrg #if defined(__MINGW64_VERSION_MAJOR) 337 1.1 mrg unsigned int* b = buf; 338 1.1 mrg for (size_t i = 0; i < buflen / sizeof (unsigned int); i++) 339 1.1 mrg rand_s (&b[i]); 340 1.1 mrg return buflen; 341 1.1 mrg #else 342 1.1 mrg #ifdef HAVE_GETENTROPY 343 1.1 mrg if (getentropy (buf, buflen) == 0) 344 1.1 mrg return buflen; 345 1.1 mrg #endif 346 1.1 mrg int flags = O_RDONLY; 347 1.1 mrg #ifdef O_CLOEXEC 348 1.1 mrg flags |= O_CLOEXEC; 349 1.1 mrg #endif 350 1.1 mrg int fd = open("/dev/urandom", flags); 351 1.1 mrg if (fd != -1) 352 1.1 mrg { 353 1.1 mrg int res = read(fd, buf, buflen); 354 1.1 mrg close (fd); 355 1.1 mrg return res; 356 1.1 mrg } 357 1.1 mrg uint64_t seed = 0x047f7684e9fc949dULL; 358 1.1 mrg time_t secs; 359 1.1 mrg long usecs; 360 1.1 mrg if (gf_gettime (&secs, &usecs) == 0) 361 1.1 mrg { 362 1.1 mrg seed ^= secs; 363 1.1 mrg seed ^= usecs; 364 1.1 mrg } 365 1.1 mrg #ifdef HAVE_GETPID 366 1.1 mrg pid_t pid = getpid(); 367 1.1 mrg seed ^= pid; 368 1.1 mrg #endif 369 1.1 mrg size_t size = buflen < sizeof (uint64_t) ? buflen : sizeof (uint64_t); 370 1.1 mrg memcpy (buf, &seed, size); 371 1.1 mrg return size; 372 1.1 mrg #endif /* __MINGW64_VERSION_MAJOR */ 373 1.1 mrg } 374 1.1 mrg 375 1.1 mrg 376 1.1 mrg /* Initialize the random number generator for the current thread, 377 1.1 mrg using the master state and the number of times we must jump. */ 378 1.1 mrg 379 1.1 mrg static void 380 1.1.1.2 mrg init_rand_state (prng_state* rs, const bool locked) 381 1.1 mrg { 382 1.1 mrg if (!locked) 383 1.1 mrg __gthread_mutex_lock (&random_lock); 384 1.1.1.2 mrg if (!master_state.init) 385 1.1 mrg { 386 1.1 mrg uint64_t os_seed; 387 1.1 mrg getosrandom (&os_seed, sizeof (os_seed)); 388 1.1.1.2 mrg for (uint64_t i = 0; i < sizeof (master_state.s) / sizeof (uint64_t); i++) 389 1.1 mrg { 390 1.1.1.2 mrg os_seed = splitmix64 (os_seed); 391 1.1.1.2 mrg master_state.s[i] = os_seed; 392 1.1.1.2 mrg } 393 1.1.1.2 mrg master_state.init = true; 394 1.1 mrg } 395 1.1.1.2 mrg memcpy (&rs->s, master_state.s, sizeof (master_state.s)); 396 1.1.1.2 mrg jump (&master_state); 397 1.1 mrg if (!locked) 398 1.1 mrg __gthread_mutex_unlock (&random_lock); 399 1.1 mrg rs->init = true; 400 1.1 mrg } 401 1.1 mrg 402 1.1 mrg 403 1.1 mrg /* This function produces a REAL(4) value from the uniform distribution 404 1.1 mrg with range [0,1). */ 405 1.1 mrg 406 1.1 mrg void 407 1.1 mrg random_r4 (GFC_REAL_4 *x) 408 1.1 mrg { 409 1.1.1.2 mrg prng_state* rs = get_rand_state(); 410 1.1 mrg 411 1.1 mrg if (unlikely (!rs->init)) 412 1.1 mrg init_rand_state (rs, false); 413 1.1.1.2 mrg uint64_t r = prng_next (rs); 414 1.1 mrg /* Take the higher bits, ensuring that a stream of real(4), real(8), 415 1.1 mrg and real(10) will be identical (except for precision). */ 416 1.1 mrg uint32_t high = (uint32_t) (r >> 32); 417 1.1 mrg rnumber_4 (x, high); 418 1.1 mrg } 419 1.1 mrg iexport(random_r4); 420 1.1 mrg 421 1.1 mrg /* This function produces a REAL(8) value from the uniform distribution 422 1.1 mrg with range [0,1). */ 423 1.1 mrg 424 1.1 mrg void 425 1.1 mrg random_r8 (GFC_REAL_8 *x) 426 1.1 mrg { 427 1.1 mrg GFC_UINTEGER_8 r; 428 1.1.1.2 mrg prng_state* rs = get_rand_state(); 429 1.1 mrg 430 1.1 mrg if (unlikely (!rs->init)) 431 1.1 mrg init_rand_state (rs, false); 432 1.1.1.2 mrg r = prng_next (rs); 433 1.1 mrg rnumber_8 (x, r); 434 1.1 mrg } 435 1.1 mrg iexport(random_r8); 436 1.1 mrg 437 1.1 mrg #ifdef HAVE_GFC_REAL_10 438 1.1 mrg 439 1.1 mrg /* This function produces a REAL(10) value from the uniform distribution 440 1.1 mrg with range [0,1). */ 441 1.1 mrg 442 1.1 mrg void 443 1.1 mrg random_r10 (GFC_REAL_10 *x) 444 1.1 mrg { 445 1.1 mrg GFC_UINTEGER_8 r; 446 1.1.1.2 mrg prng_state* rs = get_rand_state(); 447 1.1 mrg 448 1.1 mrg if (unlikely (!rs->init)) 449 1.1 mrg init_rand_state (rs, false); 450 1.1.1.2 mrg r = prng_next (rs); 451 1.1 mrg rnumber_10 (x, r); 452 1.1 mrg } 453 1.1 mrg iexport(random_r10); 454 1.1 mrg 455 1.1 mrg #endif 456 1.1 mrg 457 1.1 mrg /* This function produces a REAL(16) value from the uniform distribution 458 1.1 mrg with range [0,1). */ 459 1.1 mrg 460 1.1 mrg #ifdef HAVE_GFC_REAL_16 461 1.1 mrg 462 1.1 mrg void 463 1.1 mrg random_r16 (GFC_REAL_16 *x) 464 1.1 mrg { 465 1.1 mrg GFC_UINTEGER_8 r1, r2; 466 1.1.1.2 mrg prng_state* rs = get_rand_state(); 467 1.1 mrg 468 1.1 mrg if (unlikely (!rs->init)) 469 1.1 mrg init_rand_state (rs, false); 470 1.1.1.2 mrg r1 = prng_next (rs); 471 1.1.1.2 mrg r2 = prng_next (rs); 472 1.1 mrg rnumber_16 (x, r1, r2); 473 1.1 mrg } 474 1.1 mrg iexport(random_r16); 475 1.1 mrg 476 1.1 mrg 477 1.1 mrg #endif 478 1.1 mrg 479 1.1.1.3 mrg /* This function produces a REAL(16) value from the uniform distribution 480 1.1.1.3 mrg with range [0,1). */ 481 1.1.1.3 mrg 482 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17 483 1.1.1.3 mrg 484 1.1.1.3 mrg void 485 1.1.1.3 mrg random_r17 (GFC_REAL_17 *x) 486 1.1.1.3 mrg { 487 1.1.1.3 mrg GFC_UINTEGER_8 r1, r2; 488 1.1.1.3 mrg prng_state* rs = get_rand_state(); 489 1.1.1.3 mrg 490 1.1.1.3 mrg if (unlikely (!rs->init)) 491 1.1.1.3 mrg init_rand_state (rs, false); 492 1.1.1.3 mrg r1 = prng_next (rs); 493 1.1.1.3 mrg r2 = prng_next (rs); 494 1.1.1.3 mrg rnumber_17 (x, r1, r2); 495 1.1.1.3 mrg } 496 1.1.1.3 mrg iexport(random_r17); 497 1.1.1.3 mrg 498 1.1.1.3 mrg 499 1.1.1.3 mrg #endif 500 1.1.1.3 mrg 501 1.1 mrg /* This function fills a REAL(4) array with values from the uniform 502 1.1 mrg distribution with range [0,1). */ 503 1.1 mrg 504 1.1 mrg void 505 1.1 mrg arandom_r4 (gfc_array_r4 *x) 506 1.1 mrg { 507 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 508 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 509 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS]; 510 1.1 mrg index_type stride0; 511 1.1 mrg index_type dim; 512 1.1 mrg GFC_REAL_4 *dest; 513 1.1.1.2 mrg prng_state* rs = get_rand_state(); 514 1.1 mrg 515 1.1 mrg dest = x->base_addr; 516 1.1 mrg 517 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x); 518 1.1 mrg 519 1.1 mrg for (index_type n = 0; n < dim; n++) 520 1.1 mrg { 521 1.1 mrg count[n] = 0; 522 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); 523 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); 524 1.1 mrg if (extent[n] <= 0) 525 1.1 mrg return; 526 1.1 mrg } 527 1.1 mrg 528 1.1 mrg stride0 = stride[0]; 529 1.1 mrg 530 1.1 mrg if (unlikely (!rs->init)) 531 1.1 mrg init_rand_state (rs, false); 532 1.1 mrg 533 1.1 mrg while (dest) 534 1.1 mrg { 535 1.1 mrg /* random_r4 (dest); */ 536 1.1.1.2 mrg uint64_t r = prng_next (rs); 537 1.1 mrg uint32_t high = (uint32_t) (r >> 32); 538 1.1 mrg rnumber_4 (dest, high); 539 1.1 mrg 540 1.1 mrg /* Advance to the next element. */ 541 1.1 mrg dest += stride0; 542 1.1 mrg count[0]++; 543 1.1 mrg /* Advance to the next source element. */ 544 1.1 mrg index_type n = 0; 545 1.1 mrg while (count[n] == extent[n]) 546 1.1 mrg { 547 1.1 mrg /* When we get to the end of a dimension, reset it and increment 548 1.1 mrg the next dimension. */ 549 1.1 mrg count[n] = 0; 550 1.1 mrg /* We could precalculate these products, but this is a less 551 1.1 mrg frequently used path so probably not worth it. */ 552 1.1 mrg dest -= stride[n] * extent[n]; 553 1.1 mrg n++; 554 1.1 mrg if (n == dim) 555 1.1 mrg { 556 1.1 mrg dest = NULL; 557 1.1 mrg break; 558 1.1 mrg } 559 1.1 mrg else 560 1.1 mrg { 561 1.1 mrg count[n]++; 562 1.1 mrg dest += stride[n]; 563 1.1 mrg } 564 1.1 mrg } 565 1.1 mrg } 566 1.1 mrg } 567 1.1 mrg 568 1.1 mrg /* This function fills a REAL(8) array with values from the uniform 569 1.1 mrg distribution with range [0,1). */ 570 1.1 mrg 571 1.1 mrg void 572 1.1 mrg arandom_r8 (gfc_array_r8 *x) 573 1.1 mrg { 574 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 575 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 576 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS]; 577 1.1 mrg index_type stride0; 578 1.1 mrg index_type dim; 579 1.1 mrg GFC_REAL_8 *dest; 580 1.1.1.2 mrg prng_state* rs = get_rand_state(); 581 1.1 mrg 582 1.1 mrg dest = x->base_addr; 583 1.1 mrg 584 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x); 585 1.1 mrg 586 1.1 mrg for (index_type n = 0; n < dim; n++) 587 1.1 mrg { 588 1.1 mrg count[n] = 0; 589 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); 590 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); 591 1.1 mrg if (extent[n] <= 0) 592 1.1 mrg return; 593 1.1 mrg } 594 1.1 mrg 595 1.1 mrg stride0 = stride[0]; 596 1.1 mrg 597 1.1 mrg if (unlikely (!rs->init)) 598 1.1 mrg init_rand_state (rs, false); 599 1.1 mrg 600 1.1 mrg while (dest) 601 1.1 mrg { 602 1.1 mrg /* random_r8 (dest); */ 603 1.1.1.2 mrg uint64_t r = prng_next (rs); 604 1.1 mrg rnumber_8 (dest, r); 605 1.1 mrg 606 1.1 mrg /* Advance to the next element. */ 607 1.1 mrg dest += stride0; 608 1.1 mrg count[0]++; 609 1.1 mrg /* Advance to the next source element. */ 610 1.1 mrg index_type n = 0; 611 1.1 mrg while (count[n] == extent[n]) 612 1.1 mrg { 613 1.1 mrg /* When we get to the end of a dimension, reset it and increment 614 1.1 mrg the next dimension. */ 615 1.1 mrg count[n] = 0; 616 1.1 mrg /* We could precalculate these products, but this is a less 617 1.1 mrg frequently used path so probably not worth it. */ 618 1.1 mrg dest -= stride[n] * extent[n]; 619 1.1 mrg n++; 620 1.1 mrg if (n == dim) 621 1.1 mrg { 622 1.1 mrg dest = NULL; 623 1.1 mrg break; 624 1.1 mrg } 625 1.1 mrg else 626 1.1 mrg { 627 1.1 mrg count[n]++; 628 1.1 mrg dest += stride[n]; 629 1.1 mrg } 630 1.1 mrg } 631 1.1 mrg } 632 1.1 mrg } 633 1.1 mrg 634 1.1 mrg #ifdef HAVE_GFC_REAL_10 635 1.1 mrg 636 1.1 mrg /* This function fills a REAL(10) array with values from the uniform 637 1.1 mrg distribution with range [0,1). */ 638 1.1 mrg 639 1.1 mrg void 640 1.1 mrg arandom_r10 (gfc_array_r10 *x) 641 1.1 mrg { 642 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 643 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 644 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS]; 645 1.1 mrg index_type stride0; 646 1.1 mrg index_type dim; 647 1.1 mrg GFC_REAL_10 *dest; 648 1.1.1.2 mrg prng_state* rs = get_rand_state(); 649 1.1 mrg 650 1.1 mrg dest = x->base_addr; 651 1.1 mrg 652 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x); 653 1.1 mrg 654 1.1 mrg for (index_type n = 0; n < dim; n++) 655 1.1 mrg { 656 1.1 mrg count[n] = 0; 657 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); 658 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); 659 1.1 mrg if (extent[n] <= 0) 660 1.1 mrg return; 661 1.1 mrg } 662 1.1 mrg 663 1.1 mrg stride0 = stride[0]; 664 1.1 mrg 665 1.1 mrg if (unlikely (!rs->init)) 666 1.1 mrg init_rand_state (rs, false); 667 1.1 mrg 668 1.1 mrg while (dest) 669 1.1 mrg { 670 1.1 mrg /* random_r10 (dest); */ 671 1.1.1.2 mrg uint64_t r = prng_next (rs); 672 1.1 mrg rnumber_10 (dest, r); 673 1.1 mrg 674 1.1 mrg /* Advance to the next element. */ 675 1.1 mrg dest += stride0; 676 1.1 mrg count[0]++; 677 1.1 mrg /* Advance to the next source element. */ 678 1.1 mrg index_type n = 0; 679 1.1 mrg while (count[n] == extent[n]) 680 1.1 mrg { 681 1.1 mrg /* When we get to the end of a dimension, reset it and increment 682 1.1 mrg the next dimension. */ 683 1.1 mrg count[n] = 0; 684 1.1 mrg /* We could precalculate these products, but this is a less 685 1.1 mrg frequently used path so probably not worth it. */ 686 1.1 mrg dest -= stride[n] * extent[n]; 687 1.1 mrg n++; 688 1.1 mrg if (n == dim) 689 1.1 mrg { 690 1.1 mrg dest = NULL; 691 1.1 mrg break; 692 1.1 mrg } 693 1.1 mrg else 694 1.1 mrg { 695 1.1 mrg count[n]++; 696 1.1 mrg dest += stride[n]; 697 1.1 mrg } 698 1.1 mrg } 699 1.1 mrg } 700 1.1 mrg } 701 1.1 mrg 702 1.1 mrg #endif 703 1.1 mrg 704 1.1 mrg #ifdef HAVE_GFC_REAL_16 705 1.1 mrg 706 1.1 mrg /* This function fills a REAL(16) array with values from the uniform 707 1.1 mrg distribution with range [0,1). */ 708 1.1 mrg 709 1.1 mrg void 710 1.1 mrg arandom_r16 (gfc_array_r16 *x) 711 1.1 mrg { 712 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 713 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 714 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS]; 715 1.1 mrg index_type stride0; 716 1.1 mrg index_type dim; 717 1.1 mrg GFC_REAL_16 *dest; 718 1.1.1.2 mrg prng_state* rs = get_rand_state(); 719 1.1 mrg 720 1.1 mrg dest = x->base_addr; 721 1.1 mrg 722 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x); 723 1.1 mrg 724 1.1 mrg for (index_type n = 0; n < dim; n++) 725 1.1 mrg { 726 1.1 mrg count[n] = 0; 727 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); 728 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); 729 1.1 mrg if (extent[n] <= 0) 730 1.1 mrg return; 731 1.1 mrg } 732 1.1 mrg 733 1.1 mrg stride0 = stride[0]; 734 1.1 mrg 735 1.1 mrg if (unlikely (!rs->init)) 736 1.1 mrg init_rand_state (rs, false); 737 1.1 mrg 738 1.1 mrg while (dest) 739 1.1 mrg { 740 1.1 mrg /* random_r16 (dest); */ 741 1.1.1.2 mrg uint64_t r1 = prng_next (rs); 742 1.1.1.2 mrg uint64_t r2 = prng_next (rs); 743 1.1 mrg rnumber_16 (dest, r1, r2); 744 1.1 mrg 745 1.1 mrg /* Advance to the next element. */ 746 1.1 mrg dest += stride0; 747 1.1 mrg count[0]++; 748 1.1 mrg /* Advance to the next source element. */ 749 1.1 mrg index_type n = 0; 750 1.1 mrg while (count[n] == extent[n]) 751 1.1 mrg { 752 1.1 mrg /* When we get to the end of a dimension, reset it and increment 753 1.1 mrg the next dimension. */ 754 1.1 mrg count[n] = 0; 755 1.1 mrg /* We could precalculate these products, but this is a less 756 1.1 mrg frequently used path so probably not worth it. */ 757 1.1 mrg dest -= stride[n] * extent[n]; 758 1.1 mrg n++; 759 1.1 mrg if (n == dim) 760 1.1 mrg { 761 1.1 mrg dest = NULL; 762 1.1 mrg break; 763 1.1 mrg } 764 1.1 mrg else 765 1.1 mrg { 766 1.1 mrg count[n]++; 767 1.1 mrg dest += stride[n]; 768 1.1 mrg } 769 1.1 mrg } 770 1.1 mrg } 771 1.1 mrg } 772 1.1 mrg 773 1.1 mrg #endif 774 1.1 mrg 775 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17 776 1.1.1.3 mrg 777 1.1.1.3 mrg /* This function fills a REAL(16) array with values from the uniform 778 1.1.1.3 mrg distribution with range [0,1). */ 779 1.1.1.3 mrg 780 1.1.1.3 mrg void 781 1.1.1.3 mrg arandom_r17 (gfc_array_r17 *x) 782 1.1.1.3 mrg { 783 1.1.1.3 mrg index_type count[GFC_MAX_DIMENSIONS]; 784 1.1.1.3 mrg index_type extent[GFC_MAX_DIMENSIONS]; 785 1.1.1.3 mrg index_type stride[GFC_MAX_DIMENSIONS]; 786 1.1.1.3 mrg index_type stride0; 787 1.1.1.3 mrg index_type dim; 788 1.1.1.3 mrg GFC_REAL_17 *dest; 789 1.1.1.3 mrg prng_state* rs = get_rand_state(); 790 1.1.1.3 mrg 791 1.1.1.3 mrg dest = x->base_addr; 792 1.1.1.3 mrg 793 1.1.1.3 mrg dim = GFC_DESCRIPTOR_RANK (x); 794 1.1.1.3 mrg 795 1.1.1.3 mrg for (index_type n = 0; n < dim; n++) 796 1.1.1.3 mrg { 797 1.1.1.3 mrg count[n] = 0; 798 1.1.1.3 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); 799 1.1.1.3 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); 800 1.1.1.3 mrg if (extent[n] <= 0) 801 1.1.1.3 mrg return; 802 1.1.1.3 mrg } 803 1.1.1.3 mrg 804 1.1.1.3 mrg stride0 = stride[0]; 805 1.1.1.3 mrg 806 1.1.1.3 mrg if (unlikely (!rs->init)) 807 1.1.1.3 mrg init_rand_state (rs, false); 808 1.1.1.3 mrg 809 1.1.1.3 mrg while (dest) 810 1.1.1.3 mrg { 811 1.1.1.3 mrg /* random_r17 (dest); */ 812 1.1.1.3 mrg uint64_t r1 = prng_next (rs); 813 1.1.1.3 mrg uint64_t r2 = prng_next (rs); 814 1.1.1.3 mrg rnumber_17 (dest, r1, r2); 815 1.1.1.3 mrg 816 1.1.1.3 mrg /* Advance to the next element. */ 817 1.1.1.3 mrg dest += stride0; 818 1.1.1.3 mrg count[0]++; 819 1.1.1.3 mrg /* Advance to the next source element. */ 820 1.1.1.3 mrg index_type n = 0; 821 1.1.1.3 mrg while (count[n] == extent[n]) 822 1.1.1.3 mrg { 823 1.1.1.3 mrg /* When we get to the end of a dimension, reset it and increment 824 1.1.1.3 mrg the next dimension. */ 825 1.1.1.3 mrg count[n] = 0; 826 1.1.1.3 mrg /* We could precalculate these products, but this is a less 827 1.1.1.3 mrg frequently used path so probably not worth it. */ 828 1.1.1.3 mrg dest -= stride[n] * extent[n]; 829 1.1.1.3 mrg n++; 830 1.1.1.3 mrg if (n == dim) 831 1.1.1.3 mrg { 832 1.1.1.3 mrg dest = NULL; 833 1.1.1.3 mrg break; 834 1.1.1.3 mrg } 835 1.1.1.3 mrg else 836 1.1.1.3 mrg { 837 1.1.1.3 mrg count[n]++; 838 1.1.1.3 mrg dest += stride[n]; 839 1.1.1.3 mrg } 840 1.1.1.3 mrg } 841 1.1.1.3 mrg } 842 1.1.1.3 mrg } 843 1.1.1.3 mrg 844 1.1.1.3 mrg #endif 845 1.1.1.3 mrg 846 1.1 mrg 847 1.1 mrg /* Number of elements in master_state array. */ 848 1.1.1.2 mrg #define SZU64 (sizeof (master_state.s) / sizeof (uint64_t)) 849 1.1 mrg 850 1.1.1.3 mrg /* Equivalent number of elements in an array of GFC_INTEGER_{4,8}. */ 851 1.1.1.3 mrg #define SZ_IN_INT_4 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_4))) 852 1.1.1.3 mrg #define SZ_IN_INT_8 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_8))) 853 1.1 mrg 854 1.1 mrg /* Keys for scrambling the seed in order to avoid poor seeds. */ 855 1.1 mrg 856 1.1 mrg static const uint64_t xor_keys[] = { 857 1.1 mrg 0xbd0c5b6e50c2df49ULL, 0xd46061cd46e1df38ULL, 0xbb4f4d4ed6103544ULL, 858 1.1.1.2 mrg 0x114a583d0756ad39ULL 859 1.1 mrg }; 860 1.1 mrg 861 1.1 mrg 862 1.1 mrg /* Since a XOR cipher is symmetric, we need only one routine, and we 863 1.1 mrg can use it both for encryption and decryption. */ 864 1.1 mrg 865 1.1 mrg static void 866 1.1 mrg scramble_seed (uint64_t *dest, const uint64_t *src) 867 1.1 mrg { 868 1.1 mrg for (size_t i = 0; i < SZU64; i++) 869 1.1 mrg dest[i] = src[i] ^ xor_keys[i]; 870 1.1 mrg } 871 1.1 mrg 872 1.1 mrg 873 1.1 mrg /* random_seed is used to seed the PRNG with either a default 874 1.1 mrg set of seeds or user specified set of seeds. random_seed 875 1.1 mrg must be called with no argument or exactly one argument. */ 876 1.1 mrg 877 1.1 mrg void 878 1.1 mrg random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) 879 1.1 mrg { 880 1.1 mrg uint64_t seed[SZU64]; 881 1.1 mrg 882 1.1 mrg /* Check that we only have one argument present. */ 883 1.1 mrg if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1) 884 1.1 mrg runtime_error ("RANDOM_SEED should have at most one argument present."); 885 1.1 mrg 886 1.1 mrg if (size != NULL) 887 1.1.1.3 mrg *size = SZ_IN_INT_4; 888 1.1 mrg 889 1.1.1.2 mrg prng_state* rs = get_rand_state(); 890 1.1 mrg 891 1.1 mrg /* Return the seed to GET data. */ 892 1.1 mrg if (get != NULL) 893 1.1 mrg { 894 1.1 mrg /* If the rank of the array is not 1, abort. */ 895 1.1 mrg if (GFC_DESCRIPTOR_RANK (get) != 1) 896 1.1 mrg runtime_error ("Array rank of GET is not 1."); 897 1.1 mrg 898 1.1 mrg /* If the array is too small, abort. */ 899 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_4) 900 1.1 mrg runtime_error ("Array size of GET is too small."); 901 1.1 mrg 902 1.1 mrg if (!rs->init) 903 1.1 mrg init_rand_state (rs, false); 904 1.1 mrg 905 1.1 mrg /* Unscramble the seed. */ 906 1.1 mrg scramble_seed (seed, rs->s); 907 1.1 mrg 908 1.1 mrg /* Then copy it back to the user variable. */ 909 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_4 ; i++) 910 1.1.1.3 mrg memcpy (&(get->base_addr[(SZ_IN_INT_4 - 1 - i) * 911 1.1.1.3 mrg GFC_DESCRIPTOR_STRIDE(get,0)]), 912 1.1 mrg (unsigned char*) seed + i * sizeof(GFC_UINTEGER_4), 913 1.1 mrg sizeof(GFC_UINTEGER_4)); 914 1.1 mrg } 915 1.1 mrg 916 1.1 mrg else 917 1.1 mrg { 918 1.1 mrg __gthread_mutex_lock (&random_lock); 919 1.1 mrg 920 1.1 mrg /* From the standard: "If no argument is present, the processor assigns 921 1.1 mrg a processor-dependent value to the seed." */ 922 1.1 mrg if (size == NULL && put == NULL && get == NULL) 923 1.1 mrg { 924 1.1.1.2 mrg master_state.init = false; 925 1.1 mrg init_rand_state (rs, true); 926 1.1 mrg } 927 1.1 mrg 928 1.1 mrg if (put != NULL) 929 1.1 mrg { 930 1.1 mrg /* If the rank of the array is not 1, abort. */ 931 1.1 mrg if (GFC_DESCRIPTOR_RANK (put) != 1) 932 1.1 mrg runtime_error ("Array rank of PUT is not 1."); 933 1.1 mrg 934 1.1 mrg /* If the array is too small, abort. */ 935 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_4) 936 1.1 mrg runtime_error ("Array size of PUT is too small."); 937 1.1 mrg 938 1.1 mrg /* We copy the seed given by the user. */ 939 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_4; i++) 940 1.1 mrg memcpy ((unsigned char*) seed + i * sizeof(GFC_UINTEGER_4), 941 1.1.1.3 mrg &(put->base_addr[(SZ_IN_INT_4 - 1 - i) * 942 1.1.1.3 mrg GFC_DESCRIPTOR_STRIDE(put,0)]), 943 1.1 mrg sizeof(GFC_UINTEGER_4)); 944 1.1 mrg 945 1.1 mrg /* We put it after scrambling the bytes, to paper around users who 946 1.1 mrg provide seeds with quality only in the lower or upper part. */ 947 1.1.1.2 mrg scramble_seed (master_state.s, seed); 948 1.1.1.2 mrg master_state.init = true; 949 1.1 mrg init_rand_state (rs, true); 950 1.1 mrg } 951 1.1 mrg 952 1.1 mrg __gthread_mutex_unlock (&random_lock); 953 1.1 mrg } 954 1.1 mrg } 955 1.1 mrg iexport(random_seed_i4); 956 1.1 mrg 957 1.1 mrg 958 1.1 mrg void 959 1.1 mrg random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get) 960 1.1 mrg { 961 1.1 mrg uint64_t seed[SZU64]; 962 1.1 mrg 963 1.1 mrg /* Check that we only have one argument present. */ 964 1.1 mrg if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1) 965 1.1 mrg runtime_error ("RANDOM_SEED should have at most one argument present."); 966 1.1 mrg 967 1.1 mrg if (size != NULL) 968 1.1.1.3 mrg *size = SZ_IN_INT_8; 969 1.1 mrg 970 1.1.1.2 mrg prng_state* rs = get_rand_state(); 971 1.1 mrg 972 1.1 mrg /* Return the seed to GET data. */ 973 1.1 mrg if (get != NULL) 974 1.1 mrg { 975 1.1 mrg /* If the rank of the array is not 1, abort. */ 976 1.1 mrg if (GFC_DESCRIPTOR_RANK (get) != 1) 977 1.1 mrg runtime_error ("Array rank of GET is not 1."); 978 1.1 mrg 979 1.1 mrg /* If the array is too small, abort. */ 980 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_8) 981 1.1 mrg runtime_error ("Array size of GET is too small."); 982 1.1 mrg 983 1.1 mrg if (!rs->init) 984 1.1 mrg init_rand_state (rs, false); 985 1.1 mrg 986 1.1 mrg /* Unscramble the seed. */ 987 1.1 mrg scramble_seed (seed, rs->s); 988 1.1 mrg 989 1.1 mrg /* This code now should do correct strides. */ 990 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_8; i++) 991 1.1 mrg memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &seed[i], 992 1.1 mrg sizeof (GFC_UINTEGER_8)); 993 1.1 mrg } 994 1.1 mrg 995 1.1 mrg else 996 1.1 mrg { 997 1.1 mrg __gthread_mutex_lock (&random_lock); 998 1.1 mrg 999 1.1 mrg /* From the standard: "If no argument is present, the processor assigns 1000 1.1 mrg a processor-dependent value to the seed." */ 1001 1.1 mrg if (size == NULL && put == NULL && get == NULL) 1002 1.1 mrg { 1003 1.1.1.2 mrg master_state.init = false; 1004 1.1 mrg init_rand_state (rs, true); 1005 1.1 mrg } 1006 1.1 mrg 1007 1.1 mrg if (put != NULL) 1008 1.1 mrg { 1009 1.1 mrg /* If the rank of the array is not 1, abort. */ 1010 1.1 mrg if (GFC_DESCRIPTOR_RANK (put) != 1) 1011 1.1 mrg runtime_error ("Array rank of PUT is not 1."); 1012 1.1 mrg 1013 1.1 mrg /* If the array is too small, abort. */ 1014 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_8) 1015 1.1 mrg runtime_error ("Array size of PUT is too small."); 1016 1.1 mrg 1017 1.1 mrg /* This code now should do correct strides. */ 1018 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_8; i++) 1019 1.1 mrg memcpy (&seed[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]), 1020 1.1 mrg sizeof (GFC_UINTEGER_8)); 1021 1.1 mrg 1022 1.1.1.2 mrg scramble_seed (master_state.s, seed); 1023 1.1.1.2 mrg master_state.init = true; 1024 1.1 mrg init_rand_state (rs, true); 1025 1.1 mrg } 1026 1.1 mrg 1027 1.1 mrg 1028 1.1 mrg __gthread_mutex_unlock (&random_lock); 1029 1.1 mrg } 1030 1.1 mrg } 1031 1.1 mrg iexport(random_seed_i8); 1032 1.1 mrg 1033 1.1 mrg 1034 1.1 mrg #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS 1035 1.1 mrg static void __attribute__((constructor)) 1036 1.1 mrg constructor_random (void) 1037 1.1 mrg { 1038 1.1 mrg #ifndef __GTHREAD_MUTEX_INIT 1039 1.1 mrg __GTHREAD_MUTEX_INIT_FUNCTION (&random_lock); 1040 1.1 mrg #endif 1041 1.1 mrg if (__gthread_active_p ()) 1042 1.1 mrg __gthread_key_create (&rand_state_key, &free); 1043 1.1 mrg } 1044 1.1 mrg #endif 1045 1.1 mrg 1046 1.1 mrg #ifdef __GTHREADS 1047 1.1 mrg static void __attribute__((destructor)) 1048 1.1 mrg destructor_random (void) 1049 1.1 mrg { 1050 1.1 mrg if (__gthread_active_p ()) 1051 1.1 mrg __gthread_key_delete (rand_state_key); 1052 1.1 mrg } 1053 1.1 mrg #endif 1054