[power-ieee128,committed] Enable conversion selection via environment variable

Message ID ab380e84-088d-b876-0806-7861c668d99b@netcologne.de
State Committed
Commit a574503ff95691c932fd896568f6914a63be4a02
Headers
Series [power-ieee128,committed] Enable conversion selection via environment variable |

Commit Message

Thomas Koenig Jan. 10, 2022, 10:44 p.m. UTC
  Hello world,

I have just pushed the attched patch to the branch.

With this patch, the program

tkoenig@gcc-fortran:~/Tst$ cat write_env.f90
program main
   real(kind=16) :: x
   character (len=30) :: conv
   x = 1/3._16
   open 
(10,file="out.dat",status="replace",access="stream",form="unformatted")
   inquire(10,convert=conv)
   print *,conv
   write (10) 1/3._16
end program main

gives the result:

tkoenig@gcc-fortran:~/Tst$ GFORTRAN_CONVERT_UNIT="r16_ibm:10" ./a.out && 
od -w64 -t x1 out.dat
  LITTLE_ENDIAN,R16_IBM
0000000 55 55 55 55 55 55 d5 3f 56 55 55 55 55 55 75 3c
0000020
tkoenig@gcc-fortran:~/Tst$ GFORTRAN_CONVERT_UNIT="r16_ieee:10" ./a.out 
&& od -w64 -t x1 out.dat
  LITTLE_ENDIAN,R16_IEEE
0000000 80 55 55 55 55 55 55 55 55 55 55 55 55 55 fd 3f
0000020
tkoenig@gcc-fortran:~/Tst$ 
GFORTRAN_CONVERT_UNIT="big_endian:10;r16_ieee:10" ./a.out && od -w64 -t 
x1 out.dat
  BIG_ENDIAN,R16_IEEE
0000000 3f fd 55 55 55 55 55 55 55 55 55 55 55 55 55 80
0000020

so things look OK.  In the next few days, I will do a bit more
testing to see if I have missed any corner cases.

So, the only thing missing is handling of the options, but
I think that is not critical (and could be added later; two
separate possibilities might just be enough for most users :-)

So... time to merge the branch into trunk before stage 4
kicks in?

Best regards

	Thomas


Handle R16 conversion for POWER in the environment variables.

This patch handles the environment variables for the REAL(KIND=16)
variables like for the little/big-endian routines, so users without
who have no access to the source or are unwilling to recompile
can use this.

Syntax is, for example

GFORTRAN_CONVERT_UNIT="r16_ieee:10;little_endian:10" ./a.out

libgfortran/ChangeLog:

         * runtime/environ.c (R16_IEEE): New macro.
         (R16_IBM): New macro.
         (next_token): Handle IBM R16 conversion cases.
         (push_token): Likewise.
         (mark_single): Likewise.
         (do_parse): Likewise, initialize endian.
  

Comments

Jakub Jelinek Jan. 11, 2022, 1:19 p.m. UTC | #1
On Mon, Jan 10, 2022 at 11:44:13PM +0100, Thomas Koenig wrote:
> Hello world,
> 
> I have just pushed the attched patch to the branch.

Thanks.

Here is a patch to fix up the ppc64be vs. ppc64le byteswapping
of IBM extended real(kind=16) and complex(kind=16).
Similarly to the BT_COMPLEX case it halves size and doubles nelems
for the bswap_array calls.  Of course for r16_ibm and r16_ieee conversions
one needs to make sure it is only done when the on file data is in that
format and not in IEEE quad.

> So... time to merge the branch into trunk before stage 4
> kicks in?

IMHO yes.  We need to git merge master; git rebase of course
before trying to cherry-pick those commits into trunk and pushing there.

2022-01-11  Jakub Jelinek  <jakub@redhat.com>

	* io/transfer.c (unformatted_read, unformatted_write): When
	byteswapping IBM extended real(kind=16), handle it as byteswapping
	two real(kind=8) values.

