floating point environment, untested
authorRich Felker <dalias@aerifal.cx>
Sun, 12 Jun 2011 19:58:15 +0000 (15:58 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 12 Jun 2011 19:58:15 +0000 (15:58 -0400)
at present the i386 code does not support sse floating point, which is
not part of the standard i386 abi. while it may be desirable to
support it later, doing so will reduce performance and require some
tricks to probe if sse support is present.

this first commit is i386-only, but it should be trivial to port the
asm to x86_64.

src/fenv/fegetexceptflag.c [new file with mode: 0644]
src/fenv/feholdexcept.c [new file with mode: 0644]
src/fenv/fenv.c [new file with mode: 0644]
src/fenv/fesetexceptflag.c [new file with mode: 0644]
src/fenv/feupdateenv.c [new file with mode: 0644]
src/fenv/i386/fenv.s [new file with mode: 0644]

diff --git a/src/fenv/fegetexceptflag.c b/src/fenv/fegetexceptflag.c
new file mode 100644 (file)
index 0000000..bab0b44
--- /dev/null
@@ -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 (file)
index 0000000..4c6da23
--- /dev/null
@@ -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 (file)
index 0000000..f77599b
--- /dev/null
@@ -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 (file)
index 0000000..af5f102
--- /dev/null
@@ -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 (file)
index 0000000..50cef8e
--- /dev/null
@@ -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 (file)
index 0000000..72d2ed7
--- /dev/null
@@ -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