/* Generic implementation of the UNPACK intrinsic
- Copyright 2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2002-2020 Free Software Foundation, Inc.
Contributed by Paul Brook <paul@nowt.org>
-This file is part of the GNU Fortran 95 runtime library (libgfortran).
+This file is part of the GNU Fortran runtime library (libgfortran).
Libgfortran is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
<http://www.gnu.org/licenses/>. */
#include "libgfortran.h"
-#include <stdlib.h>
#include <assert.h>
#include <string.h>
+/* All the bounds checking for unpack in one function. If field is NULL,
+ we don't check it, for the unpack0 functions. */
+
+static void
+unpack_bounds (gfc_array_char *ret, const gfc_array_char *vector,
+ const gfc_array_l1 *mask, const gfc_array_char *field)
+{
+ index_type vec_size, mask_count;
+ vec_size = size0 ((array_t *) vector);
+ mask_count = count_0 (mask);
+ if (vec_size < mask_count)
+ runtime_error ("Incorrect size of return value in UNPACK"
+ " intrinsic: should be at least %ld, is"
+ " %ld", (long int) mask_count,
+ (long int) vec_size);
+
+ if (field != NULL)
+ bounds_equal_extents ((array_t *) field, (array_t *) mask,
+ "FIELD", "UNPACK");
+
+ if (ret->base_addr != NULL)
+ bounds_equal_extents ((array_t *) ret, (array_t *) mask,
+ "return value", "UNPACK");
+
+}
+
static void
unpack_internal (gfc_array_char *ret, const gfc_array_char *vector,
const gfc_array_l1 *mask, const gfc_array_char *field,
- index_type size, index_type fsize)
+ index_type size)
{
/* r.* indicates the return array. */
index_type rstride[GFC_MAX_DIMENSIONS];
empty = 0;
- mptr = mask->data;
+ mptr = mask->base_addr;
/* Use the same loop for all logical types, by using GFC_LOGICAL_1
and using shifting to address size and endian issues. */
else
runtime_error ("Funny sized logical array");
- if (ret->data == NULL)
+ if (ret->base_addr == NULL)
{
/* The front end has signalled that we need to populate the
return array descriptor. */
rs *= extent[n];
}
ret->offset = 0;
- ret->data = internal_malloc_size (rs * size);
+ ret->base_addr = xmallocarray (rs, size);
}
else
{
fstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(field, n);
mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n);
}
- if (rstride[0] == 0)
- rstride[0] = size;
}
if (empty)
return;
- if (fstride[0] == 0)
- fstride[0] = fsize;
- if (mstride[0] == 0)
- mstride[0] = 1;
+ /* This assert makes sure GCC knows we can access *stride[0] later. */
+ assert (dim > 0);
vstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0);
- if (vstride0 == 0)
- vstride0 = size;
rstride0 = rstride[0];
fstride0 = fstride[0];
mstride0 = mstride[0];
- rptr = ret->data;
- fptr = field->data;
- vptr = vector->data;
+ rptr = ret->base_addr;
+ fptr = field->base_addr;
+ vptr = vector->base_addr;
while (rptr)
{
index_type type_size;
index_type size;
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, field);
+
type_size = GFC_DTYPE_TYPE_SIZE (vector);
size = GFC_DESCRIPTOR_SIZE (vector);
{
case GFC_DTYPE_LOGICAL_1:
case GFC_DTYPE_INTEGER_1:
- case GFC_DTYPE_DERIVED_1:
unpack1_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector,
mask, (gfc_array_i1 *) field);
return;
mask, (gfc_array_i16 *) field);
return;
#endif
+
case GFC_DTYPE_REAL_4:
unpack1_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) vector,
mask, (gfc_array_r4 *) field);
mask, (gfc_array_r8 *) field);
return;
-#ifdef HAVE_GFC_REAL_10
+/* FIXME: This here is a hack, which will have to be removed when
+ the array descriptor is reworked. Currently, we don't store the
+ kind value for the type, but only the size. Because on targets with
+ __float128, we have sizeof(logn double) == sizeof(__float128),
+ we cannot discriminate here and have to fall back to the generic
+ handling (which is suboptimal). */
+#if !defined(GFC_REAL_16_IS_FLOAT128)
+# ifdef HAVE_GFC_REAL_10
case GFC_DTYPE_REAL_10:
unpack1_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) vector,
mask, (gfc_array_r10 *) field);
- return;
-#endif
+ return;
+# endif
-#ifdef HAVE_GFC_REAL_16
+# ifdef HAVE_GFC_REAL_16
case GFC_DTYPE_REAL_16:
unpack1_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) vector,
mask, (gfc_array_r16 *) field);
return;
+# endif
#endif
case GFC_DTYPE_COMPLEX_4:
mask, (gfc_array_c8 *) field);
return;
-#ifdef HAVE_GFC_COMPLEX_10
+/* FIXME: This here is a hack, which will have to be removed when
+ the array descriptor is reworked. Currently, we don't store the
+ kind value for the type, but only the size. Because on targets with
+ __float128, we have sizeof(logn double) == sizeof(__float128),
+ we cannot discriminate here and have to fall back to the generic
+ handling (which is suboptimal). */
+#if !defined(GFC_REAL_16_IS_FLOAT128)
+# ifdef HAVE_GFC_COMPLEX_10
case GFC_DTYPE_COMPLEX_10:
unpack1_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) vector,
mask, (gfc_array_c10 *) field);
return;
-#endif
+# endif
-#ifdef HAVE_GFC_COMPLEX_16
+# ifdef HAVE_GFC_COMPLEX_16
case GFC_DTYPE_COMPLEX_16:
unpack1_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) vector,
mask, (gfc_array_c16 *) field);
return;
+# endif
#endif
- case GFC_DTYPE_DERIVED_2:
- if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(vector->data)
- || GFC_UNALIGNED_2(field->data))
+ }
+
+ switch (GFC_DESCRIPTOR_SIZE(ret))
+ {
+ case 1:
+ unpack1_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector,
+ mask, (gfc_array_i1 *) field);
+ return;
+
+ case 2:
+ if (GFC_UNALIGNED_2(ret->base_addr) || GFC_UNALIGNED_2(vector->base_addr)
+ || GFC_UNALIGNED_2(field->base_addr))
break;
else
{
return;
}
- case GFC_DTYPE_DERIVED_4:
- if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(vector->data)
- || GFC_UNALIGNED_4(field->data))
+ case 4:
+ if (GFC_UNALIGNED_4(ret->base_addr) || GFC_UNALIGNED_4(vector->base_addr)
+ || GFC_UNALIGNED_4(field->base_addr))
break;
else
{
return;
}
- case GFC_DTYPE_DERIVED_8:
- if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(vector->data)
- || GFC_UNALIGNED_8(field->data))
+ case 8:
+ if (GFC_UNALIGNED_8(ret->base_addr) || GFC_UNALIGNED_8(vector->base_addr)
+ || GFC_UNALIGNED_8(field->base_addr))
break;
else
{
}
#ifdef HAVE_GFC_INTEGER_16
- case GFC_DTYPE_DERIVED_16:
- if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(vector->data)
- || GFC_UNALIGNED_16(field->data))
+ case 16:
+ if (GFC_UNALIGNED_16(ret->base_addr)
+ || GFC_UNALIGNED_16(vector->base_addr)
+ || GFC_UNALIGNED_16(field->base_addr))
break;
else
{
return;
}
#endif
+ default:
+ break;
}
- unpack_internal (ret, vector, mask, field, size,
- GFC_DESCRIPTOR_SIZE (field));
+ unpack_internal (ret, vector, mask, field, size);
}
GFC_INTEGER_4 ret_length __attribute__((unused)),
const gfc_array_char *vector, const gfc_array_l1 *mask,
const gfc_array_char *field, GFC_INTEGER_4 vector_length,
- GFC_INTEGER_4 field_length)
+ GFC_INTEGER_4 field_length __attribute__((unused)))
{
- unpack_internal (ret, vector, mask, field, vector_length, field_length);
+
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, field);
+
+ unpack_internal (ret, vector, mask, field, vector_length);
}
GFC_INTEGER_4 ret_length __attribute__((unused)),
const gfc_array_char *vector, const gfc_array_l1 *mask,
const gfc_array_char *field, GFC_INTEGER_4 vector_length,
- GFC_INTEGER_4 field_length)
+ GFC_INTEGER_4 field_length __attribute__((unused)))
{
+
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, field);
+
unpack_internal (ret, vector, mask, field,
- vector_length * sizeof (gfc_char4_t),
- field_length * sizeof (gfc_char4_t));
+ vector_length * sizeof (gfc_char4_t));
}
gfc_array_char tmp;
index_type type_size;
- index_type size;
+
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, NULL);
type_size = GFC_DTYPE_TYPE_SIZE (vector);
- size = GFC_DESCRIPTOR_SIZE (vector);
- switch(type_size)
+ switch (type_size)
{
case GFC_DTYPE_LOGICAL_1:
case GFC_DTYPE_INTEGER_1:
- case GFC_DTYPE_DERIVED_1:
unpack0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector,
mask, (GFC_INTEGER_1 *) field);
return;
mask, (GFC_INTEGER_16 *) field);
return;
#endif
+
case GFC_DTYPE_REAL_4:
unpack0_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) vector,
mask, (GFC_REAL_4 *) field);
mask, (GFC_REAL_8 *) field);
return;
-#ifdef HAVE_GFC_REAL_10
+/* FIXME: This here is a hack, which will have to be removed when
+ the array descriptor is reworked. Currently, we don't store the
+ kind value for the type, but only the size. Because on targets with
+ __float128, we have sizeof(logn double) == sizeof(__float128),
+ we cannot discriminate here and have to fall back to the generic
+ handling (which is suboptimal). */
+#if !defined(GFC_REAL_16_IS_FLOAT128)
+# ifdef HAVE_GFC_REAL_10
case GFC_DTYPE_REAL_10:
unpack0_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) vector,
mask, (GFC_REAL_10 *) field);
return;
-#endif
+# endif
-#ifdef HAVE_GFC_REAL_16
+# ifdef HAVE_GFC_REAL_16
case GFC_DTYPE_REAL_16:
unpack0_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) vector,
mask, (GFC_REAL_16 *) field);
return;
+# endif
#endif
case GFC_DTYPE_COMPLEX_4:
mask, (GFC_COMPLEX_8 *) field);
return;
-#ifdef HAVE_GFC_COMPLEX_10
+/* FIXME: This here is a hack, which will have to be removed when
+ the array descriptor is reworked. Currently, we don't store the
+ kind value for the type, but only the size. Because on targets with
+ __float128, we have sizeof(logn double) == sizeof(__float128),
+ we cannot discriminate here and have to fall back to the generic
+ handling (which is suboptimal). */
+#if !defined(GFC_REAL_16_IS_FLOAT128)
+# ifdef HAVE_GFC_COMPLEX_10
case GFC_DTYPE_COMPLEX_10:
unpack0_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) vector,
mask, (GFC_COMPLEX_10 *) field);
return;
-#endif
+# endif
-#ifdef HAVE_GFC_COMPLEX_16
+# ifdef HAVE_GFC_COMPLEX_16
case GFC_DTYPE_COMPLEX_16:
unpack0_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) vector,
mask, (GFC_COMPLEX_16 *) field);
return;
+# endif
#endif
- case GFC_DTYPE_DERIVED_2:
- if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(vector->data)
+
+ }
+
+ switch (GFC_DESCRIPTOR_SIZE(ret))
+ {
+ case 1:
+ unpack0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector,
+ mask, (GFC_INTEGER_1 *) field);
+ return;
+
+ case 2:
+ if (GFC_UNALIGNED_2(ret->base_addr) || GFC_UNALIGNED_2(vector->base_addr)
|| GFC_UNALIGNED_2(field))
break;
else
return;
}
- case GFC_DTYPE_DERIVED_4:
- if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(vector->data)
+ case 4:
+ if (GFC_UNALIGNED_4(ret->base_addr) || GFC_UNALIGNED_4(vector->base_addr)
|| GFC_UNALIGNED_4(field))
break;
else
return;
}
- case GFC_DTYPE_DERIVED_8:
- if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(vector->data)
+ case 8:
+ if (GFC_UNALIGNED_8(ret->base_addr) || GFC_UNALIGNED_8(vector->base_addr)
|| GFC_UNALIGNED_8(field))
break;
else
mask, (GFC_INTEGER_8 *) field);
return;
}
+
#ifdef HAVE_GFC_INTEGER_16
- case GFC_DTYPE_DERIVED_16:
- if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(vector->data)
+ case 16:
+ if (GFC_UNALIGNED_16(ret->base_addr)
+ || GFC_UNALIGNED_16(vector->base_addr)
|| GFC_UNALIGNED_16(field))
break;
else
}
memset (&tmp, 0, sizeof (tmp));
- tmp.dtype = 0;
- tmp.data = field;
- unpack_internal (ret, vector, mask, &tmp, GFC_DESCRIPTOR_SIZE (vector), 0);
+ GFC_DTYPE_CLEAR(&tmp);
+ tmp.base_addr = field;
+ unpack_internal (ret, vector, mask, &tmp, GFC_DESCRIPTOR_SIZE (vector));
}
{
gfc_array_char tmp;
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, NULL);
+
memset (&tmp, 0, sizeof (tmp));
- tmp.dtype = 0;
- tmp.data = field;
- unpack_internal (ret, vector, mask, &tmp, vector_length, 0);
+ GFC_DTYPE_CLEAR(&tmp);
+ tmp.base_addr = field;
+ unpack_internal (ret, vector, mask, &tmp, vector_length);
}
{
gfc_array_char tmp;
+ if (unlikely(compile_options.bounds_check))
+ unpack_bounds (ret, vector, mask, NULL);
+
memset (&tmp, 0, sizeof (tmp));
- tmp.dtype = 0;
- tmp.data = field;
+ GFC_DTYPE_CLEAR(&tmp);
+ tmp.base_addr = field;
unpack_internal (ret, vector, mask, &tmp,
- vector_length * sizeof (gfc_char4_t), 0);
+ vector_length * sizeof (gfc_char4_t));
}