--- libgfortran/io/transfer.c.jj	2022-01-11 13:31:14.881806323 +0100
+++ libgfortran/io/transfer.c	2022-01-11 13:46:00.584288005 +0100
@@ -1145,11 +1145,28 @@ unformatted_read (st_parameter_dt *dtp,
   	  size /= 2;
   	}
 #ifndef HAVE_GFC_REAL_17
+#if defined(HAVE_GFC_REAL_16) && GFC_REAL_16_DIGITS == 106
+      /* IBM extended format is stored as a pair of IEEE754
+	 double values, with the more significant value first
+	 in both big and little endian.  */
+      if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
+	{
+	  nelems *= 2;
+	  size /= 2;
+	}
+#endif
       bswap_array (dest, dest, size, nelems);
 #else
       unit_convert bswap = convert & ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
       if (bswap == GFC_CONVERT_SWAP)
-	bswap_array (dest, dest, size, nelems);
+	{
+	  if ((type == BT_REAL || type == BT_COMPLEX)
+	      && ((kind == 16 && (convert & GFC_CONVERT_R16_IEEE) == 0)
+		  || (kind == 17 && (convert & GFC_CONVERT_R16_IBM))))
+	    bswap_array (dest, dest, size / 2, nelems * 2);
+	  else
+	    bswap_array (dest, dest, size, nelems);
+	}
 
       if ((convert & GFC_CONVERT_R16_IEEE)
 	  && kind == 16
@@ -1274,6 +1291,18 @@ unformatted_write (st_parameter_dt *dtp,
 	  size /= 2;
 	}
 
+#if !defined(HAVE_GFC_REAL_17) && defined(HAVE_GFC_REAL_16) \
+    && GFC_REAL_16_DIGITS == 106
+      /* IBM extended format is stored as a pair of IEEE754
+	 double values, with the more significant value first
+	 in both big and little endian.  */
+      if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
+	{
+	  nelems *= 2;
+	  size /= 2;
+	}
+#endif
+
       /* By now, all complex variables have been split into their
 	 constituent reals.  */
 
@@ -1321,7 +1350,12 @@ unformatted_write (st_parameter_dt *dtp,
 	      if ((dtp->u.p.current_unit->flags.convert
 		   & ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM))
 		  == GFC_CONVERT_SWAP)
-		bswap_array (buffer, buffer, size, nc);
+		bswap_array (buffer, buffer, size / 2, nc * 2);
+	    }
+	  else if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
+	    {
+	      bswap_array (buffer, p, size / 2, nc * 2);
+	      p += size * nc;
 	    }
 	  else
 #endif


	Jakub
  
Thomas Koenig Jan. 11, 2022, 9:44 p.m. UTC | #2
On 11.01.22 14:19, Jakub Jelinek via Fortran wrote:
> On Mon, Jan 10, 2022 at 11:44:13PM +0100, Thomas Koenig wrote:
>> Hello world,
>>
>> I have just pushed the attched patch to the branch.
> 
> Thanks.
> 
> Here is a patch to fix up the ppc64be vs. ppc64le byteswapping
> of IBM extended real(kind=16) and complex(kind=16).
> Similarly to the BT_COMPLEX case it halves size and doubles nelems
> for the bswap_array calls.  Of course for r16_ibm and r16_ieee conversions
> one needs to make sure it is only done when the on file data is in that
> format and not in IEEE quad.


The patch is OK.

>> So... time to merge the branch into trunk before stage 4
>> kicks in?
> 
> IMHO yes.  We need to git merge master; git rebase of course
> before trying to cherry-pick those commits into trunk and pushing there.

I would prefer if somebody else did this - my lack of git-fu would
forseeably lead to some unforseen problems :-)


Best regards

	Thomas
  
