hppa: xfail scan-assembler-not check in g++.dg/cpp0x/initlist-const1.C
[official-gcc.git] / libgfortran / intrinsics / random.c
blob422ad23f9ff387e531828cd98bfc1dc6b456115c
1 /* Implementation of the RANDOM intrinsics
2 Copyright (C) 2002-2023 Free Software Foundation, Inc.
3 Contributed by Lars Segerlund <seger@linuxmail.org>,
4 Steve Kargl and Janne Blomqvist.
6 This file is part of the GNU Fortran runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 Ligbfortran is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
27 /* For rand_s. */
28 #define _CRT_RAND_S
30 #include "libgfortran.h"
31 #include <gthr.h>
32 #include <string.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include "time_1.h"
40 #ifdef HAVE_SYS_RANDOM_H
41 #include <sys/random.h>
42 #endif
44 #ifdef __MINGW32__
45 #define HAVE_GETPID 1
46 #include <process.h>
47 #include <_mingw.h> /* For __MINGW64_VERSION_MAJOR */
48 #endif
50 extern void random_r4 (GFC_REAL_4 *);
51 iexport_proto(random_r4);
53 extern void random_r8 (GFC_REAL_8 *);
54 iexport_proto(random_r8);
56 extern void arandom_r4 (gfc_array_r4 *);
57 export_proto(arandom_r4);
59 extern void arandom_r8 (gfc_array_r8 *);
60 export_proto(arandom_r8);
62 #ifdef HAVE_GFC_REAL_10
64 extern void random_r10 (GFC_REAL_10 *);
65 iexport_proto(random_r10);
67 extern void arandom_r10 (gfc_array_r10 *);
68 export_proto(arandom_r10);
70 #endif
72 #ifdef HAVE_GFC_REAL_16
74 extern void random_r16 (GFC_REAL_16 *);
75 iexport_proto(random_r16);
77 extern void arandom_r16 (gfc_array_r16 *);
78 export_proto(arandom_r16);
80 #endif
82 #ifdef HAVE_GFC_REAL_17
84 extern void random_r17 (GFC_REAL_17 *);
85 iexport_proto(random_r17);
87 extern void arandom_r17 (gfc_array_r17 *);
88 export_proto(arandom_r17);
90 #endif
92 #ifdef __GTHREAD_MUTEX_INIT
93 static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT;
94 #else
95 static __gthread_mutex_t random_lock;
96 #endif
98 /* Helper routines to map a GFC_UINTEGER_* to the corresponding
99 GFC_REAL_* types in the range of [0,1). If GFC_REAL_*_RADIX are 2
100 or 16, respectively, we mask off the bits that don't fit into the
101 correct GFC_REAL_*, convert to the real type, then multiply by the
102 correct offset. */
105 static void
106 rnumber_4 (GFC_REAL_4 *f, GFC_UINTEGER_4 v)
108 GFC_UINTEGER_4 mask;
109 #if GFC_REAL_4_RADIX == 2
110 mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS);
111 #elif GFC_REAL_4_RADIX == 16
112 mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4);
113 #else
114 #error "GFC_REAL_4_RADIX has unknown value"
115 #endif
116 v = v & mask;
117 *f = (GFC_REAL_4) v * GFC_REAL_4_LITERAL(0x1.p-32);
120 static void
121 rnumber_8 (GFC_REAL_8 *f, GFC_UINTEGER_8 v)
123 GFC_UINTEGER_8 mask;
124 #if GFC_REAL_8_RADIX == 2
125 mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_8_DIGITS);
126 #elif GFC_REAL_8_RADIX == 16
127 mask = ~ (GFC_UINTEGER_8) 0u << (16 - GFC_REAL_8_DIGITS) * 4);
128 #else
129 #error "GFC_REAL_8_RADIX has unknown value"
130 #endif
131 v = v & mask;
132 *f = (GFC_REAL_8) v * GFC_REAL_8_LITERAL(0x1.p-64);
135 #ifdef HAVE_GFC_REAL_10
137 static void
138 rnumber_10 (GFC_REAL_10 *f, GFC_UINTEGER_8 v)
140 GFC_UINTEGER_8 mask;
141 #if GFC_REAL_10_RADIX == 2
142 mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_10_DIGITS);
143 #elif GFC_REAL_10_RADIX == 16
144 mask = ~ (GFC_UINTEGER_10) 0u << ((16 - GFC_REAL_10_DIGITS) * 4);
145 #else
146 #error "GFC_REAL_10_RADIX has unknown value"
147 #endif
148 v = v & mask;
149 *f = (GFC_REAL_10) v * GFC_REAL_10_LITERAL(0x1.p-64);
151 #endif
153 #ifdef HAVE_GFC_REAL_16
155 /* For REAL(KIND=16), we only need to mask off the lower bits. */
157 static void
158 rnumber_16 (GFC_REAL_16 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2)
160 GFC_UINTEGER_8 mask;
161 #if GFC_REAL_16_RADIX == 2
162 mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_16_DIGITS);
163 #elif GFC_REAL_16_RADIX == 16
164 mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_16_DIGITS) * 4);
165 #else
166 #error "GFC_REAL_16_RADIX has unknown value"
167 #endif
168 v2 = v2 & mask;
169 *f = (GFC_REAL_16) v1 * GFC_REAL_16_LITERAL(0x1.p-64)
170 + (GFC_REAL_16) v2 * GFC_REAL_16_LITERAL(0x1.p-128);
172 #endif
174 #ifdef HAVE_GFC_REAL_17
176 /* For REAL(KIND=16), we only need to mask off the lower bits. */
178 static void
179 rnumber_17 (GFC_REAL_17 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2)
181 GFC_UINTEGER_8 mask;
182 #if GFC_REAL_17_RADIX == 2
183 mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_17_DIGITS);
184 #elif GFC_REAL_17_RADIX == 16
185 mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_17_DIGITS) * 4);
186 #else
187 #error "GFC_REAL_17_RADIX has unknown value"
188 #endif
189 v2 = v2 & mask;
190 *f = (GFC_REAL_17) v1 * GFC_REAL_17_LITERAL(0x1.p-64)
191 + (GFC_REAL_17) v2 * GFC_REAL_17_LITERAL(0x1.p-128);
193 #endif
198 We use the xoshiro256** generator, a fast high-quality generator
199 that:
201 - passes TestU1 without any failures
203 - provides a "jump" function making it easy to provide many
204 independent parallel streams.
206 - Long period of 2**256 - 1
208 A description can be found at
210 http://prng.di.unimi.it/
214 https://arxiv.org/abs/1805.01407
216 The paper includes public domain source code which is the basis for
217 the implementation below.
220 typedef struct
222 bool init;
223 uint64_t s[4];
225 prng_state;
228 /* master_state is the only variable protected by random_lock. */
229 static prng_state master_state = { .init = false, .s = {
230 0xad63fa1ed3b55f36ULL, 0xd94473e78978b497ULL, 0xbc60592a98172477ULL,
231 0xa3de7c6e81265301ULL }
235 static __gthread_key_t rand_state_key;
237 static prng_state*
238 get_rand_state (void)
240 /* For single threaded apps. */
241 static prng_state rand_state;
243 if (__gthread_active_p ())
245 void* p = __gthread_getspecific (rand_state_key);
246 if (!p)
248 p = xcalloc (1, sizeof (prng_state));
249 __gthread_setspecific (rand_state_key, p);
251 return p;
253 else
254 return &rand_state;
257 static inline uint64_t
258 rotl (const uint64_t x, int k)
260 return (x << k) | (x >> (64 - k));
264 static uint64_t
265 prng_next (prng_state* rs)
267 const uint64_t result = rotl(rs->s[1] * 5, 7) * 9;
269 const uint64_t t = rs->s[1] << 17;
271 rs->s[2] ^= rs->s[0];
272 rs->s[3] ^= rs->s[1];
273 rs->s[1] ^= rs->s[2];
274 rs->s[0] ^= rs->s[3];
276 rs->s[2] ^= t;
278 rs->s[3] = rotl(rs->s[3], 45);
280 return result;
284 /* This is the jump function for the generator. It is equivalent to
285 2^128 calls to prng_next(); it can be used to generate 2^128
286 non-overlapping subsequences for parallel computations. */
288 static void
289 jump (prng_state* rs)
291 static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
293 uint64_t s0 = 0;
294 uint64_t s1 = 0;
295 uint64_t s2 = 0;
296 uint64_t s3 = 0;
297 for(size_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
298 for(int b = 0; b < 64; b++) {
299 if (JUMP[i] & UINT64_C(1) << b) {
300 s0 ^= rs->s[0];
301 s1 ^= rs->s[1];
302 s2 ^= rs->s[2];
303 s3 ^= rs->s[3];
305 prng_next (rs);
308 rs->s[0] = s0;
309 rs->s[1] = s1;
310 rs->s[2] = s2;
311 rs->s[3] = s3;
315 /* Splitmix64 recommended by xoshiro author for initializing. After
316 getting one uint64_t value from the OS, this is used to fill in the
317 rest of the xoshiro state. */
319 static uint64_t
320 splitmix64 (uint64_t x)
322 uint64_t z = (x += 0x9e3779b97f4a7c15);
323 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
324 z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
325 return z ^ (z >> 31);
329 /* Get some bytes from the operating system in order to seed
330 the PRNG. */
332 static int
333 getosrandom (void *buf, size_t buflen)
335 /* rand_s is available in MinGW-w64 but not plain MinGW. */
336 #if defined(__MINGW64_VERSION_MAJOR)
337 unsigned int* b = buf;
338 for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
339 rand_s (&b[i]);
340 return buflen;
341 #else
342 #ifdef HAVE_GETENTROPY
343 if (getentropy (buf, buflen) == 0)
344 return buflen;
345 #endif
346 int flags = O_RDONLY;
347 #ifdef O_CLOEXEC
348 flags |= O_CLOEXEC;
349 #endif
350 int fd = open("/dev/urandom", flags);
351 if (fd != -1)
353 int res = read(fd, buf, buflen);
354 close (fd);
355 return res;
357 uint64_t seed = 0x047f7684e9fc949dULL;
358 time_t secs;
359 long usecs;
360 if (gf_gettime (&secs, &usecs) == 0)
362 seed ^= secs;
363 seed ^= usecs;
365 #ifdef HAVE_GETPID
366 pid_t pid = getpid();
367 seed ^= pid;
368 #endif
369 size_t size = buflen < sizeof (uint64_t) ? buflen : sizeof (uint64_t);
370 memcpy (buf, &seed, size);
371 return size;
372 #endif /* __MINGW64_VERSION_MAJOR */
376 /* Initialize the random number generator for the current thread,
377 using the master state and the number of times we must jump. */
379 static void
380 init_rand_state (prng_state* rs, const bool locked)
382 if (!locked)
383 __gthread_mutex_lock (&random_lock);
384 if (!master_state.init)
386 uint64_t os_seed;
387 getosrandom (&os_seed, sizeof (os_seed));
388 for (uint64_t i = 0; i < sizeof (master_state.s) / sizeof (uint64_t); i++)
390 os_seed = splitmix64 (os_seed);
391 master_state.s[i] = os_seed;
393 master_state.init = true;
395 memcpy (&rs->s, master_state.s, sizeof (master_state.s));
396 jump (&master_state);
397 if (!locked)
398 __gthread_mutex_unlock (&random_lock);
399 rs->init = true;
403 /* This function produces a REAL(4) value from the uniform distribution
404 with range [0,1). */
406 void
407 random_r4 (GFC_REAL_4 *x)
409 prng_state* rs = get_rand_state();
411 if (unlikely (!rs->init))
412 init_rand_state (rs, false);
413 uint64_t r = prng_next (rs);
414 /* Take the higher bits, ensuring that a stream of real(4), real(8),
415 and real(10) will be identical (except for precision). */
416 uint32_t high = (uint32_t) (r >> 32);
417 rnumber_4 (x, high);
419 iexport(random_r4);
421 /* This function produces a REAL(8) value from the uniform distribution
422 with range [0,1). */
424 void
425 random_r8 (GFC_REAL_8 *x)
427 GFC_UINTEGER_8 r;
428 prng_state* rs = get_rand_state();
430 if (unlikely (!rs->init))
431 init_rand_state (rs, false);
432 r = prng_next (rs);
433 rnumber_8 (x, r);
435 iexport(random_r8);
437 #ifdef HAVE_GFC_REAL_10
439 /* This function produces a REAL(10) value from the uniform distribution
440 with range [0,1). */
442 void
443 random_r10 (GFC_REAL_10 *x)
445 GFC_UINTEGER_8 r;
446 prng_state* rs = get_rand_state();
448 if (unlikely (!rs->init))
449 init_rand_state (rs, false);
450 r = prng_next (rs);
451 rnumber_10 (x, r);
453 iexport(random_r10);
455 #endif
457 /* This function produces a REAL(16) value from the uniform distribution
458 with range [0,1). */
460 #ifdef HAVE_GFC_REAL_16
462 void
463 random_r16 (GFC_REAL_16 *x)
465 GFC_UINTEGER_8 r1, r2;
466 prng_state* rs = get_rand_state();
468 if (unlikely (!rs->init))
469 init_rand_state (rs, false);
470 r1 = prng_next (rs);
471 r2 = prng_next (rs);
472 rnumber_16 (x, r1, r2);
474 iexport(random_r16);
477 #endif
479 /* This function produces a REAL(16) value from the uniform distribution
480 with range [0,1). */
482 #ifdef HAVE_GFC_REAL_17
484 void
485 random_r17 (GFC_REAL_17 *x)
487 GFC_UINTEGER_8 r1, r2;
488 prng_state* rs = get_rand_state();
490 if (unlikely (!rs->init))
491 init_rand_state (rs, false);
492 r1 = prng_next (rs);
493 r2 = prng_next (rs);
494 rnumber_17 (x, r1, r2);
496 iexport(random_r17);
499 #endif
501 /* This function fills a REAL(4) array with values from the uniform
502 distribution with range [0,1). */
504 void
505 arandom_r4 (gfc_array_r4 *x)
507 index_type count[GFC_MAX_DIMENSIONS];
508 index_type extent[GFC_MAX_DIMENSIONS];
509 index_type stride[GFC_MAX_DIMENSIONS];
510 index_type stride0;
511 index_type dim;
512 GFC_REAL_4 *dest;
513 prng_state* rs = get_rand_state();
515 dest = x->base_addr;
517 dim = GFC_DESCRIPTOR_RANK (x);
519 for (index_type n = 0; n < dim; n++)
521 count[n] = 0;
522 stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
523 extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
524 if (extent[n] <= 0)
525 return;
528 stride0 = stride[0];
530 if (unlikely (!rs->init))
531 init_rand_state (rs, false);
533 while (dest)
535 /* random_r4 (dest); */
536 uint64_t r = prng_next (rs);
537 uint32_t high = (uint32_t) (r >> 32);
538 rnumber_4 (dest, high);
540 /* Advance to the next element. */
541 dest += stride0;
542 count[0]++;
543 /* Advance to the next source element. */
544 index_type n = 0;
545 while (count[n] == extent[n])
547 /* When we get to the end of a dimension, reset it and increment
548 the next dimension. */
549 count[n] = 0;
550 /* We could precalculate these products, but this is a less
551 frequently used path so probably not worth it. */
552 dest -= stride[n] * extent[n];
553 n++;
554 if (n == dim)
556 dest = NULL;
557 break;
559 else
561 count[n]++;
562 dest += stride[n];
568 /* This function fills a REAL(8) array with values from the uniform
569 distribution with range [0,1). */
571 void
572 arandom_r8 (gfc_array_r8 *x)
574 index_type count[GFC_MAX_DIMENSIONS];
575 index_type extent[GFC_MAX_DIMENSIONS];
576 index_type stride[GFC_MAX_DIMENSIONS];
577 index_type stride0;
578 index_type dim;
579 GFC_REAL_8 *dest;
580 prng_state* rs = get_rand_state();
582 dest = x->base_addr;
584 dim = GFC_DESCRIPTOR_RANK (x);
586 for (index_type n = 0; n < dim; n++)
588 count[n] = 0;
589 stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
590 extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
591 if (extent[n] <= 0)
592 return;
595 stride0 = stride[0];
597 if (unlikely (!rs->init))
598 init_rand_state (rs, false);
600 while (dest)
602 /* random_r8 (dest); */
603 uint64_t r = prng_next (rs);
604 rnumber_8 (dest, r);
606 /* Advance to the next element. */
607 dest += stride0;
608 count[0]++;
609 /* Advance to the next source element. */
610 index_type n = 0;
611 while (count[n] == extent[n])
613 /* When we get to the end of a dimension, reset it and increment
614 the next dimension. */
615 count[n] = 0;
616 /* We could precalculate these products, but this is a less
617 frequently used path so probably not worth it. */
618 dest -= stride[n] * extent[n];
619 n++;
620 if (n == dim)
622 dest = NULL;
623 break;
625 else
627 count[n]++;
628 dest += stride[n];
634 #ifdef HAVE_GFC_REAL_10
636 /* This function fills a REAL(10) array with values from the uniform
637 distribution with range [0,1). */
639 void
640 arandom_r10 (gfc_array_r10 *x)
642 index_type count[GFC_MAX_DIMENSIONS];
643 index_type extent[GFC_MAX_DIMENSIONS];
644 index_type stride[GFC_MAX_DIMENSIONS];
645 index_type stride0;
646 index_type dim;
647 GFC_REAL_10 *dest;
648 prng_state* rs = get_rand_state();
650 dest = x->base_addr;
652 dim = GFC_DESCRIPTOR_RANK (x);
654 for (index_type n = 0; n < dim; n++)
656 count[n] = 0;
657 stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
658 extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
659 if (extent[n] <= 0)
660 return;
663 stride0 = stride[0];
665 if (unlikely (!rs->init))
666 init_rand_state (rs, false);
668 while (dest)
670 /* random_r10 (dest); */
671 uint64_t r = prng_next (rs);
672 rnumber_10 (dest, r);
674 /* Advance to the next element. */
675 dest += stride0;
676 count[0]++;
677 /* Advance to the next source element. */
678 index_type n = 0;
679 while (count[n] == extent[n])
681 /* When we get to the end of a dimension, reset it and increment
682 the next dimension. */
683 count[n] = 0;
684 /* We could precalculate these products, but this is a less
685 frequently used path so probably not worth it. */
686 dest -= stride[n] * extent[n];
687 n++;
688 if (n == dim)
690 dest = NULL;
691 break;
693 else
695 count[n]++;
696 dest += stride[n];
702 #endif
704 #ifdef HAVE_GFC_REAL_16
706 /* This function fills a REAL(16) array with values from the uniform
707 distribution with range [0,1). */
709 void
710 arandom_r16 (gfc_array_r16 *x)
712 index_type count[GFC_MAX_DIMENSIONS];
713 index_type extent[GFC_MAX_DIMENSIONS];
714 index_type stride[GFC_MAX_DIMENSIONS];
715 index_type stride0;
716 index_type dim;
717 GFC_REAL_16 *dest;
718 prng_state* rs = get_rand_state();
720 dest = x->base_addr;
722 dim = GFC_DESCRIPTOR_RANK (x);
724 for (index_type n = 0; n < dim; n++)
726 count[n] = 0;
727 stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
728 extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
729 if (extent[n] <= 0)
730 return;
733 stride0 = stride[0];
735 if (unlikely (!rs->init))
736 init_rand_state (rs, false);
738 while (dest)
740 /* random_r16 (dest); */
741 uint64_t r1 = prng_next (rs);
742 uint64_t r2 = prng_next (rs);
743 rnumber_16 (dest, r1, r2);
745 /* Advance to the next element. */
746 dest += stride0;
747 count[0]++;
748 /* Advance to the next source element. */
749 index_type n = 0;
750 while (count[n] == extent[n])
752 /* When we get to the end of a dimension, reset it and increment
753 the next dimension. */
754 count[n] = 0;
755 /* We could precalculate these products, but this is a less
756 frequently used path so probably not worth it. */
757 dest -= stride[n] * extent[n];
758 n++;
759 if (n == dim)
761 dest = NULL;
762 break;
764 else
766 count[n]++;
767 dest += stride[n];
773 #endif
775 #ifdef HAVE_GFC_REAL_17
777 /* This function fills a REAL(16) array with values from the uniform
778 distribution with range [0,1). */
780 void
781 arandom_r17 (gfc_array_r17 *x)
783 index_type count[GFC_MAX_DIMENSIONS];
784 index_type extent[GFC_MAX_DIMENSIONS];
785 index_type stride[GFC_MAX_DIMENSIONS];
786 index_type stride0;
787 index_type dim;
788 GFC_REAL_17 *dest;
789 prng_state* rs = get_rand_state();
791 dest = x->base_addr;
793 dim = GFC_DESCRIPTOR_RANK (x);
795 for (index_type n = 0; n < dim; n++)
797 count[n] = 0;
798 stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
799 extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
800 if (extent[n] <= 0)
801 return;
804 stride0 = stride[0];
806 if (unlikely (!rs->init))
807 init_rand_state (rs, false);
809 while (dest)
811 /* random_r17 (dest); */
812 uint64_t r1 = prng_next (rs);
813 uint64_t r2 = prng_next (rs);
814 rnumber_17 (dest, r1, r2);
816 /* Advance to the next element. */
817 dest += stride0;
818 count[0]++;
819 /* Advance to the next source element. */
820 index_type n = 0;
821 while (count[n] == extent[n])
823 /* When we get to the end of a dimension, reset it and increment
824 the next dimension. */
825 count[n] = 0;
826 /* We could precalculate these products, but this is a less
827 frequently used path so probably not worth it. */
828 dest -= stride[n] * extent[n];
829 n++;
830 if (n == dim)
832 dest = NULL;
833 break;
835 else
837 count[n]++;
838 dest += stride[n];
844 #endif
847 /* Number of elements in master_state array. */
848 #define SZU64 (sizeof (master_state.s) / sizeof (uint64_t))
850 /* Equivalent number of elements in an array of GFC_INTEGER_{4,8}. */
851 #define SZ_IN_INT_4 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_4)))
852 #define SZ_IN_INT_8 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_8)))
854 /* Keys for scrambling the seed in order to avoid poor seeds. */
856 static const uint64_t xor_keys[] = {
857 0xbd0c5b6e50c2df49ULL, 0xd46061cd46e1df38ULL, 0xbb4f4d4ed6103544ULL,
858 0x114a583d0756ad39ULL
862 /* Since a XOR cipher is symmetric, we need only one routine, and we
863 can use it both for encryption and decryption. */
865 static void
866 scramble_seed (uint64_t *dest, const uint64_t *src)
868 for (size_t i = 0; i < SZU64; i++)
869 dest[i] = src[i] ^ xor_keys[i];
873 /* random_seed is used to seed the PRNG with either a default
874 set of seeds or user specified set of seeds. random_seed
875 must be called with no argument or exactly one argument. */
877 void
878 random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
880 uint64_t seed[SZU64];
882 /* Check that we only have one argument present. */
883 if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
884 runtime_error ("RANDOM_SEED should have at most one argument present.");
886 if (size != NULL)
887 *size = SZ_IN_INT_4;
889 prng_state* rs = get_rand_state();
891 /* Return the seed to GET data. */
892 if (get != NULL)
894 /* If the rank of the array is not 1, abort. */
895 if (GFC_DESCRIPTOR_RANK (get) != 1)
896 runtime_error ("Array rank of GET is not 1.");
898 /* If the array is too small, abort. */
899 if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_4)
900 runtime_error ("Array size of GET is too small.");
902 if (!rs->init)
903 init_rand_state (rs, false);
905 /* Unscramble the seed. */
906 scramble_seed (seed, rs->s);
908 /* Then copy it back to the user variable. */
909 for (size_t i = 0; i < SZ_IN_INT_4 ; i++)
910 memcpy (&(get->base_addr[(SZ_IN_INT_4 - 1 - i) *
911 GFC_DESCRIPTOR_STRIDE(get,0)]),
912 (unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
913 sizeof(GFC_UINTEGER_4));
916 else
918 __gthread_mutex_lock (&random_lock);
920 /* From the standard: "If no argument is present, the processor assigns
921 a processor-dependent value to the seed." */
922 if (size == NULL && put == NULL && get == NULL)
924 master_state.init = false;
925 init_rand_state (rs, true);
928 if (put != NULL)
930 /* If the rank of the array is not 1, abort. */
931 if (GFC_DESCRIPTOR_RANK (put) != 1)
932 runtime_error ("Array rank of PUT is not 1.");
934 /* If the array is too small, abort. */
935 if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_4)
936 runtime_error ("Array size of PUT is too small.");
938 /* We copy the seed given by the user. */
939 for (size_t i = 0; i < SZ_IN_INT_4; i++)
940 memcpy ((unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
941 &(put->base_addr[(SZ_IN_INT_4 - 1 - i) *
942 GFC_DESCRIPTOR_STRIDE(put,0)]),
943 sizeof(GFC_UINTEGER_4));
945 /* We put it after scrambling the bytes, to paper around users who
946 provide seeds with quality only in the lower or upper part. */
947 scramble_seed (master_state.s, seed);
948 master_state.init = true;
949 init_rand_state (rs, true);
952 __gthread_mutex_unlock (&random_lock);
955 iexport(random_seed_i4);
958 void
959 random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
961 uint64_t seed[SZU64];
963 /* Check that we only have one argument present. */
964 if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
965 runtime_error ("RANDOM_SEED should have at most one argument present.");
967 if (size != NULL)
968 *size = SZ_IN_INT_8;
970 prng_state* rs = get_rand_state();
972 /* Return the seed to GET data. */
973 if (get != NULL)
975 /* If the rank of the array is not 1, abort. */
976 if (GFC_DESCRIPTOR_RANK (get) != 1)
977 runtime_error ("Array rank of GET is not 1.");
979 /* If the array is too small, abort. */
980 if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_8)
981 runtime_error ("Array size of GET is too small.");
983 if (!rs->init)
984 init_rand_state (rs, false);
986 /* Unscramble the seed. */
987 scramble_seed (seed, rs->s);
989 /* This code now should do correct strides. */
990 for (size_t i = 0; i < SZ_IN_INT_8; i++)
991 memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &seed[i],
992 sizeof (GFC_UINTEGER_8));
995 else
997 __gthread_mutex_lock (&random_lock);
999 /* From the standard: "If no argument is present, the processor assigns
1000 a processor-dependent value to the seed." */
1001 if (size == NULL && put == NULL && get == NULL)
1003 master_state.init = false;
1004 init_rand_state (rs, true);
1007 if (put != NULL)
1009 /* If the rank of the array is not 1, abort. */
1010 if (GFC_DESCRIPTOR_RANK (put) != 1)
1011 runtime_error ("Array rank of PUT is not 1.");
1013 /* If the array is too small, abort. */
1014 if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_8)
1015 runtime_error ("Array size of PUT is too small.");
1017 /* This code now should do correct strides. */
1018 for (size_t i = 0; i < SZ_IN_INT_8; i++)
1019 memcpy (&seed[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]),
1020 sizeof (GFC_UINTEGER_8));
1022 scramble_seed (master_state.s, seed);
1023 master_state.init = true;
1024 init_rand_state (rs, true);
1028 __gthread_mutex_unlock (&random_lock);
1031 iexport(random_seed_i8);
1034 #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS
1035 static void __attribute__((constructor))
1036 constructor_random (void)
1038 #ifndef __GTHREAD_MUTEX_INIT
1039 __GTHREAD_MUTEX_INIT_FUNCTION (&random_lock);
1040 #endif
1041 if (__gthread_active_p ())
1042 __gthread_key_create (&rand_state_key, &free);
1044 #endif
1046 #ifdef __GTHREADS
1047 static void __attribute__((destructor))
1048 destructor_random (void)
1050 if (__gthread_active_p ())
1051 __gthread_key_delete (rand_state_key);
1053 #endif