about summary refs log tree commit diff
path: root/src/fenv/powerpc64/fenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fenv/powerpc64/fenv.c')
-rw-r--r--src/fenv/powerpc64/fenv.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/fenv/powerpc64/fenv.c b/src/fenv/powerpc64/fenv.c
new file mode 100644
index 00000000..739420b7
--- /dev/null
+++ b/src/fenv/powerpc64/fenv.c
@@ -0,0 +1,68 @@
+#define _GNU_SOURCE
+#include <fenv.h>
+
+static inline double get_fpscr_f(void)
+{
+	double d;
+	__asm__ __volatile__("mffs %0" : "=d"(d));
+	return d;
+}
+
+static inline long get_fpscr(void)
+{
+	return (union {double f; long i;}) {get_fpscr_f()}.i;
+}
+
+static inline void set_fpscr_f(double fpscr)
+{
+	__asm__ __volatile__("mtfsf 255, %0" : : "d"(fpscr));
+}
+
+static void set_fpscr(long fpscr)
+{
+	set_fpscr_f((union {long i; double f;}) {fpscr}.f);
+}
+
+int feclearexcept(int mask)
+{
+	mask &= FE_ALL_EXCEPT;
+	if (mask & FE_INVALID) mask |= FE_ALL_INVALID;
+	set_fpscr(get_fpscr() & ~mask);
+	return 0;
+}
+
+int feraiseexcept(int mask)
+{
+	mask &= FE_ALL_EXCEPT;
+	if (mask & FE_INVALID) mask |= FE_INVALID_SOFTWARE;
+	set_fpscr(get_fpscr() | mask);
+	return 0;
+}
+
+int fetestexcept(int mask)
+{
+	return get_fpscr() & mask & FE_ALL_EXCEPT;
+}
+
+int fegetround(void)
+{
+	return get_fpscr() & 3;
+}
+
+int __fesetround(int r)
+{
+	set_fpscr(get_fpscr() & ~3L | r);
+	return 0;
+}
+
+int fegetenv(fenv_t *envp)
+{
+	*envp = get_fpscr_f();
+	return 0;
+}
+
+int fesetenv(const fenv_t *envp)
+{
+	set_fpscr_f(envp != FE_DFL_ENV ? *envp : 0);
+	return 0;
+}