This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [libgfortran] I/O of 128 bits integers


This time, the patch is really attached. Sorry.

---------------------------------------------------------
Hi all,

Attached patch is an attempt at handling I/O of 128bits integers, and
any other types of integer in the future.

The libgfortran code relied on int64_t being the largest integer kind:
many parameters were passed as int64_t before being cast into their
final type. This is obviously wrong on some platforms, such as x86_64.
So, I propose we #define GFC_INTEGER_LARGEST to the largest integer kind
available, and use this instead of int64_t.

The question is: how do we know, when compiling the library, which is
the largest available integer kind for the target?

To do some testing, I defined GFC_INTEGER_LARGEST to be __int128_t on
x86_64 and int64_t everywhere else. With that, the patch bootstraps and
is regtested on i686-linux and x86_64-linux. On the latter, I can now do:

$ uname -mo
x86_64 GNU/Linux
$ cat a.f90
  character(len=60) c
  integer(kind=16) i, j

  print *, bit_size(0_16)
  print *, huge(0_16)
  j = 2**(bit_size(0_16)-1) - 2**7
  write (c,*) j
  read (c,*) i
  if (i /= j) call abort
  write (c,'(I60)') j
  read (c,'(I60)') i
  if (i /= j) call abort
  end
$ gfc a.f90 && ./a.out
 128
 170141183460469231731687303715884105727
$


I am waiting for comments on the general idea, the coding-style and choice of name for GFC_INTEGER_LARGEST, as well as idea for a general way to determine this type at compile-time. When everything is settled, I will submit a proper patch (with ChangeLog entries and all).

Thanks,
FX

Index: libgfortran/libgfortran.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/libgfortran.h,v
retrieving revision 1.24
diff -p -u -r1.24 libgfortran.h
--- libgfortran/libgfortran.h	30 Apr 2005 20:51:29 -0000	1.24
+++ libgfortran/libgfortran.h	25 May 2005 21:10:52 -0000
@@ -212,6 +212,14 @@ typedef double GFC_REAL_8;
 typedef complex float GFC_COMPLEX_4;
 typedef complex double GFC_COMPLEX_8;
 
+#ifdef __x86_64__
+#define GFC_INTEGER_LARGEST __int128_t
+#define GFC_UINTEGER_LARGEST __uint128_t
+#else
+#define GFC_INTEGER_LARGEST int64_t
+#define GFC_UINTEGER_LARGEST uint64_t
+#endif
+
 /* The following two definitions must be consistent with the types used
    by the compiler.  */
 /* The type used of array indices, amongst other things.  */
@@ -384,10 +392,10 @@ internal_proto(get_args);
 
 /* error.c */
 
-extern char *gfc_itoa (int64_t);
+extern char *gfc_itoa (GFC_INTEGER_LARGEST);
 internal_proto(gfc_itoa);
 
-extern char *xtoa (uint64_t);
+extern char *xtoa (GFC_UINTEGER_LARGEST);
 internal_proto(xtoa);
 
 extern void os_error (const char *) __attribute__ ((noreturn));
Index: libgfortran/io/io.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/io/io.h,v
retrieving revision 1.20
diff -p -u -r1.20 io.h
--- libgfortran/io/io.h	15 May 2005 12:49:40 -0000	1.20
+++ libgfortran/io/io.h	25 May 2005 21:10:52 -0000
@@ -562,10 +562,10 @@ internal_proto(next_record);
 
 /* read.c */
 
-extern void set_integer (void *, int64_t, int);
+extern void set_integer (void *, GFC_INTEGER_LARGEST, int);
 internal_proto(set_integer);
 
-extern uint64_t max_value (int, int);
+extern GFC_UINTEGER_LARGEST max_value (int, int);
 internal_proto(max_value);
 
 extern int convert_real (void *, const char *, int);
