Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Floating point status register test fail #195

Closed
kito-cheng opened this issue Nov 7, 2016 · 2 comments
Closed

Floating point status register test fail #195

kito-cheng opened this issue Nov 7, 2016 · 2 comments

Comments

@kito-cheng
Copy link
Collaborator

GCC: riscvarchive/riscv-gcc@bfaf705
Binutils: riscvarchive/riscv-binutils-gdb@6756174
Glibc: riscvarchive/riscv-glibc@7fef429
Qemu: riscvarchive/riscv-qemu@05ac735
Arch: RV32G and RV64G

How to reproduce:

$ riscv32-unknown-linux-gnu-gcc pr68264.c  -lm
$ qemu-riscv32 -L `riscv32-unknown-linux-gnu-gcc --print-sysroot ` a.out
Aborted (core dumped)

Code for pr68264.c:

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

extern void abort (void) __attribute__ ((noreturn));

#define LARGE_NEG_MAYBE_ERANGE 0x01
#define LARGE_NEG_ERANGE       0x02
#define LARGE_POS_ERANGE       0x04
#define LARGE_NEG_EDOM         0x08
#define LARGE_POS_EDOM         0x10

#define LARGE_ERANGE (LARGE_NEG_ERANGE | LARGE_POS_ERANGE)
#define LARGE_EDOM (LARGE_NEG_EDOM | LARGE_POS_EDOM)
#define POWER_ERANGE (LARGE_NEG_MAYBE_ERANGE | LARGE_POS_ERANGE)

#define TEST(CALL, FLAGS) (CALL, tester (FLAGS))

volatile double d;
volatile int i;

static void (*tester) (int);

void
check_quiet_nan (int flags __attribute__ ((unused)))
{
  if (fetestexcept (FE_ALL_EXCEPT))
    abort ();
  if (errno)
    abort ();
}

void
check_large_neg (int flags)
{
  if (flags & LARGE_NEG_MAYBE_ERANGE)
    return;
  int expected_errno = (flags & LARGE_NEG_ERANGE ? ERANGE
			: flags & LARGE_NEG_EDOM ? EDOM
			: 0);
  if (expected_errno != errno)
    abort ();
  errno = 0;
}

void
check_large_pos (int flags)
{
  int expected_errno = (flags & LARGE_POS_ERANGE ? ERANGE
			: flags & LARGE_POS_EDOM ? EDOM
			: 0);
  if (expected_errno != errno)
    abort ();
  errno = 0;
}

void
test (void)
{
  TEST (acos (d), LARGE_EDOM);
  TEST (asin (d), LARGE_EDOM);
  TEST (acosh (d), LARGE_NEG_EDOM);
  TEST (atanh (d), LARGE_EDOM);
  TEST (cosh (d), LARGE_ERANGE);
  TEST (sinh (d), LARGE_ERANGE);
  TEST (log (d), LARGE_NEG_EDOM);
#if defined (__sun__) && defined (__unix__)
  /* Disabled due to a bug in Solaris libm.  */
  if (0)
#endif
    TEST (log2 (d), LARGE_NEG_EDOM);
  TEST (log10 (d), LARGE_NEG_EDOM);
#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 22))
  /* Disabled due to glibc PR 6792, fixed in glibc 2.22.  */
  if (0)
#endif
    TEST (log1p (d), LARGE_NEG_EDOM);
  TEST (exp (d), POWER_ERANGE);
#if (defined (__sun__) || defined(__hppa__)) && defined (__unix__)
  /* Disabled due to a bug in Solaris libm.  HP PA-RISC libm doesn't support
     ERANGE for exp2.  */
  if (0)
#endif
    {
      TEST (exp2 (d), POWER_ERANGE);
#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 11))
      /* Disabled due to glibc PR 6788, fixed in glibc 2.11.  */
      if (0)
#endif
	TEST (expm1 (d), POWER_ERANGE);
    }
  TEST (sqrt (d), LARGE_NEG_EDOM);
  TEST (pow (100.0, d), POWER_ERANGE);
  TEST (pow (i, d), POWER_ERANGE);
}

int
main (void)
{
  errno = 0;
  i = 100;
  d = __builtin_nan ("");
  tester = check_quiet_nan;
  feclearexcept (FE_ALL_EXCEPT);
  test ();

  d = -1.0e80;
  tester = check_large_neg;
  errno = 0;
  test ();

  d = 1.0e80;
  tester = check_large_pos;
  errno = 0;
  test ();

  return 0;
}

@kito-cheng
Copy link
Collaborator Author

I guess this test fail is come from qemu or glibc, so create issue here.

@aswaterman
Copy link
Collaborator

This is actually a GCC problem. We're emitting incorrect code for things like __builtin_islessgreater (using signaling comparisons FLT/FLE where we shouldn't). We should instead emit something like

feq.s t0, fa0, fa0
beqz t0, 1f
feq.s t0, fa1, fa1
beqz t0, 1f
feq.s t0, fa0, fa1
xori t0, t0, 1
1:

or even something like

frflags t2
flt.s t0, fa0, fa1
flt.s t1, fa1, fa0
or t0, t0, t1
fsflags t2

aswaterman added a commit to riscvarchive/riscv-gcc that referenced this issue Nov 9, 2016
This implementation is not ideal, but it should reslove
riscv-collab/riscv-gnu-toolchain#195

@kito-cheng can you do the usual?  Thanks.
aswaterman added a commit to riscvarchive/riscv-gcc that referenced this issue Dec 13, 2016
This implementation is not ideal, but it should reslove
riscv-collab/riscv-gnu-toolchain#195

@kito-cheng can you do the usual?  Thanks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants