Bug 59227 - [4.9 regression] FAIL: gfortran.dg/erf_3.F90 -O0 execution test
Summary: [4.9 regression] FAIL: gfortran.dg/erf_3.F90 -O0 execution test
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libfortran (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: 4.9.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on: 59230
Blocks: 49024
  Show dependency treegraph
 
Reported: 2013-11-21 08:35 UTC by Andreas Schwab
Modified: 2020-06-04 08:04 UTC (History)
1 user (show)

See Also:
Host:
Target: ia64-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-11-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas Schwab 2013-11-21 08:35:08 UTC
$ gcc/gfortran -Bgcc/ -Bia64-suse-linux/./libgfortran/ ../gcc/testsuite/gfortran.dg/erf_3.F90 -fno-diagnostics-show-caret -fdiagnostics-color=never -O0 -fno-range-check -ffree-line-length-none -O0 -Bia64-suse-linux/./libgfortran/.libs -Lia64-suse-linux/./libgfortran/.libs -Bia64-suse-linux/./libquadmath/.libs -Lia64-suse-linux/./libquadmath/.libs -lm -o ./erf_3.exe
$ LD_LIBRARY_PATH=ia64-suse-linux/libgfortran/.libs:ia64-suse-linux/libquadmath/.libs ./erf_3.exe 
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   1.00000000000000000000000000000000000E+0000
   1.00000000000000000000000000000000000E+0000
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   0.00000000000000000000000000000000000      
   1.00000000000000000000000000000000000E+0000
   3.11594175678318376063235411046565406E+0955

Program aborted. Backtrace:
#0  0x200000000008084F
#1  0x200000000008477F
#2  0x20000000002665DF
#3  0x400000000000161F in check.850 at erf_3.F90:?
#4  0x4000000000001F3F in MAIN__ at erf_3.F90:?
Aborted
Comment 1 Francois-Xavier Coudert 2013-11-21 08:45:04 UTC
Author: fxcoudert
Date: Thu Nov 21 08:45:00 2013
New Revision: 205193

URL: http://gcc.gnu.org/viewcvs?rev=205193&root=gcc&view=rev
Log:
	PR libfortran/59227
	* intrinsics/erfc_scaled.c (erfc_scaled_r16): Don't define if
	__float128 is not available.

Modified:
    trunk/libgfortran/ChangeLog
    trunk/libgfortran/intrinsics/erfc_scaled.c
Comment 2 Francois-Xavier Coudert 2013-11-21 08:46:48 UTC
Fixed on trunk. Sorry, and thanks Andreas for the report!
Comment 3 Andreas Schwab 2013-11-21 09:21:31 UTC
That's a different bug.
Comment 4 Francois-Xavier Coudert 2013-11-21 09:37:46 UTC
What does this output, when compiled with "-fno-range-check -ffree-line-length-none -O0"?

$ cat test.f90
program test
  real(kind=16) :: x
  x = 12
  print *, erfc_scaled(real(12,kind=16))
  print *, erfc_scaled(x)
end program test
Comment 5 Andreas Schwab 2013-11-21 09:51:06 UTC
   4.68542210148937626195884133993966578E-0002
  -1.87533922948603221391158058278771595E+0920
Comment 6 Francois-Xavier Coudert 2013-11-21 09:58:06 UTC
(In reply to Andreas Schwab from comment #5)
>    4.68542210148937626195884133993966578E-0002
>   -1.87533922948603221391158058278771595E+0920

And this (at -O2)?

__float128 foo (__float128 x)
{
  __float128 sum = 0, oldsum;
  __float128 inv2x2 = 1 / (2 * x * x);
  __float128 fac = 1;
  int n = 1;

  while (n < 200)
  {
    fac *= - (2*n - 1) * inv2x2;
    oldsum = sum;
    sum += fac;

    __builtin_printf ("%lg\n", (double) fac);
    if (sum == oldsum)
      break;

    n++;
  }

  return (1 + sum) / x * (1.1283791670955125738961589031215452Q / 2);
}

int main (void)
{
  __float128 x = 12;
  x = foo(x);
  __builtin_printf ("%lg\n", (double) x);
}
Comment 7 Andreas Schwab 2013-11-21 10:13:28 UTC
-0.00347222
3.6169e-05
-6.27934e-07
1.52623e-08
-4.76946e-10
1.82167e-11
-8.22281e-13
4.28272e-14
-2.52799e-15
1.66777e-16
-1.21608e-17
9.71178e-19
-8.43037e-20
7.90347e-21
-7.95835e-22
8.56628e-23
-9.81553e-24
1.19286e-24
-1.53249e-25
2.07525e-26
-2.95435e-27
4.41101e-28
-6.8922e-29
1.12477e-29
-1.91367e-30
3.38879e-31
-6.23632e-32
1.19096e-32
-2.35711e-33
4.82881e-34
-1.02277e-34
2.23731e-35
-5.04948e-36
1.17471e-36
-2.8144e-37
6.93827e-38
0.0468542
Comment 8 Francois-Xavier Coudert 2013-11-21 10:22:47 UTC
So the calculation inside __gfortran_erfc_scaled_r16 is correct, but the result is printed incorrectly. Can you try this:

program test
  real(kind=16) :: x
  x = 10.9_16 ; print *, erfc_scaled(x)
  x = 11.9_16 ; print *, erfc_scaled(x)
  x = 12.0_16 ; print *, erfc_scaled(x)
  x = 12.1_16 ; print *, erfc_scaled(x)
  x = 13.1_16 ; print *, erfc_scaled(x)
  x = 14.1_16 ; print *, erfc_scaled(x)
end program test

Also, can you confirm that binary128 is not the same as long double on ia64?

(I've sent a request to reopen my old account on the compile farm… If this drags out, I'll investigate on my own there. But for now, I don't have access to an ia64.)
Comment 9 Andreas Schwab 2013-11-21 10:25:21 UTC
Looks like inv2x2 is wrong in _gfortran_erfc_scaled_r16:

(gdb) i reg r42 r43
r42            0x0      0
r43            0x4007200000000000       4613691527636451328
Comment 10 Andreas Schwab 2013-11-21 10:27:04 UTC
   5.15453772226367323012693682499968245E-0002
   4.72452324840876699523132987063922456E-0002
  -1.87533922948603221391158058278771595E+0920
  -5.09942677661379357690770320803840300E+0921
  -2.70969365071138516780674252318715535E+0935
  -1.40653905502094549174911373980686654E+0948
Comment 11 Francois-Xavier Coudert 2013-11-21 10:34:36 UTC
So, it looks like the same code that works fine in an external C program, is miscompiled in libgfortran's _gfortran_erfc_scaled_r16. Do you agree?

Can you remove the __builtin_printf call inside foo() in comment #6, and compile with the same flags as used to compile libgfortran? For me, that would be "-std=gnu99 -fcx-fortran-rules -ffunction-sections -fdata-sections -g -O2" Just to be sure…
Comment 12 Andreas Schwab 2013-11-21 10:50:08 UTC
1 / (2 * x * x) is calling __divtf3 from glibc, which operates on long double, not quad float.  The function from libgcc.a should have been called instead.
Comment 13 Francois-Xavier Coudert 2013-11-21 10:54:37 UTC
(In reply to Andreas Schwab from comment #12)
> 1 / (2 * x * x) is calling __divtf3 from glibc, which operates on long
> double, not quad float.  The function from libgcc.a should have been called
> instead.

Because ia64 uses TFmode for both long double and __float128, while i386 uses XFmode for long double, is that it?

I'm not sure what I can do, then… and don't understand why this does not happen in the standalone test case in comment #6.
Comment 14 Andreas Schwab 2013-11-21 10:57:06 UTC
I think this can be considered a glibc bug, which should not have defined __divtf3 in the first place (the function should have been called __divxf3), and  the test should be XFAILd on ia64.
Comment 15 Francois-Xavier Coudert 2013-11-21 11:06:47 UTC
(In reply to Andreas Schwab from comment #14)
> I think this can be considered a glibc bug, which should not have defined
> __divtf3 in the first place (the function should have been called __divxf3),
> and  the test should be XFAILd on ia64.

Is "ia64-*-linux" the right triplet? If you can confirm that the following patch works as expect on your system, I'll commit it:

Index: erf_3.F90
===================================================================
--- erf_3.F90	(revision 205151)
+++ erf_3.F90	(working copy)
@@ -1,20 +1,29 @@
-! { dg-do run }
+! { dg-do run { xfail spu-*-* ia64-*-linux } }
 ! { dg-options "-fno-range-check -ffree-line-length-none -O0" }
 ! { dg-add-options ieee }
 !
 ! Check that simplification functions and runtime library agree on ERF,
 ! ERFC and ERFC_SCALED, for quadruple-precision.
+!
+! XFAILed for SPU targets because our library implementation of
+! the double-precision erf/erfc functions is not accurate enough.
+!
+! XFAILed for IA64 Linux because of a glibc bug:
+! http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59227
 
 program test
+  use, intrinsic :: iso_fortran_env
   implicit none
 
-  real(kind=16) :: x16
+  ! QP will be the largest supported real kind, possibly real(kind=16)
+  integer, parameter :: qp = real_kinds(ubound(real_kinds,dim=1))
+  real(kind=qp) :: x
 
 #define CHECK(a) \
-  x16 = a ; \
-  call check(erf(real(a,kind=16)), erf(x16)) ; \
-  call check(erfc(real(a,kind=16)), erfc(x16)) ; \
-  call check(erfc_scaled(real(a,kind=16)), erfc_scaled(x16))
+  x = a ; \
+  call check(erf(real(a,kind=qp)), erf(x)) ; \
+  call check(erfc(real(a,kind=qp)), erfc(x)) ; \
+  call check(erfc_scaled(real(a,kind=qp)), erfc_scaled(x))
 
   CHECK(0.0)
   CHECK(0.9)
@@ -36,7 +45,7 @@ program test
 contains
 
   subroutine check (a, b)
-    real(kind=16), intent(in) :: a, b
+    real(kind=qp), intent(in) :: a, b
     print *, abs(a-b) / spacing(a)
     if (abs(a - b) > 10 * spacing(a)) call abort
   end subroutine
Comment 16 Andreas Schwab 2013-11-21 11:08:18 UTC
Perhaps a suitable workaround would be to force linking the right __divtf3 into libgfortran.
Comment 17 Andreas Schwab 2013-11-21 11:19:36 UTC
ia64 was using TFmode for 80 bit long double before r72916, so the __divtf3 name sticked for compatibility.
Comment 18 Francois-Xavier Coudert 2013-11-21 11:37:09 UTC
Author: fxcoudert
Date: Thu Nov 21 11:37:07 2013
New Revision: 205210

URL: http://gcc.gnu.org/viewcvs?rev=205210&root=gcc&view=rev
Log:
	PR libfortran/59227
	* gfortran.dg/erf_3.F90: XFAIL on spu-* and ia64-*-linux*.
	Make more generic for other platforms.

Modified:
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gfortran.dg/erf_3.F90
Comment 19 Francois-Xavier Coudert 2013-11-21 11:38:44 UTC
(In reply to Andreas Schwab from comment #16)
> Perhaps a suitable workaround would be to force linking the right __divtf3
> into libgfortran.

I'm not sure how to force linking in libgfortran, but if it helps reliably fix quad-precision math on ia64, that sounds like a good option.

Meanwhile, I've xfail'ed the test (also on spu-* due to a library issue there, similar to erf_2.F90).
Comment 20 Andreas Schwab 2013-11-21 11:42:10 UTC
It's not really a glibc bug, but a compatilibity wart.
Comment 21 Andreas Schwab 2013-11-21 11:49:24 UTC
> I'm not sure how to force linking in libgfortran

Add libgcc/divtf3_s.o to the link line.
Comment 22 Andreas Schwab 2013-11-21 12:02:47 UTC
Actually it appears to be a libgcc bug.
Comment 23 Francois-Xavier Coudert 2013-11-22 09:16:32 UTC
I saw in your daily tests that the XFAIL indeed silences the failure. Closing as fixed, will un-XFAIL when PR59230 is fixed.
Comment 24 GCC Commits 2020-06-04 08:04:03 UTC
The master branch has been updated by Andreas Schwab <schwab@gcc.gnu.org>:

https://gcc.gnu.org/g:0ecf5229723ec99e6b5099dd68d48bd925da6b0d

commit r11-895-g0ecf5229723ec99e6b5099dd68d48bd925da6b0d
Author: Andreas Schwab <schwab@suse.de>
Date:   Thu Nov 21 15:15:40 2013 +0100

    Missing __divtf3@@GCC_4.4.0 on ia64
    
    gcc/testsuite/
            PR libfortran/59227
            * gfortran.dg/erf_3.F90: Remove XFAIL on ia64-*-linux*.
    
    libgcc/
            PR target/59230
            PR libfortran/59227
            * config/ia64/t-softfp-compat (softfp_file_list): Filter out
            soft-fp/divtf3.c.
            (LIB2ADD): Add config/ia64/divtf3.c.
            * config/ia64/divtf3.c: New file.