Bug 64101 - GCC considers that the erf math function does not set errno
Summary: GCC considers that the erf math function does not set errno
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.7.4
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-28 12:54 UTC by niva
Modified: 2023-12-29 01:03 UTC (History)
4 users (show)

See Also:
Host:
Target: x86_64-*-*, mips64-none-elf
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-11-28 00:00:00


Attachments
The preprocessed source of the test program (3.00 KB, text/plain)
2014-11-28 12:54 UTC, niva
Details

Note You need to log in before you can comment on or make changes to this bug.
Description niva 2014-11-28 12:54:36 UTC
Created attachment 34131 [details]
The preprocessed source of the test program

We use a cross-conpiler configured as follows: 
/home/niva/src/gcc-4.7.4/configure --target=mips64-none-elf --enable-threads=no --disable-shared --enable-long-long --enable-c99 --enable-languages=c --enable-multilib --enable-symvers=gnu --disable-libmudflap --disable-libssp --disable-libgcc_eh --with-newlib --with-dwarf2 --with-system-zlib --enable-generated-files-in-srcdir --verbose --prefix=/home/niva/local --enable-cpp

The following program (the preprocessed source is attached)

#include <assert.h>
#include <errno.h>
#include <math.h>

int main ()
{
   double res;
   errno = 0;
   res = erf (-1.2553634935946022721708238314E-308);
   assert (errno == ERANGE);
   return 0;
}

compiled as

  mips64-none-elf-gcc -O1 tst_erf.c

produces an assertion though we use a POSIX-compliant math
library and the erf function sets errno = ERANGE
according to erf description in POSIX Programmer's Manual.  

The test program works correctly (i.e. without the assertion)
if we compile it with -fno-builtin-erf.

Apparently GCC treats erf as a "clean" or "pure" function
(see gcc/builtins.def). IMHO this is not correct. 

ISO C 99 (see 7.12.8.1) does not state directly whether erf
may set errno. But in 7.12.1 (6) it is stated that
"If the result underflows, the function returns an
implementation-defined value whose magnitude is no greater than the smallest
normalized positive number in the specified type; if the integer expression
math_errhandling & MATH_ERRNO is nonzero, whether errno acquires the
value ERANGE is implementation-defined; if the integer expression
math_errhandling & MATH_ERREXCEPT is nonzero, whether the ‘‘underflow’’
floating-point exception is raised is implementation-defined."

In many Linux erf man pages we read that 
"These functions do not set errno". 

But there is a bug report
https://sourceware.org/bugzilla/show_bug.cgi?id=6785 :
"When erf() is given a subnormal argument, it raises an underflow exception. 
However errno is not set.  It should be set to ERANGE."
Comment 1 Richard Biener 2014-11-28 13:24:56 UTC
I think the issue is that you don't use the result of erf() and the function
is marked as 'const' - thus does not use ATTR_MATHFN_FPROUNDING_ERRNO.
If you make 'res' global then it will work.
Comment 2 niva 2014-12-01 11:21:35 UTC
Please explain why erf is marked as 'const' and
does not use ATTR_MATHFN_FPROUNDING_ERRNO? 
ISO C does not say that erf may not set errno. 
And POSIX directly requires that erf, erff, erfl 
set errno=ERANGE in case of underflow.

Here is another example:

#include <stdio.h>
#include <errno.h>
#include <math.h>

extern double res;
int main ()
{
   errno = 0;
   res = erf (-1.2553634935946022721708238314E-308);
   printf ("errno=%d, res=%g\n", errno, res);
   return 0;
}

As a result of

    mips64-none-elf-gcc -O1 -S tst2_erf.c -o tst2_erf.s

the following code is generated:

main:
	...
	addiu	$sp,$sp,-40
	sd	$31,32($sp)
	sw	$0,%gp_rel(errno)($28)
	jal	erf
	ldc1	$f12,%gp_rel($LC0)($28)

	sdc1	$f0,%gp_rel(res)($28)
	lui	$4,%hi($LC1)	# printf arg 0: format line
	addiu	$4,$4,%lo($LC1)
	dmfc1	$6,$f0		# printf arg 2: res
	jal	printf
	move	$5,$0		#! printf arg 1: zero (must be errno)

	move	$2,$0
	ld	$31,32($sp)
	j	$31
	addiu	$sp,$sp,40

Zero ($0) is passed to printf instead of errno.
If -fno-builtin-printf is used the compiler generates

	lw	$5,%gp_rel(errno)($28)

instead of 

	move	$5,$0

in the delay slot after "jal  printf".





В Птн, 28/11/2014 в 13:24 +0000, rguenth at gcc dot gnu.org пишет:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64101
> 
> Richard Biener <rguenth at gcc dot gnu.org> changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>              Target|                            |x86_64-*-*, mips64-none-elf
>              Status|UNCONFIRMED                 |NEW
>    Last reconfirmed|                            |2014-11-28
>      Ever confirmed|0                           |1
> 
> --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> ---
> I think the issue is that you don't use the result of erf() and the function
> is marked as 'const' - thus does not use ATTR_MATHFN_FPROUNDING_ERRNO.
> If you make 'res' global then it will work.
>
Comment 3 Eric Gallager 2019-01-12 04:56:14 UTC
possibly related to some of the other -fmath-errno bugs that have been under discussion lately?
Comment 4 Eric Gallager 2019-04-12 05:03:15 UTC
(In reply to Eric Gallager from comment #3)
> possibly related to some of the other -fmath-errno bugs that have been under
> discussion lately?

i.e., bug 88576 and bug 37073
Comment 5 Richard Biener 2020-11-13 07:14:14 UTC
Recent glibc documents

       These functions do not set errno.

(and in fact they do not).  GCC does not elide the erf() call with -O0 which is how you can verify your erf implementation sets or does not set errno, at -O1 GCC elides the erf call as the result is unused.

According to Joseph glibcs behavior is correct and so is then GCCs.