1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fenv.h>
6
7#include <zircon/compiler.h>
8#include <stdint.h>
9
10#define ROUND_MASK (FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)
11
12static inline uint32_t get_fpcr(void) {
13    uint64_t value;
14    __asm__("mrs %0, fpcr" : "=r"(value));
15    return value;
16}
17
18static inline void set_fpcr(uint32_t value) {
19    __asm__("msr fpcr, %0" :: "r"((uint64_t)value));
20}
21
22static inline uint32_t get_fpsr(void) {
23    uint64_t value;
24    __asm__("mrs %0, fpsr" : "=r"(value));
25    return value;
26}
27
28static inline void set_fpsr(uint32_t value) {
29    __asm__("msr fpsr, %0" :: "r"((uint64_t)value));
30}
31
32int fegetround(void) {
33    return get_fpcr() & ROUND_MASK;
34}
35
36__LOCAL int __fesetround(int round) {
37    uint64_t fpcr = get_fpcr();
38    set_fpcr((fpcr & ~ROUND_MASK) | round);
39    return 0;
40}
41
42int feclearexcept(int mask) {
43    set_fpsr(get_fpsr() & ~(mask & FE_ALL_EXCEPT));
44    return 0;
45}
46
47int feraiseexcept(int mask) {
48    set_fpsr(get_fpsr() | (mask & FE_ALL_EXCEPT));
49    return 0;
50}
51
52int fetestexcept(int mask) {
53    return get_fpsr() & mask & FE_ALL_EXCEPT;
54}
55
56int fegetenv(fenv_t* env) {
57    *env = (fenv_t){.__fpcr = get_fpcr(), .__fpsr = get_fpsr()};
58    return 0;
59}
60
61int fesetenv(const fenv_t* env) {
62    uint32_t fpcr = 0, fpsr = 0;
63    if (likely(env != FE_DFL_ENV)) {
64        fpcr = env->__fpcr;
65        fpsr = env->__fpsr;
66    }
67    set_fpcr(fpcr);
68    set_fpsr(fpsr);
69    return 0;
70}
71