Jakub Jelinek Jan. 11, 2022, 11:07 p.m. UTC | #3
On Tue, Jan 11, 2022 at 10:44:56PM +0100, Thomas Koenig wrote:
> > > So... time to merge the branch into trunk before stage 4
> > > kicks in?
> > 
> > IMHO yes.  We need to git merge master; git rebase of course
> > before trying to cherry-pick those commits into trunk and pushing there.
> 
> I would prefer if somebody else did this - my lack of git-fu would
> forseeably lead to some unforseen problems :-)

My git-fu is limited too, but I've pushed it to trunk now.

	Jakub
  

Patch

diff --git a/libgfortran/runtime/environ.c b/libgfortran/runtime/environ.c
index fe16c080797..ff10fe53f68 100644
--- a/libgfortran/runtime/environ.c
+++ b/libgfortran/runtime/environ.c
@@ -247,6 +247,11 @@  init_variables (void)
 #define SWAP     258
 #define BIG      259
 #define LITTLE   260
+#ifdef HAVE_GFC_REAL_17
+#define R16_IEEE 261
+#define R16_IBM  262
+#endif
+
 /* Some space for additional tokens later.  */
 #define INTEGER  273
 #define END      (-1)
@@ -392,6 +397,15 @@  next_token (void)
       result = match_word ("swap", SWAP);
       break;
 
+#ifdef HAVE_GFC_REAL_17
+    case 'r':
+    case 'R':
+      result = match_word ("r16_ieee", R16_IEEE);
+      if (result == ILLEGAL)
+	result = match_word ("r16_ibm", R16_IBM);
+      break;
+
+#endif
     case '1': case '2': case '3': case '4': case '5':
     case '6': case '7': case '8': case '9':
       result = match_integer ();
@@ -414,7 +428,8 @@  push_token (void)
 
 /* This is called when a unit is identified.  If do_count is nonzero,
    increment the number of units by one.  If do_count is zero,
-   put the unit into the table.  */
+   put the unit into the table.  For POWER, we have to make sure that
+   we can also put in the conversion btween IBM and IEEE long double.  */
 
 static void
 mark_single (int unit)
@@ -428,7 +443,11 @@  mark_single (int unit)
     }
   if (search_unit (unit, &i))
     {
+#ifdef HAVE_GFC_REAL_17
+      elist[i].conv |= endian;
+#else
       elist[i].conv = endian;
+#endif
     }
   else
     {
@@ -437,7 +456,11 @@  mark_single (int unit)
 
       n_elist += 1;
       elist[i].unit = unit;
+#ifdef HAVE_GFC_REAL_17
+      elist[i].conv |= endian;
+#else
       elist[i].conv = endian;
+#endif
     }
 }
 
@@ -481,6 +504,8 @@  do_parse (void)
 
   /* Parse the string.  First, let's look for a default.  */
   tok = next_token ();
+  endian = 0;
+
   switch (tok)
     {
     case NATIVE:
@@ -499,6 +524,15 @@  do_parse (void)
       endian = GFC_CONVERT_LITTLE;
       break;
 
+#ifdef HAVE_GFC_REAL_17
+    case R16_IEEE:
+      endian = GFC_CONVERT_R16_IEEE;
+      break;
+
+    case R16_IBM:
+      endian = GFC_CONVERT_R16_IBM;
+      break;
+#endif
     case INTEGER:
       /* A leading digit means that we are looking at an exception.
 	 Reset the position to the beginning, and continue processing
@@ -571,6 +605,19 @@  do_parse (void)
 	    goto error;
 	  endian = GFC_CONVERT_BIG;
 	  break;
+#ifdef HAVE_GFC_REAL_17
+	case R16_IEEE:
+	  if (next_token () != ':')
+	    goto error;
+	  endian = GFC_CONVERT_R16_IEEE;
+	  break;
+
+	case R16_IBM:
+	  if (next_token () != ':')
+	    goto error;
+	  endian = GFC_CONVERT_R16_IBM;
+	  break;
+#endif
 
 	case INTEGER:
 	  push_token ();