Index: libgfortran/io/list_read.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/io/list_read.c,v
retrieving revision 1.22
diff -p -u -r1.22 list_read.c
--- libgfortran/io/list_read.c	17 May 2005 16:54:51 -0000	1.22
+++ libgfortran/io/list_read.c	25 May 2005 21:10:52 -0000
@@ -344,7 +344,7 @@ convert_integer (int length, int negativ
 {
   char c, *buffer, message[100];
   int m;
-  int64_t v, max, max10;
+  GFC_INTEGER_LARGEST v, max, max10;
 
   buffer = saved_string;
   v = 0;
Index: libgfortran/io/read.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/io/read.c,v
retrieving revision 1.9
diff -p -u -r1.9 read.c
--- libgfortran/io/read.c	10 May 2005 08:34:58 -0000	1.9
+++ libgfortran/io/read.c	25 May 2005 21:10:52 -0000
@@ -43,10 +43,15 @@ Boston, MA 02111-1307, USA.  */
  * actually place the value into memory.  */
 
 void
-set_integer (void *dest, int64_t value, int length)
+set_integer (void *dest, GFC_INTEGER_LARGEST value, int length)
 {
   switch (length)
     {
+#ifdef __x86_64__
+    case 16:
+      *((__int128_t *) dest) = value;
+      break;
+#endif
     case 8:
       *((int64_t *) dest) = value;
       break;
@@ -68,13 +73,23 @@ set_integer (void *dest, int64_t value, 
 /* max_value()-- Given a length (kind), return the maximum signed or
  * unsigned value */
 
-uint64_t
+GFC_UINTEGER_LARGEST
 max_value (int length, int signed_flag)
 {
-  uint64_t value;
+  GFC_UINTEGER_LARGEST value;
+  int n;
 
   switch (length)
     {
+#ifdef __x86_64__
+    case 16:
+      value = 1;
+      for (n = 1; n < 4 * length; n++)
+        value = (value << 2) + 3;
+      if (! signed_flag)
+        value = 2*value+1;
+      break;
+#endif
     case 8:
       value = signed_flag ? 0x7fffffffffffffff : 0xffffffffffffffff;
       break;
@@ -164,11 +179,11 @@ read_l (fnode * f, char *dest, int lengt
     {
     case 't':
     case 'T':
-      set_integer (dest, 1, length);
+      set_integer (dest, (GFC_INTEGER_LARGEST) 1, length);
       break;
     case 'f':
     case 'F':
-      set_integer (dest, 0, length);
+      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
       break;
     default:
     bad:
@@ -263,8 +278,9 @@ next_char (char **p, int *w)
 void
 read_decimal (fnode * f, char *dest, int length)
 {
-  unsigned value, maxv, maxv_10;
-  int v, w, negative;
+  GFC_UINTEGER_LARGEST value, maxv, maxv_10;
+  GFC_INTEGER_LARGEST v;
+  int w, negative;
   char c, *p;
 
   w = f->u.w;
@@ -275,7 +291,7 @@ read_decimal (fnode * f, char *dest, int
   p = eat_leading_spaces (&w, p);
   if (w == 0)
     {
-      set_integer (dest, 0, length);
+      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
       return;
     }
 
@@ -324,7 +340,7 @@ read_decimal (fnode * f, char *dest, int
       value += c;
     }
 
-  v = (signed int) value;
+  v = value;
   if (negative)
     v = -v;
 
@@ -350,8 +366,9 @@ read_decimal (fnode * f, char *dest, int
 void
 read_radix (fnode * f, char *dest, int length, int radix)
 {
-  unsigned value, maxv, maxv_r;
-  int v, w, negative;
+  GFC_UINTEGER_LARGEST value, maxv, maxv_r;
+  GFC_INTEGER_LARGEST v;
+  int w, negative;
   char c, *p;
 
   w = f->u.w;
@@ -362,7 +379,7 @@ read_radix (fnode * f, char *dest, int l
   p = eat_leading_spaces (&w, p);
   if (w == 0)
     {
-      set_integer (dest, 0, length);
+      set_integer (dest, (GFC_INTEGER_LARGEST) 0, length);
       return;
     }
 
@@ -460,7 +477,7 @@ read_radix (fnode * f, char *dest, int l
       value += c;
     }
 
-  v = (signed int) value;
+  v = value;
   if (negative)
     v = -v;
 
Index: libgfortran/io/write.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/io/write.c,v
retrieving revision 1.38
diff -p -u -r1.38 write.c
--- libgfortran/io/write.c	22 May 2005 21:17:42 -0000	1.38
+++ libgfortran/io/write.c	25 May 2005 21:10:55 -0000
@@ -69,10 +69,10 @@ write_a (fnode * f, const char *source, 
     }
 }
 
-static int64_t
+static GFC_INTEGER_LARGEST
 extract_int (const void *p, int len)
 {
-  int64_t i = 0;
+  GFC_INTEGER_LARGEST i = 0;
 
   if (p == NULL)
     return i;
@@ -91,6 +91,11 @@ extract_int (const void *p, int len)
     case 8:
       i = *((const int64_t *) p);
       break;
+#ifdef __x86_64__
+    case 16:
+      i = *((const __int128_t *) p);
+      break;
+#endif
     default:
       internal_error ("bad integer kind");
     }
@@ -673,7 +678,7 @@ void
 write_l (fnode * f, char *source, int len)
 {
   char *p;
-  int64_t n;
+  GFC_INTEGER_LARGEST n;
 
   p = write_block (f->u.w);
   if (p == NULL)
@@ -756,10 +761,11 @@ write_float (fnode *f, const char *sourc
 
 
 static void
-write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t))
+write_int (fnode *f, const char *source, int len,
+           char *(*conv) (GFC_UINTEGER_LARGEST))
 {
   uint32_t ns =0;
-  uint64_t n = 0;
+  GFC_UINTEGER_LARGEST n = 0;
   int w, m, digits, nzero, nblank;
   char *p, *q;
 
@@ -842,9 +848,10 @@ write_int (fnode *f, const char *source,
 }
 
 static void
-write_decimal (fnode *f, const char *source, int len, char *(*conv) (int64_t))
+write_decimal (fnode *f, const char *source, int len,
+               char *(*conv) (GFC_INTEGER_LARGEST))
 {
-  int64_t n = 0;
+  GFC_INTEGER_LARGEST n = 0;
   int w, m, digits, nsign, nzero, nblank;
   char *p, *q;
   sign_t sign;
@@ -930,7 +937,7 @@ write_decimal (fnode *f, const char *sou
 /* Convert unsigned octal to ascii.  */
 
 static char *
-otoa (uint64_t n)
+otoa (GFC_UINTEGER_LARGEST n)
 {
   char *p;
 
@@ -958,7 +965,7 @@ otoa (uint64_t n)
 /* Convert unsigned binary to ascii.  */
 
 static char *
-btoa (uint64_t n)
+btoa (GFC_UINTEGER_LARGEST n)
 {
   char *p;
 
Index: libgfortran/runtime/error.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libgfortran/runtime/error.c,v
retrieving revision 1.9
diff -p -u -r1.9 error.c
--- libgfortran/runtime/error.c	12 Jan 2005 21:27:31 -0000	1.9
+++ libgfortran/runtime/error.c	25 May 2005 21:10:55 -0000
@@ -69,11 +69,11 @@ static char buffer[32];		/* buffer for i
 /* Returns a pointer to a static buffer. */
 
 char *
-gfc_itoa (int64_t n)
+gfc_itoa (GFC_INTEGER_LARGEST n)
 {
   int negative;
   char *p;
-  uint64_t t;
+  GFC_UINTEGER_LARGEST t;
 
   if (n == 0)
     {
@@ -109,7 +109,7 @@ gfc_itoa (int64_t n)
  * static buffer. */
 
 char *
-xtoa (uint64_t n)
+xtoa (GFC_UINTEGER_LARGEST n)
 {
   int digit;
   char *p;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]