[fortran] Add random numbers and fix some bugs.
Checks
Commit Message
This patch adds random number support for UNSIGNED, plus fixes
two bugs, with array I/O where the type used to be set to BT_INTEGER,
and for division with the divisor being a constant.
Again, depends on prevous submissions.
OK for trunk?
gcc/fortran/ChangeLog:
* check.cc (gfc_check_random_number): Adjust for unsigned.
* iresolve.cc (gfc_resolve_random_number): Handle unsinged.
* trans-expr.cc (gfc_conv_expr_op): Handle BT_UNSIGNED for divide.
* trans-types.cc (gfc_get_dtype_rank_type): Handle BT_UNSIGNED.
* gfortran.texi: Add RANDOM_NUMBER for UNSIGNED.
libgfortran/ChangeLog:
* gfortran.map: Add _gfortran_random_m1, _gfortran_random_m2,
_gfortran_random_m4, _gfortran_random_m8 and _gfortran_random_m16.
* intrinsics/random.c (random_m1): New function.
(random_m2): New function.
(random_m4): New function.
(random_m8): New function.
(random_m16): New function.
(arandom_m1): New function.
(arandom_m2): New function.
(arandom_m4): New function.
(arandom_m8): New funciton.
(arandom_m16): New function.
gcc/testsuite/ChangeLog:
* gfortran.dg/unsigned_30.f90: New test.
---
gcc/fortran/check.cc | 10 +-
gcc/fortran/gfortran.texi | 1 +
gcc/fortran/iresolve.cc | 6 +-
gcc/fortran/trans-expr.cc | 4 +-
gcc/fortran/trans-types.cc | 7 +-
gcc/testsuite/gfortran.dg/unsigned_30.f90 | 63 ++++
libgfortran/gfortran.map | 10 +
libgfortran/intrinsics/random.c | 440 ++++++++++++++++++++++
8 files changed, 534 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/gfortran.dg/unsigned_30.f90
Comments
Hi Thomas,
submitting your patch as part of the mail got it corrupted by some mailer
adding line breaks. It does not apply for me. Because I can't test it, I have
more questions, see below:
On Wed, 18 Sep 2024 22:22:15 +0200
Thomas Koenig <tkoenig@netcologne.de> wrote:
> This patch adds random number support for UNSIGNED, plus fixes
> two bugs, with array I/O where the type used to be set to BT_INTEGER,
> and for division with the divisor being a constant.
>
> Again, depends on prevous submissions.
>
> OK for trunk?
>
> gcc/fortran/ChangeLog:
>
> * check.cc (gfc_check_random_number): Adjust for unsigned.
> * iresolve.cc (gfc_resolve_random_number): Handle unsinged.
Hihi, I do this typo, too, over and over again: s/unsinged/unsigned/
> * trans-expr.cc (gfc_conv_expr_op): Handle BT_UNSIGNED for divide.
> * trans-types.cc (gfc_get_dtype_rank_type): Handle BT_UNSIGNED.
> * gfortran.texi: Add RANDOM_NUMBER for UNSIGNED.
>
<snip>
> diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
> index 533c9d7d343..1851cfb8d4a 100644
> --- a/gcc/fortran/check.cc
> +++ b/gcc/fortran/check.cc
> @@ -7007,8 +7007,14 @@ gfc_check_random_init (gfc_expr *repeatable,
> gfc_expr *image_distinct)
> bool
> gfc_check_random_number (gfc_expr *harvest)
> {
> - if (!type_check (harvest, 0, BT_REAL))
> - return false;
> + if (flag_unsigned)
> + {
> + if (!type_check2 (harvest, 0, BT_REAL, BT_UNSIGNED))
> + return false;
When the second argument is a BT_INTEGER, does this fail here?
> + }
> + else
> + if (!type_check (harvest, 0, BT_REAL))
> + return false;
>
> if (!variable_check (harvest, 0, false))
> return false;
<snip>
Regards,
Andre
--
Andre Vehreschild * Email: vehre ad gmx dot de
Am 19.09.24 um 12:16 schrieb Andre Vehreschild:
> Hi Thomas,
>
> submitting your patch as part of the mail got it corrupted by some mailer
> adding line breaks. It does not apply for me. Because I can't test it, I have
> more questions, see below:
I have attached it.
>
> On Wed, 18 Sep 2024 22:22:15 +0200
> Thomas Koenig <tkoenig@netcologne.de> wrote:
>
>> This patch adds random number support for UNSIGNED, plus fixes
>> two bugs, with array I/O where the type used to be set to BT_INTEGER,
>> and for division with the divisor being a constant.
>>
>> Again, depends on prevous submissions.
>>
>> OK for trunk?
>>
>> gcc/fortran/ChangeLog:
>>
>> * check.cc (gfc_check_random_number): Adjust for unsigned.
>> * iresolve.cc (gfc_resolve_random_number): Handle unsinged.
>
> Hihi, I do this typo, too, over and over again: s/unsinged/unsigned/
Yep :-) It's like it is burned into my fingers or something.
>> * trans-expr.cc (gfc_conv_expr_op): Handle BT_UNSIGNED for divide.
>> * trans-types.cc (gfc_get_dtype_rank_type): Handle BT_UNSIGNED.
>> * gfortran.texi: Add RANDOM_NUMBER for UNSIGNED.
>>
>
> <snip>
>
>> diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
>> index 533c9d7d343..1851cfb8d4a 100644
>> --- a/gcc/fortran/check.cc
>> +++ b/gcc/fortran/check.cc
>> @@ -7007,8 +7007,14 @@ gfc_check_random_init (gfc_expr *repeatable,
>> gfc_expr *image_distinct)
>> bool
>> gfc_check_random_number (gfc_expr *harvest)
>> {
>> - if (!type_check (harvest, 0, BT_REAL))
>> - return false;
>> + if (flag_unsigned)
>> + {
>> + if (!type_check2 (harvest, 0, BT_REAL, BT_UNSIGNED))
>> + return false;
>
> When the second argument is a BT_INTEGER, does this fail here?
As it should. RANDOM_NUMBER usually is for REALs only. I thought
it an obvious idea to extend it to unsigned integers, but only got
the idea after the document was finalized, so I'm implementing
it anyway.
>> + }
>> + else
>> + if (!type_check (harvest, 0, BT_REAL))
>> + return false;
>>
>> if (!variable_check (harvest, 0, false))
>> return false;
>
Best regards
Thomas
@@ -7007,8 +7007,14 @@ gfc_check_random_init (gfc_expr *repeatable,
gfc_expr *image_distinct)
bool
gfc_check_random_number (gfc_expr *harvest)
{
- if (!type_check (harvest, 0, BT_REAL))
- return false;
+ if (flag_unsigned)
+ {
+ if (!type_check2 (harvest, 0, BT_REAL, BT_UNSIGNED))
+ return false;
+ }
+ else
+ if (!type_check (harvest, 0, BT_REAL))
+ return false;
if (!variable_check (harvest, 0, false))
return false;
@@ -2790,6 +2790,7 @@ As of now, the following intrinsics take unsigned
arguments:
@item @code{TRANSFER}
@item @code{SUM}, @code{PRODUCT}, @code{MATMUL} and @code{DOT_PRODUCT}
@item @code{IANY}, @code{IALL} and @code{IPARITY}
+@item @code{RANDOM_NUMBER}.
@end itemize
This list will grow in the near future.
@c ---------------------------------------------------------------------
@@ -3452,12 +3452,14 @@ gfc_resolve_random_number (gfc_code *c)
{
const char *name;
int kind;
+ char type;
kind = gfc_type_abi_kind (&c->ext.actual->expr->ts);
+ type = gfc_type_letter (c->ext.actual->expr->ts.type);
if (c->ext.actual->expr->rank == 0)
- name = gfc_get_string (PREFIX ("random_r%d"), kind);
+ name = gfc_get_string (PREFIX ("random_%c%d"), type, kind);
else
- name = gfc_get_string (PREFIX ("arandom_r%d"), kind);
+ name = gfc_get_string (PREFIX ("arandom_%c%d"), type, kind);
c->resolved_sym = gfc_get_intrinsic_sub_symbol (name);
}
@@ -3982,9 +3982,9 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
case INTRINSIC_DIVIDE:
/* If expr is a real or complex expr, use an RDIV_EXPR. If op1 is
- an integer, we must round towards zero, so we use a
+ an integer or unsigned, we must round towards zero, so we use a
TRUNC_DIV_EXPR. */
- if (expr->ts.type == BT_INTEGER)
+ if (expr->ts.type == BT_INTEGER || expr->ts.type == BT_UNSIGNED)
code = TRUNC_DIV_EXPR;
else
code = RDIV_EXPR;
@@ -1651,7 +1651,12 @@ gfc_get_dtype_rank_type (int rank, tree etype)
&& TYPE_STRING_FLAG (ptype))
n = BT_CHARACTER;
else
- n = BT_INTEGER;
+ {
+ if (TYPE_UNSIGNED (etype))
+ n = BT_UNSIGNED;
+ else
+ n = BT_INTEGER;
+ }
break;
case BOOLEAN_TYPE:
b/gcc/testsuite/gfortran.dg/unsigned_30.f90
new file mode 100644
@@ -0,0 +1,63 @@
+! { dg-do run }
+! { dg-options "-funsigned" }
+
+! The leading bytes of the unsigned sequences should be the same for
+! kinds 1 to 8. This also tests array I/O for unsigneds.
+
+program memain
+ implicit none
+ integer, dimension(:), allocatable :: seed
+ integer :: n
+ call random_seed (size=n)
+ allocate(seed(n))
+ call test1
+ call test2
+contains
+ subroutine test1
+ unsigned(1) :: u1
+ unsigned(2) :: u2
+ unsigned(4) :: u4
+ unsigned(8) :: u8
+ character (len=16) :: line1, line2, line4, line8
+ integer :: i, n
+ do i=1,10
+ call random_seed(get=seed)
+ call random_number(u1)
+ write (line1,'(Z2.2)') u1
+ call random_seed(put=seed)
+ call random_number(u2)
+ write (line2,'(Z4.4)') u2
+ call random_seed(put=seed)
+ call random_number(u4)
+ write (line4,'(Z8.8)') u4
+ call random_seed(put=seed)
+ call random_number(u8)
+ write (line8,'(Z16.16)') u8
+ if (line8(1:8) /= line4 (1:8)) error stop 1
+ if (line4(1:4) /= line2 (1:4)) error stop 2
+ if (line2(1:2) /= line1 (1:2)) error stop 3
+ end do
+ end subroutine test1
+ subroutine test2
+ unsigned(1), dimension(2,2) :: v1
+ unsigned(2), dimension(2,2) :: v2
+ unsigned(4), dimension(2,2) :: v4
+ unsigned(8), dimension(2,2) :: v8
+ character(len=16), dimension(4) :: c1, c2, c4, c8
+ call random_seed(put=seed)
+ call random_number (v1)
+ write (c1,'(Z2.2)') v1
+ call random_seed(put=seed)
+ call random_number (v2)
+ write (c2,'(Z4.4)') v2
+ call random_seed(put=seed)
+ call random_number (v4)
+ write (c4,'(Z8.8)') v4
+ call random_seed(put=seed)
+ call random_number (v8)
+ write (c8,'(Z16.16)') v8
+ if (any(c8(:)(1:8) /= c4(:)(1:8))) error stop 10
+ if (any(c4(:)(1:4) /= c2(:)(1:4))) error stop 11
+ if (any(c2(:)(1:2) /= c1(:)(1:2))) error stop 12
+ end subroutine test2
+end program memain
@@ -1777,4 +1777,14 @@ GFORTRAN_15 {
_gfortran_internal_unpack_class;
_gfortran_transfer_unsigned;
_gfortran_transfer_unsigned_write;
+ _gfortran_random_m1;
+ _gfortran_random_m2;
+ _gfortran_random_m4;
+ _gfortran_random_m8;
+ _gfortran_random_m16;
+ _gfortran_arandom_m1;
+ _gfortran_arandom_m2;
+ _gfortran_arandom_m4;
+ _gfortran_arandom_m8;
+ _gfortran_arandom_m16;
} GFORTRAN_14;
b/libgfortran/intrinsics/random.c
@@ -89,6 +89,43 @@ export_proto(arandom_r17);
#endif
+extern void random_m1 (GFC_UINTEGER_1 *);
+export_proto (random_m1);
+
+extern void random_m2 (GFC_UINTEGER_2 *);
+export_proto (random_m2);
+
+extern void random_m4 (GFC_UINTEGER_4 *);
+export_proto (random_m4);
+
+extern void random_m8 (GFC_UINTEGER_8 *);
+export_proto (random_m8);
+
+#ifdef HAVE_GFC_UINTEGER_16
+extern void random_m16 (GFC_UINTEGER_16 *);
+export_proto (random_m16);
+
+#endif
+
+extern void arandom_m1 (gfc_array_m1 *);
+export_proto (arandom_m1);
+
+extern void arandom_m2 (gfc_array_m2 *);
+export_proto (arandom_m2);
+
+extern void arandom_m4 (gfc_array_m4 *);
+export_proto (arandom_m4);
+
+extern void arandom_m8 (gfc_array_m8 *);
+export_proto (arandom_m8);
+
+#ifdef HAVE_GFC_UINTEGER_16
+
+extern void arandom_m16 (gfc_array_m16 *);
+export_proto (arandom_m16);
+
+#endif
+
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT;
#else
@@ -498,6 +535,81 @@ iexport(random_r17);
#endif
+/* Versions for unsigned numbers. */
+
+/* Returns a random byte. */
+
+void
+random_m1 (GFC_UINTEGER_1 *x)
+{
+ prng_state* rs = get_rand_state();
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+ GFC_UINTEGER_8 r = prng_next (rs);
+
+ *x = r >> 56;
+}
+
+/* A random 16-bit number. */
+
+void
+random_m2 (GFC_UINTEGER_2 *x)
+{
+ prng_state* rs = get_rand_state();
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+ GFC_UINTEGER_8 r = prng_next (rs);
+
+ *x = r >> 48;
+}
+
+/* A random 32-bit number. */
+
+void
+random_m4 (GFC_UINTEGER_4 *x)
+{
+ prng_state* rs = get_rand_state();
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+ GFC_UINTEGER_8 r = prng_next (rs);
+
+ *x = r >> 32;
+}
+
+/* A random 64-bit number. */
+
+void
+random_m8 (GFC_UINTEGER_8 *x)
+{
+ prng_state* rs = get_rand_state();
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+ GFC_UINTEGER_8 r = prng_next (rs);
+
+ *x = r;
+}
+
+/* ... and a random 128-bit number, if we have the type. */
+
+#ifdef HAVE_GFC_UINTEGER_16
+void
+random_m16 (GFC_UINTEGER_16 *x)
+{
+ prng_state* rs = get_rand_state();
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+ GFC_UINTEGER_8 r1 = prng_next (rs);
+ GFC_UINTEGER_8 r2 = prng_next (rs);
+
+ *x = (((GFC_UINTEGER_16) r1) << 64) | (GFC_UINTEGER_16) r2;
+}
+#endif
+
/* This function fills a REAL(4) array with values from the uniform
distribution with range [0,1). */
@@ -843,6 +955,334 @@ arandom_r17 (gfc_array_r17 *x)
#endif
+/* Fill an unsigned array with random bytes. */
+
+void
+arandom_m1 (gfc_array_m1 *x)
+{
+ index_type count[GFC_MAX_DIMENSIONS];
+ index_type extent[GFC_MAX_DIMENSIONS];
+ index_type stride[GFC_MAX_DIMENSIONS];
+ index_type stride0;
+ index_type dim;
+ GFC_UINTEGER_1 *dest;
+ prng_state* rs = get_rand_state();
+
+ dest = x->base_addr;
+
+ dim = GFC_DESCRIPTOR_RANK (x);
+
+ for (index_type n = 0; n < dim; n++)
+ {
+ count[n] = 0;
+ stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
+ if (extent[n] <= 0)
+ return;
+ }
+
+ stride0 = stride[0];
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+
+ while (dest)
+ {
+ /* random_m1 (dest); */
+ uint64_t r = prng_next (rs);
+ *dest = r >> 56;
+
+ /* Advance to the next element. */
+ dest += stride0;
+ count[0]++;
+ /* Advance to the next source element. */
+ index_type n = 0;
+ while (count[n] == extent[n])
+ {
+ /* When we get to the end of a dimension, reset it and increment
+ the next dimension. */
+ count[n] = 0;
+ /* We could precalculate these products, but this is a less
+ frequently used path so probably not worth it. */
+ dest -= stride[n] * extent[n];
+ n++;
+ if (n == dim)
+ {
+ dest = NULL;
+ break;
+ }
+ else
+ {
+ count[n]++;
+ dest += stride[n];
+ }
+ }
+ }
+}
+
+/* Fill an unsigned array with random 16-bit unsigneds. */
+
+void
+arandom_m2 (gfc_array_m2 *x)
+{
+ index_type count[GFC_MAX_DIMENSIONS];
+ index_type extent[GFC_MAX_DIMENSIONS];
+ index_type stride[GFC_MAX_DIMENSIONS];
+ index_type stride0;
+ index_type dim;
+ GFC_UINTEGER_2 *dest;
+ prng_state* rs = get_rand_state();
+
+ dest = x->base_addr;
+
+ dim = GFC_DESCRIPTOR_RANK (x);
+
+ for (index_type n = 0; n < dim; n++)
+ {
+ count[n] = 0;
+ stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
+ if (extent[n] <= 0)
+ return;
+ }
+
+ stride0 = stride[0];
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+
+ while (dest)
+ {
+ /* random_m1 (dest); */
+ uint64_t r = prng_next (rs);
+ *dest = r >> 48;
+
+ /* Advance to the next element. */
+ dest += stride0;
+ count[0]++;
+ /* Advance to the next source element. */
+ index_type n = 0;
+ while (count[n] == extent[n])
+ {
+ /* When we get to the end of a dimension, reset it and increment
+ the next dimension. */
+ count[n] = 0;
+ /* We could precalculate these products, but this is a less
+ frequently used path so probably not worth it. */
+ dest -= stride[n] * extent[n];
+ n++;
+ if (n == dim)
+ {
+ dest = NULL;
+ break;
+ }
+ else
+ {
+ count[n]++;
+ dest += stride[n];
+ }
+ }
+ }
+}
+
+/* Fill an array with random 32-bit unsigneds. */
+
+void
+arandom_m4 (gfc_array_m4 *x)
+{
+ index_type count[GFC_MAX_DIMENSIONS];
+ index_type extent[GFC_MAX_DIMENSIONS];
+ index_type stride[GFC_MAX_DIMENSIONS];
+ index_type stride0;
+ index_type dim;
+ GFC_UINTEGER_4 *dest;
+ prng_state* rs = get_rand_state();
+
+ dest = x->base_addr;
+
+ dim = GFC_DESCRIPTOR_RANK (x);
+
+ for (index_type n = 0; n < dim; n++)
+ {
+ count[n] = 0;
+ stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
+ if (extent[n] <= 0)
+ return;
+ }
+
+ stride0 = stride[0];
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+
+ while (dest)
+ {
+ /* random_m4 (dest); */
+ uint64_t r = prng_next (rs);
+ *dest = r >> 32;
+
+ /* Advance to the next element. */
+ dest += stride0;
+ count[0]++;
+ /* Advance to the next source element. */
+ index_type n = 0;
+ while (count[n] == extent[n])
+ {
+ /* When we get to the end of a dimension, reset it and increment
+ the next dimension. */
+ count[n] = 0;
+ /* We could precalculate these products, but this is a less
+ frequently used path so probably not worth it. */
+ dest -= stride[n] * extent[n];
+ n++;
+ if (n == dim)
+ {
+ dest = NULL;
+ break;
+ }
+ else
+ {
+ count[n]++;
+ dest += stride[n];
+ }
+ }
+ }
+}
+
+/* Fill an array with random 64-bit unsigneds. */
+
+void
+arandom_m8 (gfc_array_m8 *x)
+{
+ index_type count[GFC_MAX_DIMENSIONS];
+ index_type extent[GFC_MAX_DIMENSIONS];
+ index_type stride[GFC_MAX_DIMENSIONS];
+ index_type stride0;
+ index_type dim;
+ GFC_UINTEGER_8 *dest;
+ prng_state* rs = get_rand_state();
+
+ dest = x->base_addr;
+
+ dim = GFC_DESCRIPTOR_RANK (x);
+
+ for (index_type n = 0; n < dim; n++)
+ {
+ count[n] = 0;
+ stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
+ if (extent[n] <= 0)
+ return;
+ }
+
+ stride0 = stride[0];
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+
+ while (dest)
+ {
+ /* random_m8 (dest); */
+ uint64_t r = prng_next (rs);
+ *dest = r;
+
+ /* Advance to the next element. */
+ dest += stride0;
+ count[0]++;
+ /* Advance to the next source element. */
+ index_type n = 0;
+ while (count[n] == extent[n])
+ {
+ /* When we get to the end of a dimension, reset it and increment
+ the next dimension. */
+ count[n] = 0;
+ /* We could precalculate these products, but this is a less
+ frequently used path so probably not worth it. */
+ dest -= stride[n] * extent[n];
+ n++;
+ if (n == dim)
+ {
+ dest = NULL;
+ break;
+ }
+ else
+ {
+ count[n]++;
+ dest += stride[n];
+ }
+ }
+ }
+}
+
+#ifdef GFC_HAVE_GFC_UINTEGER_16
+
+/* Fill an unsigned array with random bytes. */
+
+void
+arandom_m16 (gfc_array_m16 *x)
+{
+ index_type count[GFC_MAX_DIMENSIONS];
+ index_type extent[GFC_MAX_DIMENSIONS];
+ index_type stride[GFC_MAX_DIMENSIONS];
+ index_type stride0;
+ index_type dim;
+ GFC_UINTEGER_16 *dest;
+ prng_state* rs = get_rand_state();
+
+ dest = x->base_addr;
+
+ dim = GFC_DESCRIPTOR_RANK (x);
+
+ for (index_type n = 0; n < dim; n++)
+ {
+ count[n] = 0;
+ stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
+ if (extent[n] <= 0)
+ return;
+ }
+
+ stride0 = stride[0];
+
+ if (unlikely (!rs->init))
+ init_rand_state (rs, false);
+
+ while (dest)
+ {
+ /* random_m16 (dest); */
+ uint64_t r1 = prng_next (rs), r2 = prng_next (rs);
+ *dest = (((GFC_UINTEGER_16) r1) << 64) | (GFC_UINTEGER_16) r2;
+
+ /* Advance to the next element. */
+ dest += stride0;
+ count[0]++;
+ /* Advance to the next source element. */
+ index_type n = 0;
+ while (count[n] == extent[n])
+ {
+ /* When we get to the end of a dimension, reset it and increment
+ the next dimension. */
+ count[n] = 0;
+ /* We could precalculate these products, but this is a less
+ frequently used path so probably not worth it. */
+ dest -= stride[n] * extent[n];
+ n++;
+ if (n == dim)
+ {
+ dest = NULL;
+ break;
+ }
+ else
+ {
+ count[n]++;
+ dest += stride[n];
+ }
+ }
+ }
+}
+
+#endif
/* Number of elements in master_state array. */
#define SZU64 (sizeof (master_state.s) / sizeof (uint64_t))