summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/bits/fenv.h35
-rw-r--r--src/fenv/powerpc/fenv.s120
2 files changed, 148 insertions, 7 deletions
diff --git a/arch/powerpc/bits/fenv.h b/arch/powerpc/bits/fenv.h
index edbdea2a..b0af1ffe 100644
--- a/arch/powerpc/bits/fenv.h
+++ b/arch/powerpc/bits/fenv.h
@@ -1,10 +1,31 @@
-#define FE_ALL_EXCEPT 0
-#define FE_TONEAREST 0
+#define FE_TONEAREST 0
+#define FE_TOWARDZERO 1
+#define FE_UPWARD 2
+#define FE_DOWNWARD 3
-typedef unsigned long fexcept_t;
+#define FE_INEXACT 0x02000000
+#define FE_DIVBYZERO 0x04000000
+#define FE_UNDERFLOW 0x08000000
+#define FE_OVERFLOW 0x10000000
+#define FE_INVALID 0x20000000
-typedef struct {
- unsigned long __cw;
-} fenv_t;
+#define FE_ALL_EXCEPT 0x3e000000
-#define FE_DFL_ENV ((const fenv_t *) -1)
+#ifdef _GNU_SOURCE
+#define FE_INVALID_SNAN 0x01000000
+#define FE_INVALID_ISI 0x00800000
+#define FE_INVALID_IDI 0x00400000
+#define FE_INVALID_ZDZ 0x00200000
+#define FE_INVALID_IMZ 0x00100000
+#define FE_INVALID_COMPARE 0x00080000
+#define FE_INVALID_SOFTWARE 0x00000400
+#define FE_INVALID_SQRT 0x00000200
+#define FE_INVALID_INTEGER_CONVERSION 0x00000100
+
+#define FE_ALL_INVALID 0x01f80700
+#endif
+
+typedef unsigned fexcept_t;
+typedef double fenv_t;
+
+#define FE_DFL_ENV ((fenv_t *)-1)
diff --git a/src/fenv/powerpc/fenv.s b/src/fenv/powerpc/fenv.s
new file mode 100644
index 00000000..9c424d8e
--- /dev/null
+++ b/src/fenv/powerpc/fenv.s
@@ -0,0 +1,120 @@
+.global feclearexcept
+.type feclearexcept,@function
+feclearexcept:
+ # if (r3 & FE_INVALID) r3 |= all_invalid_flags
+ andis. 0,3,0x2000
+ stwu 1,-16(1)
+ beq- 0,1f
+ oris 3,3,0x01f8
+ ori 3,3,0x0700
+1:
+ # note: fpscr contains various fpu status and control
+ # flags and we dont check if r3 may alter other flags
+ # than the exception related ones
+ # fpscr &= ~r3
+ mffs 0
+ stfd 0,8(1)
+ lwz 9,12(1)
+ andc 9,9,3
+ stw 9,12(1)
+ lfd 0,8(1)
+ mtfsf 255,0
+
+ # return 0
+ li 3,0
+ addi 1,1,16
+ blr
+
+.global feraiseexcept
+.type feraiseexcept,@function
+feraiseexcept:
+ # if (r3 & FE_INVALID) r3 |= software_invalid_flag
+ andis. 0,3,0x2000
+ stwu 1,-16(1)
+ beq- 0,1f
+ ori 3,3,0x0400
+1:
+ # fpscr |= r3
+ mffs 0
+ stfd 0,8(1)
+ lwz 9,12(1)
+ or 9,9,3
+ stw 9,12(1)
+ lfd 0,8(1)
+ mtfsf 255,0
+
+ # return 0
+ li 3,0
+ addi 1,1,16
+ blr
+
+.global fetestexcept
+.type fetestexcept,@function
+fetestexcept:
+ # return r3 & fpscr
+ stwu 1,-16(1)
+ mffs 0
+ stfd 0,8(1)
+ lwz 9,12(1)
+ addi 1,1,16
+ and 3,3,9
+ blr
+
+.global fegetround
+.type fegetround,@function
+fegetround:
+ # return fpscr & 3
+ stwu 1,-16(1)
+ mffs 0
+ stfd 0,8(1)
+ lwz 3,12(1)
+ addi 1,1,16
+ clrlwi 3,3,30
+ blr
+
+.global fesetround
+.type fesetround,@function
+fesetround:
+ # note: invalid input is not checked, r3 < 4 must hold
+ # fpscr = (fpscr & -4U) | r3
+ stwu 1,-16(1)
+ mffs 0
+ stfd 0,8(1)
+ lwz 9,12(1)
+ clrrwi 9,9,2
+ or 9,9,3
+ stw 9,12(1)
+ lfd 0,8(1)
+ mtfsf 255,0
+
+ # return 0
+ li 3,0
+ addi 1,1,16
+ blr
+
+.global fegetenv
+.type fegetenv,@function
+fegetenv:
+ # *r3 = fpscr
+ mffs 0
+ stfd 0,0(3)
+ # return 0
+ li 3,0
+ blr
+
+.global fesetenv
+.type fesetenv,@function
+fesetenv:
+ cmpwi 3, -1
+ bne 1f
+ mflr 4
+ bl 2f
+ .zero 8
+2: mflr 3
+ mtlr 4
+1: # fpscr = *r3
+ lfd 0,0(3)
+ mtfsf 255,0
+ # return 0
+ li 3,0
+ blr