diff options
-rw-r--r-- | arch/powerpc/bits/fenv.h | 35 | ||||
-rw-r--r-- | src/fenv/powerpc/fenv.s | 120 |
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 |