summaryrefslogtreecommitdiff
path: root/src/fenv
diff options
context:
space:
mode:
Diffstat (limited to 'src/fenv')
-rw-r--r--src/fenv/fegetexceptflag.c7
-rw-r--r--src/fenv/feholdexcept.c7
-rw-r--r--src/fenv/fenv.c38
-rw-r--r--src/fenv/fesetexceptflag.c8
-rw-r--r--src/fenv/feupdateenv.c9
-rw-r--r--src/fenv/i386/fenv.s75
6 files changed, 144 insertions, 0 deletions
diff --git a/src/fenv/fegetexceptflag.c b/src/fenv/fegetexceptflag.c
new file mode 100644
index 00000000..bab0b44f
--- /dev/null
+++ b/src/fenv/fegetexceptflag.c
@@ -0,0 +1,7 @@
+#include <fenv.h>
+
+int fegetexceptflag(fexcept_t *fp, int mask)
+{
+ *fp = fetestexcept(mask);
+ return 0;
+}
diff --git a/src/fenv/feholdexcept.c b/src/fenv/feholdexcept.c
new file mode 100644
index 00000000..4c6da239
--- /dev/null
+++ b/src/fenv/feholdexcept.c
@@ -0,0 +1,7 @@
+#include <fenv.h>
+
+int feholdexcept(fenv_t *envp)
+{
+ fegetenv(envp);
+ return 0;
+}
diff --git a/src/fenv/fenv.c b/src/fenv/fenv.c
new file mode 100644
index 00000000..f77599bc
--- /dev/null
+++ b/src/fenv/fenv.c
@@ -0,0 +1,38 @@
+#include <fenv.h>
+
+/* Dummy functions for archs lacking fenv implementation */
+
+int feclearexcept(int mask)
+{
+ return 0;
+}
+
+int feraiseexcept(int mask)
+{
+ return 0;
+}
+
+int fetestexcept(int mask)
+{
+ return 0;
+}
+
+int fegetround(void)
+{
+ return 0;
+}
+
+int fesetround(int r)
+{
+ return 0;
+}
+
+int fegetenv(fenv_t *envp)
+{
+ return 0;
+}
+
+int fesetenv(const fenv_t *envp)
+{
+ return 0;
+}
diff --git a/src/fenv/fesetexceptflag.c b/src/fenv/fesetexceptflag.c
new file mode 100644
index 00000000..af5f102d
--- /dev/null
+++ b/src/fenv/fesetexceptflag.c
@@ -0,0 +1,8 @@
+#include <fenv.h>
+
+int fesetexceptflag(const fexcept_t *fp, int mask)
+{
+ feclearexcept(~*fp & mask);
+ feraiseexcept(*fp & mask);
+ return 0;
+}
diff --git a/src/fenv/feupdateenv.c b/src/fenv/feupdateenv.c
new file mode 100644
index 00000000..50cef8e5
--- /dev/null
+++ b/src/fenv/feupdateenv.c
@@ -0,0 +1,9 @@
+#include <fenv.h>
+
+int feupdateenv(const fenv_t *envp)
+{
+ int ex = fetestexcept(FE_ALL_EXCEPT);
+ fesetenv(envp);
+ feraiseexcept(ex);
+ return 0;
+}
diff --git a/src/fenv/i386/fenv.s b/src/fenv/i386/fenv.s
new file mode 100644
index 00000000..72d2ed7d
--- /dev/null
+++ b/src/fenv/i386/fenv.s
@@ -0,0 +1,75 @@
+2: not %ecx
+ sub $32,%esp
+ fnstenv (%esp)
+ and %ecx,4(%esp)
+ or %edx,4(%esp)
+ fldenv (%esp)
+ add $32,%esp
+ ret
+
+.global feclearexcept
+feclearexcept:
+ xor %eax,%eax
+ mov 4(%esp),%ecx
+ xor %edx,%edx
+ test %ecx,%ecx
+ jnz 2b
+ ret
+
+.global feraiseexcept
+feraiseexcept:
+ xor %eax,%eax
+ mov 4(%esp),%edx
+ xor %ecx,%ecx
+ test %edx,%edx
+ jnz 2b
+ ret
+
+.global fesetround
+fesetround:
+ xor %eax,%eax
+ mov $0xc00,%ecx
+ mov 4(%esp),%edx
+ jmp 2b
+
+.global fegetround
+fegetround:
+ sub $28,%esp
+ fnstenv (%esp)
+ mov 4(%esp),%eax
+ add $28,%esp
+ and $0xc,%ah
+ ret
+
+.global fegetenv
+fegetenv:
+ mov 4(%esp),%ecx
+ xor %eax,%eax
+ fnstenv (%ecx)
+ ret
+
+.global fesetenv
+fesetenv:
+ mov 4(%esp),%ecx
+ xor %eax,%eax
+ test %ecx,%ecx
+ jz 1f
+ fldenv (%ecx)
+ ret
+1: push %eax
+ push %eax
+ push %eax
+ push %eax
+ push %eax
+ push %eax
+ pushl $0x37f
+ fldenv (%esp)
+ add $28,%esp
+ ret
+
+.global fetestexcept
+fetestexcept:
+ mov 4(%esp),%ecx
+ fnstsw %ax
+ and %ecx,%eax
+ ret