From 05be7cdd836643b47dbcf92a48992526a679d8be Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Oct 2024 13:13:35 -0700 Subject: [PATCH] [compiler-rt] Don't raise Inexact exception in C FP add implementation It would be lovely if the soft float implementation were extended to fully support all IEEE exceptions and rounding modes. However, at present, there is only a single place where one exception might be raised: the C version of addition raises Inexact when the result differs from the precise value. This affects targets which have hardware support for some formats and rely on software for other formats; those will expose an implementation of __fe_raise_inexact() that modifies the FPU status register. Removing the Inexact exception generation from the C version of FP addition makes the implementation consistent across all operations and formats on all targets. In addition, it makes the implementation match the semantics of libgcc. Signed-off-by: Keith Packard --- compiler-rt/lib/builtins/fp_add_impl.inc | 2 - .../test/builtins/Unit/adddf3inexact_test.c | 81 +++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 compiler-rt/test/builtins/Unit/adddf3inexact_test.c diff --git a/compiler-rt/lib/builtins/fp_add_impl.inc b/compiler-rt/lib/builtins/fp_add_impl.inc index d20599921e7d8..1b52c163d7a3f 100644 --- a/compiler-rt/lib/builtins/fp_add_impl.inc +++ b/compiler-rt/lib/builtins/fp_add_impl.inc @@ -166,7 +166,5 @@ static __inline fp_t __addXf3__(fp_t a, fp_t b) { case CRT_FE_TOWARDZERO: break; } - if (roundGuardSticky) - __fe_raise_inexact(); return fromRep(result); } diff --git a/compiler-rt/test/builtins/Unit/adddf3inexact_test.c b/compiler-rt/test/builtins/Unit/adddf3inexact_test.c new file mode 100644 index 0000000000000..a417281ba70db --- /dev/null +++ b/compiler-rt/test/builtins/Unit/adddf3inexact_test.c @@ -0,0 +1,81 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_adddf3 + +#include "int_lib.h" +#include +#include +#include + +#if defined(__arm__) && (__ARM_FP & 0xc) == 4 + +/* Run test on arm hardware with 32-bit only FPU */ +# define PERFORM_TEST + +# define ARM_INVALID 0x0001 +# define ARM_DIVBYZERO 0x0002 +# define ARM_OVERFLOW 0x0004 +# define ARM_UNDERFLOW 0x0008 +# define ARM_INEXACT 0x0010 +# define ARM_DENORMAL 0x0080 +# define ARM_ALL_EXCEPT \ + (ARM_DIVBYZERO | ARM_INEXACT | ARM_INVALID | ARM_OVERFLOW | \ + ARM_UNDERFLOW | ARM_DENORMAL) + +static void clear_except(void) { + uint32_t fpscr; + + /* Clear all exception bits */ + __asm__ __volatile__("vmrs %0, fpscr" : "=r"(fpscr)); + fpscr &= ~(ARM_ALL_EXCEPT); + __asm__ __volatile__("vmsr fpscr, %0" : : "ri"(fpscr)); +} + +static int get_except(void) { + uint32_t fpscr; + + /* Test exception bits */ + __asm__ __volatile__("vmrs %0, fpscr" : "=r"(fpscr)); + return (int)(fpscr & ARM_ALL_EXCEPT); +} + +#endif + +#ifdef PERFORM_TEST +int test__adddf3inexact(volatile double a, volatile double b, + volatile double expected) { + volatile double actual; + int ret = 0; + int except; + + clear_except(); + actual = a + b; + if (actual != expected && isnan(actual) != isnan(expected)) { + printf("error in test__adddf3inexact(%a, %a) = %a, expected %a\n", a, b, + actual, expected); + ret = 1; + } + + except = get_except(); + if (except != 0) { + printf("error in test__adddf3inexact(%a, %a). raised exceptions 0x%x\n", a, + b, except); + ret = 1; + } + + return ret; +} +#endif + +int main() { +#ifdef PERFORM_TEST + if (test__adddf3inexact(0x1p+0, 0x1p-53, 0x1p+0)) + return 1; + if (test__adddf3inexact(0x1p+0, 0x1p-52, 0x1.0000000000001p+0)) + return 1; + if (test__adddf3inexact(0x1p+0, NAN, NAN)) + return 1; +#else + printf("skipped\n"); +#endif + return 0; +}