diff --git a/riscv64/fenv.c b/riscv64/fenv.c index 09050922..a0d7b821 100644 --- a/riscv64/fenv.c +++ b/riscv64/fenv.c @@ -26,7 +26,15 @@ * $FreeBSD: head/lib/msun/riscv/fenv.c 332792 2018-04-19 20:36:15Z brooks $ */ +/* + * Keep the hard-float functions private. The FreeBSD-derived FE_* values are + * shifted into fcsr.frm, unlike the raw encodings used on Linux, so exporting + * these functions would interpose an incompatible fenv implementation. + * Soft-float keeps external definitions because the header only declares them. + */ +#ifdef __riscv_float_abi_soft #define __fenv_static +#endif #include #ifdef __GNUC_GNU_INLINE__ @@ -45,7 +53,6 @@ const fenv_t __fe_dfl_env = {0}; #define __env_mask(env) (0) /* No exception traps. */ #define __env_round(env) (((env) >> 5) & _ROUND_MASK) #include "fenv-softfloat.h" -#endif extern inline int feclearexcept(int __excepts); extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); @@ -61,3 +68,4 @@ extern inline int feupdateenv(const fenv_t *__envp); extern inline int feenableexcept(int __mask); extern inline int fedisableexcept(int __mask); extern inline int fegetexcept(void); +#endif /* __riscv_float_abi_soft */ diff --git a/test/Makefile b/test/Makefile index 1665f52f..9e047eea 100644 --- a/test/Makefile +++ b/test/Makefile @@ -23,8 +23,9 @@ regression-build: $(REGRESSION_BINS) # -pthread lets thread-safety regressions (e.g. test-222) spawn threads. It is # harmless for the single-threaded tests and is a no-op stub on glibc >= 2.34. +# -lm lets regressions use platform services that openlibm does not export. regression/%: regression/%.c regression/regress-util.h - $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -pthread -o $@ + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -lm -pthread -o $@ bench: bench-syslibm bench-openlibm diff --git a/test/regression/test-252.c b/test/regression/test-252.c new file mode 100644 index 00000000..9a601def --- /dev/null +++ b/test/regression/test-252.c @@ -0,0 +1,61 @@ +/* + * Regression test for issue #252. Hard-float RISC-V openlibm used to + * interpose its FreeBSD-ABI fenv functions on callers using the incompatible + * Linux ABI. Use the system and pull in libopenlibm through + * isopenlibm(). + */ +#include + +#include "regress-util.h" + +int isopenlibm(void); + +#if !defined(__riscv) || defined(__riscv_float_abi_soft) || \ + !defined(FE_TONEAREST) || !defined(FE_TOWARDZERO) || !defined(FE_UPWARD) + +int +main(void) +{ + return REGRESS_SKIP; +} + +#else + +/* + * Keep the operands volatile and the division out of line: without + * -frounding-math the compiler otherwise folds or moves the divisions across + * the fesetround() calls. + */ +static volatile double one = 1.0, three = 3.0; + +static double __attribute__((noinline)) +divide(void) +{ + volatile double r = one / three; + return r; +} + +int +main(void) +{ + double nearest, down, up; + + CHECK(isopenlibm() == 1); + + nearest = divide(); + CHECK(fesetround(FE_TOWARDZERO) == 0); + CHECK(fegetround() == FE_TOWARDZERO); + down = divide(); + CHECK(fesetround(FE_UPWARD) == 0); + CHECK(fegetround() == FE_UPWARD); + up = divide(); + CHECK(fesetround(FE_TONEAREST) == 0); + CHECK(fegetround() == FE_TONEAREST); + + /* 1/3 is inexact, so the directed modes must bracket the nearest result. */ + CHECK(down < up); + CHECK(down <= nearest && nearest <= up); + return 0; +} + +#endif