about summary refs log tree commit diff
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