diff --git a/ndk/sources/android/libportable/Android.mk b/ndk/sources/android/libportable/Android.mk index 82349e9f7..63428e5cb 100644 --- a/ndk/sources/android/libportable/Android.mk +++ b/ndk/sources/android/libportable/Android.mk @@ -56,7 +56,8 @@ libportable_arch_src_files += \ arch-mips/syscall.c \ arch-mips/timer.c \ arch-mips/timerfd.c \ - arch-mips/waitpid.c + arch-mips/waitpid.c \ + arch-mips/fenv.c libportable_arch_src_files += \ arch-mips/_setjmp.S \ @@ -67,7 +68,8 @@ endif ifeq ($(TARGET_ARCH),arm) libportable_arch_src_files += \ - arch-arm/unwind.c + arch-arm/unwind.c \ + arch-arm/fenv.c endif ifeq ($(TARGET_ARCH),x86) @@ -76,7 +78,8 @@ libportable_arch_src_files += \ arch-x86/fcntl.c \ arch-x86/ioctl.c \ arch-x86/open.c \ - arch-x86/stat.c + arch-x86/stat.c \ + arch-x86/fenv.c endif LOCAL_SRC_FILES := \ diff --git a/ndk/sources/android/libportable/arch-arm/fenv.c b/ndk/sources/android/libportable/arch-arm/fenv.c new file mode 100644 index 000000000..71f370d9f --- /dev/null +++ b/ndk/sources/android/libportable/arch-arm/fenv.c @@ -0,0 +1,104 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __ARM_ARCH_7A__ + +#include +#include +#include + +int WRAP(fegetenv)(fenv_t* __envp) { + fenv_t _fpscr; + __asm__ __volatile__("vmrs %0,fpscr" : "=r" (_fpscr)); + *__envp = _fpscr; + return 0; +} + +int WRAP(fesetenv)(const fenv_t* __envp) { + fenv_t _fpscr = *__envp; + __asm__ __volatile__("vmsr fpscr,%0" : :"ri" (_fpscr)); + return 0; +} + +int WRAP(feclearexcept)(int __excepts) { + fexcept_t __fpscr; + WRAP(fegetenv)(&__fpscr); + __fpscr &= ~__excepts; + WRAP(fesetenv)(&__fpscr); + return 0; +} + +int WRAP(fegetexceptflag)(fexcept_t* __flagp, int __excepts) { + fexcept_t __fpscr; + WRAP(fegetenv)(&__fpscr); + *__flagp = __fpscr & __excepts; + return 0; +} + +int WRAP(fesetexceptflag)(const fexcept_t* __flagp, int __excepts) { + fexcept_t __fpscr; + WRAP(fegetenv)(&__fpscr); + __fpscr &= ~__excepts; + __fpscr |= *__flagp & __excepts; + WRAP(fesetenv)(&__fpscr); + return 0; +} + +int WRAP(feraiseexcept)(int __excepts) { + fexcept_t __ex = __excepts; + WRAP(fesetexceptflag)(&__ex, __excepts); + return 0; +} + +int WRAP(fetestexcept)(int __excepts) { + fexcept_t __fpscr; + WRAP(fegetenv)(&__fpscr); + return (__fpscr & __excepts); +} + +int WRAP(fegetround)(void) { + fenv_t _fpscr; + WRAP(fegetenv)(&_fpscr); + return ((_fpscr >> _FPSCR_RMODE_SHIFT) & 0x3); +} + +int WRAP(fesetround)(int __round) { + fenv_t _fpscr; + WRAP(fegetenv)(&_fpscr); + _fpscr &= ~(0x3 << _FPSCR_RMODE_SHIFT); + _fpscr |= (__round << _FPSCR_RMODE_SHIFT); + WRAP(fesetenv)(&_fpscr); + return 0; +} + +int WRAP(feholdexcept)(fenv_t* __envp) { + fenv_t __env; + WRAP(fegetenv)(&__env); + *__envp = __env; + __env &= ~(FE_ALL_EXCEPT | _FPSCR_ENABLE_MASK); + WRAP(fesetenv)(&__env); + return 0; +} + +int WRAP(feupdateenv)(const fenv_t* __envp) { + fexcept_t __fpscr; + WRAP(fegetenv)(&__fpscr); + WRAP(fesetenv)(__envp); + WRAP(feraiseexcept)(__fpscr & FE_ALL_EXCEPT); + return 0; +} + +#endif /* __ARM_ARCH_7A__ */ diff --git a/ndk/sources/android/libportable/arch-mips/fenv.c b/ndk/sources/android/libportable/arch-mips/fenv.c new file mode 100644 index 000000000..d7b600f9a --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/fenv.c @@ -0,0 +1,208 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +static inline int mips_change_except(int flags) +{ + int mipsflags = 0; + int exception = flags & FE_ALL_EXCEPT_PORTABLE; + + // exception flags + if (exception & FE_INVALID_PORTABLE) + mipsflags |= FE_INVALID; + if (exception & FE_DIVBYZERO_PORTABLE) + mipsflags |= FE_DIVBYZERO; + if (exception & FE_OVERFLOW_PORTABLE) + mipsflags |= FE_OVERFLOW; + if (exception & FE_UNDERFLOW_PORTABLE) + mipsflags |= FE_UNDERFLOW; + if (exception & FE_INEXACT_PORTABLE) + mipsflags |= FE_INEXACT; + + return mipsflags; +} + +static inline int mips_change_rounding(int flags) +{ + int mipsflags = 0; + int rounding = flags & 0x03; + + // rounding flags + switch(rounding) + { + case FE_TONEAREST_PORTABLE: + mipsflags = FE_TONEAREST; + break; + case FE_DOWNWARD_PORTABLE: + mipsflags = FE_DOWNWARD; + break; + case FE_UPWARD_PORTABLE: + mipsflags = FE_UPWARD; + break; + case FE_TOWARDZERO_PORTABLE: + mipsflags = FE_TOWARDZERO; + break; + } + return mipsflags; +} + +static inline int mips_get_except(int mipsflags) +{ + int flags = 0; + int exception = mipsflags & FE_ALL_EXCEPT; + + // exception flags + if (exception & FE_INVALID) + flags |= FE_INVALID_PORTABLE; + if (exception & FE_DIVBYZERO) + flags |= FE_DIVBYZERO_PORTABLE; + if (exception & FE_OVERFLOW) + flags |= FE_OVERFLOW_PORTABLE; + if (exception & FE_UNDERFLOW) + flags |= FE_UNDERFLOW_PORTABLE; + if (exception & FE_INEXACT) + flags |= FE_INEXACT_PORTABLE; + return flags; +} + +static inline int mips_get_rounding(int mipsflags) +{ + int flags = 0; + int rounding = mipsflags & _FCSR_RMASK; + + // rounding flags + switch(rounding) + { + case FE_TONEAREST: + flags = FE_TONEAREST_PORTABLE; + break; + case FE_DOWNWARD: + flags = FE_DOWNWARD_PORTABLE; + break; + case FE_UPWARD: + flags = FE_UPWARD_PORTABLE; + break; + case FE_TOWARDZERO: + flags = FE_TOWARDZERO_PORTABLE; + break; + } + return flags; +} + +int WRAP(fegetenv)(fenv_t* __envp) { + fenv_t _fcsr = 0; +#ifdef __mips_hard_float + __asm__ __volatile__("cfc1 %0,$31" : "=r" (_fcsr)); +#endif + *__envp = _fcsr; + return 0; +} + +int WRAP(fesetenv)(const fenv_t* __envp) { + fenv_t _fcsr = *__envp; +#ifdef __mips_hard_float + __asm__ __volatile__("ctc1 %0,$31" : : "r" (_fcsr)); +#endif + return 0; +} + +int WRAP(feclearexcept)(int __excepts) { + __excepts = mips_change_except(__excepts); + fexcept_t __fcsr; + WRAP(fegetenv)(&__fcsr); + __excepts &= FE_ALL_EXCEPT; + __fcsr &= ~(__excepts | (__excepts << _FCSR_CAUSE_SHIFT)); + WRAP(fesetenv)(&__fcsr); + return 0; +} + +int WRAP(fegetexceptflag)(fexcept_t* __flagp, int __excepts) { + __excepts = mips_change_except(__excepts); + fexcept_t __fcsr; + WRAP(fegetenv)(&__fcsr); + *__flagp = mips_get_except(__fcsr & __excepts & FE_ALL_EXCEPT); + return 0; +} + +int WRAP(fesetexceptflag)(const fexcept_t* __flagp, int __excepts) { + int __flagp_ = mips_change_except(*__flagp); + __excepts = mips_change_except(__excepts); + fexcept_t __fcsr; + WRAP(fegetenv)(&__fcsr); + /* Ensure that flags are all legal */ + __excepts &= FE_ALL_EXCEPT; + __fcsr &= ~__excepts; + __fcsr |= __flagp_ & __excepts; + WRAP(fesetenv)(&__fcsr); + return 0; +} + +int WRAP(feraiseexcept)(int __excepts) { + __excepts = mips_change_except(__excepts); + fexcept_t __fcsr; + WRAP(fegetenv)(&__fcsr); + /* Ensure that flags are all legal */ + __excepts &= FE_ALL_EXCEPT; + /* Cause bit needs to be set as well for generating the exception*/ + __fcsr |= __excepts | (__excepts << _FCSR_CAUSE_SHIFT); + WRAP(fesetenv)(&__fcsr); + return 0; +} + +int WRAP(fetestexcept)(int __excepts) { + __excepts = mips_change_except(__excepts); + fexcept_t __FCSR; + WRAP(fegetenv)(&__FCSR); + return mips_get_except(__FCSR & __excepts & FE_ALL_EXCEPT); +} + +int WRAP(fegetround)(void) { + fenv_t _fcsr; + WRAP(fegetenv)(&_fcsr); + return mips_get_rounding(_fcsr & _FCSR_RMASK); +} + +int WRAP(fesetround)(int __round) { + __round = mips_change_rounding(__round); + fenv_t _fcsr; + WRAP(fegetenv)(&_fcsr); + _fcsr &= ~_FCSR_RMASK; + _fcsr |= (__round & _FCSR_RMASK ); + WRAP(fesetenv)(&_fcsr); + return 0; +} + +int WRAP(feholdexcept)(fenv_t* __envp) { + fenv_t __env; + WRAP(fegetenv)(&__env); + *__envp = __env; + __env &= ~(FE_ALL_EXCEPT | _FCSR_ENABLE_MASK); + WRAP(fesetenv)(&__env); + return 0; +} + +int WRAP(feupdateenv)(const fenv_t* __envp) { + fexcept_t __fcsr; + WRAP(fegetenv)(&__fcsr); + WRAP(fesetenv)(__envp); + WRAP(feraiseexcept)(__fcsr & FE_ALL_EXCEPT); + return 0; +} + diff --git a/ndk/sources/android/libportable/arch-x86/fenv.c b/ndk/sources/android/libportable/arch-x86/fenv.c new file mode 100644 index 000000000..adf6f3048 --- /dev/null +++ b/ndk/sources/android/libportable/arch-x86/fenv.c @@ -0,0 +1,166 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +#include +#include +#include +#include + +static inline int x86_change_except(int flags) +{ + int x86flags = 0; + int exception = flags & FE_ALL_EXCEPT_PORTABLE; + + // exception flags + if (exception & FE_INVALID_PORTABLE) + x86flags |= FE_INVALID; + if (exception & FE_DIVBYZERO_PORTABLE) + x86flags |= FE_DIVBYZERO; + if (exception & FE_OVERFLOW_PORTABLE) + x86flags |= FE_OVERFLOW; + if (exception & FE_UNDERFLOW_PORTABLE) + x86flags |= FE_UNDERFLOW; + if (exception & FE_INEXACT_PORTABLE) + x86flags |= FE_INEXACT; + + return x86flags; +} + +static inline int x86_change_rounding(int flags) +{ + int x86flags = 0; + int rounding = flags & 0x03; + + // rounding flags + switch(rounding) + { + case FE_TONEAREST_PORTABLE: + x86flags = FE_TONEAREST; + break; + case FE_DOWNWARD_PORTABLE: + x86flags = FE_DOWNWARD; + break; + case FE_UPWARD_PORTABLE: + x86flags = FE_UPWARD; + break; + case FE_TOWARDZERO_PORTABLE: + x86flags = FE_TOWARDZERO; + break; + } + return x86flags; +} + +static inline int x86_get_except(int x86flags) +{ + int flags = 0; + int exception = x86flags & FE_ALL_EXCEPT; + + // exception flags + if (exception & FE_INVALID) + flags |= FE_INVALID_PORTABLE; + if (exception & FE_DIVBYZERO) + flags |= FE_DIVBYZERO_PORTABLE; + if (exception & FE_OVERFLOW) + flags |= FE_OVERFLOW_PORTABLE; + if (exception & FE_UNDERFLOW) + flags |= FE_UNDERFLOW_PORTABLE; + if (exception & FE_INEXACT) + flags |= FE_INEXACT_PORTABLE; + + return flags; +} +static inline int x86_get_rounding(int x86flags) +{ + int flags = 0; + int rounding = x86flags & _ROUND_MASK; + + // rounding flags + switch(rounding) + { + case FE_TONEAREST: + flags = FE_TONEAREST_PORTABLE; + break; + case FE_DOWNWARD: + flags = FE_DOWNWARD_PORTABLE; + break; + case FE_UPWARD: + flags = FE_UPWARD_PORTABLE; + break; + case FE_TOWARDZERO: + flags = FE_TOWARDZERO_PORTABLE; + break; + } + + return flags; +} + +int +WRAP(fesetexceptflag)(const fexcept_t *flagp, int excepts) +{ + const fexcept_t flagp_ = x86_change_except(*flagp); + int excepts_ = x86_change_except(excepts); + return REAL(fesetexceptflag)(&flagp_, excepts_); +} + +int +WRAP(fegetexceptflag)(fexcept_t *flagp, int excepts) +{ + REAL(fegetexceptflag)(flagp, x86_change_except(excepts)); + *flagp = x86_get_except(*flagp); + return 0; +} + +int +WRAP(feraiseexcept)(int excepts) +{ + return REAL(feraiseexcept)(x86_change_except(excepts)); +} + +int +WRAP(feclearexcept)(int excepts) +{ + return REAL(feclearexcept)(x86_change_except(excepts)); +} + +int +WRAP(fetestexcept)(int excepts) +{ + return REAL(fetestexcept)(x86_change_except(excepts)); +} + +int +WRAP(fegetround)(void) +{ + int round = REAL(fegetround)(); + return x86_get_rounding(round); +} + +int +WRAP(fesetround)(int round) +{ + return REAL(fesetround)(x86_change_rounding(round)); +} + +int +WRAP(fegetexcept)(void) +{ + int flags = REAL(fegetexcept)(); + return x86_get_except(flags); +} + diff --git a/ndk/sources/android/libportable/common/include/fenv_portable.h b/ndk/sources/android/libportable/common/include/fenv_portable.h new file mode 100644 index 000000000..902c141ae --- /dev/null +++ b/ndk/sources/android/libportable/common/include/fenv_portable.h @@ -0,0 +1,37 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _FENV_PORTABLE_H_ +#define _FENV_PORTABLE_H_ + +#include + +/* Exception flags. */ +#define FE_INVALID_PORTABLE 0x01 +#define FE_DIVBYZERO_PORTABLE 0x02 +#define FE_OVERFLOW_PORTABLE 0x04 +#define FE_UNDERFLOW_PORTABLE 0x08 +#define FE_INEXACT_PORTABLE 0x10 +#define FE_ALL_EXCEPT_PORTABLE (FE_DIVBYZERO_PORTABLE | FE_INEXACT_PORTABLE | FE_INVALID_PORTABLE |\ + FE_OVERFLOW_PORTABLE | FE_UNDERFLOW_PORTABLE) + +/* Rounding modes. */ +#define FE_TONEAREST_PORTABLE 0x0 +#define FE_UPWARD_PORTABLE 0x1 +#define FE_DOWNWARD_PORTABLE 0x2 +#define FE_TOWARDZERO_PORTABLE 0x3 + +#endif /* _FENV_PORTABLE_H_ */