PR 78534, 83704 Handle large formatted I/O
[gcc.git] / libgfortran / runtime / in_pack_generic.c
index 067cd280e0838eeb49d8b83a39f8c5a3c2b205fe..dcc0db92ed3a9ec038988393cf006817cdab2881 100644 (file)
@@ -1,36 +1,29 @@
 /* Generic helper function for repacking arrays.
-   Copyright 2003, 2004, 2005, 2007  Free Software Foundation, Inc.
+   Copyright (C) 2003-2018 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
 License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file.  (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
+version 3 of the License, or (at your option) any later version.
 
 Libgfortran is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public
-License along with libgfortran; see the file COPYING.  If not,
-write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
 
 #include "libgfortran.h"
-#include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 
 extern void *internal_pack (gfc_array_char *);
@@ -51,82 +44,111 @@ internal_pack (gfc_array_char * source)
   int n;
   int packed;
   index_type size;
-  int type;
+  index_type type_size;
 
-  if (source->dim[0].stride == 0)
-    {
-      source->dim[0].stride = 1;
-      return source->data;
-    }
+  if (source->base_addr == NULL)
+    return NULL;
 
-  type = GFC_DESCRIPTOR_TYPE (source);
+  type_size = GFC_DTYPE_TYPE_SIZE(source);
   size = GFC_DESCRIPTOR_SIZE (source);
-  switch (type)
+  switch (type_size)
     {
-    case GFC_DTYPE_INTEGER:
-    case GFC_DTYPE_LOGICAL:
-      switch (size)
-       {
-       case sizeof (GFC_INTEGER_1):
-         return internal_pack_1 ((gfc_array_i1 *) source);
-
-       case sizeof (GFC_INTEGER_2):
-         return internal_pack_2 ((gfc_array_i2 *) source);
-
-       case sizeof (GFC_INTEGER_4):
-         return internal_pack_4 ((gfc_array_i4 *) source);
-         
-       case sizeof (GFC_INTEGER_8):
-         return internal_pack_8 ((gfc_array_i8 *) source);
+    case GFC_DTYPE_INTEGER_1:
+    case GFC_DTYPE_LOGICAL_1:
+    case GFC_DTYPE_DERIVED_1:
+      return internal_pack_1 ((gfc_array_i1 *) source);
+
+    case GFC_DTYPE_INTEGER_2:
+    case GFC_DTYPE_LOGICAL_2:
+      return internal_pack_2 ((gfc_array_i2 *) source);
+
+    case GFC_DTYPE_INTEGER_4:
+    case GFC_DTYPE_LOGICAL_4:
+      return internal_pack_4 ((gfc_array_i4 *) source);
+       
+    case GFC_DTYPE_INTEGER_8:
+    case GFC_DTYPE_LOGICAL_8:
+      return internal_pack_8 ((gfc_array_i8 *) source);
 
 #if defined(HAVE_GFC_INTEGER_16)
-       case sizeof (GFC_INTEGER_16):
-         return internal_pack_16 ((gfc_array_i16 *) source);
+    case GFC_DTYPE_INTEGER_16:
+    case GFC_DTYPE_LOGICAL_16:
+      return internal_pack_16 ((gfc_array_i16 *) source);
 #endif
-       }
-      break;
-
-    case GFC_DTYPE_REAL:
-      switch (size)
-       {
-       case sizeof (GFC_REAL_4):
-         return internal_pack_r4 ((gfc_array_r4 *) source);
-
-       case sizeof (GFC_REAL_8):
-         return internal_pack_r8 ((gfc_array_r8 *) source);
-
-#if defined (HAVE_GFC_REAL_10)
-       case sizeof (GFC_REAL_10):
-         return internal_pack_r10 ((gfc_array_r10 *) source);
+    case GFC_DTYPE_REAL_4:
+      return internal_pack_r4 ((gfc_array_r4 *) source);
+
+    case GFC_DTYPE_REAL_8:
+      return internal_pack_r8 ((gfc_array_r8 *) source);
+
+/* 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)
+# if defined (HAVE_GFC_REAL_10)
+    case GFC_DTYPE_REAL_10:
+      return internal_pack_r10 ((gfc_array_r10 *) source);
+# endif
+
+# if defined (HAVE_GFC_REAL_16)
+    case GFC_DTYPE_REAL_16:
+      return internal_pack_r16 ((gfc_array_r16 *) source);
+# endif
 #endif
 
-#if defined (HAVE_GFC_REAL_16)
-       case sizeof (GFC_REAL_16):
-         return internal_pack_r16 ((gfc_array_r16 *) source);
-#endif
-       }
-    case GFC_DTYPE_COMPLEX:
-      switch (size)
-       {
-       case sizeof (GFC_COMPLEX_4):
-         return internal_pack_c4 ((gfc_array_c4 *) source);
-         
-       case sizeof (GFC_COMPLEX_8):
-         return internal_pack_c8 ((gfc_array_c8 *) source);
-
-#if defined (HAVE_GFC_COMPLEX_10)
-       case sizeof (GFC_COMPLEX_10):
-         return internal_pack_c10 ((gfc_array_c10 *) source);
+    case GFC_DTYPE_COMPLEX_4:
+      return internal_pack_c4 ((gfc_array_c4 *) source);
+       
+    case GFC_DTYPE_COMPLEX_8:
+      return internal_pack_c8 ((gfc_array_c8 *) source);
+
+/* 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)
+# if defined (HAVE_GFC_COMPLEX_10)
+    case GFC_DTYPE_COMPLEX_10:
+      return internal_pack_c10 ((gfc_array_c10 *) source);
+# endif
+
+# if defined (HAVE_GFC_COMPLEX_16)
+    case GFC_DTYPE_COMPLEX_16:
+      return internal_pack_c16 ((gfc_array_c16 *) source);
+# endif
 #endif
 
-#if defined (HAVE_GFC_COMPLEX_16)
-       case sizeof (GFC_COMPLEX_16):
-         return internal_pack_c16 ((gfc_array_c16 *) source);
+    case GFC_DTYPE_DERIVED_2:
+      if (GFC_UNALIGNED_2(source->base_addr))
+       break;
+      else
+       return internal_pack_2 ((gfc_array_i2 *) source);
+
+    case GFC_DTYPE_DERIVED_4:
+      if (GFC_UNALIGNED_4(source->base_addr))
+       break;
+      else
+       return internal_pack_4 ((gfc_array_i4 *) source);
+
+    case GFC_DTYPE_DERIVED_8:
+      if (GFC_UNALIGNED_8(source->base_addr))
+       break;
+      else
+       return internal_pack_8 ((gfc_array_i8 *) source);
+
+#ifdef HAVE_GFC_INTEGER_16
+    case GFC_DTYPE_DERIVED_16:
+      if (GFC_UNALIGNED_16(source->base_addr))
+       break;
+      else
+       return internal_pack_16 ((gfc_array_i16 *) source);
 #endif
 
-       }
-      break;
-
     default:
       break;
     }
@@ -137,8 +159,8 @@ internal_pack (gfc_array_char * source)
   for (n = 0; n < dim; n++)
     {
       count[n] = 0;
-      stride[n] = source->dim[n].stride;
-      extent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound;
+      stride[n] = GFC_DESCRIPTOR_STRIDE(source,n);
+      extent[n] = GFC_DESCRIPTOR_EXTENT(source,n);
       if (extent[n] <= 0)
         {
           /* Do nothing.  */
@@ -153,12 +175,12 @@ internal_pack (gfc_array_char * source)
     }
 
   if (packed)
-    return source->data;
+    return source->base_addr;
 
    /* Allocate storage for the destination.  */
-  destptr = internal_malloc_size (ssize * size);
+  destptr = xmallocarray (ssize, size);
   dest = (char *)destptr;
-  src = source->data;
+  src = source->base_addr;
   stride0 = stride[0] * size;
 
   while (src)