fenv support for ppc, untested
authorRich Felker <dalias@aerifal.cx>
Sun, 18 Nov 2012 21:31:14 +0000 (16:31 -0500)
committerRich Felker <dalias@aerifal.cx>
Sun, 18 Nov 2012 21:31:14 +0000 (16:31 -0500)
based on code sent to the mailing list by nsz, with minor changes.

arch/powerpc/bits/fenv.h
src/fenv/powerpc/fenv.s [new file with mode: 0644]

index edbdea2a5efcda22054568550ef555acdf14cd35..b0af1ffee851683c8aa89d2d4ebe37e04a59ebbb 100644 (file)
@@ -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 (file)
index 0000000..9c424d8
--- /dev/null
@@ -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